@lumencast/runtime 0.9.0 → 0.10.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 (90) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/app.d.ts +6 -1
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/app.js +3 -1
  5. package/dist/app.js.map +1 -1
  6. package/dist/{broadcast-ryjLRD5q.js → broadcast-L5wm2I6J.js} +3 -3
  7. package/dist/{broadcast-ryjLRD5q.js.map → broadcast-L5wm2I6J.js.map} +1 -1
  8. package/dist/{control-AgxbXOVS.js → control-eEUG7unp.js} +4 -4
  9. package/dist/{control-AgxbXOVS.js.map → control-eEUG7unp.js.map} +1 -1
  10. package/dist/index-Clrya_9l.js +1281 -0
  11. package/dist/index-Clrya_9l.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.html +1 -1
  15. package/dist/index.js +11 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/lumencast.js +18 -13
  18. package/dist/mount.d.ts.map +1 -1
  19. package/dist/mount.js +11 -0
  20. package/dist/mount.js.map +1 -1
  21. package/dist/overlay/runtime-context.d.ts +10 -0
  22. package/dist/overlay/runtime-context.d.ts.map +1 -1
  23. package/dist/overlay/runtime-context.js.map +1 -1
  24. package/dist/render/bundle.d.ts +1 -1
  25. package/dist/render/bundle.d.ts.map +1 -1
  26. package/dist/render/bundle.js.map +1 -1
  27. package/dist/render/primitives/capture.d.ts +13 -4
  28. package/dist/render/primitives/capture.d.ts.map +1 -1
  29. package/dist/render/primitives/capture.js +54 -22
  30. package/dist/render/primitives/capture.js.map +1 -1
  31. package/dist/render/primitives/index.d.ts.map +1 -1
  32. package/dist/render/primitives/index.js +4 -0
  33. package/dist/render/primitives/index.js.map +1 -1
  34. package/dist/render/primitives/live-peer-video.d.ts +27 -0
  35. package/dist/render/primitives/live-peer-video.d.ts.map +1 -0
  36. package/dist/render/primitives/live-peer-video.js +64 -0
  37. package/dist/render/primitives/live-peer-video.js.map +1 -0
  38. package/dist/render/primitives/media.d.ts +37 -12
  39. package/dist/render/primitives/media.d.ts.map +1 -1
  40. package/dist/render/primitives/media.js +43 -17
  41. package/dist/render/primitives/media.js.map +1 -1
  42. package/dist/render/primitives/meet-peer.d.ts +31 -0
  43. package/dist/render/primitives/meet-peer.d.ts.map +1 -0
  44. package/dist/render/primitives/meet-peer.js +46 -0
  45. package/dist/render/primitives/meet-peer.js.map +1 -0
  46. package/dist/render/prop-allowlist.d.ts.map +1 -1
  47. package/dist/render/prop-allowlist.js +27 -1
  48. package/dist/render/prop-allowlist.js.map +1 -1
  49. package/dist/render/tree.js +42 -8
  50. package/dist/render/tree.js.map +1 -1
  51. package/dist/{status-pill-BxCdj-KZ.js → status-pill-elORkMrh.js} +2 -2
  52. package/dist/{status-pill-BxCdj-KZ.js.map → status-pill-elORkMrh.js.map} +1 -1
  53. package/dist/{test-CaRHj_J6.js → test-7q_KJkdX.js} +4 -4
  54. package/dist/{test-CaRHj_J6.js.map → test-7q_KJkdX.js.map} +1 -1
  55. package/dist/{tree-BLIxJbD3.js → tree-BMxx5170.js} +522 -436
  56. package/dist/tree-BMxx5170.js.map +1 -0
  57. package/dist/types.d.ts +13 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/webrtc/index.d.ts +76 -0
  60. package/dist/webrtc/index.d.ts.map +1 -0
  61. package/dist/webrtc/index.js +180 -0
  62. package/dist/webrtc/index.js.map +1 -0
  63. package/dist/webrtc/meet-viewer.d.ts +139 -0
  64. package/dist/webrtc/meet-viewer.d.ts.map +1 -0
  65. package/dist/webrtc/meet-viewer.js +379 -0
  66. package/dist/webrtc/meet-viewer.js.map +1 -0
  67. package/dist/webrtc/peer-stream-registry.d.ts +21 -0
  68. package/dist/webrtc/peer-stream-registry.d.ts.map +1 -0
  69. package/dist/webrtc/peer-stream-registry.js +77 -0
  70. package/dist/webrtc/peer-stream-registry.js.map +1 -0
  71. package/package.json +4 -4
  72. package/src/app.tsx +9 -0
  73. package/src/index.ts +35 -0
  74. package/src/mount.ts +11 -0
  75. package/src/overlay/runtime-context.tsx +10 -0
  76. package/src/render/bundle.ts +11 -1
  77. package/src/render/primitives/capture.tsx +73 -28
  78. package/src/render/primitives/index.ts +4 -0
  79. package/src/render/primitives/live-peer-video.tsx +90 -0
  80. package/src/render/primitives/media.tsx +66 -17
  81. package/src/render/primitives/meet-peer.tsx +57 -0
  82. package/src/render/prop-allowlist.ts +27 -1
  83. package/src/render/tree.tsx +44 -8
  84. package/src/types.ts +13 -0
  85. package/src/webrtc/index.ts +252 -0
  86. package/src/webrtc/meet-viewer.ts +497 -0
  87. package/src/webrtc/peer-stream-registry.ts +93 -0
  88. package/dist/index-DrXsLYhe.js +0 -903
  89. package/dist/index-DrXsLYhe.js.map +0 -1
  90. package/dist/tree-BLIxJbD3.js.map +0 -1
