@lumencast/runtime 0.11.0 → 0.12.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.
Files changed (43) hide show
  1. package/README.md +39 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{broadcast-DtHoU_fS.js → broadcast-ydSpPUje.js} +3 -3
  4. package/dist/{broadcast-DtHoU_fS.js.map → broadcast-ydSpPUje.js.map} +1 -1
  5. package/dist/{control-B9frEbNG.js → control-zTsF-bHP.js} +4 -4
  6. package/dist/{control-B9frEbNG.js.map → control-zTsF-bHP.js.map} +1 -1
  7. package/dist/{index-Dz27r92m.js → index-ClWi5UzJ.js} +361 -326
  8. package/dist/index-ClWi5UzJ.js.map +1 -0
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.html +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/lumencast.js +1 -1
  14. package/dist/mount.d.ts.map +1 -1
  15. package/dist/mount.js +52 -0
  16. package/dist/mount.js.map +1 -1
  17. package/dist/{status-pill-B2vBTwRC.js → status-pill-DkHIOL5V.js} +2 -2
  18. package/dist/{status-pill-B2vBTwRC.js.map → status-pill-DkHIOL5V.js.map} +1 -1
  19. package/dist/{test-DD2SBDku.js → test-COpMkyms.js} +4 -4
  20. package/dist/{test-DD2SBDku.js.map → test-COpMkyms.js.map} +1 -1
  21. package/dist/transport/ws.d.ts +4 -1
  22. package/dist/transport/ws.d.ts.map +1 -1
  23. package/dist/transport/ws.js +7 -0
  24. package/dist/transport/ws.js.map +1 -1
  25. package/dist/{tree-CgU_sUwI.js → tree-Cubmxeqo.js} +2 -2
  26. package/dist/{tree-CgU_sUwI.js.map → tree-Cubmxeqo.js.map} +1 -1
  27. package/dist/types.d.ts +18 -2
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/webrtc/index.d.ts +1 -1
  30. package/dist/webrtc/index.d.ts.map +1 -1
  31. package/dist/webrtc/index.js.map +1 -1
  32. package/dist/webrtc/peer-stream-registry.d.ts +17 -0
  33. package/dist/webrtc/peer-stream-registry.d.ts.map +1 -1
  34. package/dist/webrtc/peer-stream-registry.js +22 -0
  35. package/dist/webrtc/peer-stream-registry.js.map +1 -1
  36. package/package.json +4 -4
  37. package/src/index.ts +1 -0
  38. package/src/mount.ts +54 -0
  39. package/src/transport/ws.ts +11 -0
  40. package/src/types.ts +18 -2
  41. package/src/webrtc/index.ts +1 -0
  42. package/src/webrtc/peer-stream-registry.ts +38 -0
  43. package/dist/index-Dz27r92m.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ErrorCode } from "@lumencast/protocol";
1
+ import type { ErrorCode, SceneRosterEntry } from "@lumencast/protocol";
2
2
  import type { ResolveCaptureDevice } from "./render/primitives/capture";
3
3
  import type { ResolvePeerStream, SubscribePeerStream } from "./render/primitives/media";
4
4
  import type { ReservedCamLeaves } from "./state/reserved-leaves";
@@ -14,7 +14,12 @@ export interface LumencastError {
14
14
  recoverable: boolean;
15
15
  }
16
16
  export interface LumencastMetric {
17
- name: "delta_received" | "delta_applied" | "frame_dropped" | "reconnect" | "snapshot_received" | "scene_changed";
17
+ name: "delta_received" | "delta_applied" | "frame_dropped" | "reconnect" | "snapshot_received" | "scene_changed"
18
+ /** A render bundle was warmed ahead of time from a roster entry (either a
19
+ * `scene_roster` frame or the `preloadRoster` mount option). Emitted once
20
+ * the warm fetch resolves (or from cache). Carries `scene_id` +
21
+ * `scene_version` + `source` ("frame" | "option"). */
22
+ | "roster_preloaded";
18
23
  [key: string]: unknown;
19
24
  }
20
25
  /** Anti-silent-drop render diagnostic (ADR 001 §3.4, issue #34).
@@ -88,6 +93,17 @@ export interface MountOptions {
88
93
  * reads it. Omit it and the reserved leaves are simply not surfaced (the
89
94
  * preview/headless paths are unaffected). */
90
95
  onReservedLeaves?: (leaves: ReservedCamLeaves) => void;
