streamkit-orchestrator 0.4.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 StreamKit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # @streamkit/orchestrator
2
+
3
+ Lightweight stream orchestrator for coordinating multiple WebRTC streams.
4
+
5
+ ## What This Package Does
6
+
7
+ The orchestrator acts as a coordination layer that:
8
+
9
+ - **Registers** multiple named streams (binary or JSON)
10
+ - **Enables/disables** streams dynamically
11
+ - **Routes** incoming data to the correct handler
12
+ - **Coordinates** stream state via control messages
13
+
14
+ ## What This Package Does NOT Do
15
+
16
+ - ❌ WebRTC signaling (offer/answer exchange)
17
+ - ❌ Binary frame parsing (delegated to @streamkit/binary-stream)
18
+ - ❌ DataChannel management (delegated to @streamkit/webrtc)
19
+ - ❌ Data decoding or rendering
20
+ - ❌ Retry or reconnection logic
21
+
22
+ ## Position in the Stack
23
+
24
+ ```
25
+ ┌─────────────────────┐
26
+ │ Your Application │
27
+ └──────────┬──────────┘
28
+
29
+
30
+ ┌─────────────────────┐
31
+ │ @streamkit/ │ ← THIS PACKAGE
32
+ │ orchestrator │ Coordinates streams
33
+ └──────────┬──────────┘
34
+
35
+ ┌─────┴─────┐
36
+ │ │
37
+ ▼ ▼
38
+ ┌─────────┐ ┌─────────┐
39
+ │ binary │ │ json │
40
+ │ streams │ │ streams │
41
+ └────┬────┘ └────┬────┘
42
+ │ │
43
+ ▼ │
44
+ ┌─────────────┐ │
45
+ │ @streamkit/ │ │
46
+ │ webrtc │ │
47
+ └──────┬──────┘ │
48
+ │ │
49
+ ▼ │
50
+ ┌─────────────┐ │
51
+ │ @streamkit/ │ │
52
+ │ binary- │ │
53
+ │ stream │ │
54
+ └──────┬──────┘ │
55
+ │ │
56
+ └────┬────┘
57
+
58
+
59
+ ┌─────────────────────┐
60
+ │ RTCPeerConnection │
61
+ └─────────────────────┘
62
+ ```
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ npm install @streamkit/orchestrator
68
+ ```
69
+
70
+ ## Quick Start
71
+
72
+ ```typescript
73
+ import { createOrchestrator } from "@streamkit/orchestrator";
74
+
75
+ // You create and configure the peer connection
76
+ const pc = new RTCPeerConnection();
77
+
78
+ // Create orchestrator
79
+ const orch = createOrchestrator({ pc });
80
+
81
+ // Register a binary stream (e.g., point cloud data)
82
+ orch.registerStream({
83
+ name: "pointcloud",
84
+ type: "binary",
85
+ onFrame(frame) {
86
+ console.log("PointCloud frame:", frame.id, frame.payload.byteLength);
87
+ // Pass to @streamkit/pointcloud decoder
88
+ },
89
+ });
90
+
91
+ // Register a JSON stream (e.g., telemetry)
92
+ orch.registerStream({
93
+ name: "telemetry",
94
+ type: "json",
95
+ onMessage(data) {
96
+ console.log("Telemetry:", data);
97
+ },
98
+ });
99
+
100
+ // Enable streams when ready
101
+ orch.enable("pointcloud");
102
+ orch.enable("telemetry");
103
+
104
+ // Later: disable a stream
105
+ orch.disable("pointcloud");
106
+
107
+ // Cleanup
108
+ orch.dispose();
109
+ ```
110
+
111
+ ## Mental Model
112
+
113
+ Think of the orchestrator as a **switchboard operator**:
114
+
115
+ 1. **Registration** = Plugging in a phone line (no connection yet)
116
+ 2. **Enable** = Connecting the call (DataChannel created)
117
+ 3. **Disable** = Hanging up (DataChannel closed)
118
+ 4. **Control messages** = Signaling to the remote switchboard
119
+
120
+ ```
121
+ Local Orchestrator Remote Orchestrator
122
+ │ │
123
+ │ ──── control: enable ───► │
124
+ │ │
125
+ │ ◄─── data frames ──────── │
126
+ │ │
127
+ │ ──── control: disable ──► │
128
+ │ │
129
+ ```
130
+
131
+ ## API Reference
132
+
133
+ ### `createOrchestrator(options)`
134
+
135
+ Creates a stream orchestrator.
136
+
137
+ **Options:**
138
+
139
+ | Option | Type | Description |
140
+ | ------------------ | ------------------------------- | --------------------------------- |
141
+ | `pc` | `RTCPeerConnection` | The peer connection to manage |
142
+ | `onError` | `(error: Error) => void` | Optional error callback |
143
+ | `onControlMessage` | `(msg: ControlMessage) => void` | Optional control message observer |
144
+
145
+ **Returns:** `Orchestrator`
146
+
147
+ ### `Orchestrator`
148
+
149
+ ```typescript
150
+ interface Orchestrator {
151
+ registerStream(descriptor: StreamDescriptor): void;
152
+ enable(name: string): void;
153
+ disable(name: string): void;
154
+ isEnabled(name: string): boolean;
155
+ isRegistered(name: string): boolean;
156
+ getStreamNames(): string[];
157
+ sendControl(message: ControlMessage): void;
158
+ dispose(): void;
159
+ }
160
+ ```
161
+
162
+ ### Stream Descriptors
163
+
164
+ #### Binary Stream
165
+
166
+ For frame-based binary data (point clouds, video frames, sensor data):
167
+
168
+ ```typescript
169
+ orch.registerStream({
170
+ name: "pointcloud",
171
+ type: "binary",
172
+ enabledByDefault: false,
173
+ maxFrameSize: 10_000_000, // 10MB max frame
174
+ maxBufferSize: 50_000_000, // 50MB buffer limit
175
+ onFrame(frame) {
176
+ // frame.id: number
177
+ // frame.timestamp: number
178
+ // frame.payload: ArrayBuffer
179
+ },
180
+ });
181
+ ```
182
+
183
+ #### JSON Stream
184
+
185
+ For structured messages (telemetry, commands, events):
186
+
187
+ ```typescript
188
+ orch.registerStream({
189
+ name: "telemetry",
190
+ type: "json",
191
+ enabledByDefault: true,
192
+ onMessage(data) {
193
+ // data: unknown (parsed JSON)
194
+ },
195
+ });
196
+ ```
197
+
198
+ ### Control Messages
199
+
200
+ Control messages coordinate stream state between peers:
201
+
202
+ ```typescript
203
+ interface ControlMessage {
204
+ type: "control";
205
+ stream: string;
206
+ enabled: boolean;
207
+ }
208
+ ```
209
+
210
+ **Automatic behavior:**
211
+
212
+ - `enable()` sends `{ type: 'control', stream: 'name', enabled: true }`
213
+ - `disable()` sends `{ type: 'control', stream: 'name', enabled: false }`
214
+
215
+ **Manual control:**
216
+
217
+ ```typescript
218
+ orch.sendControl({
219
+ type: "control",
220
+ stream: "custom",
221
+ enabled: true,
222
+ });
223
+ ```
224
+
225
+ ## Integration with @streamkit/pointcloud
226
+
227
+ ```typescript
228
+ import { createOrchestrator } from "@streamkit/orchestrator";
229
+ import { createPointCloudLayer, decodeDraco } from "@streamkit/pointcloud";
230
+
231
+ const scene = new THREE.Scene();
232
+ const layer = createPointCloudLayer({ scene });
233
+
234
+ const orch = createOrchestrator({ pc });
235
+
236
+ orch.registerStream({
237
+ name: "pointcloud",
238
+ type: "binary",
239
+ async onFrame(frame) {
240
+ // Decode Draco-compressed point cloud
241
+ const data = await decodeDraco(frame.payload);
242
+ // Update Three.js layer
243
+ layer.update(data, { mode: "append" });
244
+ },
245
+ });
246
+
247
+ orch.enable("pointcloud");
248
+ ```
249
+
250
+ ## Lifecycle
251
+
252
+ ```
253
+ ┌──────────────┐
254
+ │ registered │ ← registerStream()
255
+ └──────┬───────┘
256
+ │ enable()
257
+
258
+ ┌──────────────┐
259
+ │ enabled │ ← DataChannel open, receiving data
260
+ └──────┬───────┘
261
+ │ disable()
262
+
263
+ ┌──────────────┐
264
+ │ disabled │ ← DataChannel closed
265
+ └──────┬───────┘
266
+ │ enable() (can re-enable)
267
+
268
+ ...
269
+
270
+ │ dispose()
271
+
272
+ ┌──────────────┐
273
+ │ disposed │ ← All resources released
274
+ └──────────────┘
275
+ ```
276
+
277
+ ## TypeScript
278
+
279
+ Full type exports:
280
+
281
+ ```typescript
282
+ import type {
283
+ Orchestrator,
284
+ OrchestratorOptions,
285
+ StreamDescriptor,
286
+ BinaryStreamDescriptor,
287
+ JSONStreamDescriptor,
288
+ StreamType,
289
+ ControlMessage,
290
+ BinaryFrame,
291
+ } from "@streamkit/orchestrator";
292
+ ```
293
+
294
+ ## Design Principles
295
+
296
+ 1. **Lazy initialization**: Channels created only on `enable()`
297
+ 2. **Explicit lifecycle**: No hidden state transitions
298
+ 3. **Delegation**: Frame parsing and channel management delegated to specialized packages
299
+ 4. **Coordination**: Control messages keep both peers in sync
300
+ 5. **Minimal surface**: Only what's needed for orchestration
301
+
302
+ ## License
303
+
304
+ MIT
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @streamkit/orchestrator - Control Channel
3
+ *
4
+ * Dedicated channel for orchestrator control messages.
5
+ */
6
+ import type { ControlMessage } from "./types.js";
7
+ /** Reserved channel name for control messages */
8
+ export declare const CONTROL_CHANNEL_LABEL = "__streamkit_control__";
9
+ /**
10
+ * Validates and parses a control message.
11
+ * @param data - Raw message data
12
+ * @returns Parsed ControlMessage or null if invalid
13
+ */
14
+ export declare function parseControlMessage(data: unknown): ControlMessage | null;
15
+ /**
16
+ * Serializes a control message to JSON string.
17
+ * @param message - Control message to serialize
18
+ */
19
+ export declare function serializeControlMessage(message: ControlMessage): string;
20
+ /**
21
+ * Creates a control message for stream state change.
22
+ * @param streamName - Name of the stream
23
+ * @param enabled - Whether stream is being enabled
24
+ */
25
+ export declare function createControlMessage(streamName: string, enabled: boolean): ControlMessage;
26
+ /**
27
+ * Internal control channel manager.
28
+ */
29
+ export interface ControlChannel {
30
+ send(message: ControlMessage): void;
31
+ close(): void;
32
+ readonly isOpen: boolean;
33
+ }
34
+ /**
35
+ * Creates a control channel on the peer connection.
36
+ * @param pc - RTCPeerConnection
37
+ * @param onMessage - Callback for incoming control messages
38
+ * @param onError - Optional error callback
39
+ */
40
+ export declare function createControlChannel(pc: RTCPeerConnection, onMessage: (message: ControlMessage) => void, onError?: (error: Error) => void): ControlChannel;
41
+ /**
42
+ * Sets up handler for incoming control channels from remote peer.
43
+ * @param pc - RTCPeerConnection
44
+ * @param onMessage - Callback for incoming control messages
45
+ */
46
+ export declare function handleIncomingControlChannel(pc: RTCPeerConnection, onMessage: (message: ControlMessage) => void): void;
47
+ //# sourceMappingURL=controlChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controlChannel.d.ts","sourceRoot":"","sources":["../src/controlChannel.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,iDAAiD;AACjD,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAoBxE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAEvE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,cAAc,CAMhB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,EAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC/B,cAAc,CA0EhB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,EAAE,EAAE,iBAAiB,EACrB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,GAC3C,IAAI,CA2BN"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @streamkit/orchestrator - Control Channel
3
+ *
4
+ * Dedicated channel for orchestrator control messages.
5
+ */
6
+ /** Reserved channel name for control messages */
7
+ export const CONTROL_CHANNEL_LABEL = "__streamkit_control__";
8
+ /**
9
+ * Validates and parses a control message.
10
+ * @param data - Raw message data
11
+ * @returns Parsed ControlMessage or null if invalid
12
+ */
13
+ export function parseControlMessage(data) {
14
+ if (typeof data !== "object" || data === null) {
15
+ return null;
16
+ }
17
+ const msg = data;
18
+ if (msg.type !== "control" ||
19
+ typeof msg.stream !== "string" ||
20
+ typeof msg.enabled !== "boolean") {
21
+ return null;
22
+ }
23
+ return {
24
+ type: "control",
25
+ stream: msg.stream,
26
+ enabled: msg.enabled,
27
+ };
28
+ }
29
+ /**
30
+ * Serializes a control message to JSON string.
31
+ * @param message - Control message to serialize
32
+ */
33
+ export function serializeControlMessage(message) {
34
+ return JSON.stringify(message);
35
+ }
36
+ /**
37
+ * Creates a control message for stream state change.
38
+ * @param streamName - Name of the stream
39
+ * @param enabled - Whether stream is being enabled
40
+ */
41
+ export function createControlMessage(streamName, enabled) {
42
+ return {
43
+ type: "control",
44
+ stream: streamName,
45
+ enabled,
46
+ };
47
+ }
48
+ /**
49
+ * Creates a control channel on the peer connection.
50
+ * @param pc - RTCPeerConnection
51
+ * @param onMessage - Callback for incoming control messages
52
+ * @param onError - Optional error callback
53
+ */
54
+ export function createControlChannel(pc, onMessage, onError) {
55
+ const channel = pc.createDataChannel(CONTROL_CHANNEL_LABEL, {
56
+ ordered: true,
57
+ });
58
+ // Control channel uses string messages (JSON)
59
+ channel.binaryType = "arraybuffer"; // Not used, but required
60
+ let isOpen = false;
61
+ let isClosed = false;
62
+ channel.onopen = () => {
63
+ isOpen = true;
64
+ };
65
+ channel.onclose = () => {
66
+ isOpen = false;
67
+ isClosed = true;
68
+ };
69
+ channel.onerror = (event) => {
70
+ const error = new Error(`Control channel error: ${event}`);
71
+ onError?.(error);
72
+ console.error("Orchestrator control channel error:", event);
73
+ };
74
+ channel.onmessage = (event) => {
75
+ try {
76
+ const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
77
+ const message = parseControlMessage(data);
78
+ if (message) {
79
+ onMessage(message);
80
+ }
81
+ }
82
+ catch (err) {
83
+ console.warn("Orchestrator: invalid control message received", err);
84
+ }
85
+ };
86
+ return {
87
+ send(message) {
88
+ if (isClosed) {
89
+ throw new Error("Control channel is closed");
90
+ }
91
+ if (!isOpen) {
92
+ // Queue message until channel opens
93
+ const checkAndSend = () => {
94
+ if (isOpen && !isClosed) {
95
+ channel.send(serializeControlMessage(message));
96
+ }
97
+ else if (!isClosed) {
98
+ setTimeout(checkAndSend, 10);
99
+ }
100
+ };
101
+ checkAndSend();
102
+ return;
103
+ }
104
+ channel.send(serializeControlMessage(message));
105
+ },
106
+ close() {
107
+ if (!isClosed) {
108
+ isClosed = true;
109
+ isOpen = false;
110
+ channel.close();
111
+ }
112
+ },
113
+ get isOpen() {
114
+ return isOpen;
115
+ },
116
+ };
117
+ }
118
+ /**
119
+ * Sets up handler for incoming control channels from remote peer.
120
+ * @param pc - RTCPeerConnection
121
+ * @param onMessage - Callback for incoming control messages
122
+ */
123
+ export function handleIncomingControlChannel(pc, onMessage) {
124
+ const existingHandler = pc.ondatachannel;
125
+ pc.ondatachannel = (event) => {
126
+ if (event.channel.label === CONTROL_CHANNEL_LABEL) {
127
+ const channel = event.channel;
128
+ channel.onmessage = (msgEvent) => {
129
+ try {
130
+ const data = typeof msgEvent.data === "string"
131
+ ? JSON.parse(msgEvent.data)
132
+ : null;
133
+ const message = parseControlMessage(data);
134
+ if (message) {
135
+ onMessage(message);
136
+ }
137
+ }
138
+ catch (err) {
139
+ console.warn("Orchestrator: invalid control message received", err);
140
+ }
141
+ };
142
+ }
143
+ else {
144
+ // Pass through to existing handler if any
145
+ existingHandler?.call(pc, event);
146
+ }
147
+ };
148
+ }
149
+ //# sourceMappingURL=controlChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controlChannel.js","sourceRoot":"","sources":["../src/controlChannel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @streamkit/orchestrator
3
+ *
4
+ * Lightweight stream orchestrator for coordinating multiple WebRTC streams.
5
+ *
6
+ * This package provides:
7
+ * - Multi-stream registration and management
8
+ * - Dynamic enable/disable of streams
9
+ * - Control message coordination
10
+ * - Automatic routing to stream handlers
11
+ *
12
+ * This package does NOT provide:
13
+ * - WebRTC signaling
14
+ * - Binary frame parsing (delegated to @streamkit/binary-stream)
15
+ * - DataChannel management (delegated to @streamkit/webrtc)
16
+ * - Data decoding or rendering
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ export type { BaseStreamDescriptor, BinaryFrame, BinaryStreamDescriptor, ControlMessage, JSONStreamDescriptor, Orchestrator, OrchestratorOptions, StreamDescriptor, StreamType, } from "./types.js";
21
+ export { createOrchestrator } from "./orchestrator.js";
22
+ export { CONTROL_CHANNEL_LABEL, createControlMessage, parseControlMessage, } from "./controlChannel.js";
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,oBAAoB,EACpB,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAMvD,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @streamkit/orchestrator
3
+ *
4
+ * Lightweight stream orchestrator for coordinating multiple WebRTC streams.
5
+ *
6
+ * This package provides:
7
+ * - Multi-stream registration and management
8
+ * - Dynamic enable/disable of streams
9
+ * - Control message coordination
10
+ * - Automatic routing to stream handlers
11
+ *
12
+ * This package does NOT provide:
13
+ * - WebRTC signaling
14
+ * - Binary frame parsing (delegated to @streamkit/binary-stream)
15
+ * - DataChannel management (delegated to @streamkit/webrtc)
16
+ * - Data decoding or rendering
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ // =============================================================================
21
+ // Orchestrator Factory
22
+ // =============================================================================
23
+ export { createOrchestrator } from "./orchestrator.js";
24
+ // =============================================================================
25
+ // Control Channel Utilities
26
+ // =============================================================================
27
+ export { CONTROL_CHANNEL_LABEL, createControlMessage, parseControlMessage, } from "./controlChannel.js";
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAkBH,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,gFAAgF;AAChF,4BAA4B;AAC5B,gFAAgF;AAEhF,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @streamkit/orchestrator - Stream Orchestrator Implementation
3
+ *
4
+ * Coordinates multiple logical streams over a single RTCPeerConnection.
5
+ */
6
+ import type { Orchestrator, OrchestratorOptions } from "./types.js";
7
+ /**
8
+ * Creates a stream orchestrator for coordinating multiple WebRTC streams.
9
+ *
10
+ * The orchestrator:
11
+ * - Registers streams by unique name
12
+ * - Lazily creates DataChannels on enable()
13
+ * - Routes incoming data to correct handlers
14
+ * - Sends/receives control messages for coordination
15
+ *
16
+ * @param options - Orchestrator configuration
17
+ * @returns Orchestrator controller
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const orch = createOrchestrator({ pc });
22
+ *
23
+ * orch.registerStream({
24
+ * name: 'pointcloud',
25
+ * type: 'binary',
26
+ * onFrame(frame) {
27
+ * console.log('Frame:', frame.id);
28
+ * }
29
+ * });
30
+ *
31
+ * orch.enable('pointcloud');
32
+ * ```
33
+ */
34
+ export declare function createOrchestrator(options: OrchestratorOptions): Orchestrator;
35
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,KAAK,EAIV,YAAY,EACZ,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAepB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAgV7E"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * @streamkit/orchestrator - Stream Orchestrator Implementation
3
+ *
4
+ * Coordinates multiple logical streams over a single RTCPeerConnection.
5
+ */
6
+ import { createBinaryStream } from "@streamkit/binary-stream";
7
+ import { createWebRTCBinaryChannel, wrapDataChannel } from "@streamkit/webrtc";
8
+ import { CONTROL_CHANNEL_LABEL, createControlChannel, createControlMessage, handleIncomingControlChannel, } from "./controlChannel.js";
9
+ /**
10
+ * Creates a stream orchestrator for coordinating multiple WebRTC streams.
11
+ *
12
+ * The orchestrator:
13
+ * - Registers streams by unique name
14
+ * - Lazily creates DataChannels on enable()
15
+ * - Routes incoming data to correct handlers
16
+ * - Sends/receives control messages for coordination
17
+ *
18
+ * @param options - Orchestrator configuration
19
+ * @returns Orchestrator controller
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const orch = createOrchestrator({ pc });
24
+ *
25
+ * orch.registerStream({
26
+ * name: 'pointcloud',
27
+ * type: 'binary',
28
+ * onFrame(frame) {
29
+ * console.log('Frame:', frame.id);
30
+ * }
31
+ * });
32
+ *
33
+ * orch.enable('pointcloud');
34
+ * ```
35
+ */
36
+ export function createOrchestrator(options) {
37
+ const { pc, onError, onControlMessage } = options;
38
+ if (!pc) {
39
+ throw new Error("Orchestrator: RTCPeerConnection is required");
40
+ }
41
+ // Internal state
42
+ const streams = new Map();
43
+ let controlChannel = null;
44
+ let disposed = false;
45
+ // ─────────────────────────────────────────────────────────────────────────
46
+ // Control Channel Setup
47
+ // ─────────────────────────────────────────────────────────────────────────
48
+ /**
49
+ * Handles incoming control messages.
50
+ */
51
+ function handleControlMessage(message) {
52
+ // Notify application
53
+ onControlMessage?.(message);
54
+ // Handle stream enable/disable from remote
55
+ const stream = streams.get(message.stream);
56
+ if (stream) {
57
+ if (message.enabled && !stream.enabled) {
58
+ enableStreamInternal(message.stream, false); // Don't send control back
59
+ }
60
+ else if (!message.enabled && stream.enabled) {
61
+ disableStreamInternal(message.stream, false); // Don't send control back
62
+ }
63
+ }
64
+ }
65
+ // Create outgoing control channel
66
+ controlChannel = createControlChannel(pc, handleControlMessage, onError);
67
+ // Handle incoming control channel from remote peer
68
+ handleIncomingControlChannel(pc, handleControlMessage);
69
+ // Handle incoming data channels from remote peer
70
+ setupIncomingDataChannelHandler();
71
+ // ─────────────────────────────────────────────────────────────────────────
72
+ // Incoming Channel Handling
73
+ // ─────────────────────────────────────────────────────────────────────────
74
+ function setupIncomingDataChannelHandler() {
75
+ const existingHandler = pc.ondatachannel;
76
+ pc.ondatachannel = (event) => {
77
+ const channel = event.channel;
78
+ const label = channel.label;
79
+ // Skip control channel (handled separately)
80
+ if (label === CONTROL_CHANNEL_LABEL) {
81
+ existingHandler?.call(pc, event);
82
+ return;
83
+ }
84
+ // Find registered stream
85
+ const managed = streams.get(label);
86
+ if (!managed) {
87
+ console.warn(`Orchestrator: received channel for unknown stream '${label}'`);
88
+ channel.close();
89
+ return;
90
+ }
91
+ // Setup channel based on stream type
92
+ if (managed.descriptor.type === "binary") {
93
+ setupIncomingBinaryChannel(managed, channel);
94
+ }
95
+ else {
96
+ setupIncomingJSONChannel(managed, channel);
97
+ }
98
+ managed.enabled = true;
99
+ };
100
+ }
101
+ function setupIncomingBinaryChannel(managed, channel) {
102
+ const descriptor = managed.descriptor;
103
+ // Create binary stream for frame reassembly
104
+ managed.binaryStream = createBinaryStream({
105
+ maxFrameSize: descriptor.maxFrameSize,
106
+ maxBufferSize: descriptor.maxBufferSize,
107
+ dropStrategy: "oldest",
108
+ onFrame: descriptor.onFrame,
109
+ });
110
+ // Wrap incoming channel
111
+ managed.webrtcChannel = wrapDataChannel(channel, (chunk) => managed.binaryStream?.push(chunk));
112
+ }
113
+ function setupIncomingJSONChannel(managed, channel) {
114
+ const descriptor = managed.descriptor;
115
+ channel.binaryType = "arraybuffer";
116
+ managed.jsonChannel = channel;
117
+ channel.onmessage = (event) => {
118
+ try {
119
+ const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
120
+ if (data !== null) {
121
+ descriptor.onMessage(data);
122
+ }
123
+ }
124
+ catch (err) {
125
+ console.warn(`Orchestrator: invalid JSON on stream '${descriptor.name}'`, err);
126
+ }
127
+ };
128
+ }
129
+ // ─────────────────────────────────────────────────────────────────────────
130
+ // Stream Management
131
+ // ─────────────────────────────────────────────────────────────────────────
132
+ function assertNotDisposed() {
133
+ if (disposed) {
134
+ throw new Error("Orchestrator has been disposed");
135
+ }
136
+ }
137
+ function enableStreamInternal(name, sendControl) {
138
+ const managed = streams.get(name);
139
+ if (!managed) {
140
+ throw new Error(`Orchestrator: stream '${name}' not registered`);
141
+ }
142
+ if (managed.enabled) {
143
+ return; // Already enabled
144
+ }
145
+ if (managed.descriptor.type === "binary") {
146
+ enableBinaryStream(managed);
147
+ }
148
+ else {
149
+ enableJSONStream(managed);
150
+ }
151
+ managed.enabled = true;
152
+ // Send control message to remote
153
+ if (sendControl) {
154
+ controlChannel?.send(createControlMessage(name, true));
155
+ }
156
+ }
157
+ function disableStreamInternal(name, sendControl) {
158
+ const managed = streams.get(name);
159
+ if (!managed) {
160
+ throw new Error(`Orchestrator: stream '${name}' not registered`);
161
+ }
162
+ if (!managed.enabled) {
163
+ return; // Already disabled
164
+ }
165
+ // Cleanup resources
166
+ if (managed.descriptor.type === "binary") {
167
+ managed.webrtcChannel?.close();
168
+ managed.binaryStream?.dispose();
169
+ managed.webrtcChannel = undefined;
170
+ managed.binaryStream = undefined;
171
+ }
172
+ else {
173
+ managed.jsonChannel?.close();
174
+ managed.jsonChannel = undefined;
175
+ }
176
+ managed.enabled = false;
177
+ // Send control message to remote
178
+ if (sendControl) {
179
+ controlChannel?.send(createControlMessage(name, false));
180
+ }
181
+ }
182
+ function enableBinaryStream(managed) {
183
+ const descriptor = managed.descriptor;
184
+ // Create binary stream for frame reassembly
185
+ managed.binaryStream = createBinaryStream({
186
+ maxFrameSize: descriptor.maxFrameSize,
187
+ maxBufferSize: descriptor.maxBufferSize,
188
+ dropStrategy: "oldest",
189
+ onFrame: descriptor.onFrame,
190
+ });
191
+ // Create WebRTC channel
192
+ managed.webrtcChannel = createWebRTCBinaryChannel({
193
+ pc,
194
+ label: descriptor.name,
195
+ ordered: true,
196
+ onChunk: (chunk) => managed.binaryStream?.push(chunk),
197
+ onStateChange: (state) => {
198
+ if (state === "closed") {
199
+ managed.enabled = false;
200
+ }
201
+ },
202
+ });
203
+ }
204
+ function enableJSONStream(managed) {
205
+ const descriptor = managed.descriptor;
206
+ const channel = pc.createDataChannel(descriptor.name, {
207
+ ordered: true,
208
+ });
209
+ channel.binaryType = "arraybuffer";
210
+ managed.jsonChannel = channel;
211
+ channel.onmessage = (event) => {
212
+ try {
213
+ const data = typeof event.data === "string" ? JSON.parse(event.data) : null;
214
+ if (data !== null) {
215
+ descriptor.onMessage(data);
216
+ }
217
+ }
218
+ catch (err) {
219
+ console.warn(`Orchestrator: invalid JSON on stream '${descriptor.name}'`, err);
220
+ }
221
+ };
222
+ channel.onclose = () => {
223
+ managed.enabled = false;
224
+ };
225
+ }
226
+ // ─────────────────────────────────────────────────────────────────────────
227
+ // Public Interface
228
+ // ─────────────────────────────────────────────────────────────────────────
229
+ return {
230
+ registerStream(descriptor) {
231
+ assertNotDisposed();
232
+ if (!descriptor.name) {
233
+ throw new Error("Orchestrator: stream name is required");
234
+ }
235
+ if (streams.has(descriptor.name)) {
236
+ throw new Error(`Orchestrator: stream '${descriptor.name}' already registered`);
237
+ }
238
+ const streamType = descriptor.type;
239
+ if (streamType !== "binary" && streamType !== "json") {
240
+ throw new Error(`Orchestrator: invalid stream type '${streamType}'`);
241
+ }
242
+ const managed = {
243
+ descriptor,
244
+ enabled: false,
245
+ };
246
+ streams.set(descriptor.name, managed);
247
+ // Enable if configured
248
+ if (descriptor.enabledByDefault) {
249
+ enableStreamInternal(descriptor.name, true);
250
+ }
251
+ },
252
+ enable(name) {
253
+ assertNotDisposed();
254
+ enableStreamInternal(name, true);
255
+ },
256
+ disable(name) {
257
+ assertNotDisposed();
258
+ disableStreamInternal(name, true);
259
+ },
260
+ isEnabled(name) {
261
+ const managed = streams.get(name);
262
+ return managed?.enabled ?? false;
263
+ },
264
+ isRegistered(name) {
265
+ return streams.has(name);
266
+ },
267
+ getStreamNames() {
268
+ return Array.from(streams.keys());
269
+ },
270
+ sendControl(message) {
271
+ assertNotDisposed();
272
+ controlChannel?.send(message);
273
+ },
274
+ dispose() {
275
+ if (disposed)
276
+ return;
277
+ disposed = true;
278
+ // Disable all streams (without sending control)
279
+ for (const name of streams.keys()) {
280
+ const managed = streams.get(name);
281
+ if (managed?.enabled) {
282
+ if (managed.descriptor.type === "binary") {
283
+ managed.webrtcChannel?.close();
284
+ managed.binaryStream?.dispose();
285
+ }
286
+ else {
287
+ managed.jsonChannel?.close();
288
+ }
289
+ }
290
+ }
291
+ streams.clear();
292
+ // Close control channel
293
+ controlChannel?.close();
294
+ controlChannel = null;
295
+ },
296
+ };
297
+ }
298
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @streamkit/orchestrator - Type Definitions
3
+ *
4
+ * Types for stream orchestration and coordination.
5
+ */
6
+ import type { BinaryFrame } from "@streamkit/binary-stream";
7
+ /**
8
+ * Stream transport type.
9
+ */
10
+ export type StreamType = "binary" | "json";
11
+ /**
12
+ * Base descriptor for all stream types.
13
+ */
14
+ export interface BaseStreamDescriptor {
15
+ /** Unique stream identifier */
16
+ name: string;
17
+ /** Transport type */
18
+ type: StreamType;
19
+ /** Whether stream is enabled on registration (default: false) */
20
+ enabledByDefault?: boolean;
21
+ }
22
+ /**
23
+ * Descriptor for binary frame streams.
24
+ * Uses @streamkit/binary-stream for frame reassembly.
25
+ */
26
+ export interface BinaryStreamDescriptor extends BaseStreamDescriptor {
27
+ type: "binary";
28
+ /** Callback for complete binary frames */
29
+ onFrame: (frame: BinaryFrame) => void;
30
+ /** Maximum frame size in bytes (default: 10MB) */
31
+ maxFrameSize?: number;
32
+ /** Maximum buffer size in bytes (default: 50MB) */
33
+ maxBufferSize?: number;
34
+ }
35
+ /**
36
+ * Descriptor for JSON message streams.
37
+ * Used for control messages, telemetry, and structured data.
38
+ */
39
+ export interface JSONStreamDescriptor extends BaseStreamDescriptor {
40
+ type: "json";
41
+ /** Callback for parsed JSON messages */
42
+ onMessage: (data: unknown) => void;
43
+ }
44
+ /**
45
+ * Union type for all stream descriptors.
46
+ */
47
+ export type StreamDescriptor = BinaryStreamDescriptor | JSONStreamDescriptor;
48
+ /**
49
+ * Control message format for stream coordination.
50
+ */
51
+ export interface ControlMessage {
52
+ type: "control";
53
+ stream: string;
54
+ enabled: boolean;
55
+ }
56
+ /**
57
+ * Options for creating an orchestrator.
58
+ */
59
+ export interface OrchestratorOptions {
60
+ /** RTCPeerConnection to manage streams on */
61
+ pc: RTCPeerConnection;
62
+ /** Optional callback for orchestrator-level errors */
63
+ onError?: (error: Error) => void;
64
+ /** Optional callback for control messages received */
65
+ onControlMessage?: (message: ControlMessage) => void;
66
+ }
67
+ /**
68
+ * Stream orchestrator interface.
69
+ */
70
+ export interface Orchestrator {
71
+ /**
72
+ * Register a stream descriptor.
73
+ * Does not open the channel until enable() is called.
74
+ * @param descriptor - Stream configuration
75
+ */
76
+ registerStream(descriptor: StreamDescriptor): void;
77
+ /**
78
+ * Enable a registered stream.
79
+ * Creates the DataChannel and starts receiving data.
80
+ * Sends control message to remote peer.
81
+ * @param name - Stream name
82
+ */
83
+ enable(name: string): void;
84
+ /**
85
+ * Disable an active stream.
86
+ * Closes the DataChannel and stops receiving data.
87
+ * Sends control message to remote peer.
88
+ * @param name - Stream name
89
+ */
90
+ disable(name: string): void;
91
+ /**
92
+ * Check if a stream is currently enabled.
93
+ * @param name - Stream name
94
+ */
95
+ isEnabled(name: string): boolean;
96
+ /**
97
+ * Check if a stream is registered.
98
+ * @param name - Stream name
99
+ */
100
+ isRegistered(name: string): boolean;
101
+ /**
102
+ * Get list of all registered stream names.
103
+ */
104
+ getStreamNames(): string[];
105
+ /**
106
+ * Send a control message to the remote peer.
107
+ * @param message - Control message to send
108
+ */
109
+ sendControl(message: ControlMessage): void;
110
+ /**
111
+ * Dispose all streams and release resources.
112
+ */
113
+ dispose(): void;
114
+ }
115
+ export type { BinaryFrame } from "@streamkit/binary-stream";
116
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,iEAAiE;IACjE,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,0CAA0C;IAC1C,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,6CAA6C;IAC7C,EAAE,EAAE,iBAAiB,CAAC;IACtB,sDAAsD;IACtD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEnD;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3B;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAEjC;;;OAGG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAEpC;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE,CAAC;IAE3B;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAE3C;;OAEG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB;AAGD,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @streamkit/orchestrator - Type Definitions
3
+ *
4
+ * Types for stream orchestration and coordination.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "streamkit-orchestrator",
3
+ "version": "0.4.0-alpha.0",
4
+ "description": "Lightweight stream orchestrator for coordinating multiple WebRTC binary streams",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "clean": "rimraf dist",
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "prepublishOnly": "npm run clean && npm run build"
22
+ },
23
+ "keywords": [
24
+ "webrtc",
25
+ "stream",
26
+ "orchestrator",
27
+ "binary",
28
+ "real-time"
29
+ ],
30
+ "dependencies": {
31
+ "@jervis/streamkit-binary-stream": "^0.4.0-alpha.0",
32
+ "@jervis/streamkit-webrtc": "^0.4.0-alpha.0"
33
+ },
34
+ "devDependencies": {
35
+ "rimraf": "^5.0.5",
36
+ "typescript": "^5.3.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=18.0.0"
40
+ }
41
+ }