@@ -1,903 +0,0 @@
1
- import { batch as w, signal as g } from "@preact/signals-react";
2
- import { createRoot as D } from "react-dom/client";
3
- import { createContext as K, useContext as C, lazy as S, Suspense as Z, createElement as J, StrictMode as Q } from "react";
4
- import { jsx as h } from "react/jsx-runtime";
5
- import { useSignals as V } from "@preact/signals-react/runtime";
6
- import { AnimatePresence as ee, motion as te } from "framer-motion";
7
- import { SequenceTracker as se, encodeFrame as O, input as ne, WS_SUBPROTOCOLS as re, WS_SUBPROTOCOL_V1_1 as ie, subscribe as oe, decodeServerFrame as ce, LumencastError as L } from "@lumencast/protocol";
8
- const T = K(null);
9
- function F({
10
- value: t,
11
- children: e
12
- }) {
13
- return /* @__PURE__ */ h(T.Provider, { value: t, children: e });
14
- }
15
- function Ve() {
16
- const t = C(T);
17
- if (!t)
18
- throw new Error(
19
- "Lumencast overlay components must be rendered inside LumencastRuntimeProvider"
20
- );
21
- return t;
22
- }
23
- function et() {
24
- return C(T);
25
- }
26
- const ae = S(
27
- () => import("./broadcast-ryjLRD5q.js").then((t) => ({ default: t.BroadcastMode }))
28
- ), ue = S(
29
- () => import("./control-AgxbXOVS.js").then((t) => ({ default: t.ControlMode }))
30
- ), le = S(() => import("./test-CaRHj_J6.js").then((t) => ({ default: t.TestMode })));
31
- function he({
32
- mode: t,
33
- store: e,
34
- bundleSignal: s,
35
- statusSignal: n,
36
- crossfadeKeySignal: r,
37
- sendInput: i,
38
- resolveCaptureDevice: c
39
- }) {
40
- V();
41
- const a = s.value, f = n.value, u = r.value;
42
- if (!a) return null;
43
- const p = t === "broadcast" ? ae : t === "control" ? ue : le;
44
- return /* @__PURE__ */ h(ee, { mode: "sync", children: /* @__PURE__ */ h(
45
- te.div,
46
- {
47
- initial: { opacity: 0 },
48
- animate: { opacity: 1 },
49
- exit: { opacity: 0 },
50
- transition: { duration: 0.4, ease: "easeInOut" },
51
- style: { position: "absolute", inset: 0 },
52
- children: /* @__PURE__ */ h(
53
- F,
54
- {
55
- value: {
56
- mode: t,
57
- store: e,
58
- bundle: a,
59
- status: f,
60
- sendInput: i,
61
- ...c !== void 0 ? { resolveCaptureDevice: c } : {}
62
- },
63
- children: /* @__PURE__ */ h(Z, { fallback: null, children: /* @__PURE__ */ h(p, {}) })
64
- }
65
- )
66
- },
67
- u
68
- ) });
69
- }
70
- const fe = "<anon>", b = /* @__PURE__ */ new Set();
71
- function q(t) {
72
- return b.add(t), () => {
73
- b.delete(t);
74
- };
75
- }
76
- function B(t, e, s) {
77
- const n = { nodeId: t ?? fe, field: e, reason: s };
78
- if (b.size > 0) {
79
- for (const r of b)
80
- try {
81
- r(n);
82
- } catch {
83
- }
84
- return;
85
- }
86
- }
87
- const de = 100, me = 4, pe = 64, ge = {
88
- blur: de,
89
- brightness: me
90
- };
91
- function N(t, e) {
92
- if (typeof e != "number" || !Number.isFinite(e) || e < 0 || Object.is(e, -0)) return null;
93
- const s = ge[t];
94
- return e > s ? s : e;
95
- }
96
- const ve = /^blur\((\d{1,7}(?:\.\d{1,4})?)px\) brightness\((\d{1,7}(?:\.\d{1,4})?)\)$/, tt = "blur(0px) brightness(1)";
97
- function be(t) {
98
- if (typeof t != "string" || t.length === 0 || t.length > pe) return null;
99
- const e = ve.exec(t);
100
- if (!e) return null;
101
- const s = N("blur", Number(e[1])), n = N("brightness", Number(e[2]));
102
- return s === null || n === null ? null : `blur(${s}px) brightness(${n})`;
103
- }
104
- function ye(t, e) {
105
- B(
106
- e,
107
- t,
108
- "rejected unsafe filter value : outside the R8 caps or not a finite number >= 0"
109
- );
110
- }
111
- const ke = { duration: 0 }, we = {
112
- linear: "linear",
113
- "cubic-in": "easeIn",
114
- "cubic-out": "easeOut",
115
- "cubic-in-out": "easeInOut"
116
- };
117
- function st(t) {
118
- return !t || t.kind === "none" ? ke : t.kind === "tween" ? {
119
- type: "tween",
120
- duration: (t.duration_ms ?? 0) / 1e3,
121
- ease: t.ease ? we[t.ease] ?? "easeOut" : "easeOut"
122
- } : t.kind === "spring" ? {
123
- type: "spring",
124
- ...t.stiffness !== void 0 ? { stiffness: t.stiffness } : {},
125
- ...t.damping !== void 0 ? { damping: t.damping } : {},
126
- ...t.mass !== void 0 ? { mass: t.mass } : {}
127
- } : {
128
- type: "tween",
129
- duration: (t.duration_ms ?? 400) / 1e3,
130
- ease: "easeInOut"
131
- };
132
- }
133
- const Se = {
134
- opacity: 1,
135
- scale: 1,
136
- scaleX: 1,
137
- scaleY: 1,
138
- rotate: 0,
139
- x: 0,
140
- y: 0,
141
- // LSML §6.1 filter identity — both functions are always present so
142
- // framer interpolates between structurally-identical filter lists
143
- // (the compiler emits the same two-function form, clamped per R8).
144
- filter: "blur(0px) brightness(1)"
145
- }, Te = {
146
- kind: "tween",
147
- duration_ms: 400,
148
- ease: "cubic-out"
149
- };
150
- function nt(t, e, s) {
151
- for (const n of e) {
152
- const r = t(n);
153
- if (r !== void 0) return r;
154
- }
155
- if (s && Object.keys(s).length > 0) {
156
- for (const n of Object.keys(s)) {
157
- const r = t(n);
158
- if (r !== void 0) return r;
159
- }
160
- return Te;
161
- }
162
- }
163
- function rt(t, e, s) {
164
- if (!e || Object.keys(e).length === 0)
165
- return { initial: t, animate: t };
166
- let n = e;
167
- if (e.filter !== void 0) {
168
- const i = be(e.filter);
169
- n = { ...e }, i === null ? (ye("animate_initial.filter", s), delete n.filter) : n.filter = i;
170
- }
171
- const r = { ...t };
172
- for (const i of Object.keys(n))
173
- i in r || (r[i] = Se[i] ?? 0);
174
- return { initial: n, animate: r };
175
- }
176
- function _e(t) {
177
- if (typeof t != "object" || t === null) return;
178
- const e = t, s = e.kind;
179
- if (s === "snap")
180
- return { kind: "none" };
181
- if (s === "tween") {
182
- const n = typeof e.duration_ms == "number" ? e.duration_ms : 0, r = Ee[e.easing] ?? "cubic-out";
183
- return { kind: "tween", duration_ms: n, ease: r };
184
- }
185
- if (s === "spring") {
186
- const n = { kind: "spring" };
187
- return typeof e.stiffness == "number" && (n.stiffness = e.stiffness), typeof e.damping == "number" && (n.damping = e.damping), typeof e.mass == "number" && (n.mass = e.mass), n;
188
- }
189
- }
190
- const Ee = {
191
- linear: "linear",
192
- "ease-in": "cubic-in",
193
- "ease-out": "cubic-out",
194
- "ease-in-out": "cubic-in-out"
195
- };
196
- function Ie(t, e) {
197
- w(() => {
198
- for (const s of e.patches) {
199
- const n = _e(s.transition);
200
- n !== void 0 ? t.setWithTransition(s.path, s.value, n) : t.set(s.path, s.value);
201
- }
202
- });
203
- }
204
- function Ae(t, e) {
205
- t.reset(e.state);
206
- }
207
- class Re {
208
- signals = /* @__PURE__ */ new Map();
209
- transitions = /* @__PURE__ */ new Map();
210
- signal(e) {
211
- let s = this.signals.get(e);
212
- return s || (s = g(void 0), this.signals.set(e, s)), s;
213
- }
214
- transitionSignal(e) {
215
- let s = this.transitions.get(e);
216
- return s || (s = g(void 0), this.transitions.set(e, s)), s;
217
- }
218
- set(e, s) {
219
- const n = this.signal(e);
220
- k(n.peek(), s) || (n.value = s);
221
- }
222
- setWithTransition(e, s, n) {
223
- w(() => {
224
- const r = this.transitionSignal(e);
225
- r.peek() !== n && (r.value = n);
226
- const i = this.signal(e);
227
- k(i.peek(), s) || (i.value = s);
228
- });
229
- }
230
- reset(e) {
231
- w(() => {
232
- const s = /* @__PURE__ */ new Set();
233
- for (const [n, r] of Object.entries(e)) {
234
- s.add(n);
235
- const i = this.signal(n);
236
- k(i.peek(), r) || (i.value = r);
237
- const c = this.transitions.get(n);
238
- c && c.peek() !== void 0 && (c.value = void 0);
239
- }
240
- for (const n of this.signals.keys())
241
- if (!s.has(n)) {
242
- const r = this.signals.get(n);
243
- r && r.peek() !== void 0 && (r.value = void 0);
244
- }
245
- });
246
- }
247
- toRecord() {
248
- const e = {};
249
- for (const [s, n] of this.signals.entries())
250
- e[s] = n.peek();
251
- return e;
252
- }
253
- }
254
- function W() {
255
- return new Re();
256
- }
257
- function k(t, e) {
258
- if (t === e) return !0;
259
- if (t === null || e === null || typeof t != typeof e || typeof t != "object" || Array.isArray(t) !== Array.isArray(e)) return !1;
260
- if (Array.isArray(t) && Array.isArray(e)) {
261
- if (t.length !== e.length) return !1;
262
- for (let c = 0; c < t.length; c++)
263
- if (t[c] !== e[c]) return !1;
264
- return !0;
265
- }
266
- const s = t, n = e, r = Object.keys(s), i = Object.keys(n);
267
- if (r.length !== i.length) return !1;
268
- for (const c of r)
269
- if (s[c] !== n[c]) return !1;
270
- return !0;
271
- }
272
- const Oe = /* @__PURE__ */ new Set([
273
- "x-lumencast.color-srgb-1.0",
274
- // RFC-0001 / ADR 004 — this runtime ships the Zab capture plugin, so a
275
- // bundle declaring `x-zab.capture/1` in `profiles[]` is compatible (it is
276
- // NOT rejected as BUNDLE_INCOMPATIBLE, §17.3.1).
277
- "x-zab.capture/1"
278
- ]), Le = /^x-[a-z0-9-]+(?:\.[a-z0-9-]+)*$/, Ne = /^(?:0|[1-9][0-9]*)$/, x = ".authoring";
279
- function xe(t) {
280
- const e = t.indexOf("/");
281
- if (e < 0) return !1;
282
- const s = t.slice(0, e), n = t.slice(e + 1);
283
- return !Ne.test(n) || !s.endsWith(x) ? !1 : Le.test(s.slice(0, -x.length));
284
- }
285
- class U extends Error {
286
- code = "BUNDLE_INCOMPATIBLE";
287
- unsupportedProfiles;
288
- constructor(e) {
289
- super(
290
- `BUNDLE_INCOMPATIBLE: profile(s) not supported by this runtime: ${e.join(
291
- ", "
292
- )}`
293
- ), this.name = "BundleIncompatibleError", this.unsupportedProfiles = e;
294
- }
295
- }
296
- function P(t, e = Oe) {
297
- const s = t.profiles;
298
- if (!s) return;
299
- if (!Array.isArray(s))
300
- throw new U(["<malformed: profiles is not an array>"]);
301
- if (s.length === 0) return;
302
- const n = s.filter((r) => typeof r != "string" || !xe(r) && !e.has(r)).map((r) => typeof r == "string" ? r : "<malformed: non-string profile entry>");
303
- if (n.length > 0)
304
- throw new U(n);
305
- }
306
- class Ue {
307
- cache = /* @__PURE__ */ new Map();
308
- baseUrl;
309
- pathPrefix;
310
- resolveUrl;
311
- getAuthToken;
312
- fetchImpl;
313
- constructor(e) {
314
- this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.pathPrefix = (e.pathPrefix ?? "/lsdp/v1/scenes").replace(/\/$/, ""), this.resolveUrl = e.resolveUrl, this.getAuthToken = e.getAuthToken, this.fetchImpl = e.fetchImpl ?? globalThis.fetch.bind(globalThis);
315
- }
316
- /** Build the request init carrying the bearer token, if any. Returns
317
- * `undefined` when no token is available — the fetch stays header-less,
318
- * preserving v0.5.0 behaviour. */
319
- async buildInit() {
320
- if (!this.getAuthToken) return;
321
- const e = await this.getAuthToken();
322
- if (e)
323
- return { headers: { Authorization: `Bearer ${e}` } };
324
- }
325
- buildUrl(e, s) {
326
- return this.resolveUrl ? this.resolveUrl(e, s) : `${this.baseUrl}${this.pathPrefix}/${encodeURIComponent(e)}/bundle?v=${encodeURIComponent(s)}`;
327
- }
328
- preload(e) {
329
- P(e), this.cache.set(e.scene_version, e);
330
- }
331
- async get(e, s) {
332
- const n = this.cache.get(s);
333
- if (n) return n;
334
- const r = this.buildUrl(e, s), i = await this.buildInit(), c = i ? await this.fetchImpl(r, i) : await this.fetchImpl(r);
335
- if (!c.ok)
336
- throw new Error(`bundle fetch failed: ${c.status} ${c.statusText}`);
337
- const a = await c.json();
338
- if (a.scene_version !== s)
339
- throw new Error(
340
- `bundle scene_version mismatch: expected ${s}, got ${a.scene_version}`
341
- );
342
- return P(a), this.cache.set(s, a), a;
343
- }
344
- }
345
- function Pe(t) {
346
- return new Ue(t);
347
- }
348
- const v = {
349
- initial: 200,
350
- max: 5e3,
351
- factor: 2,
352
- jitter: 0.2
353
- };
354
- class je {
355
- constructor(e, s) {
356
- this.opts = e, this.random = s;
357
- }
358
- _attempt = 0;
359
- get attempt() {
360
- return this._attempt;
361
- }
362
- delayFor(e) {
363
- if (!Number.isInteger(e) || e < 1)
364
- throw new RangeError(`attempt must be a positive integer, got ${e}`);
365
- this._attempt = e;
366
- const s = Math.min(
367
- this.opts.initial * Math.pow(this.opts.factor, e - 1),
368
- this.opts.max
369
- );
370
- if (this.opts.jitter <= 0) return s;
371
- const n = (this.random() * 2 - 1) * this.opts.jitter * s;
372
- return Math.max(0, s + n);
373
- }
374
- reset() {
375
- this._attempt = 0;
376
- }
377
- }
378
- function Me(t = {}) {
379
- const e = {
380
- initial: t.initial ?? v.initial,
381
- max: t.max ?? v.max,
382
- factor: t.factor ?? v.factor,
383
- jitter: t.jitter ?? v.jitter
384
- };
385
- if (e.initial <= 0) throw new RangeError("initial must be > 0");
386
- if (e.max < e.initial) throw new RangeError("max must be >= initial");
387
- if (e.factor < 1) throw new RangeError("factor must be >= 1");
388
- if (e.jitter < 0 || e.jitter > 1) throw new RangeError("jitter must be within [0, 1]");
389
- return new je(e, t.random ?? Math.random);
390
- }
391
- class m extends Error {
392
- recoverable;
393
- code;
394
- cause;
395
- constructor(e, s, n = "INTERNAL", r) {
396
- super(e), this.name = "TransportError", this.recoverable = s, this.code = n, this.cause = r;
397
- }
398
- }
399
- class $e {
400
- status = "disconnected";
401
- socket = null;
402
- token;
403
- url;
404
- WebSocketCtor;
405
- schedule;
406
- seq = new se();
407
- opts;
408
- scheduler;
409
- reconnectTimer = null;
410
- active = !0;
411
- constructor(e) {
412
- this.opts = e, this.url = e.url, this.token = e.token;
413
- const s = e.webSocketImpl ?? globalThis.WebSocket;
414
- if (!s)
415
- throw new TypeError(
416
- "Lumencast WsClient: no WebSocket implementation found in this environment"
417
- );
418
- this.WebSocketCtor = s, this.schedule = Me(e.reconnect), this.scheduler = e.scheduler ?? {
419
- setTimeout: globalThis.setTimeout.bind(globalThis),
420
- clearTimeout: globalThis.clearTimeout.bind(globalThis)
421
- };
422
- }
423
- /** Open and start the connection lifecycle. Idempotent. */
424
- start() {
425
- this.active && (this.socket || this.status === "connecting" || this.openSocket());
426
- }
427
- /** Resolve the current session token (the one used for the WS
428
- * subscription). Mirrors `setToken` swaps. Used by the bundle fetcher to
429
- * authenticate the render-bundle GET with the same credential. A
430
- * `LumencastTokenProvider` is awaited. */
431
- resolveCurrentToken() {
432
- return j(this.token);
433
- }
434
- /** Send `input` patches to the server. No-op if not connected. */
435
- sendInput(e) {
436
- !this.socket || this.socket.readyState !== this.WebSocketCtor.OPEN || e.length !== 0 && this.socket.send(O(ne(e)));
437
- }
438
- /** Replace the auth token. Closes and reopens with the new token. */
439
- setToken(e) {
440
- this.token = e, this.active && this.socket && (this.closeSocket(), this.scheduleReconnect(!0));
441
- }
442
- /** Tear down for good. No more reconnect attempts. */
443
- close() {
444
- this.active && (this.active = !1, this.cancelReconnect(), this.closeSocket(), this.setStatus("disconnected"));
445
- }
446
- // --- internals --------------------------------------------------
447
- async openSocket() {
448
- if (!this.active) return;
449
- this.setStatus("connecting");
450
- let e;
451
- try {
452
- e = await j(this.token);
453
- } catch (n) {
454
- this.opts.onTransportError?.(
455
- new m(
456
- `failed to resolve token: ${n.message}`,
457
- !0,
458
- "AUTH_DENIED",
459
- n
460
- )
461
- ), this.scheduleReconnect();
462
- return;
463
- }
464
- if (!this.active) return;
465
- let s;
466
- try {
467
- s = new this.WebSocketCtor(this.url, [...re]);
468
- } catch (n) {
469
- this.opts.onTransportError?.(
470
- new m(
471
- `failed to open WebSocket: ${n.message}`,
472
- !0,
473
- "INTERNAL",
474
- n
475
- )
476
- ), this.scheduleReconnect();
477
- return;
478
- }
479
- this.socket = s, s.onopen = () => this.handleOpen(e), s.onmessage = (n) => this.handleMessage(n), s.onerror = (n) => this.handleError(n), s.onclose = (n) => this.handleClose(n);
480
- }
481
- handleOpen(e) {
482
- if (!this.socket) return;
483
- const n = this.socket.protocol === ie && this.seq.last > 0, r = n ? this.seq.last : void 0;
484
- n || this.seq.reset();
485
- const i = oe({
486
- token: e,
487
- ...this.opts.scene !== void 0 ? { scene: this.opts.scene } : {},
488
- ...this.opts.session !== void 0 ? { session: this.opts.session } : {},
489
- ...r !== void 0 ? { since_sequence: r } : {}
490
- });
491
- this.socket.send(O(i));
492
- }
493
- handleMessage(e) {
494
- const s = typeof e.data == "string" ? e.data : "";
495
- if (!s) return;
496
- let n;
497
- try {
498
- n = ce(s);
499
- } catch (r) {
500
- const i = (r instanceof L, r.message), c = r instanceof L ? r.code : "INTERNAL";
501
- this.opts.onTransportError?.(new m(`codec: ${i}`, !0, c, r)), this.closeSocket(), this.scheduleReconnect();
502
- return;
503
- }
504
- if (n !== null)
505
- switch (n.type) {
506
- case "snapshot": {
507
- if (n.seq < 1) {
508
- this.opts.onTransportError?.(
509
- new m(`snapshot seq must be >= 1, got ${n.seq}`, !0, "VERSION_GAP")
510
- ), this.closeSocket(), this.scheduleReconnect();
511
- return;
512
- }
513
- this.seq.observeSnapshot(n.seq), this.schedule.reset(), this.setStatus("live"), this.opts.onSnapshot?.(n);
514
- return;
515
- }
516
- case "delta": {
517
- const r = this.seq.observe(n.seq);
518
- if (r.kind === "gap") {
519
- this.opts.onTransportError?.(
520
- new m(
521
- `sequence gap: expected ${this.seq.last + 1}, got ${n.seq}`,
522
- !0,
523
- "VERSION_GAP"
524
- )
525
- ), this.closeSocket(), this.scheduleReconnect();
526
- return;
527
- }
528
- if (r.kind === "duplicate") return;
529
- this.opts.onDelta?.(n);
530
- return;
531
- }
532
- case "scene_changed": {
533
- this.seq.reset(), this.opts.onSceneChanged?.(n);
534
- return;
535
- }
536
- case "error": {
537
- this.opts.onServerError?.(n), n.recoverable || this.close();
538
- return;
539
- }
540
- case "pong":
541
- return;
542
- }
543
- }
544
- handleError(e) {
545
- }
546
- handleClose(e) {
547
- if (this.socket = null, !this.active) {
548
- this.setStatus("disconnected");
549
- return;
550
- }
551
- if (e.code === 4401 || e.code === 4403 || e.code === 1008) {
552
- this.opts.onTransportError?.(
553
- new m(`server closed: ${e.code} ${e.reason}`, !1, "AUTH_DENIED")
554
- ), this.close();
555
- return;
556
- }
557
- this.scheduleReconnect();
558
- }
559
- scheduleReconnect(e = !1) {
560
- if (!this.active) return;
561
- this.cancelReconnect();
562
- const s = (this.schedule.attempt || 0) + 1, n = e ? 0 : this.schedule.delayFor(s);
563
- this.setStatus("disconnected"), this.reconnectTimer = this.scheduler.setTimeout(() => {
564
- this.reconnectTimer = null, this.openSocket();
565
- }, n);
566
- }
567
- cancelReconnect() {
568
- this.reconnectTimer && (this.scheduler.clearTimeout(this.reconnectTimer), this.reconnectTimer = null);
569
- }
570
- closeSocket() {
571
- if (this.socket) {
572
- try {
573
- this.socket.close(1e3, "client closing");
574
- } catch {
575
- }
576
- this.socket = null;
577
- }
578
- }
579
- setStatus(e) {
580
- this.status !== e && (this.status = e, this.opts.onStatus?.(e));
581
- }
582
- }
583
- async function j(t) {
584
- return typeof t == "string" ? t : await t.fetch();
585
- }
586
- function De(t) {
587
- if (!(t.target instanceof HTMLElement))
588
- throw new TypeError("mount: `target` must be an HTMLElement");
589
- if (typeof t.serverUrl != "string" || t.serverUrl.length === 0)
590
- throw new TypeError("mount: `serverUrl` must be a non-empty string");
591
- if (t.mode === "test") {
592
- if (!t.testSession)
593
- throw new TypeError("mount: `testSession` is required when mode === 'test'");
594
- if (!t.scene)
595
- throw new TypeError("mount: `scene` is required when mode === 'test'");
596
- }
597
- }
598
- function it(t) {
599
- De(t), t.onStatus?.("disconnected");
600
- const e = W(), s = Fe(t.serverUrl), n = Pe({
601
- baseUrl: s,
602
- ...t.resolveBundleUrl !== void 0 ? { resolveUrl: t.resolveBundleUrl } : {},
603
- getAuthToken: () => d.resolveCurrentToken()
604
- }), r = g(null), i = g("disconnected"), c = g("__initial__"), a = (o) => {
605
- i.value = o, t.onStatus?.(o);
606
- }, f = (o) => {
607
- t.onError?.(o);
608
- };
609
- let u = !0;
610
- const p = t.onDiagnostic ? q(t.onDiagnostic) : void 0, d = new $e({
611
- url: t.serverUrl,
612
- token: t.token,
613
- ...t.scene !== void 0 ? { scene: t.scene } : {},
614
- ...t.testSession !== void 0 ? { session: t.testSession } : {},
615
- onStatus: a,
616
- onSnapshot: (o) => {
617
- u && (H(
618
- n,
619
- r,
620
- c,
621
- o.scene_id,
622
- o.scene_version,
623
- () => Ae(e, o),
624
- f
625
- ), t.onMetric?.({
626
- name: "snapshot_received",
627
- scene_id: o.scene_id,
628
- path_count: Object.keys(o.state).length
629
- }));
630
- },
631
- onDelta: (o) => {
632
- if (!u) return;
633
- const y = performance.now();
634
- Ie(e, o), t.onMetric?.({
635
- name: "delta_applied",
636
- duration_ms: performance.now() - y
637
- }), t.onMetric?.({ name: "delta_received", count: 1, path_count: o.patches.length });
638
- },
639
- onSceneChanged: (o) => {
640
- u && t.onMetric?.({
641
- name: "scene_changed",
642
- from: r.value?.scene_version ?? null,
643
- to: o.scene_version
644
- });
645
- },
646
- onServerError: (o) => {
647
- f({
648
- code: o.code,
649
- message: o.message,
650
- recoverable: o.recoverable
651
- });
652
- },
653
- onTransportError: (o) => {
654
- f(Ce(o));
655
- }
656
- });
657
- d.start();
658
- const _ = D(t.target);
659
- return _.render(
660
- J(he, {
661
- mode: t.mode,
662
- store: e,
663
- bundleSignal: r,
664
- statusSignal: i,
665
- crossfadeKeySignal: c,
666
- sendInput: (o) => d.sendInput(o),
667
- // ADR 004 §A1.3 — thread the host capture resolver to the runtime context
668
- // so the `x-zab.capture` primitive's ACQUIRE mode can pin a device.
669
- ...t.resolveCaptureDevice !== void 0 ? { resolveCaptureDevice: t.resolveCaptureDevice } : {}
670
- })
671
- ), {
672
- disconnect() {
673
- u && (u = !1, p?.(), d.close(), _.unmount());
674
- },
675
- setToken(o) {
676
- u && d.setToken(o);
677
- }
678
- };
679
- async function H(o, y, G, E, I, X, Y) {
680
- let A;
681
- try {
682
- A = await o.get(E, I);
683
- } catch (R) {
684
- Y({
685
- code: "BUNDLE_FETCH_FAILED",
686
- message: R instanceof Error ? R.message : "render bundle fetch failed",
687
- recoverable: !0
688
- });
689
- return;
690
- }
691
- u && (X(), y.value = A, G.value = `${E}::${I}`);
692
- }
693
- }
694
- function Ce(t) {
695
- return {
696
- code: t.code,
697
- message: t.message,
698
- recoverable: t.recoverable
699
- };
700
- }
701
- function Fe(t) {
702
- try {
703
- const e = new URL(t);
704
- return `${e.protocol === "wss:" ? "https:" : "http:"}//${e.host}`;
705
- } catch {
706
- return "";
707
- }
708
- }
709
- const qe = [
710
- "visible",
711
- "opacity",
712
- "universal_opacity",
713
- "rotation",
714
- "sizing",
715
- "x",
716
- "y",
717
- "width",
718
- "height",
719
- // ADR 002 §3.2 (D2 / #D) — `blendMode` is consumed universally by the
720
- // wrapper (→ CSS `mix-blend-mode`) on every primitive.
721
- "blendMode",
722
- // ADR 002 §3.2 (#E) — a typed `mask` is lowered onto EVERY primitive by the
723
- // compiler and consumed by the Tree (built into a `<mask>` SVG element).
724
- "mask"
725
- ];
726
- function l(t) {
727
- return /* @__PURE__ */ new Set([...qe, ...t]);
728
- }
729
- const Be = {
730
- stack: l(["direction", "gap", "wrap", "crossGap", "align", "justify"]),
731
- grid: l(["cols", "rows", "gap"]),
732
- frame: l([
733
- "x",
734
- "y",
735
- "width",
736
- "height",
737
- "scale",
738
- "rotate",
739
- "background",
740
- "backgrounds",
741
- "clipsContent"
742
- ]),
743
- text: l([
744
- "value",
745
- "size",
746
- "font",
747
- "weight",
748
- "colour",
749
- "align",
750
- "lineHeight",
751
- "letterSpacing",
752
- "textTransform",
753
- "textDecoration",
754
- "fontStyle",
755
- "maxLines"
756
- ]),
757
- image: l(["src", "alt", "fit", "position", "width", "height"]),
758
- shape: l([
759
- "geometry",
760
- "kind",
761
- "width",
762
- "height",
763
- "radius",
764
- "fill",
765
- "fills",
766
- "stroke",
767
- "stroke_width",
768
- "strokes",
769
- "pathData",
770
- "paths",
771
- "ariaLabel"
772
- ]),
773
- media: l(["src", "loop", "mute", "autoplay", "fit"]),
774
- instance: l(["scene_id", "scene_version", "size", "position"]),
775
- // RFC-0001 / ADR 004 — vendor capture placeholder. `width`/`height` are the
776
- // flattened geometry (universal) ; the `x-zab.*` props are carried as
777
- // metadata (the renderer reserves the box, ignores deviceRef). Listed so
778
- // they are NOT flagged as silent drops by the anti-drop audit.
779
- "x-zab.capture": l(["x-zab.sourceKind", "x-zab.deviceRef", "width", "height"]),
780
- // `repeat` is dispatched specially by the tree ; its only consumed
781
- // binding is `items`.
782
- repeat: /* @__PURE__ */ new Set(["items"])
783
- };
784
- function We(t, e) {
785
- const s = Be[t];
786
- return !!(s === void 0 || s.has(e) || t === "instance" && (e === "params" || e.startsWith("params.")));
787
- }
788
- const M = /* @__PURE__ */ new WeakSet();
789
- function ot(t) {
790
- if (M.has(t)) return;
791
- M.add(t);
792
- const e = /* @__PURE__ */ new Set([
793
- ...Object.keys(t.props ?? {}),
794
- ...Object.keys(t.bindings ?? {})
795
- ]);
796
- for (const s of e)
797
- We(t.kind, s) || B(
798
- t.id,
799
- `${t.kind}.${s}`,
800
- "is not consumed by this primitive's renderer ; the prop is ignored (anti-silent-drop, ADR 001 §3.4)"
801
- );
802
- }
803
- const ze = { width: 1920, height: 1080 }, He = () => {
804
- };
805
- function ct(t) {
806
- const e = t.stage ?? ze, s = t.target;
807
- s.style.position ||= "relative", s.style.width = `${e.width}px`, s.style.height = `${e.height}px`, s.style.overflow = "hidden";
808
- const n = t.onDiagnostic ? q(t.onDiagnostic) : void 0, r = W();
809
- r.reset(t.defaults ?? {});
810
- const i = D(s);
811
- return {
812
- ready: new Promise((a) => {
813
- import("./broadcast-ryjLRD5q.js").then(({ BroadcastMode: f }) => {
814
- i.render(
815
- /* @__PURE__ */ h(Q, { children: /* @__PURE__ */ h(
816
- F,
817
- {
818
- value: {
819
- mode: "broadcast",
820
- store: r,
821
- bundle: t.bundle,
822
- status: "live",
823
- sendInput: He
824
- },
825
- children: /* @__PURE__ */ h(f, {})
826
- }
827
- ) })
828
- );
829
- const u = new Promise((d) => {
830
- requestAnimationFrame(() => requestAnimationFrame(() => d()));
831
- }), p = typeof document < "u" && document.fonts ? document.fonts.ready.then(() => {
832
- }) : Promise.resolve();
833
- Promise.all([u, p]).then(() => a());
834
- });
835
- }),
836
- unmount() {
837
- n?.(), i.unmount();
838
- }
839
- };
840
- }
841
- function z(t, e) {
842
- if (typeof t != "string") return t;
843
- if (e[t]) return e[t];
844
- const s = /^assets\/([A-Za-z0-9]+)\.[A-Za-z0-9]+$/.exec(t);
845
- return s && s[1] !== void 0 && e[s[1]] ? e[s[1]] : t;
846
- }
847
- function $(t, e) {
848
- if (t === null || typeof t != "object") return;
849
- if (Array.isArray(t)) {
850
- for (const n of t) $(n, e);
851
- return;
852
- }
853
- const s = t;
854
- "src" in s && (s.src = z(s.src, e));
855
- for (const n of Object.values(s))
856
- n && typeof n == "object" && $(n, e);
857
- }
858
- function at(t, e) {
859
- const s = { ...t };
860
- for (const [n, r] of Object.entries(s))
861
- n.startsWith("__lit.image.") && (s[n] = z(r, e));
862
- return s;
863
- }
864
- async function ut(t) {
865
- const e = [];
866
- for (const s of t)
867
- try {
868
- const n = new FontFace(s.family, s.src, {
869
- weight: String(s.weight),
870
- style: s.style ?? "normal"
871
- });
872
- await n.load(), document.fonts.add(n), e.push(s.family);
873
- } catch {
874
- }
875
- return e;
876
- }
877
- export {
878
- fe as A,
879
- U as B,
880
- tt as F,
881
- Be as P,
882
- Oe as S,
883
- et as a,
884
- ot as b,
885
- N as c,
886
- q as d,
887
- B as e,
888
- xe as f,
889
- it as g,
890
- ct as h,
891
- ut as i,
892
- z as j,
893
- at as k,
894
- $ as l,
895
- rt as m,
896
- nt as r,
897
- be as s,
898
- st as t,
899
- Ve as u,
900
- P as v,
901
- ye as w
902
- };
903
- //# sourceMappingURL=index-DrXsLYhe.js.map