96
+ /** Preload the render bundles of a known scene roster so the FIRST switch to
97
+ * each scene is instant (a warm cache hit instead of a blocking fetch).
98
+ * Each entry is `{ scene_id, scene_version }`. Warmed in the background right
99
+ * after mount — best-effort: a failed warm is swallowed (the scene still
100
+ * fetches on demand at switch time) and never blocks or errors the mount.
101
+ *
102
+ * This is the PUBLIC preload surface (lumencast-js #87b) for hosts that
103
+ * already know the roster at mount time. When the server also emits
104
+ * `scene_roster` frames the runtime warms from those too — both paths feed
105
+ * the same cache and are idempotent (a version is warmed at most once). */
106
+ preloadRoster?: readonly SceneRosterEntry[];
91
107
  }
92
108
  export interface LumencastHandle {
93
109
  /** Tear down the WS, unmount the React tree, release timers. Idempotent. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;AAErE,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,sBAAsB,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EACA,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,eAAe,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;+BAE+B;AAC/B,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IACrE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C;;;yDAGqD;IACrD,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;;;;;yEAOqE;IACrE,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;;gFAK4E;IAC5E,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;qEAGiE;IACjE,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;;;;;;;kDAS8C;IAC9C,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;AAErE,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,sBAAsB,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EACA,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,WAAW,GACX,mBAAmB,GACnB,eAAe;IACjB;;;2DAGuD;OACrD,kBAAkB,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;+BAE+B;AAC/B,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,aAAa,CAAC;IACpB,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IACrE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C;;;yDAGqD;IACrD,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;;;;;yEAOqE;IACrE,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;;gFAK4E;IAC5E,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC;;;qEAGiE;IACjE,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;;;;;;;kDAS8C;IAC9C,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACvD;;;;;;;;;gFAS4E;IAC5E,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,4EAA4E;IAC5E,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC3C;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { MeetViewer, type MeetViewerOptions } from "./meet-viewer.js";
2
2
  import { type PeerStreamListener, type PeerStreamRegistry } from "./peer-stream-registry.js";
3
3
  export { MeetViewer, type MeetViewerOptions, type MeetViewerDeps, type PeerInfo, type RemoteTrackEvent, } from "./meet-viewer.js";
4
- export { createPeerStreamRegistry, type PeerStreamRegistry, type PeerStreamListener, } from "./peer-stream-registry.js";
4
+ export { createPeerStreamRegistry, type PeerStreamRegistry, type PeerStreamListener, type RosterListener, } from "./peer-stream-registry.js";
5
5
  export interface PeerViewer {
6
6
  /** Join the room(s) (viewer role, no capture). */
7
7
  join: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAyB,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,yEAAyE;IACzE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IAC7D,8EAA8E;IAC9E,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAC;IACrF,mDAAmD;IACnD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;gDAC4C;IAC5C,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;mFAImF;AACnF;;;;;;;8BAO8B;AAC9B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1C;AA+BD;8EAC8E;AAC9E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAevE;AAED,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG;IAC1D,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;oFACgF;IAChF,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,mBAAoB,SAAQ,UAAU;IACrD;;oEAEgE;IAChE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED;;;;;;;;;;2EAU2E;AAC3E,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CA8ErB;AAED;;oEAEoE;AACpE,MAAM,MAAM,mBAAmB,GAC3B,0BAA0B,GAC1B,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1D;;oCAEoC;AACpC,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAYjG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAyB,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,UAAU;IACzB,kDAAkD;IAClD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,8EAA8E;IAC9E,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,yEAAyE;IACzE,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IAC7D,8EAA8E;IAC9E,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAC;IACrF,mDAAmD;IACnD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B;gDAC4C;IAC5C,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;mFAImF;AACnF;;;;;;;8BAO8B;AAC9B,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAK1C;AA+BD;8EAC8E;AAC9E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,UAAU,CAevE;AAED,8DAA8D;AAC9D,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG;IAC1D,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB;oFACgF;IAChF,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,mBAAoB,SAAQ,UAAU;IACrD;;oEAEgE;IAChE,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED;;;;;;;;;;2EAU2E;AAC3E,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CA8ErB;AAED;;oEAEoE;AACpE,MAAM,MAAM,mBAAmB,GAC3B,0BAA0B,GAC1B,CAAC,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1D;;oCAEoC;AACpC,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,mBAAmB,GAAG,mBAAmB,CAYjG"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,29 @@
1
1
  export type PeerStreamListener = (stream: MediaStream | null) => void;
2
+ /** Notified whenever the live roster changes ORDER (a peer connects for the first
3
+ * time, or a connected peer drops). A pure re-`set` of an already-present label's
4
+ * stream is NOT a roster change (same arrival order) — it reaches per-label
5
+ * `subscribe` listeners only. Carries no payload : the listener re-reads
6
+ * `orderedLabels()`. */
7
+ export type RosterListener = () => void;
2
8
  export interface PeerStreamRegistry {
3
9
  /** #4 contract — the current stream for a label, or `null` if the peer is not
4
10
  * connected (yet / any more). Synchronous, side-effect free. */
5
11
  resolve(peerLabel: string): MediaStream | null;
12
+ /** The live `peer_label`s in ARRIVAL ORDER (insertion order of the backing Map,
13
+ * restricted to labels that currently hold a stream). Drives positional slot
14
+ * resolution (`@<n>` → `orderedLabels()[n]`, ADR Blue 009 axe 1 positional
15
+ * variant). Returns a fresh array — safe for the caller to keep / index. */
16
+ orderedLabels(): string[];
6
17
  /** Push channel for the LIVE `media` primitive : invoked immediately with the
7
18
  * current value, then on every change for `peerLabel`. Returns an
8
19
  * unsubscribe. */
9
20
  subscribe(peerLabel: string, listener: PeerStreamListener): () => void;
21
+ /** Roster-change channel : invoked whenever a peer connects (new label) or
22
+ * leaves (label dropped) — i.e. whenever `orderedLabels()` could shift. Lets a
23
+ * positional consumer re-resolve `@<n>` when arrivals/departures shuffle the
24
+ * order. NOT invoked on a pure stream replacement of an existing label. Returns
25
+ * an unsubscribe. */
26
+ subscribeRoster(listener: RosterListener): () => void;
10
27
  /** Viewer-side : publish / replace a peer's stream (peer connected). */
11
28
  set(peerLabel: string, stream: MediaStream): void;
12
29
  /** Viewer-side : drop a peer's stream (peer left / connection failed). The
@@ -1 +1 @@
1
- {"version":3,"file":"peer-stream-registry.d.ts","sourceRoot":"","sources":["../../src/webrtc/peer-stream-registry.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;AAEtE,MAAM,WAAW,kBAAkB;IACjC;qEACiE;IACjE,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAC/C;;uBAEmB;IACnB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAAC;IACvE,wEAAwE;IACxE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD;;gDAE4C;IAC5C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;iBACa;IACb,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAgD7D"}
1
+ {"version":3,"file":"peer-stream-registry.d.ts","sourceRoot":"","sources":["../../src/webrtc/peer-stream-registry.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;AAEtE;;;;yBAIyB;AACzB,MAAM,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC;qEACiE;IACjE,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAC/C;;;iFAG6E;IAC7E,aAAa,IAAI,MAAM,EAAE,CAAC;IAC1B;;uBAEmB;IACnB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAAC;IACvE;;;;0BAIsB;IACtB,eAAe,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,IAAI,CAAC;IACtD,wEAAwE;IACxE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAClD;;gDAE4C;IAC5C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;iBACa;IACb,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAoE7D"}
@@ -23,6 +23,7 @@
23
23
  export function createPeerStreamRegistry() {
24
24
  const streams = new Map();
25
25
  const listeners = new Map();
26
+ const rosterListeners = new Set();
26
27
  function notify(peerLabel) {
27
28
  const set = listeners.get(peerLabel);
28
29
  if (set === undefined)
@@ -31,10 +32,25 @@ export function createPeerStreamRegistry() {
31
32
  for (const listener of set)
32
33
  listener(value);
33
34
  }
35
+ function notifyRoster() {
36
+ for (const listener of [...rosterListeners])
37
+ listener();
38
+ }
34
39
  return {
35
40
  resolve(peerLabel) {
36
41
  return streams.get(peerLabel) ?? null;
37
42
  },
43
+ orderedLabels() {
44
+ // Map preserves insertion order = arrival order ; every key holds a stream
45
+ // (a dropped peer is `delete`d in remove()).
46
+ return [...streams.keys()];
47
+ },
48
+ subscribeRoster(listener) {
49
+ rosterListeners.add(listener);
50
+ return () => {
51
+ rosterListeners.delete(listener);
52
+ };
53
+ },
38
54
  subscribe(peerLabel, listener) {
39
55
  let set = listeners.get(peerLabel);
40
56
  if (set === undefined) {
@@ -57,20 +73,26 @@ export function createPeerStreamRegistry() {
57
73
  set(peerLabel, stream) {
58
74
  if (streams.get(peerLabel) === stream)
59
75
  return; // idempotent re-emit guard
76
+ const isNew = !streams.has(peerLabel); // a brand-new arrival shifts the roster
60
77
  streams.set(peerLabel, stream);
61
78
  notify(peerLabel);
79
+ if (isNew)
80
+ notifyRoster();
62
81
  },
63
82
  remove(peerLabel) {
64
83
  if (!streams.has(peerLabel))
65
84
  return;
66
85
  streams.delete(peerLabel);
67
86
  notify(peerLabel);
87
+ notifyRoster(); // a departure shifts every later position
68
88
  },
69
89
  clear() {
70
90
  const labels = [...streams.keys()];
71
91
  streams.clear();
72
92
  for (const label of labels)
73
93
  notify(label);
94
+ if (labels.length > 0)
95
+ notifyRoster();
74
96
  },
75
97
  };
76
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"peer-stream-registry.js","sourceRoot":"","sources":["../../src/webrtc/peer-stream-registry.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,sCAAsC;AACtC,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,uEAAuE;AACvE,EAAE;AACF,gFAAgF;AAChF,4EAA4E;AAC5E,wEAAwE;AACxE,oEAAoE;AACpE,2EAA2E;AAC3E,2EAA2E;AAC3E,+EAA+E;AAC/E,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,4DAA4D;AAuB5D,MAAM,UAAU,wBAAwB;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmC,CAAC;IAE7D,SAAS,MAAM,CAAC,SAAiB;QAC/B,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;QAC7C,KAAK,MAAM,QAAQ,IAAI,GAAG;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,OAAO,CAAC,SAAS;YACf,OAAO,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;QACxC,CAAC;QACD,SAAS,CAAC,SAAS,EAAE,QAAQ;YAC3B,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;gBAChB,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YAChC,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClB,oEAAoE;YACpE,8DAA8D;YAC9D,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,CAAC;YACzC,OAAO,GAAG,EAAE;gBACV,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACnC,IAAI,CAAC,KAAK,SAAS;oBAAE,OAAO;gBAC5B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACnB,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC;oBAAE,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChD,CAAC,CAAC;QACJ,CAAC;QACD,GAAG,CAAC,SAAS,EAAE,MAAM;YACnB,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM;gBAAE,OAAO,CAAC,2BAA2B;YAC1E,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC/B,MAAM,CAAC,SAAS,CAAC,CAAC;QACpB,CAAC;QACD,MAAM,CAAC,SAAS;YACd,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;gBAAE,OAAO;YACpC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC1B,MAAM,CAAC,SAAS,CAAC,CAAC;QACpB,CAAC;QACD,KAAK;YACH,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,EAAE,CAAC;YAChB,KAAK,MAAM,KAAK,IAAI,MAAM;gBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"peer-stream-registry.js","sourceRoot":"","sources":["../../src/webrtc/peer-stream-registry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumencast/runtime",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Browser runtime for Lumencast — mount(), LSDP/1 transport, leaf-grain store, LSML render, animations, overlays.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -36,7 +36,7 @@
36
36
  "framer-motion": "^12.0.0",
37
37
  "react": "^19.0.0",
38
38
  "react-dom": "^19.0.0",
39
- "@lumencast/protocol": "0.11.0"
39
+ "@lumencast/protocol": "0.12.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@playwright/test": "^1.49.1",
@@ -50,8 +50,8 @@
50
50
  "vite-plugin-dts": "^4.5.0",
51
51
  "vitest": "^4.1.5",
52
52
  "ws": "^8.18.0",
53
- "@lumencast/server": "0.11.0",
54
- "@lumencast/dev-server": "0.11.0"
53
+ "@lumencast/dev-server": "0.12.0",
54
+ "@lumencast/server": "0.12.0"
55
55
  },
56
56
  "scripts": {
57
57
  "dev": "vite",
package/src/index.ts CHANGED
@@ -76,6 +76,7 @@ export {
76
76
  type RemoteTrackEvent,
77
77
  type PeerStreamRegistry,
78
78
  type PeerStreamListener,
79
+ type RosterListener,
79
80
  } from "./webrtc/index.js";
80
81
 
81
82
  // Bundle types are useful for hosts that want to typecheck pre-compiled scenes.
package/src/mount.ts CHANGED
@@ -46,6 +46,11 @@ export function mount(options: MountOptions): LumencastHandle {
46
46
 
47
47
  let active = true;
48
48
 
49
+ // Render-bundle versions already warmed (or warming) by the preload path.
50
+ // Keeps both roster sources (the `scene_roster` frame and the `preloadRoster`
51
+ // mount option) idempotent — a version is fetched by the warmer at most once.
52
+ const warmedVersions = new Set<string>();
53
+
49
54
  // ADR Blue 009 §3.2–3.3 — surface the reserved `__cam.*` LSDP leaves (the
50
55
  // slot→peer assignments + the receive-only viewer creds) to the host so its
51
56
  // WebRTC viewer (Solar) can drive room joins + `x-zab.meet-peer` slot re-keying.
@@ -107,6 +112,13 @@ export function mount(options: MountOptions): LumencastHandle {
107
112
  to: frame.scene_version,
108
113
  });
109
114
  },
115
+ onSceneRoster: (frame) => {
116
+ if (!active) return;
117
+ // The server advertised the show roster (LSDP/1.1 `scene_roster`).
118
+ // Warm every scene's render bundle in the background so the first switch
119
+ // to each is a cache hit, not a blocking fetch.
120
+ warmRoster(frame.entries, "frame");
121
+ },
110
122
  onServerError: (frame) => {
111
123
  reportError({
112
124
  code: frame.code,
@@ -121,6 +133,12 @@ export function mount(options: MountOptions): LumencastHandle {
121
133
 
122
134
  ws.start();
123
135
 
136
+ // Public preload surface (#87b) — warm a host-supplied roster right after
137
+ // mount, before any switch. Same warmer + cache as the `scene_roster` frame.
138
+ if (options.preloadRoster !== undefined && options.preloadRoster.length > 0) {
139
+ warmRoster(options.preloadRoster, "option");
140
+ }
141
+
124
142
  const root: Root = createRoot(options.target);
125
143
  root.render(
126
144
  createElement(LumencastApp, {
@@ -165,6 +183,42 @@ export function mount(options: MountOptions): LumencastHandle {
165
183
 
166
184
  // --- helpers ----------------------------------------------------------
167
185
 
186
+ /**
187
+ * Warm the render bundles for a set of roster entries in the background.
188
+ * Best-effort and non-blocking: each `get()` populates the fetcher's cache
189
+ * keyed by `scene_version`, so the eventual `onSnapshot` fetch for that scene
190
+ * is an instant cache hit. Idempotent via `warmedVersions`; the already-active
191
+ * scene is skipped (its bundle is already loaded or in flight). A failed warm
192
+ * is swallowed and its version released so a later roster can retry — the
193
+ * scene still fetches on demand at switch time.
194
+ */
195
+ function warmRoster(
196
+ entries: readonly { scene_id: string; scene_version: string }[],
197
+ source: "frame" | "option",
198
+ ): void {
199
+ const activeVersion = bundleSignal.value?.scene_version;
200
+ for (const { scene_id, scene_version } of entries) {
201
+ if (scene_version === activeVersion) continue;
202
+ if (warmedVersions.has(scene_version)) continue;
203
+ warmedVersions.add(scene_version);
204
+ void bundleFetcher
205
+ .get(scene_id, scene_version)
206
+ .then(() => {
207
+ if (!active) return;
208
+ options.onMetric?.({
209
+ name: "roster_preloaded",
210
+ scene_id,
211
+ scene_version,
212
+ source,
213
+ });
214
+ })
215
+ .catch(() => {
216
+ // Release so a subsequent roster advertisement can retry the warm.
217
+ warmedVersions.delete(scene_version);
218
+ });
219
+ }
220
+ }
221
+
168
222
  async function onSnapshot(
169
223
  fetcher: BundleFetcher,
170
224
  bSignal: typeof bundleSignal,
@@ -25,6 +25,7 @@ import {
25
25
  type ErrorFrame,
26
26
  type Patch,
27
27
  type SceneChangedFrame,
28
+ type SceneRosterFrame,
28
29
  type SnapshotFrame,
29
30
  } from "@lumencast/protocol";
30
31
  import type { LumencastToken } from "../types.js";
@@ -57,6 +58,9 @@ export interface WsClientOptions {
57
58
  onSnapshot?: (frame: SnapshotFrame) => void;
58
59
  onDelta?: (frame: DeltaFrame) => void;
59
60
  onSceneChanged?: (frame: SceneChangedFrame) => void;
61
+ /** Out-of-band roster advertisement (LSDP/1.1 `scene_roster`, additive).
62
+ * Carries no sequence — dispatched without touching the sequence tracker. */
63
+ onSceneRoster?: (frame: SceneRosterFrame) => void;
60
64
  onServerError?: (frame: ErrorFrame) => void;
61
65
  /** Wire-level / codec / unrecoverable errors. */
62
66
  onTransportError?: (err: TransportError) => void;
@@ -298,6 +302,13 @@ export class WsClient {
298
302
  if (!frame.recoverable) this.close();
299
303
  return;
300
304
  }
305
+ case "scene_roster": {
306
+ // Out-of-band roster metadata: NOT part of the snapshot/delta stream.
307
+ // It carries no seq and MUST NOT touch the sequence tracker — forward
308
+ // it verbatim so the host can warm its render-bundle cache.
309
+ this.opts.onSceneRoster?.(frame);
310
+ return;
311
+ }
301
312
  case "pong":
302
313
  return;
303
314
  }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Public types of @lumencast/runtime — must align with RUNTIME-API.md.
2
2
 
3
- import type { ErrorCode } from "@lumencast/protocol";
3
+ import type { ErrorCode, SceneRosterEntry } from "@lumencast/protocol";
4
4
  import type { ResolveCaptureDevice } from "./render/primitives/capture";
5
5
  import type { ResolvePeerStream, SubscribePeerStream } from "./render/primitives/media";
6
6
  import type { ReservedCamLeaves } from "./state/reserved-leaves";
@@ -28,7 +28,12 @@ export interface LumencastMetric {
28
28
  | "frame_dropped"
29
29
  | "reconnect"
30
30
  | "snapshot_received"
31
- | "scene_changed";
31
+ | "scene_changed"
32
+ /** A render bundle was warmed ahead of time from a roster entry (either a
33
+ * `scene_roster` frame or the `preloadRoster` mount option). Emitted once
34
+ * the warm fetch resolves (or from cache). Carries `scene_id` +
35
+ * `scene_version` + `source` ("frame" | "option"). */
36
+ | "roster_preloaded";
32
37
  [key: string]: unknown;
33
38
  }
34
39
 
@@ -104,6 +109,17 @@ export interface MountOptions {
104
109
  * reads it. Omit it and the reserved leaves are simply not surfaced (the
105
110
  * preview/headless paths are unaffected). */
106
111
  onReservedLeaves?: (leaves: ReservedCamLeaves) => void;
112
+ /** Preload the render bundles of a known scene roster so the FIRST switch to
113
+ * each scene is instant (a warm cache hit instead of a blocking fetch).
114
+ * Each entry is `{ scene_id, scene_version }`. Warmed in the background right
115
+ * after mount — best-effort: a failed warm is swallowed (the scene still
116
+ * fetches on demand at switch time) and never blocks or errors the mount.
117
+ *
118
+ * This is the PUBLIC preload surface (lumencast-js #87b) for hosts that
119
+ * already know the roster at mount time. When the server also emits
120
+ * `scene_roster` frames the runtime warms from those too — both paths feed
121
+ * the same cache and are idempotent (a version is warmed at most once). */
122
+ preloadRoster?: readonly SceneRosterEntry[];
107
123
  }
108
124
 
109
125
  export interface LumencastHandle {
@@ -28,6 +28,7 @@ export {
28
28
  createPeerStreamRegistry,
29
29
  type PeerStreamRegistry,
30
30
  type PeerStreamListener,
31
+ type RosterListener,
31
32
  } from "./peer-stream-registry.js";
32
33
 
33
34
  export interface PeerViewer {
@@ -23,14 +23,32 @@
23
23
 
24
24
  export type PeerStreamListener = (stream: MediaStream | null) => void;
25
25
 
26
+ /** Notified whenever the live roster changes ORDER (a peer connects for the first
27
+ * time, or a connected peer drops). A pure re-`set` of an already-present label's
28
+ * stream is NOT a roster change (same arrival order) — it reaches per-label
29
+ * `subscribe` listeners only. Carries no payload : the listener re-reads
30
+ * `orderedLabels()`. */
31
+ export type RosterListener = () => void;
32
+
26
33
  export interface PeerStreamRegistry {
27
34
  /** #4 contract — the current stream for a label, or `null` if the peer is not
28
35
  * connected (yet / any more). Synchronous, side-effect free. */
29
36
  resolve(peerLabel: string): MediaStream | null;
37
+ /** The live `peer_label`s in ARRIVAL ORDER (insertion order of the backing Map,
38
+ * restricted to labels that currently hold a stream). Drives positional slot
39
+ * resolution (`@<n>` → `orderedLabels()[n]`, ADR Blue 009 axe 1 positional
40
+ * variant). Returns a fresh array — safe for the caller to keep / index. */
41
+ orderedLabels(): string[];
30
42
  /** Push channel for the LIVE `media` primitive : invoked immediately with the
31
43
  * current value, then on every change for `peerLabel`. Returns an
32
44
  * unsubscribe. */
33
45
  subscribe(peerLabel: string, listener: PeerStreamListener): () => void;
46
+ /** Roster-change channel : invoked whenever a peer connects (new label) or
47
+ * leaves (label dropped) — i.e. whenever `orderedLabels()` could shift. Lets a
48
+ * positional consumer re-resolve `@<n>` when arrivals/departures shuffle the
49
+ * order. NOT invoked on a pure stream replacement of an existing label. Returns
50
+ * an unsubscribe. */
51
+ subscribeRoster(listener: RosterListener): () => void;
34
52
  /** Viewer-side : publish / replace a peer's stream (peer connected). */
35
53
  set(peerLabel: string, stream: MediaStream): void;
36
54
  /** Viewer-side : drop a peer's stream (peer left / connection failed). The
@@ -45,6 +63,7 @@ export interface PeerStreamRegistry {
45
63
  export function createPeerStreamRegistry(): PeerStreamRegistry {
46
64
  const streams = new Map<string, MediaStream>();
47
65
  const listeners = new Map<string, Set<PeerStreamListener>>();
66
+ const rosterListeners = new Set<RosterListener>();
48
67
 
49
68
  function notify(peerLabel: string): void {
50
69
  const set = listeners.get(peerLabel);
@@ -53,10 +72,25 @@ export function createPeerStreamRegistry(): PeerStreamRegistry {
53
72
  for (const listener of set) listener(value);
54
73
  }
55
74
 
75
+ function notifyRoster(): void {
76
+ for (const listener of [...rosterListeners]) listener();
77
+ }
78
+
56
79
  return {
57
80
  resolve(peerLabel) {
58
81
  return streams.get(peerLabel) ?? null;
59
82
  },
83
+ orderedLabels() {
84
+ // Map preserves insertion order = arrival order ; every key holds a stream
85
+ // (a dropped peer is `delete`d in remove()).
86
+ return [...streams.keys()];
87
+ },
88
+ subscribeRoster(listener) {
89
+ rosterListeners.add(listener);
90
+ return () => {
91
+ rosterListeners.delete(listener);
92
+ };
93
+ },
60
94
  subscribe(peerLabel, listener) {
61
95
  let set = listeners.get(peerLabel);
62
96
  if (set === undefined) {
@@ -76,18 +110,22 @@ export function createPeerStreamRegistry(): PeerStreamRegistry {
76
110
  },
77
111
  set(peerLabel, stream) {
78
112
  if (streams.get(peerLabel) === stream) return; // idempotent re-emit guard
113
+ const isNew = !streams.has(peerLabel); // a brand-new arrival shifts the roster
79
114
  streams.set(peerLabel, stream);
80
115
  notify(peerLabel);
116
+ if (isNew) notifyRoster();
81
117
  },
82
118
  remove(peerLabel) {
83
119
  if (!streams.has(peerLabel)) return;
84
120
  streams.delete(peerLabel);
85
121
  notify(peerLabel);
122
+ notifyRoster(); // a departure shifts every later position
86
123
  },
87
124
  clear() {
88
125
  const labels = [...streams.keys()];
89
126
  streams.clear();
90
127
  for (const label of labels) notify(label);
128
+ if (labels.length > 0) notifyRoster();
91
129
  },
92
130
  };
93
131
  }