@zero-server/orm 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-featured ORM with seven adapters (memory, JSON file, SQLite, MySQL, Postgre
10
10
  npm install @zero-server/orm
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/orm';
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/orm");
4
4
 
package/lib/debug.js CHANGED
@@ -16,7 +16,7 @@
16
16
  * log.error('failed to connect', err);
17
17
  * log('shorthand for debug level');
18
18
  *
19
- * // Set minimum level anything below is silenced
19
+ * // Set minimum level - anything below is silenced
20
20
  * debug.level('warn'); // only warn, error, fatal
21
21
  * debug.level('silent'); // suppress all output
22
22
  * debug.level('trace'); // show everything
@@ -81,7 +81,7 @@ _enabledPatterns = _parsePatterns();
81
81
  */
82
82
  function _isEnabled(ns)
83
83
  {
84
- if (!_enabledPatterns) return true; // No DEBUG set enable all
84
+ if (!_enabledPatterns) return true; // No DEBUG set - enable all
85
85
  let enabled = false;
86
86
  for (const { neg, re } of _enabledPatterns)
87
87
  {
@@ -116,7 +116,7 @@ function _ts()
116
116
  }
117
117
 
118
118
  /**
119
- * Format arguments (like console.log supports %s, %d, %j, %o).
119
+ * Format arguments (like console.log - supports %s, %d, %j, %o).
120
120
  * @private
121
121
  */
122
122
  function _format(args)
@@ -278,13 +278,13 @@ function debug(namespace)
278
278
  * Messages below this level are silenced.
279
279
  *
280
280
  * @param {string|number} level - Level name or number.
281
- * `'trace'` (0) all output
282
- * `'debug'` (1) debug and above
283
- * `'info'` (2) info and above
284
- * `'warn'` (3) warn and above
285
- * `'error'` (4) error and fatal only
286
- * `'fatal'` (5) fatal only
287
- * `'silent'` (6) nothing
281
+ * `'trace'` (0) - all output
282
+ * `'debug'` (1) - debug and above
283
+ * `'info'` (2) - info and above
284
+ * `'warn'` (3) - warn and above
285
+ * `'error'` (4) - error and fatal only
286
+ * `'fatal'` (5) - fatal only
287
+ * `'silent'` (6) - nothing
288
288
  */
289
289
  debug.level = function(level)
290
290
  {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module orm/adapters/json
3
3
  * @description JSON file-backed database adapter.
4
- * Persists data to JSON files on disk one file per table.
4
+ * Persists data to JSON files on disk - one file per table.
5
5
  * Zero-dependency, suitable for prototyping, small apps, and
6
6
  * embedded scenarios. Uses atomic writes for safety.
7
7
  *
@@ -413,7 +413,7 @@ class MemoryAdapter
413
413
  for (let i = 0; i < where.length; i++)
414
414
  {
415
415
  const clause = where[i];
416
- // Skip raw SQL clauses not supported in memory adapter
416
+ // Skip raw SQL clauses - not supported in memory adapter
417
417
  if (clause.raw) continue;
418
418
  const matches = this._matchClause(row, clause);
419
419
 
@@ -695,7 +695,7 @@ class MemoryAdapter
695
695
 
696
696
  /**
697
697
  * Drop an index.
698
- * @param {string} _table - Table name (unused searches all tables).
698
+ * @param {string} _table - Table name (unused - searches all tables).
699
699
  * @param {string} name - Index name.
700
700
  * @returns {Promise<void>}
701
701
  */
@@ -369,7 +369,7 @@ class MongoAdapter
369
369
 
370
370
  let results = await cursor.toArray();
371
371
 
372
- // Distinct in-memory since MongoDB distinct() only returns values for a single field
372
+ // Distinct - in-memory since MongoDB distinct() only returns values for a single field
373
373
  if (distinct && fields && fields.length > 0)
374
374
  {
375
375
  const seen = new Set();
@@ -420,7 +420,7 @@ class MongoAdapter
420
420
  for (let i = 0; i < where.length; i++)
421
421
  {
422
422
  const w = where[i];
423
- // Skip raw SQL clauses not applicable to MongoDB
423
+ // Skip raw SQL clauses - not applicable to MongoDB
424
424
  if (w.raw) continue;
425
425
  const { field, op, value, logic } = w;
426
426
  const clause = this._opToMongo(field, op, value);
@@ -685,7 +685,7 @@ class MysqlAdapter extends BaseSqlAdapter
685
685
  }
686
686
 
687
687
  /**
688
- * Get full database overview all tables with size and row counts.
688
+ * Get full database overview - all tables with size and row counts.
689
689
  * Returns a structured database summary.
690
690
  * @returns {Promise<{ tables: Array, totalSize: string, totalRows: number }>}
691
691
  */
@@ -724,7 +724,7 @@ class MysqlAdapter extends BaseSqlAdapter
724
724
  }
725
725
 
726
726
  /**
727
- * Get processlist active connections/queries.
727
+ * Get processlist - active connections/queries.
728
728
  * @returns {Promise<Array<{ id: number, user: string, host: string, db: string, command: string, time: number, state: string, info: string }>>}
729
729
  */
730
730
  async processlist()
@@ -129,7 +129,7 @@ class PostgresAdapter extends BaseSqlAdapter
129
129
  {
130
130
  const w = where[i];
131
131
 
132
- // Handle raw WHERE clauses (from whereRaw) convert ? to $N
132
+ // Handle raw WHERE clauses (from whereRaw) - convert ? to $N
133
133
  if (w.raw)
134
134
  {
135
135
  let rawExpr = w.raw;
@@ -847,7 +847,7 @@ class PostgresAdapter extends BaseSqlAdapter
847
847
  }
848
848
 
849
849
  /**
850
- * Get full database overview all tables with size and row counts.
850
+ * Get full database overview - all tables with size and row counts.
851
851
  * @returns {Promise<{ tables: Array, totalSize: string, totalRows: number }>}
852
852
  */
853
853
  async overview()
@@ -84,7 +84,7 @@ class SqliteAdapter extends BaseSqlAdapter
84
84
  this._db = new Database(filename, dbOpts);
85
85
  this._filename = filename;
86
86
 
87
- /** @private Prepared statement cache avoids recompilation overhead */
87
+ /** @private Prepared statement cache - avoids recompilation overhead */
88
88
  this._stmtCache = new Map();
89
89
  /** @private Maximum cached statements before LRU eviction */
90
90
  this._stmtCacheMax = options.stmtCacheSize || 256;
@@ -685,7 +685,7 @@ class SqliteAdapter extends BaseSqlAdapter
685
685
  }
686
686
 
687
687
  /**
688
- * Get counts for all tables structured database overview.
688
+ * Get counts for all tables - structured database overview.
689
689
  * @returns {{ tables: Array<{ name: string, rows: number }>, totalRows: number, fileSize: string }}
690
690
  */
691
691
  overview()
@@ -807,7 +807,7 @@ class SqliteAdapter extends BaseSqlAdapter
807
807
 
808
808
  /**
809
809
  * Drop an index.
810
- * @param {string} _table - Table name (unused SQLite indexes are schema-scoped).
810
+ * @param {string} _table - Table name (unused - SQLite indexes are schema-scoped).
811
811
  * @param {string} name - Index name.
812
812
  */
813
813
  dropIndex(_table, name)
package/lib/orm/audit.js CHANGED
@@ -134,7 +134,7 @@ class AuditLog
134
134
  }
135
135
  else
136
136
  {
137
- // Memory/JSON adapter ensure table structure
137
+ // Memory/JSON adapter - ensure table structure
138
138
  if (typeof adapter.createTable === 'function')
139
139
  {
140
140
  const schema = {
package/lib/orm/index.js CHANGED
@@ -5,12 +5,12 @@
5
5
  * `TYPES` enum, and schema helpers.
6
6
  *
7
7
  * Supported adapters (all optional "bring your own driver"):
8
- * - `memory` in-process (no driver needed)
9
- * - `json` JSON file persistence (no driver needed)
10
- * - `sqlite` requires `better-sqlite3`
11
- * - `mysql` requires `mysql2`
12
- * - `postgres` requires `pg`
13
- * - `mongo` requires `mongodb`
8
+ * - `memory` - in-process (no driver needed)
9
+ * - `json` - JSON file persistence (no driver needed)
10
+ * - `sqlite` - requires `better-sqlite3`
11
+ * - `mysql` - requires `mysql2`
12
+ * - `postgres` - requires `pg`
13
+ * - `mongo` - requires `mongodb`
14
14
  *
15
15
  * @example
16
16
  * const { Database, Model, TYPES } = require('@zero-server/sdk');
@@ -231,7 +231,7 @@ class Database
231
231
  }
232
232
 
233
233
  /**
234
- * Synchronise all registered models create tables if they don't exist.
234
+ * Synchronise all registered models - create tables if they don't exist.
235
235
  * Tables are ordered so referenced tables are created first (topological sort).
236
236
  * @returns {Promise<void>}
237
237
  */
@@ -322,7 +322,7 @@ class Migrator
322
322
 
323
323
  /**
324
324
  * Fresh start: drop ALL tables (not just migrated ones) then re-migrate.
325
- * ⚠️ DESTRUCTIVE use with caution.
325
+ * ⚠️ DESTRUCTIVE - use with caution.
326
326
  *
327
327
  * @returns {Promise<{ migrated: string[], batch: number }>}
328
328
  */
package/lib/orm/model.js CHANGED
@@ -38,13 +38,13 @@ const { EventEmitter } = require('events');
38
38
  class Model
39
39
  {
40
40
  /**
41
- * Table name override in subclass.
41
+ * Table name - override in subclass.
42
42
  * @type {string}
43
43
  */
44
44
  static table = '';
45
45
 
46
46
  /**
47
- * Column schema override in subclass.
47
+ * Column schema - override in subclass.
48
48
  * @type {Object<string, object>}
49
49
  */
50
50
  static schema = {};
@@ -74,7 +74,7 @@ class Model
74
74
  static hidden = [];
75
75
 
76
76
  /**
77
- * Named query scopes reusable query conditions.
77
+ * Named query scopes - reusable query conditions.
78
78
  * Each scope is a function that receives a Query and returns it.
79
79
  * @type {Object<string, Function>}
80
80
  *
@@ -103,7 +103,7 @@ class Model
103
103
  // -- Computed & Virtual Columns ---------------------
104
104
 
105
105
  /**
106
- * Computed column definitions virtual columns derived from other fields.
106
+ * Computed column definitions - virtual columns derived from other fields.
107
107
  * Not stored in the database; calculated on the fly.
108
108
  * Each entry maps a column name to a getter function `(instance) => value`.
109
109
  * @type {Object<string, Function>}
@@ -122,17 +122,17 @@ class Model
122
122
  static computed = {};
123
123
 
124
124
  /**
125
- * Attribute casts automatic type transformations on get/set.
125
+ * Attribute casts - automatic type transformations on get/set.
126
126
  * Maps column names to cast types or custom cast objects.
127
127
  *
128
128
  * Built-in cast types:
129
- * - `'json'` JSON.parse on get, JSON.stringify on set
130
- * - `'boolean'` Cast to true/false
131
- * - `'integer'` parseInt
132
- * - `'float'` parseFloat
133
- * - `'date'` Cast to Date object
134
- * - `'string'` Cast to String
135
- * - `'array'` JSON parse/stringify for array data
129
+ * - `'json'` - JSON.parse on get, JSON.stringify on set
130
+ * - `'boolean'` - Cast to true/false
131
+ * - `'integer'` - parseInt
132
+ * - `'float'` - parseFloat
133
+ * - `'date'` - Cast to Date object
134
+ * - `'string'` - Cast to String
135
+ * - `'array'` - JSON parse/stringify for array data
136
136
  *
137
137
  * Custom casts:
138
138
  * - `{ get: (v) => transformed, set: (v) => transformed }`
@@ -211,7 +211,7 @@ class Model
211
211
  static _relations = {};
212
212
 
213
213
  /**
214
- * Database adapter reference set by Database.register().
214
+ * Database adapter reference - set by Database.register().
215
215
  * @type {object|null}
216
216
  * @private
217
217
  */
@@ -222,7 +222,7 @@ class Model
222
222
  /**
223
223
  * @constructor
224
224
  * Create a model instance from a data row.
225
- * Generally you won't call this directly use static methods.
225
+ * Generally you won't call this directly - use static methods.
226
226
  *
227
227
  * @param {object} data - Row data.
228
228
  */
@@ -825,7 +825,7 @@ class Model
825
825
 
826
826
  /**
827
827
  * Get all records, optionally filtered.
828
- * Alias for find() for LINQ-familiarity.
828
+ * Alias for find() - for LINQ-familiarity.
829
829
  *
830
830
  * @param {object} [conditions={}] - WHERE conditions.
831
831
  * @returns {Promise<Model[]>} All matching records.
@@ -56,7 +56,7 @@ class StoredProcedure
56
56
  throw new Error('StoredProcedure requires a "body" string');
57
57
  }
58
58
 
59
- // Sanitize name only allow identifiers
59
+ // Sanitize name - only allow identifiers
60
60
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name))
61
61
  {
62
62
  throw new Error(`Invalid procedure name: "${name}"`);
@@ -117,7 +117,7 @@ class QueryProfiler
117
117
 
118
118
  if (!counter || (now - counter.firstTs) >= this._n1Window)
119
119
  {
120
- // Window expired or first query start a new window
120
+ // Window expired or first query - start a new window
121
121
  counter = { count: 1, firstTs: now };
122
122
  this._selectCounters.set(table, counter);
123
123
  return;
package/lib/orm/query.js CHANGED
@@ -388,7 +388,7 @@ class Query
388
388
  }
389
389
 
390
390
  /**
391
- * Alias for with() mirrors Entity Framework include syntax.
391
+ * Alias for with() - mirrors Entity Framework include syntax.
392
392
  * @param {...string|object} relations - Relation names or config objects to eager-load.
393
393
  * @returns {Query} This query for chaining.
394
394
  */
@@ -998,7 +998,7 @@ class Query
998
998
  }
999
999
 
1000
1000
  /**
1001
- * Make Query thenable allows `await query`.
1001
+ * Make Query thenable - allows `await query`.
1002
1002
  * @param {Function} resolve - Fulfillment handler.
1003
1003
  * @param {Function} reject - Rejection handler.
1004
1004
  * @returns {Promise} Result of exec().
@@ -1043,7 +1043,7 @@ class Query
1043
1043
  }
1044
1044
 
1045
1045
  /**
1046
- * Alias for exec explicitly convert to array.
1046
+ * Alias for exec - explicitly convert to array.
1047
1047
  * @returns {Promise<Array>} Matching rows as an array.
1048
1048
  */
1049
1049
  toArray()
@@ -1072,7 +1072,7 @@ class Query
1072
1072
  }
1073
1073
 
1074
1074
  /**
1075
- * Alias for first() C# FirstOrDefault returns null on empty.
1075
+ * Alias for first() - C# FirstOrDefault returns null on empty.
1076
1076
  * @returns {Promise<object|null>} Matching row or null.
1077
1077
  */
1078
1078
  firstOrDefault()
@@ -1081,7 +1081,7 @@ class Query
1081
1081
  }
1082
1082
 
1083
1083
  /**
1084
- * Alias for avg() C# naming.
1084
+ * Alias for avg() - C# naming.
1085
1085
  * @param {string} field - Column name.
1086
1086
  * @returns {Promise<number>} Average of the column values.
1087
1087
  */
@@ -1091,7 +1091,7 @@ class Query
1091
1091
  }
1092
1092
 
1093
1093
  /**
1094
- * Alias for reduce() C# Aggregate naming.
1094
+ * Alias for reduce() - C# Aggregate naming.
1095
1095
  * @param {Function} fn - Callback function.
1096
1096
  * @param {*} seed - Initial accumulator value.
1097
1097
  * @returns {Promise<*>} Accumulated value.
@@ -1126,7 +1126,7 @@ class Query
1126
1126
  }
1127
1127
 
1128
1128
  /**
1129
- * Alias for last() C# naming.
1129
+ * Alias for last() - C# naming.
1130
1130
  * @returns {Promise<object|null>} Matching row or null.
1131
1131
  */
1132
1132
  lastOrDefault()
@@ -1346,7 +1346,7 @@ class Query
1346
1346
  // -- Projection --
1347
1347
 
1348
1348
  /**
1349
- * FlatMap project each element to an array and flatten.
1349
+ * FlatMap - project each element to an array and flatten.
1350
1350
  * @param {Function} fn - (item, index) => Array
1351
1351
  * @returns {Promise<Array>} Flattened projected results.
1352
1352
  */
@@ -1599,7 +1599,7 @@ class Query
1599
1599
  }
1600
1600
 
1601
1601
  /**
1602
- * Inverse of when apply query logic when condition is falsy.
1602
+ * Inverse of when - apply query logic when condition is falsy.
1603
1603
  *
1604
1604
  * @param {*} condition - Condition to evaluate.
1605
1605
  * @param {Function} fn - Callback function.
package/lib/orm/schema.js CHANGED
@@ -180,7 +180,7 @@ function validateValue(value, colDef, colName)
180
180
  try { return JSON.parse(value); }
181
181
  catch (e) { throw new Error(`"${colName}" must be valid JSON`); }
182
182
  }
183
- // Already an object/array return as-is for storage
183
+ // Already an object/array - return as-is for storage
184
184
  return value;
185
185
  }
186
186
  case 'uuid':
@@ -6,7 +6,7 @@
6
6
  * job titles, prefixes/suffixes, gender, bio phrases, zodiac signs.
7
7
  */
8
8
 
9
- /** Title prefixes separate lists per target sex for contextual use. */
9
+ /** Title prefixes - separate lists per target sex for contextual use. */
10
10
  const NAME_PREFIXES = {
11
11
  male: ['Mr.', 'Dr.', 'Prof.'],
12
12
  female: ['Ms.', 'Mrs.', 'Dr.', 'Prof.', 'Miss'],
@@ -5,13 +5,13 @@
5
5
  * @description Extensible fake data generator.
6
6
  *
7
7
  * Key capabilities:
8
- * • Seeded / reproducible output Fake.seed(42)
9
- * • Guaranteed-unique values Fake.unique(() => Fake.email())
10
- * • Multi-locale names Fake.firstName({ locale: 'ja', sex: 'female' })
11
- * • Rich phone formats Fake.phone({ countryCode: 'DE', format: 'international' })
12
- * • Configurable emails Fake.email({ provider: 'company.io' })
13
- * • Flexible usernames Fake.username({ style: 'underscore' })
14
- * • Fixed-length numeric strings Fake.numericString(8)
8
+ * • Seeded / reproducible output - Fake.seed(42)
9
+ * • Guaranteed-unique values - Fake.unique(() => Fake.email())
10
+ * • Multi-locale names - Fake.firstName({ locale: 'ja', sex: 'female' })
11
+ * • Rich phone formats - Fake.phone({ countryCode: 'DE', format: 'international' })
12
+ * • Configurable emails - Fake.email({ provider: 'company.io' })
13
+ * • Flexible usernames - Fake.username({ style: 'underscore' })
14
+ * • Fixed-length numeric strings - Fake.numericString(8)
15
15
  * • Person: job titles, bio, zodiac, gender, prefix/suffix
16
16
  * • Location: city, country, state, address, lat/lng, timezone
17
17
  * • Commerce: product, company, category, price, industry
@@ -928,7 +928,7 @@ class Fake
928
928
  // -- Internet & Network -------------------------------------------------
929
929
 
930
930
  /**
931
- * Random email address (backward-compatible shorthand same as email()).
931
+ * Random email address (backward-compatible shorthand - same as email()).
932
932
  * Accepts no arguments for historical use.
933
933
  */
934
934
 
@@ -1051,7 +1051,7 @@ class Fake
1051
1051
  static userAgent() { return _pick(USER_AGENTS); }
1052
1052
 
1053
1053
  /**
1054
- * Random password-like string. NOT suitable for real passwords uses a
1054
+ * Random password-like string. NOT suitable for real passwords - uses a
1055
1055
  * PRNG seeded from Math.random, not a CSPRNG.
1056
1056
  *
1057
1057
  * @param {object} [options] - Configuration options.
@@ -1180,7 +1180,7 @@ class Fake
1180
1180
  }
1181
1181
  }
1182
1182
 
1183
- // Static uniqueness tracker shared across all calls in the process lifetime
1183
+ // Static uniqueness tracker - shared across all calls in the process lifetime
1184
1184
  Fake._tracker = new UniqueTracker();
1185
1185
 
1186
1186
  module.exports = { Fake };
@@ -5,10 +5,10 @@
5
5
  * @description Public API for the seed subsystem.
6
6
  *
7
7
  * Re-exports:
8
- * - `Fake` static fake-data generator
9
- * - `Factory` model factory for defining / creating test fixtures
10
- * - `Seeder` base class for database seeders
11
- * - `SeederRunner` orchestrates running multiple seeders
8
+ * - `Fake` - static fake-data generator
9
+ * - `Factory` - model factory for defining / creating test fixtures
10
+ * - `Seeder` - base class for database seeders
11
+ * - `SeederRunner` - orchestrates running multiple seeders
12
12
  */
13
13
 
14
14
  const { Fake } = require('./fake');
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  /**
17
- * mulberry32 minimal, high-quality 32-bit PRNG.
17
+ * mulberry32 - minimal, high-quality 32-bit PRNG.
18
18
  * @param {number} s - Unsigned 32-bit integer seed.
19
19
  * @returns {() => number} Float in [0, 1).
20
20
  */
@@ -234,7 +234,7 @@ function generateMigrationCode(migrationName, changes, currentSnap)
234
234
  for (const table of changes.tables.dropped)
235
235
  {
236
236
  upLines.push(` await db.adapter.dropTable('${table}');`);
237
- // down recreates but we need the previous snapshot's schema for that
237
+ // down recreates - but we need the previous snapshot's schema for that
238
238
  // This is handled via the `prev` reference embedded in the dropped table
239
239
  }
240
240
 
@@ -268,7 +268,7 @@ function generateMigrationCode(migrationName, changes, currentSnap)
268
268
  return `'use strict';
269
269
 
270
270
  /**
271
- * Auto-generated migration ${migrationName}
271
+ * Auto-generated migration - ${migrationName}
272
272
  * Generated by: npx zh make:migration
273
273
  */
274
274
  module.exports = {
@@ -43,8 +43,8 @@ class TenantContext
43
43
  /**
44
44
  * Multi-tenancy manager.
45
45
  * Supports two strategies:
46
- * - `'row'` adds a tenant column to every query (row-level isolation)
47
- * - `'schema'` uses separate database schemas per tenant (PostgreSQL)
46
+ * - `'row'` - adds a tenant column to every query (row-level isolation)
47
+ * - `'schema'` - uses separate database schemas per tenant (PostgreSQL)
48
48
  */
49
49
  class TenantManager
50
50
  {
@@ -242,7 +242,7 @@ class TenantManager
242
242
  const origCount = ModelClass.count.bind(ModelClass);
243
243
  const origExists = ModelClass.exists.bind(ModelClass);
244
244
 
245
- // Patch query() all query builder paths
245
+ // Patch query() - all query builder paths
246
246
  ModelClass.query = function ()
247
247
  {
248
248
  const q = origQuery();
@@ -251,7 +251,7 @@ class TenantManager
251
251
  return q;
252
252
  };
253
253
 
254
- // Patch create() inject tenant column
254
+ // Patch create() - inject tenant column
255
255
  ModelClass.create = async function (data)
256
256
  {
257
257
  const tid = manager.getCurrentTenant();
@@ -283,7 +283,7 @@ class TenantManager
283
283
  return origFindOne(conditions);
284
284
  };
285
285
 
286
- // Patch findById() still applies tenant scope
286
+ // Patch findById() - still applies tenant scope
287
287
  ModelClass.findById = async function (id)
288
288
  {
289
289
  const tid = manager.getCurrentTenant();
@@ -344,7 +344,7 @@ class TenantManager
344
344
  throw new Error('Schema-based tenancy requires a SQL adapter');
345
345
  }
346
346
 
347
- // Sanitize schema name only allow alphanumerics and underscores
347
+ // Sanitize schema name - only allow alphanumerics and underscores
348
348
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(schema))
349
349
  {
350
350
  throw new Error(`Invalid schema name: "${schema}"`);
package/lib/orm/views.js CHANGED
@@ -293,7 +293,7 @@ class DatabaseView
293
293
  const descriptor = this._query.build();
294
294
  const table = descriptor.table;
295
295
 
296
- // Validate field names and table identifier-safe only
296
+ // Validate field names and table - identifier-safe only
297
297
  const idRe = /^[a-zA-Z_][a-zA-Z0-9_.*]*$/;
298
298
  const fields = descriptor.fields
299
299
  ? descriptor.fields.filter(f => idRe.test(f)).join(', ') || '*'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zero-server/orm",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
4
4
  "description": "Database, Model, Query, migrations, seeds, search, geo, tenancy, audit.",
5
5
  "keywords": [
6
6
  "zero-server",
@@ -45,10 +45,10 @@
45
45
  },
46
46
  "sideEffects": false,
47
47
  "dependencies": {
48
- "@zero-server/errors": "0.9.5"
48
+ "@zero-server/errors": "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 {}