@mebius-io/web 0.6.2 → 0.7.0
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/dist/index.cjs +244 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -7
- package/dist/index.d.ts +100 -7
- package/dist/index.global.js +244 -41
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +244 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -34,6 +34,21 @@ interface MebiusConnectOptions {
|
|
|
34
34
|
* The app secret must never be embedded in client code.
|
|
35
35
|
*/
|
|
36
36
|
token: string;
|
|
37
|
+
/**
|
|
38
|
+
* Called when the current token is about to expire, to mint the next one.
|
|
39
|
+
* Return a fresh token from the same backend endpoint that produced `token`.
|
|
40
|
+
*
|
|
41
|
+
* WITHOUT this, a connection lives exactly as long as its token: Mebius emits
|
|
42
|
+
* `TOKEN_EXPIRED` at that moment and playback stops. That is fine for a short
|
|
43
|
+
* watch and wrong for anything unattended — a stream left running overnight,
|
|
44
|
+
* a lobby screen, a 24/7 broadcast — where nobody is there to reconnect.
|
|
45
|
+
*
|
|
46
|
+
* WITH it, Mebius refreshes ahead of expiry and keeps the session going
|
|
47
|
+
* indefinitely; a `"token-refreshed"` event is emitted each time. If the call
|
|
48
|
+
* fails it is retried with backoff until the old token genuinely expires, so a
|
|
49
|
+
* brief backend blip costs nothing.
|
|
50
|
+
*/
|
|
51
|
+
getToken?: () => string | Promise<string>;
|
|
37
52
|
/**
|
|
38
53
|
* The `deliveries` list your backend received together with the token. Pass it
|
|
39
54
|
* through as-is and Mebius will pick the best route for each viewer's device,
|
|
@@ -84,6 +99,28 @@ type PlaybackMode = "auto" | "low-latency" | "balanced" | "scale";
|
|
|
84
99
|
interface PlayerOptions {
|
|
85
100
|
/** Defaults to `"auto"` — let Mebius choose per viewer. */
|
|
86
101
|
mode?: PlaybackMode;
|
|
102
|
+
/**
|
|
103
|
+
* How much delay to trade for smoothness, in milliseconds. Higher is steadier.
|
|
104
|
+
*
|
|
105
|
+
* Mebius holds roughly this much video ahead of the picture. That buffer is
|
|
106
|
+
* what absorbs an unsteady network: when a piece of video arrives late or has
|
|
107
|
+
* to be re-sent, it still lands before its turn to be shown, and the viewer
|
|
108
|
+
* sees nothing. With too small a buffer the same event freezes the picture —
|
|
109
|
+
* and a freeze is not brief, because video can only resume at the next
|
|
110
|
+
* complete frame, typically a second or two later. Small buffers therefore do
|
|
111
|
+
* not produce small glitches; they produce multi-second stalls.
|
|
112
|
+
*
|
|
113
|
+
* Pick from the viewing experience, not the number:
|
|
114
|
+
* - `~300` (default on the real-time route) — conversational: co-hosts, PK
|
|
115
|
+
* battles, anything where people talk back and delay is felt.
|
|
116
|
+
* - `1500`-`3000` — watching: screen shares, presentations, long unattended
|
|
117
|
+
* broadcasts. Costs a couple of seconds nobody notices and removes the
|
|
118
|
+
* stalls everybody notices.
|
|
119
|
+
*
|
|
120
|
+
* Applies to whichever route serves the viewer, so the trade you choose holds
|
|
121
|
+
* even when Mebius falls back to another one.
|
|
122
|
+
*/
|
|
123
|
+
targetLatencyMs?: number;
|
|
87
124
|
}
|
|
88
125
|
/**
|
|
89
126
|
* Where a player renders video: a `<video>` element, or a CSS selector that
|
|
@@ -120,8 +157,25 @@ interface PlaybackStats {
|
|
|
120
157
|
bitrateKbps?: number;
|
|
121
158
|
/** Frames per second currently being rendered, when known. */
|
|
122
159
|
framesPerSecond?: number;
|
|
123
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* How far behind the source the picture is running, in milliseconds, when the
|
|
162
|
+
* route can measure it. This is the delay the viewer actually experiences.
|
|
163
|
+
*/
|
|
124
164
|
latencyMs?: number;
|
|
165
|
+
/** Round-trip time to the serving edge in milliseconds, if known. */
|
|
166
|
+
rttMs?: number;
|
|
167
|
+
/** Percentage of video that had to be re-sent or was lost, if known. */
|
|
168
|
+
packetLossPct?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Milliseconds the picture was frozen since the previous reading, when the
|
|
171
|
+
* route measures this itself.
|
|
172
|
+
*
|
|
173
|
+
* Some routes must: a real-time connection can sit frozen for seconds while
|
|
174
|
+
* the connection reports perfect health and the video element raises no
|
|
175
|
+
* event, so a freeze there is invisible from the outside. A route that leaves
|
|
176
|
+
* this absent is one whose stalls are already visible to the player.
|
|
177
|
+
*/
|
|
178
|
+
freezeMs?: number;
|
|
125
179
|
}
|
|
126
180
|
/** Options for {@link MebiusClient.createCaptions}. */
|
|
127
181
|
interface CaptionsOptions {
|
|
@@ -187,6 +241,13 @@ type ClientEventMap = {
|
|
|
187
241
|
reason?: string;
|
|
188
242
|
};
|
|
189
243
|
error: MebiusError;
|
|
244
|
+
/**
|
|
245
|
+
* A fresh access token was fetched and is now in use. Purely informational —
|
|
246
|
+
* playback and publishing continue uninterrupted; nothing needs to be done in
|
|
247
|
+
* response. Useful for logging that an unattended long-running session is
|
|
248
|
+
* still renewing itself.
|
|
249
|
+
*/
|
|
250
|
+
"token-refreshed": void;
|
|
190
251
|
};
|
|
191
252
|
/** Event payloads emitted by a broadcaster. */
|
|
192
253
|
type BroadcasterEventMap = {
|
|
@@ -248,8 +309,19 @@ interface SessionResult {
|
|
|
248
309
|
}
|
|
249
310
|
declare class SignalingClient {
|
|
250
311
|
private readonly gateway;
|
|
251
|
-
private
|
|
312
|
+
private token;
|
|
252
313
|
constructor(gateway: string, token: string);
|
|
314
|
+
/**
|
|
315
|
+
* Swap in a freshly-minted access token.
|
|
316
|
+
*
|
|
317
|
+
* Every URL this class builds is built at call time, so a session that starts
|
|
318
|
+
* a new request after this point uses the new token with no further wiring.
|
|
319
|
+
* What it does NOT reach is a request already in flight or a media URL another
|
|
320
|
+
* library has memorised — see the scale route's loader for that half.
|
|
321
|
+
*/
|
|
322
|
+
setToken(token: string): void;
|
|
323
|
+
/** The current access token, for transports that must re-stamp their own URLs. */
|
|
324
|
+
accessToken(): string;
|
|
253
325
|
private base;
|
|
254
326
|
private headers;
|
|
255
327
|
/** Append the access token as a query param (the form the engine enforces). */
|
|
@@ -379,13 +451,15 @@ declare class MebiusPlayer extends TypedEmitter<PlayerEventMap> {
|
|
|
379
451
|
setVolume(volume: number): void;
|
|
380
452
|
/**
|
|
381
453
|
* Wall-clock time (Unix ms) currently on screen, or `null` when the active
|
|
382
|
-
* route cannot produce one
|
|
454
|
+
* route cannot produce one. A real-time route carries no wall clock at all,
|
|
455
|
+
* and a segmented route has none until its first timestamped segment arrives
|
|
456
|
+
* (see {@link ViewTransport}).
|
|
383
457
|
*
|
|
384
458
|
* This is what {@link MebiusClient.createCaptions} compares against a
|
|
385
459
|
* segment's `epochMs` to know when it is due. Delegating to the transport
|
|
386
460
|
* rather than reading the element directly is what keeps this correct across
|
|
387
|
-
* a route failover: the player may
|
|
388
|
-
*
|
|
461
|
+
* a route failover: the player may change route mid-session, and the clock
|
|
462
|
+
* source has to follow.
|
|
389
463
|
*/
|
|
390
464
|
currentEpochMs(): number | null;
|
|
391
465
|
private attach;
|
|
@@ -464,17 +538,36 @@ declare class MebiusCaptions extends TypedEmitter<CaptionsEventMap> {
|
|
|
464
538
|
* create broadcasters and players from it.
|
|
465
539
|
*/
|
|
466
540
|
declare class MebiusClient extends TypedEmitter<ClientEventMap> {
|
|
467
|
-
private
|
|
541
|
+
private token;
|
|
468
542
|
private readonly deliveries;
|
|
469
543
|
private readonly telemetry;
|
|
470
544
|
private readonly userId?;
|
|
545
|
+
private readonly getToken?;
|
|
471
546
|
private readonly signaling;
|
|
472
547
|
private expiryTimer;
|
|
473
548
|
private connected;
|
|
549
|
+
private refreshFailures;
|
|
474
550
|
/** @internal */
|
|
475
|
-
constructor(config: MebiusInitOptions, token: string, deliveries?: readonly MebiusDelivery[], telemetry?: TelemetryTarget | null, userId?: string | undefined);
|
|
551
|
+
constructor(config: MebiusInitOptions, token: string, deliveries?: readonly MebiusDelivery[], telemetry?: TelemetryTarget | null, userId?: string | undefined, getToken?: (() => string | Promise<string>) | undefined);
|
|
476
552
|
/** @internal Called by {@link Mebius.connect}. */
|
|
477
553
|
open(): void;
|
|
554
|
+
/**
|
|
555
|
+
* Arm whatever has to happen as this token approaches its expiry: renew it if
|
|
556
|
+
* the app gave us a way to, otherwise report that the session is over.
|
|
557
|
+
*
|
|
558
|
+
* Renewing is what makes an unattended session possible at all. The gateway
|
|
559
|
+
* checks the token on every media request, so without a fresh one playback
|
|
560
|
+
* stops the moment it expires — no matter how healthy the stream is.
|
|
561
|
+
*/
|
|
562
|
+
private scheduleTokenWork;
|
|
563
|
+
private refreshToken;
|
|
564
|
+
/**
|
|
565
|
+
* A failed refresh is not a dead session: the current token is still valid
|
|
566
|
+
* until `expiryMs`, and the viewer is still watching. Retry inside that window
|
|
567
|
+
* and only report expiry once it has actually run out.
|
|
568
|
+
*/
|
|
569
|
+
private onRefreshFailed;
|
|
570
|
+
private clearTimer;
|
|
478
571
|
/** Create a broadcaster bound to this connection. */
|
|
479
572
|
createBroadcaster(options?: BroadcasterOptions): MebiusBroadcaster;
|
|
480
573
|
/** Create a player bound to this connection. */
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,21 @@ interface MebiusConnectOptions {
|
|
|
34
34
|
* The app secret must never be embedded in client code.
|
|
35
35
|
*/
|
|
36
36
|
token: string;
|
|
37
|
+
/**
|
|
38
|
+
* Called when the current token is about to expire, to mint the next one.
|
|
39
|
+
* Return a fresh token from the same backend endpoint that produced `token`.
|
|
40
|
+
*
|
|
41
|
+
* WITHOUT this, a connection lives exactly as long as its token: Mebius emits
|
|
42
|
+
* `TOKEN_EXPIRED` at that moment and playback stops. That is fine for a short
|
|
43
|
+
* watch and wrong for anything unattended — a stream left running overnight,
|
|
44
|
+
* a lobby screen, a 24/7 broadcast — where nobody is there to reconnect.
|
|
45
|
+
*
|
|
46
|
+
* WITH it, Mebius refreshes ahead of expiry and keeps the session going
|
|
47
|
+
* indefinitely; a `"token-refreshed"` event is emitted each time. If the call
|
|
48
|
+
* fails it is retried with backoff until the old token genuinely expires, so a
|
|
49
|
+
* brief backend blip costs nothing.
|
|
50
|
+
*/
|
|
51
|
+
getToken?: () => string | Promise<string>;
|
|
37
52
|
/**
|
|
38
53
|
* The `deliveries` list your backend received together with the token. Pass it
|
|
39
54
|
* through as-is and Mebius will pick the best route for each viewer's device,
|
|
@@ -84,6 +99,28 @@ type PlaybackMode = "auto" | "low-latency" | "balanced" | "scale";
|
|
|
84
99
|
interface PlayerOptions {
|
|
85
100
|
/** Defaults to `"auto"` — let Mebius choose per viewer. */
|
|
86
101
|
mode?: PlaybackMode;
|
|
102
|
+
/**
|
|
103
|
+
* How much delay to trade for smoothness, in milliseconds. Higher is steadier.
|
|
104
|
+
*
|
|
105
|
+
* Mebius holds roughly this much video ahead of the picture. That buffer is
|
|
106
|
+
* what absorbs an unsteady network: when a piece of video arrives late or has
|
|
107
|
+
* to be re-sent, it still lands before its turn to be shown, and the viewer
|
|
108
|
+
* sees nothing. With too small a buffer the same event freezes the picture —
|
|
109
|
+
* and a freeze is not brief, because video can only resume at the next
|
|
110
|
+
* complete frame, typically a second or two later. Small buffers therefore do
|
|
111
|
+
* not produce small glitches; they produce multi-second stalls.
|
|
112
|
+
*
|
|
113
|
+
* Pick from the viewing experience, not the number:
|
|
114
|
+
* - `~300` (default on the real-time route) — conversational: co-hosts, PK
|
|
115
|
+
* battles, anything where people talk back and delay is felt.
|
|
116
|
+
* - `1500`-`3000` — watching: screen shares, presentations, long unattended
|
|
117
|
+
* broadcasts. Costs a couple of seconds nobody notices and removes the
|
|
118
|
+
* stalls everybody notices.
|
|
119
|
+
*
|
|
120
|
+
* Applies to whichever route serves the viewer, so the trade you choose holds
|
|
121
|
+
* even when Mebius falls back to another one.
|
|
122
|
+
*/
|
|
123
|
+
targetLatencyMs?: number;
|
|
87
124
|
}
|
|
88
125
|
/**
|
|
89
126
|
* Where a player renders video: a `<video>` element, or a CSS selector that
|
|
@@ -120,8 +157,25 @@ interface PlaybackStats {
|
|
|
120
157
|
bitrateKbps?: number;
|
|
121
158
|
/** Frames per second currently being rendered, when known. */
|
|
122
159
|
framesPerSecond?: number;
|
|
123
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* How far behind the source the picture is running, in milliseconds, when the
|
|
162
|
+
* route can measure it. This is the delay the viewer actually experiences.
|
|
163
|
+
*/
|
|
124
164
|
latencyMs?: number;
|
|
165
|
+
/** Round-trip time to the serving edge in milliseconds, if known. */
|
|
166
|
+
rttMs?: number;
|
|
167
|
+
/** Percentage of video that had to be re-sent or was lost, if known. */
|
|
168
|
+
packetLossPct?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Milliseconds the picture was frozen since the previous reading, when the
|
|
171
|
+
* route measures this itself.
|
|
172
|
+
*
|
|
173
|
+
* Some routes must: a real-time connection can sit frozen for seconds while
|
|
174
|
+
* the connection reports perfect health and the video element raises no
|
|
175
|
+
* event, so a freeze there is invisible from the outside. A route that leaves
|
|
176
|
+
* this absent is one whose stalls are already visible to the player.
|
|
177
|
+
*/
|
|
178
|
+
freezeMs?: number;
|
|
125
179
|
}
|
|
126
180
|
/** Options for {@link MebiusClient.createCaptions}. */
|
|
127
181
|
interface CaptionsOptions {
|
|
@@ -187,6 +241,13 @@ type ClientEventMap = {
|
|
|
187
241
|
reason?: string;
|
|
188
242
|
};
|
|
189
243
|
error: MebiusError;
|
|
244
|
+
/**
|
|
245
|
+
* A fresh access token was fetched and is now in use. Purely informational —
|
|
246
|
+
* playback and publishing continue uninterrupted; nothing needs to be done in
|
|
247
|
+
* response. Useful for logging that an unattended long-running session is
|
|
248
|
+
* still renewing itself.
|
|
249
|
+
*/
|
|
250
|
+
"token-refreshed": void;
|
|
190
251
|
};
|
|
191
252
|
/** Event payloads emitted by a broadcaster. */
|
|
192
253
|
type BroadcasterEventMap = {
|
|
@@ -248,8 +309,19 @@ interface SessionResult {
|
|
|
248
309
|
}
|
|
249
310
|
declare class SignalingClient {
|
|
250
311
|
private readonly gateway;
|
|
251
|
-
private
|
|
312
|
+
private token;
|
|
252
313
|
constructor(gateway: string, token: string);
|
|
314
|
+
/**
|
|
315
|
+
* Swap in a freshly-minted access token.
|
|
316
|
+
*
|
|
317
|
+
* Every URL this class builds is built at call time, so a session that starts
|
|
318
|
+
* a new request after this point uses the new token with no further wiring.
|
|
319
|
+
* What it does NOT reach is a request already in flight or a media URL another
|
|
320
|
+
* library has memorised — see the scale route's loader for that half.
|
|
321
|
+
*/
|
|
322
|
+
setToken(token: string): void;
|
|
323
|
+
/** The current access token, for transports that must re-stamp their own URLs. */
|
|
324
|
+
accessToken(): string;
|
|
253
325
|
private base;
|
|
254
326
|
private headers;
|
|
255
327
|
/** Append the access token as a query param (the form the engine enforces). */
|
|
@@ -379,13 +451,15 @@ declare class MebiusPlayer extends TypedEmitter<PlayerEventMap> {
|
|
|
379
451
|
setVolume(volume: number): void;
|
|
380
452
|
/**
|
|
381
453
|
* Wall-clock time (Unix ms) currently on screen, or `null` when the active
|
|
382
|
-
* route cannot produce one
|
|
454
|
+
* route cannot produce one. A real-time route carries no wall clock at all,
|
|
455
|
+
* and a segmented route has none until its first timestamped segment arrives
|
|
456
|
+
* (see {@link ViewTransport}).
|
|
383
457
|
*
|
|
384
458
|
* This is what {@link MebiusClient.createCaptions} compares against a
|
|
385
459
|
* segment's `epochMs` to know when it is due. Delegating to the transport
|
|
386
460
|
* rather than reading the element directly is what keeps this correct across
|
|
387
|
-
* a route failover: the player may
|
|
388
|
-
*
|
|
461
|
+
* a route failover: the player may change route mid-session, and the clock
|
|
462
|
+
* source has to follow.
|
|
389
463
|
*/
|
|
390
464
|
currentEpochMs(): number | null;
|
|
391
465
|
private attach;
|
|
@@ -464,17 +538,36 @@ declare class MebiusCaptions extends TypedEmitter<CaptionsEventMap> {
|
|
|
464
538
|
* create broadcasters and players from it.
|
|
465
539
|
*/
|
|
466
540
|
declare class MebiusClient extends TypedEmitter<ClientEventMap> {
|
|
467
|
-
private
|
|
541
|
+
private token;
|
|
468
542
|
private readonly deliveries;
|
|
469
543
|
private readonly telemetry;
|
|
470
544
|
private readonly userId?;
|
|
545
|
+
private readonly getToken?;
|
|
471
546
|
private readonly signaling;
|
|
472
547
|
private expiryTimer;
|
|
473
548
|
private connected;
|
|
549
|
+
private refreshFailures;
|
|
474
550
|
/** @internal */
|
|
475
|
-
constructor(config: MebiusInitOptions, token: string, deliveries?: readonly MebiusDelivery[], telemetry?: TelemetryTarget | null, userId?: string | undefined);
|
|
551
|
+
constructor(config: MebiusInitOptions, token: string, deliveries?: readonly MebiusDelivery[], telemetry?: TelemetryTarget | null, userId?: string | undefined, getToken?: (() => string | Promise<string>) | undefined);
|
|
476
552
|
/** @internal Called by {@link Mebius.connect}. */
|
|
477
553
|
open(): void;
|
|
554
|
+
/**
|
|
555
|
+
* Arm whatever has to happen as this token approaches its expiry: renew it if
|
|
556
|
+
* the app gave us a way to, otherwise report that the session is over.
|
|
557
|
+
*
|
|
558
|
+
* Renewing is what makes an unattended session possible at all. The gateway
|
|
559
|
+
* checks the token on every media request, so without a fresh one playback
|
|
560
|
+
* stops the moment it expires — no matter how healthy the stream is.
|
|
561
|
+
*/
|
|
562
|
+
private scheduleTokenWork;
|
|
563
|
+
private refreshToken;
|
|
564
|
+
/**
|
|
565
|
+
* A failed refresh is not a dead session: the current token is still valid
|
|
566
|
+
* until `expiryMs`, and the viewer is still watching. Retry inside that window
|
|
567
|
+
* and only report expiry once it has actually run out.
|
|
568
|
+
*/
|
|
569
|
+
private onRefreshFailed;
|
|
570
|
+
private clearTimer;
|
|
478
571
|
/** Create a broadcaster bound to this connection. */
|
|
479
572
|
createBroadcaster(options?: BroadcasterOptions): MebiusBroadcaster;
|
|
480
573
|
/** Create a player bound to this connection. */
|