@observertc/observer-js 1.2.0 → 1.3.0-rc.2
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 +149 -86
- package/dist/index.d.mts +237 -92
- package/dist/index.d.ts +237 -92
- package/dist/index.js +342 -150
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +340 -148
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -15
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,128 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import { types } from 'mediasoup';
|
|
3
3
|
|
|
4
|
+
/** The lifecycle events a sink emits. */
|
|
5
|
+
type SinkEvents = {
|
|
6
|
+
/**
|
|
7
|
+
* `end()` was called: the sink accepts no more writes. **Required**: a sink emits it
|
|
8
|
+
* synchronously, once, from `end()` — it is how its registry removes it and frees its id.
|
|
9
|
+
*/
|
|
10
|
+
ended: [];
|
|
11
|
+
/** The destination is fully written and closed (e.g. a file flushed and its fd closed). */
|
|
12
|
+
close: [];
|
|
13
|
+
/** The destination failed. */
|
|
14
|
+
error: [Error];
|
|
15
|
+
/** All queued data was flushed (before `close`). */
|
|
16
|
+
finish: [];
|
|
17
|
+
/** The buffer drained after backpressure; safe to write more. */
|
|
18
|
+
drain: [];
|
|
19
|
+
};
|
|
20
|
+
/** What a registry passes to a sink's constructor. Implementations extend it with their own settings. */
|
|
21
|
+
type SinkSettings = {
|
|
22
|
+
/** Unique per observer. The registry generates one (uuid v4) when it is omitted. */
|
|
23
|
+
id: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A destination for records. It is **object-mode** and agnostic about what passes through it:
|
|
27
|
+
* `write` receives the record itself, and the implementation decides how to serialize it (JSON
|
|
28
|
+
* line, protobuf, a remote payload, …). `JsonlFileSink` and `InMemorySink` are the built-in
|
|
29
|
+
* implementations; `ClientSampleSink` is `Sink<ClientSample>`.
|
|
30
|
+
*
|
|
31
|
+
* Create sinks with a registry's `create(SinkClass, settings)`, which constructs
|
|
32
|
+
* `new SinkClass({ ...settings, id })` and registers it on the object that owns its lifecycle.
|
|
33
|
+
* `end()` closes a sink and — through the `ended` event — removes it from its registry; the owner
|
|
34
|
+
* ends whatever is left when it closes.
|
|
35
|
+
*
|
|
36
|
+
* An implementation typically `extends EventEmitter implements Sink<T>`, and must:
|
|
37
|
+
* - emit `ended` synchronously, once, from `end()` (and make a second `end()` a no-op);
|
|
38
|
+
* - refuse writes after `end()` (return `false`);
|
|
39
|
+
* - emit `close` when the destination is ready, and `error` when it fails.
|
|
40
|
+
*/
|
|
41
|
+
interface Sink<T = unknown> {
|
|
42
|
+
readonly id: string;
|
|
43
|
+
/** Accept one record. `false` once ended (nothing written), or on backpressure. */
|
|
44
|
+
write(record: T): boolean;
|
|
45
|
+
/** No more writes; emit `ended`, then flush and emit `close`. Idempotent. */
|
|
46
|
+
end(): void;
|
|
47
|
+
on(event: keyof SinkEvents, listener: (...args: any[]) => void): this;
|
|
48
|
+
once(event: keyof SinkEvents, listener: (...args: any[]) => void): this;
|
|
49
|
+
off(event: keyof SinkEvents, listener: (...args: any[]) => void): this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** A sink class `SinkRegistry.create` can construct: its constructor takes one settings object (with `id`). */
|
|
53
|
+
type SinkConstructor = new (settings: any) => Sink<any>;
|
|
54
|
+
/** The settings `create` takes for `SinkClass`: its constructor's, with `id` optional. */
|
|
55
|
+
type SinkCreateSettings<C extends SinkConstructor> = Omit<ConstructorParameters<C>[0], 'id'> & {
|
|
56
|
+
id?: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The sinks of one object, ended by that object's lifecycle. `create(SinkClass, settings)` builds a
|
|
60
|
+
* sink and registers it; `sink.end()` closes it and removes it; the owner calls `clear()` when it
|
|
61
|
+
* closes, ending whatever is left.
|
|
62
|
+
*
|
|
63
|
+
* Registries form a tree like the issue registries: `observer.sinks` is the parent of every
|
|
64
|
+
* `observedCall.sinks` and `observedMediasoupRouter.sinks`. **A sink id is unique per observer**:
|
|
65
|
+
* `create` refuses an id that any registry of the tree holds. Each registry sees its own sinks and
|
|
66
|
+
* its descendants', so `get`, `write` and `clear` on a parent reach a child's sinks too.
|
|
67
|
+
*
|
|
68
|
+
* A client's sample sink is the one under its client id in its call's registry.
|
|
69
|
+
*/
|
|
70
|
+
declare class SinkRegistry {
|
|
71
|
+
readonly parent?: SinkRegistry | undefined;
|
|
72
|
+
private readonly _sinks;
|
|
73
|
+
constructor(parent?: SinkRegistry | undefined);
|
|
74
|
+
/** Number of open sinks in this registry and its descendants. */
|
|
75
|
+
get size(): number;
|
|
76
|
+
keys(): IterableIterator<string>;
|
|
77
|
+
values(): IterableIterator<Sink<any>>;
|
|
78
|
+
get<T extends Sink<any> = Sink>(id: string): T | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Construct `new SinkClass(settings)` and register it. The id (`settings.id`, generated when
|
|
81
|
+
* omitted) is checked first, so nothing is constructed — no file is opened — when it is taken:
|
|
82
|
+
* `undefined` is returned and a warning logged.
|
|
83
|
+
*/
|
|
84
|
+
create<C extends SinkConstructor>(SinkClass: C, settings: SinkCreateSettings<C>): InstanceType<C> | undefined;
|
|
85
|
+
/** Write `record` to the sink `id`. `false` when there is no such sink, or on backpressure. */
|
|
86
|
+
write(id: string, record: unknown): boolean;
|
|
87
|
+
/** End every sink of this registry and of its descendants. */
|
|
88
|
+
clear(): void;
|
|
89
|
+
/** This registry and its ancestors, up to the root. */
|
|
90
|
+
private _lineage;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** The settings of `createExtensionStats` on an observer, a call or a mediasoup router. */
|
|
94
|
+
type CreateExtensionStatsSettings<C extends SinkConstructor> = {
|
|
95
|
+
/** Unique per observer: it is also the id of the sink that receives the stats. */
|
|
96
|
+
id: string;
|
|
97
|
+
/** What `sinks.create` takes; the sink is created under `id` (an `id` in its settings is ignored). */
|
|
98
|
+
createSink?: [SinkClass: C, settings: Omit<SinkCreateSettings<C>, 'id'>];
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The extension stats of one object — `observer.extensionStats`, `observedCall.extensionStats`,
|
|
102
|
+
* `observedMediasoupRouter.extensionStats`: the last data per id (`values`), written to the
|
|
103
|
+
* object's sink with the same id. The owner closes it when it closes.
|
|
104
|
+
*/
|
|
105
|
+
declare class ExtensionStatsRegistry {
|
|
106
|
+
/** The owner's id (call id, router id, or `observer`), used in log messages. */
|
|
107
|
+
readonly id: string;
|
|
108
|
+
private readonly _sinks;
|
|
109
|
+
/** The last data accepted for each extension stats id. */
|
|
110
|
+
readonly values: Map<string, unknown>;
|
|
111
|
+
closed: boolean;
|
|
112
|
+
constructor(
|
|
113
|
+
/** The owner's id (call id, router id, or `observer`), used in log messages. */
|
|
114
|
+
id: string, _sinks: SinkRegistry);
|
|
115
|
+
/**
|
|
116
|
+
* Refuse further `create` / `accept`, and end the extension stats' sinks (the sinks whose id is
|
|
117
|
+
* an extension stats id). Other sinks of the owner, e.g. client sample sinks, are left to the
|
|
118
|
+
* owner's `sinks.clear()`. Called by the owner when it closes.
|
|
119
|
+
*/
|
|
120
|
+
close(): void;
|
|
121
|
+
create<C extends SinkConstructor>(settings: CreateExtensionStatsSettings<C>): InstanceType<C> | undefined;
|
|
122
|
+
accept(id: string, data: unknown): void;
|
|
123
|
+
get<T>(id: string): T | undefined;
|
|
124
|
+
}
|
|
125
|
+
|
|
4
126
|
declare const schemaVersion = "3.7.0";
|
|
5
127
|
/**
|
|
6
128
|
* The WebRTC app provided custom stats payload
|
|
@@ -1947,7 +2069,9 @@ declare function mannKendallVerdict(s: number, variance: number, alpha?: number)
|
|
|
1947
2069
|
* holds the values in `[i * bucketWidth, (i + 1) * bucketWidth)`. Interpolates linearly inside
|
|
1948
2070
|
* the bucket the rank falls in, so the error is at most one bucket width. With `openEnded`, the
|
|
1949
2071
|
* last bucket holds every value above its lower bound, and a percentile falling in it is reported
|
|
1950
|
-
* as `max`.
|
|
2072
|
+
* as `max`. With `min`/`max` (the observed extremes), the bucket holding them is narrowed to the
|
|
2073
|
+
* observed range before interpolating, so the estimate never leaves `[min, max]`. `undefined` for an
|
|
2074
|
+
* empty histogram.
|
|
1951
2075
|
*/
|
|
1952
2076
|
declare function percentileOfHistogram(histogram: readonly number[], bucketWidth: number, p: number, options?: {
|
|
1953
2077
|
min?: number;
|
|
@@ -3023,52 +3147,38 @@ declare function isClientIssueResolutionEntry(issue: ClientIssue): boolean;
|
|
|
3023
3147
|
/** Strip the `-resolved` suffix, so both entries of a lifecycle share one logical type. */
|
|
3024
3148
|
declare function baseIssueType(type: string): string;
|
|
3025
3149
|
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
error: [Error];
|
|
3032
|
-
/** `end()` was processed and all queued data was flushed (before `close`). */
|
|
3033
|
-
finish: [];
|
|
3034
|
-
/** The buffer drained after backpressure; safe to write more. */
|
|
3035
|
-
drain: [];
|
|
3150
|
+
type JsonlFileSinkOptions<T = ClientSample> = Partial<SinkSettings> & {
|
|
3151
|
+
/** Absolute or relative file path to append JSONL lines to. */
|
|
3152
|
+
path: string;
|
|
3153
|
+
/** Optional custom serializer; defaults to `JSON.stringify`. */
|
|
3154
|
+
serializeSample?: (record: T) => string;
|
|
3036
3155
|
};
|
|
3037
|
-
declare interface ClientSampleSink {
|
|
3038
|
-
on<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;
|
|
3039
|
-
once<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;
|
|
3040
|
-
off<E extends keyof ClientSampleSinkEvents>(event: E, listener: (...args: ClientSampleSinkEvents[E]) => void): this;
|
|
3041
|
-
emit<E extends keyof ClientSampleSinkEvents>(event: E, ...args: ClientSampleSinkEvents[E]): boolean;
|
|
3042
|
-
}
|
|
3043
3156
|
/**
|
|
3044
|
-
* A
|
|
3045
|
-
*
|
|
3046
|
-
* `
|
|
3047
|
-
*
|
|
3048
|
-
*
|
|
3049
|
-
* The library calls `write(sample)` synchronously per accepted sample (not awaited), `end()`s the
|
|
3050
|
-
* sink when the client closes, and attaches an `error` listener so a failing sink can't crash the
|
|
3051
|
-
* process. The application — which created the sink — listens for `close` (destination ready,
|
|
3052
|
-
* e.g. a file flushed and its fd closed) and `error`.
|
|
3053
|
-
*
|
|
3054
|
-
* Subclass this and implement `write`/`end` (and `emit` your lifecycle events). Built-in sinks
|
|
3055
|
-
* (`JsonlFileSink`, `InMemorySink`) and their factories are exported from the package root.
|
|
3157
|
+
* A sink that serializes each record to a JSON line and appends it to a file. Defaults to client
|
|
3158
|
+
* samples, but takes any record type: `sinks.create(JsonlFileSink<PipeTransportStats[]>, { id, path })`. It wraps an
|
|
3159
|
+
* `fs.WriteStream` and re-emits its lifecycle events, so `close` fires once the file is flushed
|
|
3160
|
+
* and its descriptor is closed (file ready) and `error` surfaces file errors.
|
|
3056
3161
|
*/
|
|
3057
|
-
declare
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3162
|
+
declare interface JsonlFileSink {
|
|
3163
|
+
on<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
3164
|
+
once<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
3165
|
+
off<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
3166
|
+
emit<E extends keyof SinkEvents>(event: E, ...args: SinkEvents[E]): boolean;
|
|
3062
3167
|
}
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3168
|
+
declare class JsonlFileSink<T = ClientSample> extends EventEmitter implements Sink<T> {
|
|
3169
|
+
readonly id: string;
|
|
3170
|
+
/** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */
|
|
3171
|
+
readonly path: string;
|
|
3172
|
+
private readonly _stream;
|
|
3173
|
+
private readonly _serializeSample;
|
|
3174
|
+
private _ended;
|
|
3175
|
+
constructor(options: JsonlFileSinkOptions<T>);
|
|
3176
|
+
get ended(): boolean;
|
|
3177
|
+
write(record: T): boolean;
|
|
3178
|
+
end(): void;
|
|
3179
|
+
}
|
|
3180
|
+
/** Build a JSONL file sink for a single path. */
|
|
3181
|
+
declare function createJsonlFileSink<T = ClientSample>(options: JsonlFileSinkOptions<T>): JsonlFileSink<T>;
|
|
3072
3182
|
|
|
3073
3183
|
/** mediasoup `TransportTuple` (the selected local/remote address pair of a transport). */
|
|
3074
3184
|
type TransportTuple = {
|
|
@@ -3320,13 +3430,19 @@ declare class ObservedMediasoupRouter<AppData extends Record<string, unknown> =
|
|
|
3320
3430
|
readonly sample: MediasoupRouterSample;
|
|
3321
3431
|
readonly webrtcTransportIds: Set<string>;
|
|
3322
3432
|
closed: boolean;
|
|
3433
|
+
readonly sinks: SinkRegistry;
|
|
3434
|
+
readonly extensionStats: ExtensionStatsRegistry;
|
|
3323
3435
|
private readonly _transportSamples;
|
|
3324
3436
|
private readonly _producerSamples;
|
|
3325
3437
|
private readonly _consumerSamples;
|
|
3326
3438
|
private readonly _dataProducerSamples;
|
|
3327
3439
|
private readonly _dataConsumerSamples;
|
|
3328
3440
|
private readonly _enrich?;
|
|
3329
|
-
|
|
3441
|
+
/**
|
|
3442
|
+
* @param parentSinks the parent of `sinks`: `observer.sinks`, passed by
|
|
3443
|
+
* `Observer.createObservedMediasoupRouter`. Internal; a router constructed directly has none.
|
|
3444
|
+
*/
|
|
3445
|
+
constructor(settings: ObservedMediasoupRouterSettings<AppData>, parentSinks?: SinkRegistry);
|
|
3330
3446
|
get id(): string;
|
|
3331
3447
|
get attachments(): Record<string, unknown>;
|
|
3332
3448
|
getTransportSample(id: string): MediasoupTransportSample | undefined;
|
|
@@ -3351,6 +3467,9 @@ declare class ObservedMediasoupRouter<AppData extends Record<string, unknown> =
|
|
|
3351
3467
|
*/
|
|
3352
3468
|
snapshot(): MediasoupRouterSample;
|
|
3353
3469
|
close(): void;
|
|
3470
|
+
createExtensionStats<C extends SinkConstructor>(settings: CreateExtensionStatsSettings<C>): InstanceType<C> | undefined;
|
|
3471
|
+
acceptExtensionStats(id: string, data: unknown): void;
|
|
3472
|
+
getExtensionStats<T>(id: string): T | undefined;
|
|
3354
3473
|
addTransport: (transport: types.Transport) => void;
|
|
3355
3474
|
addWebRtcTransport(transport: types.WebRtcTransport): void;
|
|
3356
3475
|
addPlainTransport(transport: types.PlainTransport): void;
|
|
@@ -3446,7 +3565,7 @@ type ObserverEvents = {
|
|
|
3446
3565
|
}];
|
|
3447
3566
|
'client-added': [ObservedClientScope];
|
|
3448
3567
|
'client-sink-created': [ObservedClientScope & {
|
|
3449
|
-
sink:
|
|
3568
|
+
sink: JsonlFileSink;
|
|
3450
3569
|
}];
|
|
3451
3570
|
'client-updated': [ObservedClientScope & {
|
|
3452
3571
|
sample: ClientSample;
|
|
@@ -3755,8 +3874,6 @@ declare class ObservedClient<AppData extends Record<string, unknown> = Record<st
|
|
|
3755
3874
|
readonly call: ObservedCall;
|
|
3756
3875
|
readonly clientId: string;
|
|
3757
3876
|
readonly observedPeerConnections: Map<string, ObservedPeerConnection>;
|
|
3758
|
-
/** Per-client sink (from `ObserverConfig.createClientSink`), if any. */
|
|
3759
|
-
readonly sink?: ClientSampleSink;
|
|
3760
3877
|
/** Ancestry base shared by all Observer-bus events originating at this client. */
|
|
3761
3878
|
readonly eventScope: ObservedClientScope;
|
|
3762
3879
|
readonly calculatedScore: CalculatedScore;
|
|
@@ -3886,6 +4003,11 @@ declare class ObservedClient<AppData extends Record<string, unknown> = Record<st
|
|
|
3886
4003
|
private closeTimer?;
|
|
3887
4004
|
constructor(settings: ObservedClientSettings<AppData>, call: ObservedCall, activeIssues: ObservedClientIssueRegistry);
|
|
3888
4005
|
/** The distinct `publicAddress`es currently known by this client's open peer connections. */
|
|
4006
|
+
/**
|
|
4007
|
+
* The sink this client's samples are written to: whatever is registered under its client id in
|
|
4008
|
+
* `call.sinks` (the `createClientJsonlSink` file, or a sink the application added), if any.
|
|
4009
|
+
*/
|
|
4010
|
+
get sink(): Sink<ClientSample> | undefined;
|
|
3889
4011
|
get publicAddresses(): string[];
|
|
3890
4012
|
get numberOfPeerConnections(): number;
|
|
3891
4013
|
get score(): number | undefined;
|
|
@@ -5698,6 +5820,8 @@ declare class ObservedCall<AppData extends Record<string, unknown> = Record<stri
|
|
|
5698
5820
|
readonly settings: Pick<ObservedCallSettings, 'closeCallIfEmptyForMs' | 'autoUpdateOnClientUpdate'>;
|
|
5699
5821
|
/** Ancestry base shared by all Observer-bus events originating at this call. */
|
|
5700
5822
|
readonly eventScope: ObservedCallScope;
|
|
5823
|
+
readonly sinks: SinkRegistry;
|
|
5824
|
+
readonly extensionStats: ExtensionStatsRegistry;
|
|
5701
5825
|
private closeTimer?;
|
|
5702
5826
|
constructor(settings: ObservedCallSettings<AppData>, observer: Observer, activeIssuesRegistry: ActiveIssuesRegistry);
|
|
5703
5827
|
get numberOfClients(): number;
|
|
@@ -5750,6 +5874,9 @@ declare class ObservedCall<AppData extends Record<string, unknown> = Record<stri
|
|
|
5750
5874
|
*/
|
|
5751
5875
|
addIssue(issue: Omit<CallIssue, 'scope'>): void;
|
|
5752
5876
|
close(): void;
|
|
5877
|
+
createExtensionStats<C extends SinkConstructor>(settings: CreateExtensionStatsSettings<C>): InstanceType<C> | undefined;
|
|
5878
|
+
acceptExtensionStats(id: string, data: unknown): void;
|
|
5879
|
+
getExtensionStats<T>(id: string): T | undefined;
|
|
5753
5880
|
getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined;
|
|
5754
5881
|
createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
|
|
5755
5882
|
getOrCreateObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>, acceptCtx?: AcceptContext): ObservedClient<ClientAppData> | undefined;
|
|
@@ -6471,11 +6598,38 @@ type ObserverConfig<AppData extends Record<string, unknown> = Record<string, unk
|
|
|
6471
6598
|
/** Same as `createCallAppData`, for clients. Receives the (already-created) parent call. */
|
|
6472
6599
|
createClientAppData?: ClientAppDataFactory;
|
|
6473
6600
|
/**
|
|
6474
|
-
*
|
|
6475
|
-
*
|
|
6476
|
-
*
|
|
6601
|
+
* Write every sample a client accepts to a JSONL file: return the file path for a newly-created
|
|
6602
|
+
* client, or `undefined` for no file. The directory must exist. The `JsonlFileSink` is added to
|
|
6603
|
+
* `observedCall.sinks` under the client id and is ended when the client closes; `client-sink-created`
|
|
6604
|
+
* announces it, so a `close` handler can upload or move the file once it is flushed.
|
|
6605
|
+
*
|
|
6606
|
+
* For any other destination, add your own sink under the client id instead, e.g. on
|
|
6607
|
+
* `client-added`: `observedCall.sinks.create(MySink, { id: observedClient.clientId, ... })`.
|
|
6608
|
+
*
|
|
6609
|
+
* Replaces `createClientSink` (removed in 1.3.0), and with it `createJsonlFileSinkFactory`.
|
|
6610
|
+
* To migrate:
|
|
6611
|
+
*
|
|
6612
|
+
* ```ts
|
|
6613
|
+
* // before (1.2): JSONL files
|
|
6614
|
+
* new Observer({ createClientSink: createJsonlFileSinkFactory({ directory: './stats' }) });
|
|
6615
|
+
* // after: return the path; `${callId}__${clientId}.jsonl` was the factory's default file name
|
|
6616
|
+
* new Observer({
|
|
6617
|
+
* createClientJsonlSink: ({ observedCall, clientId }) => path.join('./stats', `${observedCall.callId}__${clientId}.jsonl`),
|
|
6618
|
+
* });
|
|
6619
|
+
*
|
|
6620
|
+
* // before (1.2): any other sink
|
|
6621
|
+
* new Observer({ createClientSink: ({ clientId, observedCall }) => new HttpSink(url(observedCall, clientId)) });
|
|
6622
|
+
* // after: create it under the client id when the client is added (HttpSink implements
|
|
6623
|
+
* // `ClientSampleSink`, takes `SinkSettings & { ... }` and emits `ended` from `end()`)
|
|
6624
|
+
* observer.on('client-added', ({ observedCall, observedClient }) => {
|
|
6625
|
+
* observedCall.sinks.create(HttpSink, { id: observedClient.clientId, url: url(observedCall, observedClient.clientId) });
|
|
6626
|
+
* });
|
|
6627
|
+
* ```
|
|
6477
6628
|
*/
|
|
6478
|
-
|
|
6629
|
+
createClientJsonlSink?: (params: {
|
|
6630
|
+
observedCall: ObservedCall;
|
|
6631
|
+
clientId: string;
|
|
6632
|
+
}) => string | undefined;
|
|
6479
6633
|
/**
|
|
6480
6634
|
* Optional factory invoked when a call is created, producing the call's `RemoteTrackResolver`
|
|
6481
6635
|
* (or `undefined` for none). Use the built-ins
|
|
@@ -6494,6 +6648,8 @@ declare class Observer<AppData extends Record<string, unknown> = Record<string,
|
|
|
6494
6648
|
readonly observedTURN: ObservedTURN;
|
|
6495
6649
|
readonly observedCalls: Map<string, ObservedCall<Record<string, unknown>>>;
|
|
6496
6650
|
readonly observedMediasoupRouters: Map<string, ObservedMediasoupRouter<Record<string, unknown>>>;
|
|
6651
|
+
readonly sinks: SinkRegistry;
|
|
6652
|
+
readonly extensionStats: ExtensionStatsRegistry;
|
|
6497
6653
|
/** Ancestry base shared by all Observer-bus events originating at the observer. */
|
|
6498
6654
|
readonly eventScope: ObserverEventBase;
|
|
6499
6655
|
readonly config: ObserverConfig<AppData>;
|
|
@@ -6644,6 +6800,9 @@ declare class Observer<AppData extends Record<string, unknown> = Record<string,
|
|
|
6644
6800
|
matchPeerConnectionByWebRtcTransportId?: boolean;
|
|
6645
6801
|
}): ObservedMediasoupRouter<Record<string, unknown>> | undefined;
|
|
6646
6802
|
close(): void;
|
|
6803
|
+
createExtensionStats<C extends SinkConstructor>(settings: CreateExtensionStatsSettings<C>): InstanceType<C> | undefined;
|
|
6804
|
+
acceptExtensionStats(id: string, data: unknown): void;
|
|
6805
|
+
getExtensionStats<T>(id: string): T | undefined;
|
|
6647
6806
|
accept(sample: ClientSample, context?: AcceptContext): void;
|
|
6648
6807
|
update(): void;
|
|
6649
6808
|
/**
|
|
@@ -7037,52 +7196,38 @@ declare function createLogger(moduleName: string): Logger;
|
|
|
7037
7196
|
*/
|
|
7038
7197
|
declare function setObserverLogger(logger: ObserverLogger): void;
|
|
7039
7198
|
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
path: string;
|
|
7043
|
-
/** Optional custom serializer; defaults to `JSON.stringify`. */
|
|
7044
|
-
serializeSample?: (sample: ClientSample) => string;
|
|
7045
|
-
};
|
|
7199
|
+
/** The lifecycle events a client sample sink may emit. Same as {@link SinkEvents}. */
|
|
7200
|
+
type ClientSampleSinkEvents = SinkEvents;
|
|
7046
7201
|
/**
|
|
7047
|
-
* A
|
|
7048
|
-
* `
|
|
7049
|
-
*
|
|
7202
|
+
* A per-client destination for accepted samples. Create one under the client id with
|
|
7203
|
+
* `observedCall.sinks.create(MySink, { id: clientId, ... })`, or let
|
|
7204
|
+
* `ObserverConfig.createClientJsonlSink` create a `JsonlFileSink` there.
|
|
7205
|
+
*
|
|
7206
|
+
* The library calls `write(sample)` synchronously per accepted sample (not awaited) and `end()`s
|
|
7207
|
+
* the sink when the client closes; the registry attaches an `error` listener so a failing sink
|
|
7208
|
+
* can't crash the process. Because `write` isn't awaited, backpressure and batching are the sink's
|
|
7209
|
+
* concern.
|
|
7050
7210
|
*/
|
|
7051
|
-
|
|
7052
|
-
/** The file this sink writes to. Read it (e.g. in a `close` handler) to upload/move the file. */
|
|
7053
|
-
readonly path: string;
|
|
7054
|
-
private readonly _stream;
|
|
7055
|
-
private readonly _serializeSample;
|
|
7056
|
-
constructor(options: JsonlFileSinkOptions);
|
|
7057
|
-
write(sample: ClientSample): boolean;
|
|
7058
|
-
end(): void;
|
|
7059
|
-
}
|
|
7060
|
-
/** Build a JSONL file sink for a single path. */
|
|
7061
|
-
declare function createJsonlFileSink(options: JsonlFileSinkOptions): ClientSampleSink;
|
|
7062
|
-
type JsonlFileSinkFactoryOptions = {
|
|
7063
|
-
/** Directory the per-client files are written into (must exists). */
|
|
7064
|
-
directory: string;
|
|
7065
|
-
/** Builds the file name from the call/client ids. Defaults to `${callId}__${clientId}.jsonl`. */
|
|
7066
|
-
getFileName?: (params: {
|
|
7067
|
-
callId: string;
|
|
7068
|
-
clientId: string;
|
|
7069
|
-
}) => string;
|
|
7070
|
-
/** Optional custom serializer; defaults to `JSON.stringify`. */
|
|
7071
|
-
serializeSample?: (sample: ClientSample) => string;
|
|
7072
|
-
};
|
|
7073
|
-
/**
|
|
7074
|
-
* Convenience factory that writes one JSONL file per client, with the path derived from
|
|
7075
|
-
* `callId` / `clientId`. Plug into `ObserverConfig.createClientSink`.
|
|
7076
|
-
*/
|
|
7077
|
-
declare function createJsonlFileSinkFactory(options: JsonlFileSinkFactoryOptions): ClientSampleSinkFactory;
|
|
7211
|
+
type ClientSampleSink = Sink<ClientSample>;
|
|
7078
7212
|
|
|
7213
|
+
declare interface InMemorySink {
|
|
7214
|
+
on<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
7215
|
+
once<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
7216
|
+
off<E extends keyof SinkEvents>(event: E, listener: (...args: SinkEvents[E]) => void): this;
|
|
7217
|
+
emit<E extends keyof SinkEvents>(event: E, ...args: SinkEvents[E]): boolean;
|
|
7218
|
+
}
|
|
7079
7219
|
/**
|
|
7080
|
-
* A
|
|
7081
|
-
*
|
|
7220
|
+
* A client sample sink that collects the accepted sample objects into an array. Useful for tests
|
|
7221
|
+
* and offline replay. Emits `ended` and `close` on `end()`.
|
|
7082
7222
|
*/
|
|
7083
|
-
declare class InMemorySink extends
|
|
7223
|
+
declare class InMemorySink extends EventEmitter implements Sink<ClientSample> {
|
|
7224
|
+
readonly id: string;
|
|
7084
7225
|
readonly samples: ClientSample[];
|
|
7085
|
-
|
|
7226
|
+
private _ended;
|
|
7227
|
+
constructor(settings?: Partial<SinkSettings> & {
|
|
7228
|
+
samples?: ClientSample[];
|
|
7229
|
+
});
|
|
7230
|
+
get ended(): boolean;
|
|
7086
7231
|
write(sample: ClientSample): boolean;
|
|
7087
7232
|
end(): void;
|
|
7088
7233
|
}
|
|
@@ -7091,4 +7236,4 @@ declare function createInMemorySink(samples?: ClientSample[]): InMemorySink;
|
|
|
7091
7236
|
declare function createDefaultMediasoupRemoteTrackResolverFactory(): RemoteTrackResolverFactory;
|
|
7092
7237
|
declare function createP2pRemoteTrackResolverFactory(): RemoteTrackResolverFactory;
|
|
7093
7238
|
|
|
7094
|
-
export { type AcceptContext, type AcceptMiddleware, type AcceptMiddlewarePayload, type ActiveClientIssue, type ActiveIssueTracker, ActiveIssuesRegistry, AudioEchoDetector, type AudioEchoDetectorConfig, AudioEchoTypes, type AudioInputDevice, type AvailableCallScopeDetectorsConfigs, type AvailableDetectorsConfigs, type AvailableObserverScopeDetectorsConfigs, type AvailableValidatorConfigs, CODEC_MISMATCH_ISSUE, type CalculatedScore, type CallAppDataFactory, CallConcurrentIssueDetector, type CallConcurrentIssueDetectorConfig, type CallConcurrentIssueGroup, CallConcurrentIssueTypes, type CallHealth, CallHealthAggregator, type CallIssue, type CallIssueSpread, type CallScopedEventName, type CallSummary, type CallSummaryClients, CallSummaryCollector, type CallSummaryConfig, type CallSummaryEnricher, type CallSummaryEnrichers, type CallSummaryScores, type CallSummarySection, type CallSummaryTruncation, type CallSummaryTurnServers, type CertificateStats, type ClientAppDataFactory, type ClientEvent, ClientEventTypes, type ClientHealth, type ClientHealthThresholds, type ClientIssue, type ClientLocation, type ClientLocationResolver, type ClientMetaData, ClientMetaTypes, type ClientPopulation, type ClientPopulationAxis, ClientPopulationIssueDetector, type ClientPopulationIssueDetectorConfig, ClientPopulationIssueTypes, type ClientSample, ClientSampleSink, type ClientSampleSinkEvents, type
|
|
7239
|
+
export { type AcceptContext, type AcceptMiddleware, type AcceptMiddlewarePayload, type ActiveClientIssue, type ActiveIssueTracker, ActiveIssuesRegistry, AudioEchoDetector, type AudioEchoDetectorConfig, AudioEchoTypes, type AudioInputDevice, type AvailableCallScopeDetectorsConfigs, type AvailableDetectorsConfigs, type AvailableObserverScopeDetectorsConfigs, type AvailableValidatorConfigs, CODEC_MISMATCH_ISSUE, type CalculatedScore, type CallAppDataFactory, CallConcurrentIssueDetector, type CallConcurrentIssueDetectorConfig, type CallConcurrentIssueGroup, CallConcurrentIssueTypes, type CallHealth, CallHealthAggregator, type CallIssue, type CallIssueSpread, type CallScopedEventName, type CallSummary, type CallSummaryClients, CallSummaryCollector, type CallSummaryConfig, type CallSummaryEnricher, type CallSummaryEnrichers, type CallSummaryScores, type CallSummarySection, type CallSummaryTruncation, type CallSummaryTurnServers, type CertificateStats, type ClientAppDataFactory, type ClientEvent, ClientEventTypes, type ClientHealth, type ClientHealthThresholds, type ClientIssue, type ClientLocation, type ClientLocationResolver, type ClientMetaData, ClientMetaTypes, type ClientPopulation, type ClientPopulationAxis, ClientPopulationIssueDetector, type ClientPopulationIssueDetectorConfig, ClientPopulationIssueTypes, type ClientSample, type ClientSampleSink, type ClientSampleSinkEvents, type CodecConsistencyReportPayload, CodecConsistencyValidator, type CodecConsistencyValidatorConfig, type CodecEvidence, type CodecStats, type CorroboratedPublisherFault, type CreateExtensionStatsSettings, type DataChannelStats, type Detector, Detectors, type ExtensionStat, ExtensionStatsRegistry, GEOHASH_CELL_SIZES, type IceCandidatePairStats, type IceCandidateStats, type IceTransportStats, InMemorySink, type InboundRtpStats, type InboundTrackSample, type Issue, type IssueBase, type IssueConclusion, IssueFanOutDetector, type IssueFanOutDetectorConfig, IssueFanOutTypes, type IssueFaultDomain, JsonlFileSink, type JsonlFileSinkOptions, LOWEST_COMMON_DENOMINATOR_ISSUE, type Logger, type MannKendallResult, type MediaKind, type MediaPlayoutStats, type MediaSourceStats, type MediasoupConsumerSample, type MediasoupConsumerSampleEvent, type MediasoupDataConsumerSample, type MediasoupDataProducerSample, type MediasoupDirectTransportSample, type MediasoupDirectTransportSampleEventMap, type MediasoupPipeTransportSample, type MediasoupPipeTransportSampleEventMap, type MediasoupPlainTransportSample, type MediasoupPlainTransportSampleEventMap, type MediasoupProducerSample, type MediasoupProducerSampleEvent, type MediasoupRouterSample, type MediasoupSampleEnricher, type MediasoupTransportSample, type MediasoupWebRtcTransportSample, type MediasoupWebRtcTransportSampleEventMap, type Middleware, MiddlewareProcessor, ObservedCall, type ObservedCallScope, type ObservedCallSettings, ObservedCertificate, ObservedClient, ObservedClientIssueRegistry, type ObservedClientScope, type ObservedClientSettings, ObservedCodec, ObservedDataChannel, ObservedIceCandidate, ObservedIceCandidatePair, ObservedIceTransport, ObservedInboundRtp, ObservedInboundTrack, ObservedMediaPlayout, ObservedMediaSource, ObservedMediasoupRouter, type ObservedMediasoupRouterEvents, type ObservedMediasoupRouterScope, type ObservedMediasoupRouterSettings, ObservedOutboundRtp, ObservedOutboundTrack, ObservedPeerConnection, type ObservedPeerConnectionScope, ObservedPeerConnectionTransport, ObservedRemoteInboundRtp, ObservedRemoteOutboundRtp, ObservedTURN, type ObservedTURNEventMap, ObservedTurnServer, Observer, ObserverConcurrentIssueDetector, type ObserverConcurrentIssueDetectorConfig, type ObserverConcurrentIssueGroup, ObserverConcurrentIssueTypes, type ObserverEventBase, type ObserverEvents, type ObserverIssue, type ObserverIssueSpread, type ObserverLogger, type OutboundRtpStats, type OutboundTrackSample, type PageHinkleyResult, type PeerConnectionSample, type PeerConnectionTransportStats, type PsnrSum, PublisherFaultCorroborationDetector, type PublisherFaultCorroborationDetectorConfig, PublisherFaultTypes, type QualityLimitationDurations, RESOLVED_ISSUE_SUFFIX, RTT_HISTOGRAM_BUCKET_WIDTH_IN_MS, RTT_HISTOGRAM_NUMBER_OF_BUCKETS, type RemoteInboundRtpStats, type RemoteOutboundRtpStats, type RemoteTrackLinkEvidence, RemoteTrackResolver, type RemoteTrackResolverFactory, type RemoteTrackResolverReportPayload, RemoteTrackResolverValidator, type RemoteTrackResolverValidatorConfig, type RemoteTrackResolvers, type ResolvedActiveClientIssue, type RttSummary, type RunningValidator, SCORE_HISTOGRAM_BUCKET_WIDTH, SCORE_HISTOGRAM_NUMBER_OF_BUCKETS, type SampleRejectedReason, type ScoreCalculator, type ScoreSummary, SfuCongestionDetector, type SfuCongestionDetectorBucket, type SfuCongestionDetectorConfig, type SfuCongestionDetectorEvaluation, type SfuCongestionDetectorReport, type SimulcastReceiverEvidence, type SimulcastReceiverReportPayload, SimulcastReceiverValidator, type SimulcastReceiverValidatorConfig, type Sink, type SinkConstructor, type SinkCreateSettings, type SinkEvents, SinkRegistry, type SinkSettings, SlidingWindow, type SlidingWindowEntry, type StatsSummary, TrackDeliveryMismatchDetector, type TrackDeliveryMismatchDetectorConfig, TrackDeliveryMismatchTypes, TrendTester, type TrendTesterConfig, type TurnServerHealth, TurnServerHealthDetector, type TurnServerHealthDetectorConfig, TurnServerHealthTypes, TurnServerOutageDetector, type TurnServerOutageDetectorConfig, TurnServerOutageTypes, UNRESOLVED_TRACK_LINKS_ISSUE, UnconsumedTrackDetector, type UnconsumedTrackDetectorConfig, UnconsumedTrackTypes, type ValidationReport, type Validator, type ValidatorName, baseIssueType, concludeCallIssue, concludeObserverIssue, correlation, counterDelta, createCallSummary, createDefaultMediasoupRemoteTrackResolverFactory, createInMemorySink, createJsonlFileSink, createLogger, createP2pRemoteTrackResolverFactory, defaultCallSummaryConfig, defaultClientHealthThresholds, geohash, isClientIssueResolutionEntry, isPublicIpAddress, issuePayloadAsString, mannKendall, mannKendallVerdict, median, medianAbsoluteDeviation, pageHinkley, percentile, percentileOfHistogram, percentileOfSorted, robustZScore, schemaVersion, setObserverLogger, summarize };
|