@zero-server/auth 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 CHANGED
@@ -10,7 +10,7 @@ Full auth layer with no external libraries: JWT (sign/verify/decode/JWKS/refresh
10
10
  npm install @zero-server/auth
11
11
  ```
12
12
 
13
- Or grab everything via the optional aggregate:
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 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/auth';
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/auth");
4
4
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module auth/authorize
3
- * @description Authorization helpers role-based access control (RBAC),
3
+ * @description Authorization helpers - role-based access control (RBAC),
4
4
  * permission-based access, and policy classes.
5
5
  *
6
6
  * Works with any authentication middleware that sets `req.user`.
@@ -13,22 +13,22 @@
13
13
  * app.use(jwt({ secret: process.env.JWT_SECRET }));
14
14
  * app.use(attachUserHelpers());
15
15
  *
16
- * // Role-based only admins and editors can modify posts
16
+ * // Role-based - only admins and editors can modify posts
17
17
  * app.put('/posts/:id', authorize('admin', 'editor'), (req, res) => {
18
18
  * res.json({ updated: true });
19
19
  * });
20
20
  *
21
- * // Permission-based require ALL listed permissions
21
+ * // Permission-based - require ALL listed permissions
22
22
  * app.delete('/users/:id', can('users:read', 'users:delete'), (req, res) => {
23
23
  * res.json({ deleted: true });
24
24
  * });
25
25
  *
26
- * // ANY permission useful for overlapping access
26
+ * // ANY permission - useful for overlapping access
27
27
  * app.get('/reports', canAny('reports:read', 'admin:read'), (req, res) => {
28
28
  * res.json({ reports: [] });
29
29
  * });
30
30
  *
31
- * // Policy class resource-level authorization
31
+ * // Policy class - resource-level authorization
32
32
  * class PostPolicy extends Policy {
33
33
  * before(user) { if (user.role === 'superadmin') return true; }
34
34
  * update(user, post) { return user.id === post.authorId || user.role === 'admin'; }
@@ -114,9 +114,9 @@ function authorize(...roles)
114
114
  * Checks `req.user.permissions` (array or Set) for the required permission(s).
115
115
  *
116
116
  * Permission strings follow a `resource:action` convention:
117
- * - `'posts:write'` write access to posts
118
- * - `'users:delete'` delete users
119
- * - `'*'` superuser wildcard
117
+ * - `'posts:write'` - write access to posts
118
+ * - `'users:delete'` - delete users
119
+ * - `'*'` - superuser wildcard
120
120
  *
121
121
  * @param {...string} permissions - Required permissions (ALL must be present unless `opts.any` is true).
122
122
  * @returns {Function} Middleware `(req, res, next) => void`.
@@ -293,7 +293,7 @@ function gate(policy, action, getResource)
293
293
  });
294
294
  }
295
295
 
296
- // Attach resource if loaded saves a redundant DB query in the handler
296
+ // Attach resource if loaded - saves a redundant DB query in the handler
297
297
  if (resource && !req.resource) req.resource = resource;
298
298
  next();
299
299
  };
@@ -306,8 +306,8 @@ function gate(policy, action, getResource)
306
306
  * Call this middleware after JWT/session middleware.
307
307
  *
308
308
  * Adds:
309
- * - `req.user.is(...roles)` check roles
310
- * - `req.user.can(...perms)` check permissions
309
+ * - `req.user.is(...roles)` - check roles
310
+ * - `req.user.can(...perms)` - check permissions
311
311
  *
312
312
  * @returns {Function} Middleware.
313
313
  *
@@ -5,10 +5,10 @@
5
5
  * for TOTP-based two-factor authentication.
6
6
  *
7
7
  * Steps:
8
- * 1. `start()` Generate secret + backup codes, store in session
9
- * 2. `verify()` Confirm user can produce a valid TOTP code
10
- * 3. `complete()` Persist the verified secret to the database
11
- * 4. `disable()` Remove 2FA from the account
8
+ * 1. `start()` - Generate secret + backup codes, store in session
9
+ * 2. `verify()` - Confirm user can produce a valid TOTP code
10
+ * 3. `complete()` - Persist the verified secret to the database
11
+ * 4. `disable()` - Remove 2FA from the account
12
12
  *
13
13
  * @example | Full enrollment flow
14
14
  * const { enrollment } = require('@zero-server/sdk');
@@ -356,7 +356,7 @@ function enrollment(opts = {})
356
356
 
357
357
  function _defaultGetAccount(req)
358
358
  {
359
- if (!req.user) throw new Error('No user on request authentication middleware required');
359
+ if (!req.user) throw new Error('No user on request - authentication middleware required');
360
360
  return req.user.email || req.user.id || req.user.sub;
361
361
  }
362
362
 
package/lib/auth/jwt.js CHANGED
@@ -13,7 +13,7 @@
13
13
  * const app = createApp();
14
14
  * const SECRET = process.env.JWT_SECRET;
15
15
  *
16
- * // Public issue tokens
16
+ * // Public - issue tokens
17
17
  * app.post('/login', json(), async (req, res) => {
18
18
  * const { email, password } = req.body;
19
19
  * const user = await db.users.findOne({ email });
@@ -24,7 +24,7 @@
24
24
  * res.json({ token });
25
25
  * });
26
26
  *
27
- * // Protected everything under /api requires a valid token
27
+ * // Protected - everything under /api requires a valid token
28
28
  * const api = Router();
29
29
  * api.use(jwt({ secret: SECRET }));
30
30
  * api.get('/me', (req, res) => res.json({ id: req.user.sub, role: req.user.role }));
@@ -79,7 +79,7 @@ function _base64urlDecode(str)
79
79
 
80
80
  /**
81
81
  * Decode a JWT without verifying the signature.
82
- * Returns `null` for malformed tokens never throws.
82
+ * Returns `null` for malformed tokens - never throws.
83
83
  *
84
84
  * @param {string} token - Raw JWT string.
85
85
  * @returns {{ header: object, payload: object, signature: string }|null}
@@ -268,7 +268,7 @@ function verify(token, secretOrKey, opts = {})
268
268
  * @param {Function} [opts.fetcher] - Custom fetch function (default: built-in fetch).
269
269
  * @param {number} [opts.cacheTtl=600000] - Cache TTL in ms (default 10 minutes).
270
270
  * @param {number} [opts.requestTimeout=5000] - Request timeout in ms.
271
- * @returns {Function} `async (header) => publicKey` resolves the signing key for a JWT header.
271
+ * @returns {Function} `async (header) => publicKey` - resolves the signing key for a JWT header.
272
272
  *
273
273
  * @example
274
274
  * const getKey = jwks('https://auth.example.com/.well-known/jwks.json');
@@ -330,7 +330,7 @@ function jwks(jwksUri, opts = {})
330
330
  return pem;
331
331
  }
332
332
 
333
- // No kid return the first RSA key
333
+ // No kid - return the first RSA key
334
334
  const first = keys.values().next().value;
335
335
  if (!first) throw _jwtError('No suitable key in JWKS', 'JWKS_NO_KEY');
336
336
  return first;
@@ -347,9 +347,9 @@ function jwks(jwksUri, opts = {})
347
347
  * Create JWT authentication middleware.
348
348
  *
349
349
  * On success, populates:
350
- * - `req.user` decoded payload
351
- * - `req.auth` `{ header, payload, token }` full decode info
352
- * - `req.token` raw JWT string
350
+ * - `req.user` - decoded payload
351
+ * - `req.auth` - `{ header, payload, token }` full decode info
352
+ * - `req.token` - raw JWT string
353
353
  *
354
354
  * @param {object} opts - Configuration.
355
355
  * @param {string|Buffer} [opts.secret] - HMAC secret for HS* algorithms.
@@ -367,7 +367,7 @@ function jwks(jwksUri, opts = {})
367
367
  * @param {number} [opts.clockTolerance=0] - Clock skew tolerance in seconds.
368
368
  * @param {number} [opts.maxAge] - Maximum token age in seconds.
369
369
  * @param {boolean} [opts.credentialsRequired=true] - Return 401 if no token found (false = optional auth).
370
- * @param {Function} [opts.isRevoked] - `async (payload) => boolean` check token revocation.
370
+ * @param {Function} [opts.isRevoked] - `async (payload) => boolean` - check token revocation.
371
371
  * @param {Function} [opts.onError] - Custom error handler `(err, req, res) => void`.
372
372
  * @returns {Function} Middleware `(req, res, next) => void`.
373
373
  *
package/lib/auth/oauth.js CHANGED
@@ -224,7 +224,7 @@ function oauth(opts = {})
224
224
  // Validate state (CSRF prevention)
225
225
  if (verify.state && query.state !== verify.state)
226
226
  {
227
- throw _oauthError('State mismatch possible CSRF attack', 'OAUTH_STATE_MISMATCH');
227
+ throw _oauthError('State mismatch - possible CSRF attack', 'OAUTH_STATE_MISMATCH');
228
228
  }
229
229
 
230
230
  const body = {
@@ -263,7 +263,7 @@ class Session
263
263
  return { ...this._flash };
264
264
  }
265
265
 
266
- /** @private serialize to JSON for cookie/store */
266
+ /** @private - serialize to JSON for cookie/store */
267
267
  _serialize()
268
268
  {
269
269
  const obj = { d: this._data };
@@ -271,7 +271,7 @@ class Session
271
271
  return JSON.stringify(obj);
272
272
  }
273
273
 
274
- /** @private deserialize from JSON */
274
+ /** @private - deserialize from JSON */
275
275
  static _deserialize(json, id)
276
276
  {
277
277
  try
@@ -472,7 +472,7 @@ function session(opts = {})
472
472
  req.session = sess;
473
473
 
474
474
  // Intercept response to persist session
475
- // Hook into res.raw.end (Node ServerResponse) the Response wrapper
475
+ // Hook into res.raw.end (Node ServerResponse) - the Response wrapper
476
476
  // has no .end() method; its .send()/.json() helpers call raw.end().
477
477
  const raw = res.raw;
478
478
  const origEnd = raw.end.bind(raw);
@@ -481,7 +481,7 @@ function session(opts = {})
481
481
  try
482
482
  {
483
483
  // _saveSession calls res.cookie() / res.clearCookie() which set
484
- // Set-Cookie headers on raw via raw.setHeader safe because
484
+ // Set-Cookie headers on raw via raw.setHeader - safe because
485
485
  // headers aren't flushed until the original end() runs.
486
486
  // NOTE: store-based sessions are sync-compatible because
487
487
  // MemoryStore.set/get return resolved promises synchronously
@@ -574,7 +574,7 @@ function _saveSession(req, res, sess, ctx)
574
574
  const encrypted = _encrypt(payload, ctx.keys[0]);
575
575
  if (encrypted.length > MAX_COOKIE_SIZE)
576
576
  {
577
- log.warn('session cookie exceeds %d bytes consider using a store', MAX_COOKIE_SIZE);
577
+ log.warn('session cookie exceeds %d bytes - consider using a store', MAX_COOKIE_SIZE);
578
578
  }
579
579
  res.cookie(ctx.cookieName, encrypted, cOpts);
580
580
  log.debug('cookie session saved');
@@ -7,7 +7,7 @@
7
7
  * Subsequent requests skip the 2FA prompt if the trust token is valid.
8
8
  * Supports secret rotation, IP binding, and revocation.
9
9
  *
10
- * Uses AES-256-GCM encryption tokens are encrypted, not just signed,
10
+ * Uses AES-256-GCM encryption - tokens are encrypted, not just signed,
11
11
  * preventing information leakage.
12
12
  *
13
13
  * @example
@@ -370,7 +370,7 @@ function _defaultFingerprint(req)
370
370
  */
371
371
  function _defaultGetUserId(req)
372
372
  {
373
- if (!req.user) throw new Error('No user on request authentication middleware required');
373
+ if (!req.user) throw new Error('No user on request - authentication middleware required');
374
374
  return req.user.id || req.user.sub || req.user._id;
375
375
  }
376
376
 
@@ -4,7 +4,7 @@
4
4
  * Implements TOTP (RFC 6238 / RFC 4226), backup codes,
5
5
  * and composable middleware for step-up verification.
6
6
  *
7
- * Uses only Node.js built-in `crypto` no external packages.
7
+ * Uses only Node.js built-in `crypto` - no external packages.
8
8
  *
9
9
  * @example | Setup 2FA for a user
10
10
  * const { twoFactor } = require('@zero-server/sdk');
@@ -228,7 +228,7 @@ function _base32Decode(str)
228
228
 
229
229
  /**
230
230
  * Generate an HOTP code for a given counter value.
231
- * Implements RFC 4226 §5 HMAC-based One-Time Password.
231
+ * Implements RFC 4226 §5 - HMAC-based One-Time Password.
232
232
  *
233
233
  * @param {Buffer} secret - Shared secret key.
234
234
  * @param {number} counter - 8-byte counter value.
@@ -498,13 +498,13 @@ function verifyBackupCode(code, hashes)
498
498
 
499
499
  /**
500
500
  * Middleware that requires completed 2FA verification on the session.
501
- * Checks `req.session.get('twoFactorVerified')` returns 403 if not set.
501
+ * Checks `req.session.get('twoFactorVerified')` - returns 403 if not set.
502
502
  *
503
503
  * Designed to compose with `jwt()` or `session()` middleware:
504
504
  *
505
505
  * app.use(jwt({ secret }));
506
506
  * app.use(require2FA());
507
- * // or
507
+ * // - or -
508
508
  * app.use(session({ secret }));
509
509
  * app.use(require2FA());
510
510
  *
@@ -517,7 +517,7 @@ function verifyBackupCode(code, hashes)
517
517
  * Defaults to always requiring 2FA.
518
518
  * @returns {Function} Middleware `(req, res, next) => void`.
519
519
  *
520
- * @example | Basic all authenticated users must complete 2FA
520
+ * @example | Basic - all authenticated users must complete 2FA
521
521
  * app.use(require2FA());
522
522
  *
523
523
  * @example | Only enforce for users who have enrolled
@@ -548,7 +548,7 @@ function require2FA(opts = {})
548
548
  const enabled = await isEnabled(req);
549
549
  if (!enabled)
550
550
  {
551
- log('2FA not enabled for user skipping');
551
+ log('2FA not enabled for user - skipping');
552
552
  return next();
553
553
  }
554
554
  }
@@ -568,7 +568,7 @@ function require2FA(opts = {})
568
568
  const session = req.session;
569
569
  if (!session || typeof session.get !== 'function')
570
570
  {
571
- log.warn('require2FA: no session found is session() middleware active?');
571
+ log.warn('require2FA: no session found - is session() middleware active?');
572
572
  const raw = res.raw || res;
573
573
  if (raw.headersSent) return;
574
574
  raw.statusCode = 500;
@@ -583,7 +583,7 @@ function require2FA(opts = {})
583
583
  return next();
584
584
  }
585
585
 
586
- log.warn('2FA not completed blocking request');
586
+ log.warn('2FA not completed - blocking request');
587
587
  const raw = res.raw || res;
588
588
  if (raw.headersSent) return;
589
589
  raw.statusCode = statusCode;
@@ -690,7 +690,7 @@ function verifyTOTPMiddleware(opts = {})
690
690
  raw.end(JSON.stringify({ error: 'Too many attempts. Try again later.', retryAfter }));
691
691
  return;
692
692
  }
693
- // Lockout expired reset
693
+ // Lockout expired - reset
694
694
  attempts.delete(ip);
695
695
  }
696
696
 
@@ -735,7 +735,7 @@ function verifyTOTPMiddleware(opts = {})
735
735
 
736
736
  if (result.valid)
737
737
  {
738
- // Replay prevention (RFC 6238 §5.2) check AFTER signature
738
+ // Replay prevention (RFC 6238 §5.2) - check AFTER signature
739
739
  // verification to avoid leaking timing information about whether
740
740
  // a code was previously used.
741
741
  if (opts.replayStore)
@@ -775,7 +775,7 @@ function verifyTOTPMiddleware(opts = {})
775
775
  catch (err)
776
776
  {
777
777
  log.error('replay store error: %s', err.message);
778
- // Fail open for store errors don't block legitimate users
778
+ // Fail open for store errors - don't block legitimate users
779
779
  }
780
780
  }
781
781
 
@@ -145,7 +145,7 @@ const cbor = {
145
145
  if (additionalInfo === 23) return undefined;
146
146
  if (additionalInfo === 25)
147
147
  {
148
- // float16 not commonly used in WebAuthn but handle it
148
+ // float16 - not commonly used in WebAuthn but handle it
149
149
  offset -= 0; // already read
150
150
  return readArgument(additionalInfo);
151
151
  }
@@ -593,7 +593,7 @@ function verifyRegistration(opts)
593
593
  if (clientData.type !== 'webauthn.create')
594
594
  return { verified: false, credential: null, error: `Invalid type: ${clientData.type}` };
595
595
 
596
- // Strict origin validation exact match, no regex
596
+ // Strict origin validation - exact match, no regex
597
597
  if (clientData.origin !== expectedOrigin)
598
598
  return { verified: false, credential: null, error: `Origin mismatch: ${clientData.origin}` };
599
599
 
@@ -627,7 +627,7 @@ function verifyRegistration(opts)
627
627
 
628
628
  if (fmt === 'none')
629
629
  {
630
- // No attestation acceptable for 'none' conveyance
630
+ // No attestation - acceptable for 'none' conveyance
631
631
  log.debug('registration with "none" attestation format');
632
632
  }
633
633
  else if (fmt === 'packed')
@@ -644,7 +644,7 @@ function verifyRegistration(opts)
644
644
  }
645
645
  else
646
646
  {
647
- log.warn('unknown attestation format: %s treating as none', fmt);
647
+ log.warn('unknown attestation format: %s - treating as none', fmt);
648
648
  }
649
649
 
650
650
  // 8. Extract public key from COSE format
@@ -703,7 +703,7 @@ function _verifyPackedAttestation(attStmt, parsedAuthData, rawAuthData, clientDa
703
703
  }
704
704
  else
705
705
  {
706
- // Self-attestation verify with the credential public key
706
+ // Self-attestation - verify with the credential public key
707
707
  const { key } = _coseToPublicKey(parsedAuthData.credentialPublicKey);
708
708
  const algName = _coseAlgToNodeAlg(alg);
709
709
  return crypto.verify(algName, signedData, key, sig);
@@ -881,7 +881,7 @@ function verifyAuthentication(opts)
881
881
  if (!authData.userPresent)
882
882
  return { verified: false, newCounter: null, error: 'User not present' };
883
883
 
884
- // 5. Counter validation detect cloned authenticators
884
+ // 5. Counter validation - detect cloned authenticators
885
885
  if (authData.signCount > 0 || credential.counter > 0)
886
886
  {
887
887
  if (authData.signCount <= credential.counter)
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
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zero-server/auth",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
4
4
  "description": "JWT, sessions, OAuth, authorize, MFA stack.",
5
5
  "keywords": [
6
6
  "zero-server",
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "sideEffects": false,
47
47
  "dependencies": {
48
- "@zero-server/fetch": "0.9.5"
48
+ "@zero-server/fetch": "0.9.7"
49
49
  },
50
50
  "peerDependencies": {
51
- "@zero-server/sdk": ">=0.9.5"
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 {}