@zero-server/middleware 0.9.6 → 0.9.7

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/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- // AUTO-GENERATED by .tools/generate-package-stubs.js edit .tools/scope-manifest.js and re-run `npm run packages:generate`.
1
+ // AUTO-GENERATED by .tools/generate-package-stubs.js - edit .tools/scope-manifest.js and re-run `npm run packages:generate`.
2
2
  export * from './types/middleware';
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // AUTO-GENERATED by .tools/generate-package-stubs.js edit .tools/scope-manifest.js and re-run `npm run packages:generate`.
1
+ // AUTO-GENERATED by .tools/generate-package-stubs.js - edit .tools/scope-manifest.js and re-run `npm run packages:generate`.
2
2
  'use strict';
3
3
  const lib = require("./lib/middleware");
4
4
 
package/lib/debug.js CHANGED
@@ -16,7 +16,7 @@
16
16
  * log.error('failed to connect', err);
17
17
  * log('shorthand for debug level');
18
18
  *
19
- * // Set minimum level anything below is silenced
19
+ * // Set minimum level - anything below is silenced
20
20
  * debug.level('warn'); // only warn, error, fatal
21
21
  * debug.level('silent'); // suppress all output
22
22
  * debug.level('trace'); // show everything
@@ -81,7 +81,7 @@ _enabledPatterns = _parsePatterns();
81
81
  */
82
82
  function _isEnabled(ns)
