Skip to content

Commit 01731e0

Browse files
authored
fix(types): add type declarations for the rclnodejs/rosocket subpath (#1533)
The `./rosocket` subpath export shipped **no type declarations**, so under `node16`/`nodenext` module resolution: - `import { startRosocket } from 'rclnodejs/rosocket'` failed with **TS7016** (the module implicitly had an `any` type). - `@arethetypeswrong` reported **No types** for the subpath across every resolution mode. ### Changes - **Add `rosocket/index.d.ts`** — types the public entry point (`startRosocket`, `StartRosocketOptions`, `RosocketServer`), matched against `rosocket/index.js` (`port=9000`, `host='0.0.0.0'`, required `node`, returns `{ wss, close, port }`). `wss` is typed as its `EventEmitter` supertype to avoid a hard dependency on `ws` types. - **Add `rosocket/index.d.cts`** — a CommonJS-format companion (re-exporting the `.d.ts`) so the `require` condition resolves to a CJS type file and is not flagged as "Masquerading as ESM". - **Wire per-condition `types` into the `./rosocket` export** in `package.json` (`import` → `index.d.ts`, `require` → `index.d.cts`). Fix: #1532
1 parent 774b637 commit 01731e0

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,14 @@
2626
"default": "./dist/server.js"
2727
},
2828
"./rosocket": {
29-
"import": "./dist/rosocket.js",
30-
"require": "./dist/rosocket.cjs",
29+
"import": {
30+
"types": "./rosocket/index.d.ts",
31+
"default": "./dist/rosocket.js"
32+
},
33+
"require": {
34+
"types": "./rosocket/index.d.cts",
35+
"default": "./dist/rosocket.cjs"
36+
},
3137
"default": "./dist/rosocket.js"
3238
},
3339
"./lib/*": "./lib/*.js",

rosocket/index.d.cts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2026 RobotWebTools Contributors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// CommonJS type entry for `require('rclnodejs/rosocket')`.
16+
//
17+
// Re-exports the ESM declarations so the `require` condition has a CommonJS
18+
// (`.d.cts`) type file whose module format matches the CommonJS JavaScript
19+
// served by the same condition.
20+
export * from './index.js';

rosocket/index.d.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright (c) 2026 RobotWebTools Contributors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Type surface for the `rclnodejs/rosocket` subpath export.
16+
//
17+
// `rosocket` exposes ROS 2 topics and services as plain WebSocket URLs that
18+
// carry ROS messages as JSON. Only the public `startRosocket` entry point is
19+
// typed here.
20+
21+
import type { EventEmitter } from 'node:events';
22+
import type { IncomingMessage } from 'node:http';
23+
import type { Node } from 'rclnodejs';
24+
25+
/** Options accepted by {@link startRosocket}. */
26+
export interface StartRosocketOptions {
27+
/** rclnodejs Node to host publishers/subscriptions/clients on. */
28+
node: Node;
29+
/** Port to listen on. Default `9000`. */
30+
port?: number;
31+
/** Host to bind to. Default `'0.0.0.0'`. */
32+
host?: string;
33+
/**
34+
* Optional default type per topic name,
35+
* e.g. `{ '/chatter': 'std_msgs/msg/String' }`.
36+
*/
37+
topicTypes?: Record<string, string>;
38+
/** Optional default type per service name. */
39+
serviceTypes?: Record<string, string>;
40+
/**
41+
* Optional auth hook called with the raw HTTP upgrade request; return
42+
* `false` to reject the connection.
43+
*/
44+
verifyClient?: (req: IncomingMessage) => boolean;
45+
}
46+
47+
/** Handle returned by {@link startRosocket}. */
48+
export interface RosocketServer {
49+
/**
50+
* The underlying WebSocket server (a `ws` `WebSocketServer`, typed here as
51+
* its `EventEmitter` supertype to avoid a hard dependency on `ws` types).
52+
*/
53+
wss: EventEmitter;
54+
/** Stop the gateway and close all connections. */
55+
close: () => Promise<void>;
56+
/** The port the gateway is listening on. */
57+
port: number;
58+
}
59+
60+
/**
61+
* Start a resource-style WebSocket gateway that exposes ROS 2 topics and
62+
* services as plain WebSocket URLs carrying ROS messages as JSON.
63+
*
64+
* URL scheme:
65+
* - `ws://host:port/topic/<topic_name>?type=<pkg>/msg/<Type>`
66+
* - `ws://host:port/service/<service_name>?type=<pkg>/srv/<Type>`
67+
*
68+
* @param options - Gateway configuration. `options.node` is required.
69+
* @returns A Promise resolving with the gateway handle.
70+
*/
71+
export function startRosocket(
72+
options: StartRosocketOptions
73+
): Promise<RosocketServer>;

0 commit comments

Comments
 (0)