@observertc/observer-js 1.0.0-beta.17 → 1.0.0-beta.18

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
@@ -262,7 +262,10 @@ deliberately distinct:
262
262
 
263
263
  - **`appData`** — application-assigned extra info that identifies/decorates an entity, fixed at
264
264
  creation (via `settings.appData` or the `createCallAppData` / `createClientAppData` factories),
265
- or assigned by the app on the `*-added` events. The library never changes it.
265
+ or assigned by the app on the `*-added` events. The library never changes it. The factories
266
+ **receive the context of the `accept()` that triggered the creation**, so a fact carried on the
267
+ context can be baked into `appData` at birth — but it is copied by the factory, deliberately, not
268
+ written across by the library.
266
269
  - **`context`** — passed per `accept()`, may differ on every call, and is carried straight
267
270
  through to the `*-updated` events that the `accept()` triggers, then discarded.
268
271
 
@@ -470,8 +473,8 @@ type ObserverConfig<AppData = Record<string, unknown>> = {
470
473
  callSummary?: Partial<CallSummaryConfig> | null;
471
474
  // appData factories — run when an entity is created without explicit appData
472
475
  // (incl. lazily by accept()). appData is application-owned; accept `context` never touches it.
473
- createCallAppData?: (p: { callId: string; observer: Observer }) => Record<string, unknown>;
474
- createClientAppData?: (p: { clientId: string; observedCall: ObservedCall }) => Record<string, unknown>;
476
+ createCallAppData?: (p: { callId: string; observer: Observer; acceptCtx?: AcceptContext }) => Record<string, unknown>;
477
+ createClientAppData?: (p: { clientId: string; observedCall: ObservedCall; acceptCtx?: AcceptContext }) => Record<string, unknown>;
475
478
  // sink factory — produces a per-client sink that receives every accepted sample (see Sinks).
476
479
  createClientSink?: (p: { clientId: string; observedCall: ObservedCall }) => ClientSampleSink | undefined;
477
480
  // remote-track-resolver factory — produces a call's RemoteTrackResolver (see Remote track resolution).
@@ -480,26 +483,36 @@ type ObserverConfig<AppData = Record<string, unknown>> = {
480
483
  ```
481
484
 
482
485
  **appData factories.** Instead of pre-creating a call/client (or assigning on `call-added` /
483
- `client-added`) just to enrich its `appData`, register a factory once. It runs in the entity's
484
- constructor whenever it's created without an explicit `settings.appData` — including the lazy
485
- creation inside `accept()`. The `client` factory receives the already-created parent
486
- `observedCall`, so it can derive fields from it. `appData` is application-owned and is never
487
- modified by the `accept()` context.
486
+ `client-added`) just to enrich its `appData`, register a factory once. It runs whenever the entity
487
+ is created without an explicit `settings.appData` — including the lazy creation inside `accept()`.
488
+ The `client` factory receives the already-created parent `observedCall`, so it can derive fields
489
+ from it.
490
+
491
+ Both also receive **`acceptCtx`**: the [`AcceptContext`](#context-the-acceptcontext) of the
492
+ `accept()` that caused the creation, or `undefined` when you created the entity yourself. This is
493
+ what lets an [accept middleware](#accept-middlewares-global-pre-dispatch-hook) resolve something
494
+ once — a tenant, a trace id — and have it land in `appData` at birth, instead of every factory
495
+ re-deriving it from the sample.
488
496
 
489
497
  ```ts
490
498
  const observer = new Observer({
491
- createCallAppData: ({ callId }) => ({ callId, startedAt: Date.now(), region: 'eu' }),
492
- createClientAppData: ({ clientId, observedCall }) => ({ clientId, region: observedCall.appData.region }),
499
+ createCallAppData: ({ callId, acceptCtx }) => ({ callId, startedAt: Date.now(), tenant: acceptCtx?.tenant }),
500
+ createClientAppData: ({ clientId, observedCall }) => ({ clientId, tenant: observedCall.appData.tenant }),
493
501
  });
502
+
503
+ observer.accept(sample, { tenant: 'acme' });
494
504
  ```
495
505
 
506
+ `appData` stays application-owned: the context is *offered* to the factory, never written across by
507
+ the library, and it is still not stored on any entity.
508
+
496
509
  Key members:
497
510
 
498
511
  - `accept(sample: ClientSample, context?: AcceptContext): void`
499
512
  - `addAcceptMiddleware(...mw: AcceptMiddleware[]): this` / `removeAcceptMiddleware(...mw): this` — global pre-dispatch sample hooks (see [Accept middlewares](#accept-middlewares-global-pre-dispatch-hook))
500
513
  - `getObservedCall<T>(callId): ObservedCall<T> | undefined`
501
- - `createObservedCall<T>(settings): ObservedCall<T> | undefined`
502
- - `getOrCreateObservedCall<T>(settings): ObservedCall<T> | undefined`
514
+ - `createObservedCall<T>(settings, acceptCtx?): ObservedCall<T> | undefined`
515
+ - `getOrCreateObservedCall<T>(settings, acceptCtx?): ObservedCall<T> | undefined`
503
516
  - `addIssue(issue: Omit<ObserverIssue, 'scope'>): void` — raise an **observer-level** finding → emits `observer-issue`. `scope` is stamped for you
504
517
  - `update(): void` — force an aggregation/`observer-updated` tick
505
518
  - `addObserverDetector(name, config?): this` — build a cross-call detector onto `observer.detectors`
@@ -544,7 +557,7 @@ Key members:
544
557
 
545
558
  - `readonly callId: string`, `appData: AppData`
546
559
  - `readonly observedClients: Map<string, ObservedClient>`, `get numberOfClients()`
547
- - `getObservedClient<T>(clientId)`, `createObservedClient<T>(settings)`, `getOrCreateObservedClient<T>(settings)` (all `… | undefined`)
560
+ - `getObservedClient<T>(clientId)`, `createObservedClient<T>(settings, acceptCtx?)`, `getOrCreateObservedClient<T>(settings, acceptCtx?)` (all `… | undefined`)
548
561
  - `addIssue(issue: Omit<CallIssue, 'scope'>): void` — raise a **call-level** finding → emits `call-issue`. `scope` is stamped for you
549
562
  - `addDetector(name, config?): this` — build a call-scoped detector onto this call only
550
563
  - `removeDetector(name): number` — remove it from this call, `close()`ing it. For one specific
package/dist/index.d.mts CHANGED
@@ -4952,8 +4952,8 @@ declare class ObservedCall<AppData extends Record<string, unknown> = Record<stri
4952
4952
  addIssue(issue: Omit<CallIssue, 'scope'>): void;
4953
4953
  close(): void;
4954
4954
  getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined;
4955
- createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined;
4956
- getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined;
4955
+ createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
4956
+ getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
4957
4957
  update(context?: AcceptContext): void;
4958
4958
  private _onClientUpdate;
4959
4959
  private _clientJoined;
@@ -5430,11 +5430,13 @@ type AcceptMiddleware = Middleware<AcceptMiddlewarePayload>;
5430
5430
  type CallAppDataFactory = (params: {
5431
5431
  callId: string;
5432
5432
  observer: Observer;
5433
+ acceptCtx?: AcceptContext;
5433
5434
  }) => Record<string, unknown>;
5434
5435
  /** Produces the initial `appData` for a client created without an explicit `appData`. */
5435
5436
  type ClientAppDataFactory = (params: {
5436
5437
  clientId: string;
5437
5438
  observedCall: ObservedCall;
5439
+ acceptCtx?: AcceptContext;
5438
5440
  }) => Record<string, unknown>;
5439
5441
  type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
5440
5442
  appData?: AppData;
@@ -5661,8 +5663,13 @@ declare class Observer<AppData extends Record<string, unknown> = Record<string,
5661
5663
  */
5662
5664
  cancelValidator(target: keyof AvailableValidatorConfigs | RunningValidator, reason?: string): number;
5663
5665
  getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined;
5664
- createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>): ObservedCall<T> | undefined;
5665
- getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>): ObservedCall<T> | undefined;
5666
+ /**
5667
+ * @param acceptCtx the `accept()` context, when this call is being created to receive a sample.
5668
+ * Passed on to `ObserverConfig.createCallAppData`, so the factory can read whatever the caller (or
5669
+ * an accept middleware) put there — a tenant, a region, a trace id.
5670
+ */
5671
+ createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>, acceptCtx?: AcceptContext): ObservedCall<T> | undefined;
5672
+ getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>, acceptCtx?: AcceptContext): ObservedCall<T> | undefined;
5666
5673
  createObservedMediasoupRouter<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedMediasoupRouterSettings<T> & {
5667
5674
  matchPeerConnectionByWebRtcTransportId?: boolean;
5668
5675
  }): ObservedMediasoupRouter<Record<string, unknown>> | undefined;
package/dist/index.d.ts CHANGED
@@ -4952,8 +4952,8 @@ declare class ObservedCall<AppData extends Record<string, unknown> = Record<stri
4952
4952
  addIssue(issue: Omit<CallIssue, 'scope'>): void;
4953
4953
  close(): void;
4954
4954
  getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined;
4955
- createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined;
4956
- getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> | undefined;
4955
+ createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
4956
+ getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
4957
4957
  update(context?: AcceptContext): void;
4958
4958
  private _onClientUpdate;
4959
4959
  private _clientJoined;
@@ -5430,11 +5430,13 @@ type AcceptMiddleware = Middleware<AcceptMiddlewarePayload>;
5430
5430
  type CallAppDataFactory = (params: {
5431
5431
  callId: string;
5432
5432
  observer: Observer;
5433
+ acceptCtx?: AcceptContext;
5433
5434
  }) => Record<string, unknown>;
5434
5435
  /** Produces the initial `appData` for a client created without an explicit `appData`. */
5435
5436
  type ClientAppDataFactory = (params: {
5436
5437
  clientId: string;
5437
5438
  observedCall: ObservedCall;
5439
+ acceptCtx?: AcceptContext;
5438
5440
  }) => Record<string, unknown>;
5439
5441
  type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unknown>> = {
5440
5442
  appData?: AppData;
@@ -5661,8 +5663,13 @@ declare class Observer<AppData extends Record<string, unknown> = Record<string,
5661
5663
  */
5662
5664
  cancelValidator(target: keyof AvailableValidatorConfigs | RunningValidator, reason?: string): number;
5663
5665
  getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined;
5664
- createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>): ObservedCall<T> | undefined;
5665
- getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>): ObservedCall<T> | undefined;
5666
+ /**
5667
+ * @param acceptCtx the `accept()` context, when this call is being created to receive a sample.
5668
+ * Passed on to `ObserverConfig.createCallAppData`, so the factory can read whatever the caller (or
5669
+ * an accept middleware) put there — a tenant, a region, a trace id.
5670
+ */
5671
+ createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>, acceptCtx?: AcceptContext): ObservedCall<T> | undefined;
5672
+ getOrCreateObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedCallSettings<T>, acceptCtx?: AcceptContext): ObservedCall<T> | undefined;
5666
5673
  createObservedMediasoupRouter<T extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedMediasoupRouterSettings<T> & {
5667
5674
  matchPeerConnectionByWebRtcTransportId?: boolean;
5668
5675
  }): ObservedMediasoupRouter<Record<string, unknown>> | undefined;
package/dist/index.js CHANGED
@@ -4475,7 +4475,7 @@ var ObservedCall = class extends import_events3.EventEmitter {
4475
4475
  if (this.closed || !this.observedClients.has(clientId)) return;
4476
4476
  return this.observedClients.get(clientId);
4477
4477
  }
4478
- createObservedClient(settings) {
4478
+ createObservedClient(settings, acceptCtx) {
4479
4479
  if (this.closed) {
4480
4480
  logger4.warn("Attempted to create a client (clientId: %s) on a closed call %s", settings.clientId, this.callId);
4481
4481
  return void 0;
@@ -4484,15 +4484,18 @@ var ObservedCall = class extends import_events3.EventEmitter {
4484
4484
  logger4.warn("Client with id %s already exists in call %s; returning the existing instance", settings.clientId, this.callId);
4485
4485
  return this.observedClients.get(settings.clientId);
4486
4486
  }
4487
- if (!settings.closeClientIfIdleForMs) {
4488
- settings.closeClientIfIdleForMs = this.observer.config.closeClientIfIdleForMs;
4489
- }
4490
- if (settings.appData === void 0) {
4491
- settings.appData = this.observer.config.createClientAppData?.({ clientId: settings.clientId, observedCall: this });
4492
- }
4487
+ const clientSettings = {
4488
+ ...settings,
4489
+ closeClientIfIdleForMs: settings.closeClientIfIdleForMs || this.observer.config.closeClientIfIdleForMs,
4490
+ appData: settings.appData ?? this.observer.config.createClientAppData?.({
4491
+ clientId: settings.clientId,
4492
+ observedCall: this,
4493
+ acceptCtx
4494
+ })
4495
+ };
4493
4496
  const observedClientIssueRegistry = new ObservedClientIssueRegistry(this.activeIssuesRegistry);
4494
4497
  const result = new ObservedClient(
4495
- settings,
4498
+ clientSettings,
4496
4499
  this,
4497
4500
  observedClientIssueRegistry
4498
4501
  );
@@ -4539,8 +4542,8 @@ var ObservedCall = class extends import_events3.EventEmitter {
4539
4542
  }
4540
4543
  return result;
4541
4544
  }
4542
- getOrCreateObservedClient(settings) {
4543
- return this.getObservedClient(settings.clientId) ?? this.createObservedClient(settings);
4545
+ getOrCreateObservedClient(settings, acceptCtx) {
4546
+ return this.getObservedClient(settings.clientId) ?? this.createObservedClient(settings, acceptCtx);
4544
4547
  }
4545
4548
  update(context) {
4546
4549
  if (this.closed) return;
@@ -6788,7 +6791,12 @@ var Observer = class extends import_events6.EventEmitter {
6788
6791
  if (this.closed || !this.observedCalls.has(callId)) return;
6789
6792
  return this.observedCalls.get(callId);
6790
6793
  }
6791
- createObservedCall(settings) {
6794
+ /**
6795
+ * @param acceptCtx the `accept()` context, when this call is being created to receive a sample.
6796
+ * Passed on to `ObserverConfig.createCallAppData`, so the factory can read whatever the caller (or
6797
+ * an accept middleware) put there — a tenant, a region, a trace id.
6798
+ */
6799
+ createObservedCall(settings, acceptCtx) {
6792
6800
  if (this.closed) {
6793
6801
  logger9.warn("Attempted to create a call (callId: %s) on a closed observer", settings.callId);
6794
6802
  return void 0;
@@ -6800,7 +6808,7 @@ var Observer = class extends import_events6.EventEmitter {
6800
6808
  const callSettings = {
6801
6809
  ...settings,
6802
6810
  closeCallIfEmptyForMs: settings.closeCallIfEmptyForMs ?? this.config.closeCallIfEmptyForMs,
6803
- appData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this })
6811
+ appData: settings.appData ?? this.config.createCallAppData?.({ callId: settings.callId, observer: this, acceptCtx })
6804
6812
  };
6805
6813
  const callActiveIssuesRegistry = new ActiveIssuesRegistry(this.activeIssuesRegistry);
6806
6814
  const observedCall = new ObservedCall(
@@ -6827,8 +6835,8 @@ var Observer = class extends import_events6.EventEmitter {
6827
6835
  this._notify("call-added", { ...this.eventScope, observedCall });
6828
6836
  return observedCall;
6829
6837
  }
6830
- getOrCreateObservedCall(settings) {
6831
- return this.getObservedCall(settings.callId) ?? this.createObservedCall(settings);
6838
+ getOrCreateObservedCall(settings, acceptCtx) {
6839
+ return this.getObservedCall(settings.callId) ?? this.createObservedCall(settings, acceptCtx);
6832
6840
  }
6833
6841
  createObservedMediasoupRouter(settings) {
6834
6842
  if (this.closed) {
@@ -6895,21 +6903,9 @@ var Observer = class extends import_events6.EventEmitter {
6895
6903
  this._notify("sample-rejected", { ...this.eventScope, reason: "missing-clientId", sample });
6896
6904
  return;
6897
6905
  }
6898
- let call = this.getObservedCall(sample.callId);
6899
- if (!call) {
6900
- call = this.createObservedCall({
6901
- callId: sample.callId,
6902
- appData: this.config.createCallAppData?.({ callId: sample.callId, observer: this })
6903
- });
6904
- }
6906
+ const call = this.getOrCreateObservedCall({ callId: sample.callId }, context);
6905
6907
  if (!call) return;
6906
- let client = call.getObservedClient(sample.clientId);
6907
- if (!client) {
6908
- client = call.createObservedClient({
6909
- clientId: sample.clientId,
6910
- appData: this.config.createClientAppData?.({ clientId: sample.clientId, observedCall: call })
6911
- });
6912
- }
6908
+ const client = call.getOrCreateObservedClient({ clientId: sample.clientId }, context);
6913
6909
  if (!client) return;
6914
6910
  client.accept(sample, context);
6915
6911
  }