83
83
  {
84
- if (!_enabledPatterns) return true; // No DEBUG set enable all
84
+ if (!_enabledPatterns) return true; // No DEBUG set - enable all
85
85
  let enabled = false;
86
86
  for (const { neg, re } of _enabledPatterns)
87
87
  {
@@ -116,7 +116,7 @@ function _ts()
116
116
  }
117
117
 
118
118
  /**
119
- * Format arguments (like console.log supports %s, %d, %j, %o).
119
+ * Format arguments (like console.log - supports %s, %d, %j, %o).
120
120
  * @private
121
121
  */
122
122
  function _format(args)
@@ -278,13 +278,13 @@ function debug(namespace)
278
278
  * Messages below this level are silenced.
279
279
  *
280
280
  * @param {string|number} level - Level name or number.
281
- * `'trace'` (0) all output
282
- * `'debug'` (1) debug and above
283
- * `'info'` (2) info and above
284
- * `'warn'` (3) warn and above
285
- * `'error'` (4) error and fatal only
286
- * `'fatal'` (5) fatal only
287
- * `'silent'` (6) nothing
281
+ * `'trace'` (0) - all output
282
+ * `'debug'` (1) - debug and above
283
+ * `'info'` (2) - info and above
284
+ * `'warn'` (3) - warn and above
285
+ * `'error'` (4) - error and fatal only
286
+ * `'fatal'` (5) - fatal only
287
+ * `'silent'` (6) - nothing
288
288
  */
289
289
  debug.level = function(level)
290
290
  {
@@ -28,7 +28,7 @@ const COMPRESSIBLE = /^text\/|^application\/(json|javascript|xml|x-www-form-urle
28
28
  * @param {number} [opts.threshold=1024] - Minimum body size in bytes to compress.
29
29
  * @param {number} [opts.level] - Compression level (zlib.constants.Z_DEFAULT_COMPRESSION).
30
30
  * @param {string|string[]} [opts.encoding] - Force specific encoding(s). Default: auto-negotiate.
31
- * @param {Function} [opts.filter] - `(req, res) => boolean` return false to skip compression.
31
+ * @param {Function} [opts.filter] - `(req, res) => boolean` - return false to skip compression.
32
32
  * @returns {Function} Middleware `(req, res, next) => void`.
33
33
  *
34
34
  * @example
@@ -139,14 +139,14 @@ function compress(opts = {})
139
139
  // writeHead before write), we can no longer modify them.
140
140
  if (raw.headersSent) return false;
141
141
 
142
- // Check Content-Type skip non-compressible types
142
+ // Check Content-Type - skip non-compressible types
143
143
  const ct = raw.getHeader('content-type') || '';
144
144
  if (ct && !COMPRESSIBLE.test(ct))
145
145
  {
146
146
  return false;
147
147
  }
148
148
 
149
- // Never compress SSE streams compression buffers
149
+ // Never compress SSE streams - compression buffers
150
150
  // the small frames and prevents real-time delivery.
151
151
  if (ct.includes('text/event-stream'))
152
152
  {
@@ -200,7 +200,7 @@ function compress(opts = {})
200
200
  {
201
201
  headersWritten = true;
202
202
 
203
- // Check threshold if the total body is small, skip compression
203
+ // Check threshold - if the total body is small, skip compression
204
204
  const totalChunk = chunk ? (Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))) : null;
205
205
  if (totalChunk && totalChunk.length < threshold)
206
206
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zero-server/middleware",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "description": "20+ zero-dependency middleware.",
5
5
  "keywords": [
6
6
  "zero-server",
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "sideEffects": false,
47
47
  "dependencies": {
48
- "@zero-server/errors": "0.9.6"
48
+ "@zero-server/errors": "0.9.7"
49
49
  },
50
50
  "peerDependencies": {
51
- "@zero-server/sdk": ">=0.9.6"
51
+ "@zero-server/sdk": ">=0.9.7"
52
52
  },
53
53
  "peerDependenciesMeta": {
54
54
  "@zero-server/sdk": {
package/types/body.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Re-exports for @zero-server/body body parser types
1
+ // Re-exports for @zero-server/body - body parser types
2
2
  export {
3
3
  BodyParserOptions,
4
4
  JsonParserOptions,
package/types/cli.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- // Re-exports for @zero-server/cli CLI runner types
1
+ // Re-exports for @zero-server/cli - CLI runner types
2
2
  export { CLI, runCLI } from './orm';
package/types/index.d.ts CHANGED
@@ -11,6 +11,18 @@ export { RouterInstance, RouteChain, RouteEntry, RouteInfo, RouteOptions, RouteH
11
11
  export { Request, RangeResult } from './request';
12
12
  export { Response, SendFileOptions, CookieOptions, PushOptions } from './response';
13
13
  export { SSEOptions, SSEStream } from './sse';
14
+ export {
15
+ createWebRTC, SignalingHub, Room as WebRTCRoom, Peer as WebRTCPeer,
16
+ parseSdp, stringifySdp, parseCandidate, stringifyCandidate,
17
+ stunBinding, encodeBindingRequest, decodeMessage,
18
+ encodeXorMappedAddress, decodeXorMappedAddress,
19
+ STUN_MAGIC_COOKIE, STUN_METHOD, STUN_CLASS, STUN_ATTR,
20
+ issueTurnCredentials, TurnServer, SfuAdapter,
21
+ signJoinToken, verifyJoinToken,
22
+ WebRTCOptions, RoomOptions as WebRTCRoomOptions, PeerInfo, SignalingMessage,
23
+ IceServerConfig, TurnCredentials, IssueTurnCredentialsOptions, ClusterAdapter as WebRTCClusterAdapter,
24
+ WebRTCError, SignalingError, IceError, TurnError, SdpError,
25
+ } from './webrtc';
14
26
  export { LifecycleManager, LifecycleState, LIFECYCLE_STATE } from './lifecycle';
15
27
  export { ClusterManager, ClusterOptions, cluster } from './cluster';
16
28
  export {
@@ -294,10 +306,10 @@ declare const zeroServer: {
294
306
  LIFECYCLE_STATE: typeof LIFECYCLE_STATE;
295
307
  ClusterManager: typeof ClusterManager;
296
308
  cluster: typeof clusterize;
297
- // Observability Structured Logging
309
+ // Observability - Structured Logging
298
310
  Logger: typeof Logger;
299
311
  structuredLogger: typeof structuredLogger;
300
- // Observability Metrics
312
+ // Observability - Metrics
301
313
  Counter: typeof Counter;
302
314
  Gauge: typeof Gauge;
303
315
  Histogram: typeof Histogram;
@@ -306,14 +318,14 @@ declare const zeroServer: {
306
318
  createDefaultMetrics: typeof createDefaultMetrics;
307
319
  metricsMiddleware: typeof metricsMiddleware;
308
320
  metricsEndpoint: typeof metricsEndpointHandler;
309
- // Observability Tracing
321
+ // Observability - Tracing
310
322
  Span: typeof Span;
311
323
  Tracer: typeof Tracer;
312
324
  parseTraceparent: typeof parseTraceparent;
313
325
  formatTraceparent: typeof formatTraceparent;
314
326
  tracingMiddleware: typeof tracingMiddleware;
315
327
  instrumentFetch: typeof instrumentFetch;
316
- // Observability Health Checks
328
+ // Observability - Health Checks
317
329
  healthCheck: typeof healthCheck;
318
330
  createHealthHandlers: typeof createHealthHandlers;
319
331
  memoryCheck: typeof memoryCheck;
@@ -136,7 +136,7 @@ export interface CompressOptions {
136
136
  level?: number;
137
137
  /** Force specific encoding(s). */
138
138
  encoding?: string | string[];
139
- /** Filter function return false to skip compression. */
139
+ /** Filter function - return false to skip compression. */
140
140
  filter?: (req: Request, res: Response) => boolean;
141
141
  }
142
142
 
package/types/orm.d.ts CHANGED
@@ -29,7 +29,7 @@ export interface SchemaColumnDef {
29
29
  enum?: string[];
30
30
  /** Allowed values (set type). */
31
31
  values?: string[];
32
- /** Mass-assignment protection exclude from bulk writes. */
32
+ /** Mass-assignment protection - exclude from bulk writes. */
33
33
  guarded?: boolean;
34
34
  /** Precision for decimal types. */
35
35
  precision?: number;
@@ -229,7 +229,7 @@ export class Query {
229
229
  take(n: number): Query;
230
230
  /** Alias for offset (LINQ naming). */
231
231
  skip(n: number): Query;
232
- /** Alias for exec explicitly convert to array. */
232
+ /** Alias for exec - explicitly convert to array. */
233
233
  toArray(): Promise<Model[]>;
234
234
  /** Shorthand for orderBy(field, 'desc'). */
235
235
  orderByDesc(field: string): Query;
@@ -260,7 +260,7 @@ export class Query {
260
260
  /** Inject a raw WHERE clause for SQL adapters (ignored by memory/mongo). */
261
261
  whereRaw(sql: string, ...params: any[]): Query;
262
262
 
263
- /** Thenable support `await query`. */
263
+ /** Thenable support - `await query`. */
264
264
  then<TResult1 = Model[], TResult2 = never>(
265
265
  onfulfilled?: ((value: Model[]) => TResult1 | PromiseLike<TResult1>) | null,
266
266
  onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
@@ -31,7 +31,7 @@ export interface Request {
31
31
  readonly ips: string[];
32
32
  /** `true` when the connection is over TLS (trust-proxy-aware). */
33
33
  readonly secure: boolean;
34
- /** Protocol string `'https'` or `'http'` (trust-proxy-aware). */
34
+ /** Protocol string - `'https'` or `'http'` (trust-proxy-aware). */
35
35
  readonly protocol: 'http' | 'https';
36
36
  /** HTTP version string (e.g. '1.1', '2.0'). */
37
37
  httpVersion: string;
@@ -49,7 +49,7 @@ export interface Request {
49
49
  id?: string;
50
50
  /** Whether the request timed out (populated by timeout middleware). */
51
51
  timedOut?: boolean;
52
- /** The original URL as received never rewritten by middleware. */
52
+ /** The original URL as received - never rewritten by middleware. */
53
53
  originalUrl: string;
54
54
  /** The URL path on which the current router was mounted. */
55
55
  baseUrl: string;
@@ -83,7 +83,7 @@ export interface Request {
83
83
  subdomains(offset?: number): string[];
84
84
 
85
85
  /**
86
- * Content negotiation check which types the client accepts.
86
+ * Content negotiation - check which types the client accepts.
87
87
  */
88
88
  accepts(...types: string[]): string | false;
89
89
 
@@ -0,0 +1,501 @@
1
+ /**
2
+ * TypeScript surface for @zero-server/webrtc.
3
+ *
4
+ * Mirrors the runtime surface exported from `lib/webrtc/index.js` and
5
+ * re-exported from the top-level SDK in `index.js`. Every entry listed
6
+ * in `.tools/scope-manifest.js` under the `webrtc` scope MUST have a
7
+ * matching declaration here - this is enforced by
8
+ * `test/packages/webrtc-types.test.js`.
9
+ */
10
+
11
+ import type { EventEmitter } from 'node:events';
12
+ import type { KeyObject } from 'node:crypto';
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Shared option / config types
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export interface IceServerConfig {
19
+ urls: string | string[];
20
+ username?: string;
21
+ credential?: string;
22
+ }
23
+
24
+ export interface TurnCredentials {
25
+ urls: string[];
26
+ username: string;
27
+ credential: string;
28
+ ttl: number;
29
+ }
30
+
31
+ export interface IssueTurnCredentialsOptions {
32
+ secret: string;
33
+ userId: string;
34
+ ttl?: string | number;
35
+ servers: string[];
36
+ realm?: string;
37
+ }
38
+
39
+ export interface SignalingHubOptions {
40
+ maxSdpSize?: number;
41
+ maxCandidatesPerOffer?: number;
42
+ peerMessageRate?: number;
43
+ maxProtocolErrors?: number;
44
+ ipAttachRate?: number;
45
+ originAllowlist?: string[];
46
+ joinTokenSecret?: string | Buffer;
47
+ autoCreateRooms?: boolean;
48
+ }
49
+
50
+ export interface WebRTCOptions extends SignalingHubOptions {
51
+ path?: string;
52
+ iceServers?: IceServerConfig[] | 'auto';
53
+ }
54
+
55
+ export interface PeerAttachInfo {
56
+ user?: unknown;
57
+ ip?: string;
58
+ origin?: string;
59
+ [extra: string]: unknown;
60
+ }
61
+
62
+ export interface PeerTransport {
63
+ send(data: string): void;
64
+ on(event: 'message' | 'close', cb: (...args: unknown[]) => void): void;
65
+ close(code?: number, reason?: string): void;
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // SDP / ICE helpers
70
+ // ---------------------------------------------------------------------------
71
+
72
+ export interface ParsedSdpMedia {
73
+ type: string;
74
+ port: number;
75
+ proto: string;
76
+ formats: string[];
77
+ iceUfrag?: string;
78
+ icePwd?: string;
79
+ fingerprint?: { algorithm: string; hash: string };
80
+ candidates?: ParsedIceCandidate[];
81
+ [key: string]: unknown;
82
+ }
83
+
84
+ export interface ParsedSdp {
85
+ version: number;
86
+ origin: Record<string, unknown>;
87
+ sessionName: string;
88
+ media: ParsedSdpMedia[];
89
+ [key: string]: unknown;
90
+ }
91
+
92
+ export interface ParsedIceCandidate {
93
+ foundation: string;
94
+ component: number;
95
+ transport: string;
96
+ priority: number;
97
+ address: string;
98
+ port: number;
99
+ type: string;
100
+ relatedAddress?: string;
101
+ relatedPort?: number;
102
+ tcpType?: string;
103
+ [key: string]: unknown;
104
+ }
105
+
106
+ export declare function parseSdp(sdp: string, opts?: { maxBytes?: number }): ParsedSdp;
107
+ export declare function stringifySdp(parsed: ParsedSdp): string;
108
+
109
+ export declare function parseCandidate(line: string): ParsedIceCandidate;
110
+ export declare function stringifyCandidate(parsed: ParsedIceCandidate): string;
111
+ export declare function filterCandidates(
112
+ candidates: ParsedIceCandidate[],
113
+ opts?: { allowPrivate?: boolean; allowLoopback?: boolean; allowLinkLocal?: boolean; allowMdns?: boolean }
114
+ ): ParsedIceCandidate[];
115
+
116
+ export declare function isPrivateIp(addr: string): boolean;
117
+ export declare function isLoopbackIp(addr: string): boolean;
118
+ export declare function isLinkLocalIp(addr: string): boolean;
119
+ export declare function isMdnsHostname(addr: string): boolean;
120
+
121
+ export declare const CANDIDATE_TYPES: Readonly<{ HOST: string; SRFLX: string; PRFLX: string; RELAY: string }>;
122
+ export declare const TCP_TYPES: Readonly<{ ACTIVE: string; PASSIVE: string; SO: string }>;
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // STUN / TURN
126
+ // ---------------------------------------------------------------------------
127
+
128
+ export declare function stunBinding(opts: {
129
+ host: string;
130
+ port?: number;
131
+ timeoutMs?: number;
132
+ retries?: number;
133
+ socketType?: 'udp4' | 'udp6';
134
+ }): Promise<{ family: 4 | 6; address: string; port: number }>;
135
+
136
+ export declare function encodeBindingRequest(transactionId?: Buffer): { buffer: Buffer; transactionId: Buffer };
137
+ export declare function decodeMessage(buf: Buffer): {
138
+ method: number;
139
+ class: number;
140
+ transactionId: Buffer;
141
+ attributes: Array<{ type: number; value: Buffer }>;
142
+ };
143
+ export declare function encodeXorMappedAddress(address: string, port: number, transactionId: Buffer): Buffer;
144
+ export declare function decodeXorMappedAddress(value: Buffer, transactionId: Buffer): { family: 4 | 6; address: string; port: number };
145
+
146
+ export declare const STUN_MAGIC_COOKIE: number;
147
+ export declare const STUN_METHOD: Readonly<{ BINDING: number }>;
148
+ export declare const STUN_CLASS: Readonly<{ REQUEST: number; INDICATION: number; SUCCESS: number; ERROR: number }>;
149
+ export declare const STUN_ATTR: Readonly<{ MAPPED_ADDRESS: number; XOR_MAPPED_ADDRESS: number; ERROR_CODE: number; SOFTWARE: number }>;
150
+
151
+ export declare function issueTurnCredentials(opts: IssueTurnCredentialsOptions): TurnCredentials;
152
+
153
+ export declare class TurnServer {
154
+ constructor(opts: {
155
+ secret: string;
156
+ realm?: string;
157
+ listeners: Array<{ proto: 'udp' | 'tcp' | 'tls'; port: number; host?: string; tls?: { cert: Buffer; key: Buffer } }>;
158
+ quotas?: { maxAllocationsPerUser?: number; maxBytesPerMinute?: number };
159
+ defaultLifetime?: number;
160
+ maxLifetime?: number;
161
+ relayHost?: string;
162
+ });
163
+ readonly realm: string;
164
+ start(): Promise<void>;
165
+ stop(): Promise<void>;
166
+ address(): { address: string; port: number } | null;
167
+ on(event: 'allocation', listener: (ev: { userId: string; relay: { address: string; port: number }; client: { address: string; port: number } }) => void): this;
168
+ on(event: 'deallocation', listener: (ev: { userId: string; client: { address: string; port: number }; reason?: string }) => void): this;
169
+ on(event: 'error', listener: (err: Error) => void): this;
170
+ on(event: string, listener: (...args: unknown[]) => void): this;
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Signaling core
175
+ // ---------------------------------------------------------------------------
176
+
177
+ export type PeerState = 'stable' | 'have-local-offer' | 'have-remote-offer';
178
+
179
+ export declare const PEER_STATE: Readonly<{
180
+ STABLE: 'stable';
181
+ HAVE_LOCAL_OFFER: 'have-local-offer';
182
+ HAVE_REMOTE_OFFER: 'have-remote-offer';
183
+ }>;
184
+
185
+ export declare class Peer {
186
+ readonly id: string;
187
+ readonly user: unknown;
188
+ readonly ip: string | null;
189
+ readonly transport: PeerTransport;
190
+ state: PeerState;
191
+ room: Room | null;
192
+ errors: number;
193
+ readonly connectedAt: number;
194
+ closed: boolean;
195
+ e2ee?: E2eeChannel;
196
+ constructor(transport: PeerTransport, info?: PeerAttachInfo);
197
+ send(type: string, payload?: object): void;
198
+ sendError(code: string, message: string): void;
199
+ close(code?: number, reason?: string): void;
200
+ }
201
+
202
+ export declare class Room {
203
+ readonly name: string;
204
+ readonly hub: SignalingHub | null;
205
+ isOpen: boolean;
206
+ constructor(name: string, opts?: { hub?: SignalingHub });
207
+ open(): this;
208
+ require(fn: (peer: Peer) => boolean | Promise<boolean>): this;
209
+ canPublish(fn: (peer: Peer) => boolean): this;
210
+ canSubscribe(fn: (peer: Peer) => boolean): this;
211
+ readonly size: number;
212
+ peers(): Peer[];
213
+ canJoin(peer: Peer): boolean | Promise<boolean>;
214
+ broadcast(type: string, payload?: object, exceptPeerId?: string): void;
215
+ close(reason?: string): void;
216
+ }
217
+
218
+ export interface SignalingHubEvents {
219
+ join: (ev: { peer: Peer; room: Room }) => void;
220
+ leave: (ev: { peer: Peer; room: Room }) => void;
221
+ offer: (ev: { peer: Peer; target: Peer | null; room: Room; sdp: string }) => void;
222
+ answer: (ev: { peer: Peer; target: Peer | null; room: Room; sdp: string }) => void;
223
+ signal: (ev: { peer: Peer; type: string }) => void;
224
+ joinFailed: (ev: { peer: Peer; reason: string; room?: string }) => void;
225
+ publishFailed: (ev: { peer: Peer; reason: string; room: string }) => void;
226
+ subscribeFailed: (ev: { peer: Peer; reason: string; room: string }) => void;
227
+ wireError: (ev: { peer: Peer; code: string }) => void;
228
+ e2eeKey: (ev: { peer: Peer; room: Room; epoch: number; key: string }) => void;
229
+ clusterError: (err: Error) => void;
230
+ }
231
+
232
+ export declare class SignalingHub extends EventEmitter {
233
+ constructor(opts?: SignalingHubOptions);
234
+ readonly size: number;
235
+ room(name: string): Room;
236
+ rooms(): Room[];
237
+ attach(transport: PeerTransport, info?: PeerAttachInfo): Peer;
238
+ close(): void;
239
+ on<E extends keyof SignalingHubEvents>(event: E, listener: SignalingHubEvents[E]): this;
240
+ on(event: string, listener: (...args: unknown[]) => void): this;
241
+ off<E extends keyof SignalingHubEvents>(event: E, listener: SignalingHubEvents[E]): this;
242
+ off(event: string, listener: (...args: unknown[]) => void): this;
243
+ emit<E extends keyof SignalingHubEvents>(event: E, ...args: Parameters<SignalingHubEvents[E]>): boolean;
244
+ emit(event: string, ...args: unknown[]): boolean;
245
+ }
246
+
247
+ export declare function createWebRTC(app: unknown, opts?: WebRTCOptions): SignalingHub;
248
+
249
+ // ---------------------------------------------------------------------------
250
+ // Join tokens
251
+ // ---------------------------------------------------------------------------
252
+
253
+ export interface SignJoinTokenOptions {
254
+ secret: string | Buffer;
255
+ user: string | { id?: string; userId?: string; sub?: string; [k: string]: unknown };
256
+ room: string;
257
+ ttl?: number;
258
+ claims?: Record<string, unknown>;
259
+ algorithm?: string;
260
+ audience?: string;
261
+ }
262
+
263
+ export interface VerifyJoinTokenOptions {
264
+ secret: string | Buffer;
265
+ room?: string;
266
+ audience?: string | string[];
267
+ algorithms?: string | string[];
268
+ clockTolerance?: number;
269
+ }
270
+
271
+ export declare function signJoinToken(opts: SignJoinTokenOptions): string;
272
+
273
+ export declare function verifyJoinToken(
274
+ token: string,
275
+ opts: VerifyJoinTokenOptions
276
+ ): { room: string; user: unknown; sub?: string; aud?: string; [k: string]: unknown };
277
+
278
+ // ---------------------------------------------------------------------------
279
+ // Observability
280
+ // ---------------------------------------------------------------------------
281
+
282
+ export interface ObservabilityBindOptions {
283
+ metrics?: unknown;
284
+ tracer?: unknown;
285
+ prefix?: string;
286
+ }
287
+
288
+ export declare function bindObservability(
289
+ hub: SignalingHub,
290
+ opts?: ObservabilityBindOptions
291
+ ): () => void;
292
+
293
+ // ---------------------------------------------------------------------------
294
+ // E2EE key relay
295
+ // ---------------------------------------------------------------------------
296
+
297
+ export interface E2eeKeyEvent {
298
+ from: string;
299
+ epoch: number;
300
+ key: Buffer;
301
+ }
302
+
303
+ export declare class E2eeChannel {
304
+ readonly peer: Peer;
305
+ readonly hub: SignalingHub;
306
+ epoch: number;
307
+ constructor(peer: Peer, hub: SignalingHub);
308
+ publish(epoch: number | null, key: Buffer | Uint8Array | string): number;
309
+ subscribe(fn: (ev: E2eeKeyEvent) => void): () => void;
310
+ }
311
+
312
+ export declare function attachE2ee(peer: Peer, hub: SignalingHub): E2eeChannel;
313
+ export declare function generateE2eeKeyPair(): { publicKey: KeyObject; privateKey: KeyObject };
314
+ export declare function sealKey(plaintext: Buffer | Uint8Array, recipientPubKey: KeyObject | Buffer): Buffer;
315
+ export declare function openSealedKey(sealed: Buffer | Uint8Array, recipientPrivKey: KeyObject | Buffer): Buffer;
316
+
317
+ // ---------------------------------------------------------------------------
318
+ // Cluster adapter
319
+ // ---------------------------------------------------------------------------
320
+
321
+ export interface ClusterAdapter {
322
+ publish(channel: string, message: unknown): void | Promise<void>;
323
+ subscribe(channel: string, handler: (message: unknown) => void): (() => void) | void;
324
+ }
325
+
326
+ export interface UseClusterOptions {
327
+ nodeId?: string;
328
+ }
329
+
330
+ export declare class ClusterCoordinator {
331
+ readonly hub: SignalingHub;
332
+ readonly adapter: ClusterAdapter;
333
+ readonly nodeId: string;
334
+ constructor(hub: SignalingHub, adapter: ClusterAdapter, opts?: UseClusterOptions);
335
+ locate(peerId: string): { nodeId: string; room: string } | null;
336
+ routeDirect(toPeerId: string, type: string, payload: object): boolean;
337
+ fanoutRoom(roomName: string, type: string, payload: object, excludeId?: string): void;
338
+ close(): void;
339
+ }
340
+
341
+ export declare function useCluster(
342
+ hub: SignalingHub,
343
+ adapter: ClusterAdapter,
344
+ opts?: UseClusterOptions
345
+ ): ClusterCoordinator;
346
+
347
+ export declare class MemoryClusterAdapter implements ClusterAdapter {
348
+ publish(channel: string, message: unknown): void;
349
+ subscribe(channel: string, handler: (message: unknown) => void): () => void;
350
+ }
351
+
352
+ // ---------------------------------------------------------------------------
353
+ // CLI
354
+ // ---------------------------------------------------------------------------
355
+
356
+ export interface WebRTCCommandDeps {
357
+ out?: (line: string) => void;
358
+ err?: (line: string) => void;
359
+ setExit?: (code: number) => void;
360
+ stunBinding?: typeof stunBinding;
361
+ }
362
+
363
+ export declare function runWebRTCCommand(
364
+ subcmd: 'stun' | 'turn-creds' | 'join-token' | 'verify-token' | 'help' | string,
365
+ flags?: Map<string, string>,
366
+ deps?: WebRTCCommandDeps
367
+ ): Promise<number>;
368
+
369
+ // ---------------------------------------------------------------------------
370
+ // SFU adapter (interface only - real implementations land in later PRs)
371
+ // ---------------------------------------------------------------------------
372
+
373
+ export interface SfuPeerInfo {
374
+ id: string;
375
+ user?: unknown;
376
+ room: string;
377
+ joinedAt: number;
378
+ }
379
+
380
+ export interface SfuRouter { id: string; routerId: string; }
381
+ export interface SfuTransport {
382
+ id: string;
383
+ transportId: string;
384
+ routerId: string;
385
+ peer: SfuPeerInfo | null;
386
+ iceParameters: unknown;
387
+ dtlsParameters: unknown;
388
+ }
389
+ export interface SfuProducer {
390
+ id: string;
391
+ producerId: string;
392
+ transportId: string;
393
+ kind: 'audio' | 'video';
394
+ rtpParams: unknown;
395
+ paused: boolean;
396
+ }
397
+ export interface SfuConsumer {
398
+ id: string;
399
+ consumerId: string;
400
+ transportId: string;
401
+ producerId: string;
402
+ kind: 'audio' | 'video';
403
+ rtpParams: unknown;
404
+ rtpCaps: unknown;
405
+ }
406
+ export interface SfuStats {
407
+ kind: 'global' | 'router' | 'transport';
408
+ [key: string]: unknown;
409
+ }
410
+
411
+ export type SfuEventHandler = (event: string, payload: unknown) => void;
412
+
413
+ export declare class SfuAdapter {
414
+ constructor();
415
+ createRouter(opts?: unknown): Promise<SfuRouter>;
416
+ createTransport(router: SfuRouter, peer: SfuPeerInfo): Promise<SfuTransport>;
417
+ produce(transport: SfuTransport, kind: 'audio' | 'video', rtpParams: unknown): Promise<SfuProducer>;
418
+ consume(transport: SfuTransport, producerId: string, rtpCaps: unknown): Promise<SfuConsumer>;
419
+ pauseProducer(producerId: string): Promise<void>;
420
+ resumeProducer(producerId: string): Promise<void>;
421
+ closeRouter(routerId: string): Promise<void>;
422
+ stats(scope?: string): Promise<SfuStats>;
423
+ onEvent(handler: SfuEventHandler): () => void;
424
+ }
425
+
426
+ export declare class MemorySfuAdapter extends SfuAdapter {
427
+ constructor(opts?: Record<string, unknown>);
428
+ }
429
+
430
+ export interface MediasoupAdapterOptions {
431
+ mediasoup?: unknown;
432
+ worker?: unknown;
433
+ workerSettings?: Record<string, unknown>;
434
+ mediaCodecs?: Array<Record<string, unknown>>;
435
+ webRtcTransportOptions?: Record<string, unknown>;
436
+ }
437
+
438
+ export declare class MediasoupSfuAdapter extends SfuAdapter {
439
+ constructor(opts?: MediasoupAdapterOptions);
440
+ close(): Promise<void>;
441
+ }
442
+
443
+ export interface LiveKitAdapterOptions {
444
+ url: string;
445
+ apiKey: string;
446
+ apiSecret: string;
447
+ livekit?: unknown;
448
+ client?: unknown;
449
+ defaultRoomOpts?: Record<string, unknown>;
450
+ defaultGrants?: Record<string, unknown>;
451
+ tokenTtl?: string | number;
452
+ }
453
+
454
+ export declare class LiveKitSfuAdapter extends SfuAdapter {
455
+ constructor(opts: LiveKitAdapterOptions);
456
+ }
457
+
458
+ export declare function loadSfuAdapter(
459
+ spec: SfuAdapter | 'memory' | 'mediasoup' | 'livekit' | string,
460
+ opts?: Record<string, unknown>,
461
+ ): SfuAdapter;
462
+
463
+ // ---------------------------------------------------------------------------
464
+ // Server-side bot peer (wrtc)
465
+ // ---------------------------------------------------------------------------
466
+
467
+ export interface BotPeerOptions {
468
+ hub: SignalingHub;
469
+ room: string;
470
+ user?: unknown;
471
+ ip?: string;
472
+ joinToken?: string;
473
+ iceServers?: Array<Record<string, unknown>>;
474
+ rtcConfig?: Record<string, unknown>;
475
+ wrtc?: unknown;
476
+ onTrack?: (track: unknown, streams: unknown[], fromPeerId: string) => void;
477
+ onDataChannel?: (channel: unknown, fromPeerId: string) => void;
478
+ onPeerJoin?: (remotePeerId: string) => void;
479
+ onPeerLeave?: (remotePeerId: string) => void;
480
+ onError?: (err: Error) => void;
481
+ }
482
+
483
+ export interface BotPeerHandle {
484
+ peer: Peer;
485
+ peerConnections: Map<string, unknown>;
486
+ getPeerConnection: (remotePeerId: string) => unknown | undefined;
487
+ ready: Promise<{ peerId: string }>;
488
+ close: () => void;
489
+ }
490
+
491
+ export declare function spawnBotPeer(opts: BotPeerOptions): BotPeerHandle;
492
+
493
+ // ---------------------------------------------------------------------------
494
+ // Errors
495
+ // ---------------------------------------------------------------------------
496
+
497
+ export declare class WebRTCError extends Error { readonly code: string; }
498
+ export declare class SignalingError extends WebRTCError {}
499
+ export declare class IceError extends WebRTCError {}
500
+ export declare class TurnError extends WebRTCError {}
501
+ export declare class SdpError extends WebRTCError {}