@zero-server/grpc 0.9.5 → 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/README.md +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/debug.js +10 -10
- package/lib/grpc/call.js +14 -14
- package/lib/grpc/client.js +4 -4
- package/lib/grpc/codec.js +7 -7
- package/lib/grpc/credentials.js +2 -2
- package/lib/grpc/frame.js +2 -2
- package/lib/grpc/health.js +3 -3
- package/lib/grpc/index.js +3 -3
- package/lib/grpc/metadata.js +3 -3
- package/lib/grpc/proto.js +5 -5
- package/lib/grpc/reflection.js +2 -2
- package/lib/grpc/server.js +3 -3
- package/lib/grpc/status.js +2 -2
- package/lib/grpc/watch.js +1 -1
- package/package.json +2 -2
- package/types/body.d.ts +1 -1
- package/types/cli.d.ts +1 -1
- package/types/index.d.ts +16 -4
- package/types/middleware.d.ts +1 -1
- package/types/orm.d.ts +3 -3
- package/types/request.d.ts +3 -3
- package/types/webrtc.d.ts +501 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Full HTTP/2 gRPC stack with no external dependencies: a service registry, client
|
|
|
10
10
|
npm install @zero-server/grpc
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Or
|
|
13
|
+
Or install the full SDK to get everything at once:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm install @zero-server/sdk
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// AUTO-GENERATED by .tools/generate-package-stubs.js
|
|
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/grpc';
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// AUTO-GENERATED by .tools/generate-package-stubs.js
|
|
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/grpc");
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
282
|
-
* `'debug'` (1)
|
|
283
|
-
* `'info'` (2)
|
|
284
|
-
* `'warn'` (3)
|
|
285
|
-
* `'error'` (4)
|
|
286
|
-
* `'fatal'` (5)
|
|
287
|
-
* `'silent'` (6)
|
|
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
|
{
|
package/lib/grpc/call.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Wraps HTTP/2 streams with protobuf encode/decode, metadata,
|
|
5
5
|
* framing, deadline enforcement, and cancellation support.
|
|
6
6
|
*
|
|
7
|
-
* - `UnaryCall`
|
|
8
|
-
* - `ServerStreamCall`
|
|
9
|
-
* - `ClientStreamCall`
|
|
10
|
-
* - `BidiStreamCall`
|
|
7
|
+
* - `UnaryCall` - single request, single response
|
|
8
|
+
* - `ServerStreamCall` - single request, stream of responses
|
|
9
|
+
* - `ClientStreamCall` - stream of requests, single response
|
|
10
|
+
* - `BidiStreamCall` - bidirectional streaming
|
|
11
11
|
*
|
|
12
12
|
* @example | Unary handler
|
|
13
13
|
* async function GetUser(call) {
|
|
@@ -181,7 +181,7 @@ class BaseCall extends EventEmitter
|
|
|
181
181
|
|
|
182
182
|
if (!this._headersSent)
|
|
183
183
|
{
|
|
184
|
-
// Trailers-Only response
|
|
184
|
+
// Trailers-Only response - include status in initial HEADERS frame
|
|
185
185
|
this._headersSent = true;
|
|
186
186
|
try
|
|
187
187
|
{
|
|
@@ -199,7 +199,7 @@ class BaseCall extends EventEmitter
|
|
|
199
199
|
}
|
|
200
200
|
else
|
|
201
201
|
{
|
|
202
|
-
// Headers already sent
|
|
202
|
+
// Headers already sent - send trailing HEADERS after final DATA
|
|
203
203
|
this.stream.on('wantTrailers', () =>
|
|
204
204
|
{
|
|
205
205
|
try { this.stream.sendTrailers(trailHeaders); }
|
|
@@ -359,7 +359,7 @@ class BaseCall extends EventEmitter
|
|
|
359
359
|
// -- Unary Call --------------------------------------------
|
|
360
360
|
|
|
361
361
|
/**
|
|
362
|
-
* A unary gRPC call
|
|
362
|
+
* A unary gRPC call - single request message, single response message.
|
|
363
363
|
*
|
|
364
364
|
* @class
|
|
365
365
|
* @extends BaseCall
|
|
@@ -391,7 +391,7 @@ class UnaryCall extends BaseCall
|
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
/**
|
|
394
|
-
* Initialize the call
|
|
394
|
+
* Initialize the call - collect the full request body and decode it.
|
|
395
395
|
* @private
|
|
396
396
|
* @returns {Promise<void>}
|
|
397
397
|
*/
|
|
@@ -422,7 +422,7 @@ class UnaryCall extends BaseCall
|
|
|
422
422
|
// -- Server Streaming Call ---------------------------------
|
|
423
423
|
|
|
424
424
|
/**
|
|
425
|
-
* A server-streaming gRPC call
|
|
425
|
+
* A server-streaming gRPC call - single request, multiple responses.
|
|
426
426
|
* The handler calls `call.write(msg)` for each response and `call.end()` to finish.
|
|
427
427
|
*
|
|
428
428
|
* @class
|
|
@@ -481,7 +481,7 @@ class ServerStreamCall extends BaseCall
|
|
|
481
481
|
// -- Client Streaming Call ---------------------------------
|
|
482
482
|
|
|
483
483
|
/**
|
|
484
|
-
* A client-streaming gRPC call
|
|
484
|
+
* A client-streaming gRPC call - multiple requests, single response.
|
|
485
485
|
* The handler iterates `for await (const msg of call)` to consume messages,
|
|
486
486
|
* then returns the response object.
|
|
487
487
|
*
|
|
@@ -512,7 +512,7 @@ class ClientStreamCall extends BaseCall
|
|
|
512
512
|
}
|
|
513
513
|
|
|
514
514
|
/**
|
|
515
|
-
* Initialize
|
|
515
|
+
* Initialize - set up the frame parser to enqueue decoded messages.
|
|
516
516
|
* @private
|
|
517
517
|
*/
|
|
518
518
|
_init()
|
|
@@ -560,7 +560,7 @@ class ClientStreamCall extends BaseCall
|
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
/**
|
|
563
|
-
* Async iterator
|
|
563
|
+
* Async iterator - enables `for await (const msg of call)`.
|
|
564
564
|
*
|
|
565
565
|
* @returns {AsyncIterator<object>}
|
|
566
566
|
*/
|
|
@@ -589,7 +589,7 @@ class ClientStreamCall extends BaseCall
|
|
|
589
589
|
// -- Bidirectional Streaming Call ---------------------------
|
|
590
590
|
|
|
591
591
|
/**
|
|
592
|
-
* A bidirectional streaming gRPC call
|
|
592
|
+
* A bidirectional streaming gRPC call - multiple requests AND multiple responses.
|
|
593
593
|
* The handler can `for await` incoming messages while simultaneously
|
|
594
594
|
* calling `call.write()` to send responses.
|
|
595
595
|
*
|
|
@@ -673,7 +673,7 @@ class BidiStreamCall extends BaseCall
|
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
/**
|
|
676
|
-
* Async iterator
|
|
676
|
+
* Async iterator - enables `for await (const msg of call)`.
|
|
677
677
|
*
|
|
678
678
|
* @returns {AsyncIterator<object>}
|
|
679
679
|
*/
|
package/lib/grpc/client.js
CHANGED
|
@@ -266,7 +266,7 @@ class GrpcClient extends EventEmitter
|
|
|
266
266
|
// -- Unary Call -----------------------------------------
|
|
267
267
|
|
|
268
268
|
/**
|
|
269
|
-
* Make a unary gRPC call
|
|
269
|
+
* Make a unary gRPC call - send one message, receive one response.
|
|
270
270
|
*
|
|
271
271
|
* @param {string} methodName - RPC method name as defined in the proto service.
|
|
272
272
|
* @param {object} request - Request message object.
|
|
@@ -394,7 +394,7 @@ class GrpcClient extends EventEmitter
|
|
|
394
394
|
// -- Server Streaming ----------------------------------
|
|
395
395
|
|
|
396
396
|
/**
|
|
397
|
-
* Make a server-streaming gRPC call
|
|
397
|
+
* Make a server-streaming gRPC call - send one request, receive a stream of responses.
|
|
398
398
|
* Returns an async-iterable that yields decoded response messages.
|
|
399
399
|
*
|
|
400
400
|
* @param {string} methodName - RPC method name.
|
|
@@ -509,7 +509,7 @@ class GrpcClient extends EventEmitter
|
|
|
509
509
|
// -- Client Streaming ----------------------------------
|
|
510
510
|
|
|
511
511
|
/**
|
|
512
|
-
* Make a client-streaming gRPC call
|
|
512
|
+
* Make a client-streaming gRPC call - send a stream of requests, receive one response.
|
|
513
513
|
* Returns a writable object with `write()`, `end()`, and a `response` Promise.
|
|
514
514
|
*
|
|
515
515
|
* @param {string} methodName - RPC method name.
|
|
@@ -608,7 +608,7 @@ class GrpcClient extends EventEmitter
|
|
|
608
608
|
// -- Bidirectional Streaming ----------------------------
|
|
609
609
|
|
|
610
610
|
/**
|
|
611
|
-
* Make a bidirectional streaming gRPC call
|
|
611
|
+
* Make a bidirectional streaming gRPC call - send and receive streams simultaneously.
|
|
612
612
|
* Returns an object that is both writable (`write`/`end`) and async-iterable.
|
|
613
613
|
*
|
|
614
614
|
* @param {string} methodName - RPC method name.
|
package/lib/grpc/codec.js
CHANGED
|
@@ -76,7 +76,7 @@ const TYPE_INFO = {
|
|
|
76
76
|
// -- Writer ------------------------------------------------
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
* Protobuf binary writer
|
|
79
|
+
* Protobuf binary writer - encodes JavaScript objects into wire-format bytes.
|
|
80
80
|
*
|
|
81
81
|
* @class
|
|
82
82
|
*
|
|
@@ -397,7 +397,7 @@ class Writer
|
|
|
397
397
|
// -- Reader ------------------------------------------------
|
|
398
398
|
|
|
399
399
|
/**
|
|
400
|
-
* Protobuf binary reader
|
|
400
|
+
* Protobuf binary reader - decodes wire-format bytes into JavaScript values.
|
|
401
401
|
*
|
|
402
402
|
* @class
|
|
403
403
|
*
|
|
@@ -762,7 +762,7 @@ class Reader
|
|
|
762
762
|
function encode(obj, messageDesc, allMessages, depth = 0)
|
|
763
763
|
{
|
|
764
764
|
if (depth > MAX_RECURSION_DEPTH)
|
|
765
|
-
throw new Error(`Maximum encoding depth (${MAX_RECURSION_DEPTH}) exceeded
|
|
765
|
+
throw new Error(`Maximum encoding depth (${MAX_RECURSION_DEPTH}) exceeded - possible circular reference`);
|
|
766
766
|
|
|
767
767
|
if (!obj || typeof obj !== 'object')
|
|
768
768
|
return Buffer.alloc(0);
|
|
@@ -809,7 +809,7 @@ function encode(obj, messageDesc, allMessages, depth = 0)
|
|
|
809
809
|
function decode(buffer, messageDesc, allMessages, depth = 0)
|
|
810
810
|
{
|
|
811
811
|
if (depth > MAX_RECURSION_DEPTH)
|
|
812
|
-
throw new Error(`Maximum decoding depth (${MAX_RECURSION_DEPTH}) exceeded
|
|
812
|
+
throw new Error(`Maximum decoding depth (${MAX_RECURSION_DEPTH}) exceeded - possible circular reference`);
|
|
813
813
|
|
|
814
814
|
if (!Buffer.isBuffer(buffer) || buffer.length === 0)
|
|
815
815
|
return _defaultObject(messageDesc);
|
|
@@ -830,7 +830,7 @@ function decode(buffer, messageDesc, allMessages, depth = 0)
|
|
|
830
830
|
|
|
831
831
|
if (!field)
|
|
832
832
|
{
|
|
833
|
-
// Unknown field
|
|
833
|
+
// Unknown field - skip it (forward compatibility)
|
|
834
834
|
reader.skipField(wireType);
|
|
835
835
|
continue;
|
|
836
836
|
}
|
|
@@ -868,7 +868,7 @@ function _encodeField(writer, field, value, allMessages, depth)
|
|
|
868
868
|
|
|
869
869
|
if (typeInfo)
|
|
870
870
|
{
|
|
871
|
-
// Scalar type
|
|
871
|
+
// Scalar type - skip default values in proto3
|
|
872
872
|
if (_isDefaultValue(field.type, value)) return;
|
|
873
873
|
|
|
874
874
|
writer.writeTag(field.number, typeInfo.wire);
|
|
@@ -913,7 +913,7 @@ function _encodeRepeated(writer, field, values, allMessages, depth)
|
|
|
913
913
|
}
|
|
914
914
|
else
|
|
915
915
|
{
|
|
916
|
-
// Non-packable (strings, bytes, messages)
|
|
916
|
+
// Non-packable (strings, bytes, messages) - one tag per element
|
|
917
917
|
for (const v of values) _encodeField(writer, field, v, allMessages, depth);
|
|
918
918
|
}
|
|
919
919
|
}
|
package/lib/grpc/credentials.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* and metadata-based credentials. Supports certificate rotation
|
|
6
6
|
* and credential composition.
|
|
7
7
|
*
|
|
8
|
-
* Uses only Node.js built-in `tls` and `fs`
|
|
8
|
+
* Uses only Node.js built-in `tls` and `fs` - no external packages.
|
|
9
9
|
*
|
|
10
10
|
* @example | Insecure (plaintext)
|
|
11
11
|
* const { ChannelCredentials, GrpcClient } = require('@zero-server/sdk');
|
|
@@ -71,7 +71,7 @@ class ChannelCredentials
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Create insecure (plaintext) credentials.
|
|
74
|
-
* No TLS
|
|
74
|
+
* No TLS - suitable for development or service-mesh environments
|
|
75
75
|
* where transport security is handled by the infrastructure.
|
|
76
76
|
*
|
|
77
77
|
* @returns {ChannelCredentials}
|
package/lib/grpc/frame.js
CHANGED
|
@@ -23,7 +23,7 @@ const log = require('../debug')('zero:grpc');
|
|
|
23
23
|
const FRAME_HEADER_SIZE = 5;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Maximum frame size (16 MB
|
|
26
|
+
* Maximum frame size (16 MB - matches the default gRPC max).
|
|
27
27
|
* @type {number}
|
|
28
28
|
*/
|
|
29
29
|
const MAX_FRAME_SIZE = 16 * 1024 * 1024;
|
|
@@ -92,7 +92,7 @@ function _buildFrame(payload, flag)
|
|
|
92
92
|
// -- Frame Decoder -----------------------------------------
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Stateful gRPC frame parser
|
|
95
|
+
* Stateful gRPC frame parser - buffers incoming data and emits complete
|
|
96
96
|
* decompressed messages. Designed to be fed chunks from an HTTP/2 stream.
|
|
97
97
|
*
|
|
98
98
|
* @class
|
package/lib/grpc/health.js
CHANGED
|
@@ -193,7 +193,7 @@ class HealthService
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
|
-
* Handle a Check RPC
|
|
196
|
+
* Handle a Check RPC - unary request for current health of a service.
|
|
197
197
|
* @param {import('./call').UnaryCall} call
|
|
198
198
|
*/
|
|
199
199
|
Check(call)
|
|
@@ -205,7 +205,7 @@ class HealthService
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
/**
|
|
208
|
-
* Handle a Watch RPC
|
|
208
|
+
* Handle a Watch RPC - server-stream that pushes status changes.
|
|
209
209
|
* Sends the current status immediately, then pushes on every change.
|
|
210
210
|
* @param {import('./call').ServerStreamCall} call
|
|
211
211
|
*/
|
|
@@ -232,7 +232,7 @@ class HealthService
|
|
|
232
232
|
|
|
233
233
|
/**
|
|
234
234
|
* Get the schema object needed for server registration.
|
|
235
|
-
* Avoids requiring proto parsing
|
|
235
|
+
* Avoids requiring proto parsing - returns descriptors directly.
|
|
236
236
|
* @returns {object} Schema compatible with GrpcServiceRegistry.addService
|
|
237
237
|
*/
|
|
238
238
|
getSchema()
|
package/lib/grpc/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module grpc
|
|
3
|
-
* @description Full gRPC support for zero-server
|
|
3
|
+
* @description Full gRPC support for zero-server - zero external dependencies.
|
|
4
4
|
* Provides a proto3 parser, protobuf codec, gRPC framing, call objects,
|
|
5
5
|
* a service server, and a client for all four RPC patterns.
|
|
6
6
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* - Graceful shutdown with call draining
|
|
15
15
|
* - Message size limits and deadline enforcement
|
|
16
16
|
*
|
|
17
|
-
* @example | Quick Start
|
|
17
|
+
* @example | Quick Start - Server
|
|
18
18
|
* const { createApp, parseProto } = require('@zero-server/sdk');
|
|
19
19
|
* const app = createApp();
|
|
20
20
|
* const schema = parseProto(`
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
*
|
|
36
36
|
* app.listen(50051, { http2: true });
|
|
37
37
|
*
|
|
38
|
-
* @example | Quick Start
|
|
38
|
+
* @example | Quick Start - Client
|
|
39
39
|
* const { GrpcClient, parseProto } = require('@zero-server/sdk');
|
|
40
40
|
* const schema = parseProto(fs.readFileSync('hello.proto', 'utf8'));
|
|
41
41
|
* const client = new GrpcClient('http://localhost:50051', schema, 'Greeter');
|
package/lib/grpc/metadata.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module grpc/metadata
|
|
3
|
-
* @description gRPC metadata container
|
|
3
|
+
* @description gRPC metadata container - typed key-value pairs transmitted as
|
|
4
4
|
* HTTP/2 headers (initial metadata) and trailers (trailing metadata).
|
|
5
5
|
* Keys ending in `-bin` carry binary values (base64-encoded on the wire).
|
|
6
6
|
* All other keys carry ASCII string values.
|
|
@@ -44,7 +44,7 @@ const GRPC_INTERNAL = new Set([
|
|
|
44
44
|
const MAX_KEY_LENGTH = 256;
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Maximum total metadata size in bytes (soft limit
|
|
47
|
+
* Maximum total metadata size in bytes (soft limit - 8 KB default, configurable).
|
|
48
48
|
* @type {number}
|
|
49
49
|
*/
|
|
50
50
|
const DEFAULT_MAX_METADATA_SIZE = 8192;
|
|
@@ -52,7 +52,7 @@ const DEFAULT_MAX_METADATA_SIZE = 8192;
|
|
|
52
52
|
// -- Metadata Class ----------------------------------------
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* gRPC metadata container
|
|
55
|
+
* gRPC metadata container - type-safe key-value pairs for headers and trailers.
|
|
56
56
|
*
|
|
57
57
|
* @class
|
|
58
58
|
*
|
package/lib/grpc/proto.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module grpc/proto
|
|
3
|
-
* @description Zero-dependency proto3 parser
|
|
3
|
+
* @description Zero-dependency proto3 parser - reads `.proto` file text and produces
|
|
4
4
|
* message descriptors, enum definitions, and service/RPC declarations
|
|
5
5
|
* that the codec and server use at runtime.
|
|
6
6
|
*
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
* @example
|
|
18
18
|
* const { parseProto } = require('./proto');
|
|
19
19
|
* const schema = parseProto(fs.readFileSync('chat.proto', 'utf8'));
|
|
20
|
-
* // schema.messages
|
|
21
|
-
* // schema.enums
|
|
22
|
-
* // schema.services
|
|
20
|
+
* // schema.messages - { MessageName: { fields: [...] } }
|
|
21
|
+
* // schema.enums - { EnumName: { values: { ... } } }
|
|
22
|
+
* // schema.services - { ServiceName: { methods: { ... } } }
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
const fs = require('fs');
|
|
@@ -254,7 +254,7 @@ function parseProto(source, opts = {})
|
|
|
254
254
|
{
|
|
255
255
|
next(); expect('='); schema.syntax = next().value; expect(';');
|
|
256
256
|
if (schema.syntax !== 'proto3')
|
|
257
|
-
log.warn('proto file uses syntax "%s"
|
|
257
|
+
log.warn('proto file uses syntax "%s" - only proto3 is fully supported', schema.syntax);
|
|
258
258
|
}
|
|
259
259
|
else if (tok.value === 'package')
|
|
260
260
|
{
|
package/lib/grpc/reflection.js
CHANGED
|
@@ -54,7 +54,7 @@ function buildFileDescriptorProto(schema, filename)
|
|
|
54
54
|
// field 2: package (string)
|
|
55
55
|
if (schema.package) w.string(2, schema.package);
|
|
56
56
|
|
|
57
|
-
// field 3: dependency (repeated string)
|
|
57
|
+
// field 3: dependency (repeated string) - imported file names
|
|
58
58
|
if (schema.imports)
|
|
59
59
|
{
|
|
60
60
|
for (const imp of schema.imports)
|
|
@@ -191,7 +191,7 @@ function _buildFieldDescriptorProto(field, schema)
|
|
|
191
191
|
// field 9: oneof_index (if in a oneof)
|
|
192
192
|
if (field.oneofName !== undefined)
|
|
193
193
|
{
|
|
194
|
-
// Will use the index from the parent
|
|
194
|
+
// Will use the index from the parent - simplified to 0 for now
|
|
195
195
|
w.int32(9, 0);
|
|
196
196
|
}
|
|
197
197
|
|
package/lib/grpc/server.js
CHANGED
|
@@ -130,7 +130,7 @@ class GrpcServiceRegistry
|
|
|
130
130
|
{
|
|
131
131
|
if (!handlers[methodName])
|
|
132
132
|
{
|
|
133
|
-
log.warn('no handler for %s/%s
|
|
133
|
+
log.warn('no handler for %s/%s - will return UNIMPLEMENTED', serviceName, methodName);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const routePath = pathPrefix + '/' + methodName;
|
|
@@ -178,7 +178,7 @@ class GrpcServiceRegistry
|
|
|
178
178
|
const contentType = headers['content-type'] || '';
|
|
179
179
|
if (!contentType.startsWith('application/grpc'))
|
|
180
180
|
{
|
|
181
|
-
return false; // Not a gRPC request
|
|
181
|
+
return false; // Not a gRPC request - let the normal HTTP pipeline handle it
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
const grpcPath = headers[':path'];
|
|
@@ -290,7 +290,7 @@ class GrpcServiceRegistry
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
/**
|
|
293
|
-
* Begin draining
|
|
293
|
+
* Begin draining - reject new calls and wait for active calls to finish.
|
|
294
294
|
*
|
|
295
295
|
* @param {number} [timeout=30000] - Maximum time to wait in ms.
|
|
296
296
|
* @returns {Promise<void>}
|
package/lib/grpc/status.js
CHANGED
|
@@ -25,7 +25,7 @@ const GrpcStatus = {
|
|
|
25
25
|
OK: 0,
|
|
26
26
|
/** The operation was cancelled (typically by the caller). */
|
|
27
27
|
CANCELLED: 1,
|
|
28
|
-
/** Unknown error
|
|
28
|
+
/** Unknown error - a catch-all for unexpected failures. */
|
|
29
29
|
UNKNOWN: 2,
|
|
30
30
|
/** The client specified an invalid argument. */
|
|
31
31
|
INVALID_ARGUMENT: 3,
|
|
@@ -47,7 +47,7 @@ const GrpcStatus = {
|
|
|
47
47
|
OUT_OF_RANGE: 11,
|
|
48
48
|
/** The operation is not implemented or not supported. */
|
|
49
49
|
UNIMPLEMENTED: 12,
|
|
50
|
-
/** Internal error
|
|
50
|
+
/** Internal error - invariants expected by the server have been broken. */
|
|
51
51
|
INTERNAL: 13,
|
|
52
52
|
/** The service is currently unavailable, usually a transient condition. */
|
|
53
53
|
UNAVAILABLE: 14,
|
package/lib/grpc/watch.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Watches `.proto` files for changes using `fs.watch()` and
|
|
5
5
|
* re-parses/re-registers gRPC services automatically.
|
|
6
6
|
*
|
|
7
|
-
* **Dev-only**
|
|
7
|
+
* **Dev-only** - disabled by default when `NODE_ENV=production`.
|
|
8
8
|
*
|
|
9
9
|
* @example
|
|
10
10
|
* const { createApp, watchProto } = require('@zero-server/sdk');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zero-server/grpc",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
4
4
|
"description": "gRPC server, client, codec, framing, status, metadata, health, reflection, balancer.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zero-server",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"sideEffects": false,
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@zero-server/sdk": ">=0.9.
|
|
48
|
+
"@zero-server/sdk": ">=0.9.7"
|
|
49
49
|
},
|
|
50
50
|
"peerDependenciesMeta": {
|
|
51
51
|
"@zero-server/sdk": {
|
package/types/body.d.ts
CHANGED
package/types/cli.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// Re-exports for @zero-server/cli
|
|
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
|
|
309
|
+
// Observability - Structured Logging
|
|
298
310
|
Logger: typeof Logger;
|
|
299
311
|
structuredLogger: typeof structuredLogger;
|
|
300
|
-
// Observability
|
|
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
|
|
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
|
|
328
|
+
// Observability - Health Checks
|
|
317
329
|
healthCheck: typeof healthCheck;
|
|
318
330
|
createHealthHandlers: typeof createHealthHandlers;
|
|
319
331
|
memoryCheck: typeof memoryCheck;
|
package/types/middleware.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
package/types/request.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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 {}
|