@lumencast/runtime 0.1.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 (204) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +79 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/animate/crossfade.d.ts +13 -0
  5. package/dist/animate/crossfade.d.ts.map +1 -0
  6. package/dist/animate/crossfade.js +10 -0
  7. package/dist/animate/crossfade.js.map +1 -0
  8. package/dist/animate/keyframes.d.ts +42 -0
  9. package/dist/animate/keyframes.d.ts.map +1 -0
  10. package/dist/animate/keyframes.js +94 -0
  11. package/dist/animate/keyframes.js.map +1 -0
  12. package/dist/animate/transitions.d.ts +38 -0
  13. package/dist/animate/transitions.d.ts.map +1 -0
  14. package/dist/animate/transitions.js +81 -0
  15. package/dist/animate/transitions.js.map +1 -0
  16. package/dist/app.d.ts +16 -0
  17. package/dist/app.d.ts.map +1 -0
  18. package/dist/app.js +35 -0
  19. package/dist/app.js.map +1 -0
  20. package/dist/broadcast-BqOhSNsY.js +11 -0
  21. package/dist/broadcast-BqOhSNsY.js.map +1 -0
  22. package/dist/control-CRFn328D.js +16 -0
  23. package/dist/control-CRFn328D.js.map +1 -0
  24. package/dist/dev-entry.d.ts +2 -0
  25. package/dist/dev-entry.d.ts.map +1 -0
  26. package/dist/dev-entry.js +31 -0
  27. package/dist/dev-entry.js.map +1 -0
  28. package/dist/index-DUhPPRvw.js +583 -0
  29. package/dist/index-DUhPPRvw.js.map +1 -0
  30. package/dist/index.d.ts +4 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.html +46 -0
  33. package/dist/index.js +3 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/internal/validate-options.d.ts +5 -0
  36. package/dist/internal/validate-options.d.ts.map +1 -0
  37. package/dist/internal/validate-options.js +19 -0
  38. package/dist/internal/validate-options.js.map +1 -0
  39. package/dist/lumencast.js +5 -0
  40. package/dist/lumencast.js.map +1 -0
  41. package/dist/modes/broadcast.d.ts +3 -0
  42. package/dist/modes/broadcast.d.ts.map +1 -0
  43. package/dist/modes/broadcast.js +9 -0
  44. package/dist/modes/broadcast.js.map +1 -0
  45. package/dist/modes/control.d.ts +4 -0
  46. package/dist/modes/control.d.ts.map +1 -0
  47. package/dist/modes/control.js +12 -0
  48. package/dist/modes/control.js.map +1 -0
  49. package/dist/modes/test.d.ts +4 -0
  50. package/dist/modes/test.d.ts.map +1 -0
  51. package/dist/modes/test.js +13 -0
  52. package/dist/modes/test.js.map +1 -0
  53. package/dist/mount.d.ts +3 -0
  54. package/dist/mount.d.ts.map +1 -0
  55. package/dist/mount.js +144 -0
  56. package/dist/mount.js.map +1 -0
  57. package/dist/overlay/control.d.ts +2 -0
  58. package/dist/overlay/control.d.ts.map +1 -0
  59. package/dist/overlay/control.js +127 -0
  60. package/dist/overlay/control.js.map +1 -0
  61. package/dist/overlay/runtime-context.d.ts +20 -0
  62. package/dist/overlay/runtime-context.d.ts.map +1 -0
  63. package/dist/overlay/runtime-context.js +14 -0
  64. package/dist/overlay/runtime-context.js.map +1 -0
  65. package/dist/overlay/status-pill.d.ts +2 -0
  66. package/dist/overlay/status-pill.d.ts.map +1 -0
  67. package/dist/overlay/status-pill.js +29 -0
  68. package/dist/overlay/status-pill.js.map +1 -0
  69. package/dist/overlay/test.d.ts +5 -0
  70. package/dist/overlay/test.d.ts.map +1 -0
  71. package/dist/overlay/test.js +116 -0
  72. package/dist/overlay/test.js.map +1 -0
  73. package/dist/render/bundle.d.ts +102 -0
  74. package/dist/render/bundle.d.ts.map +1 -0
  75. package/dist/render/bundle.js +86 -0
  76. package/dist/render/bundle.js.map +1 -0
  77. package/dist/render/fill.d.ts +41 -0
  78. package/dist/render/fill.d.ts.map +1 -0
  79. package/dist/render/fill.js +95 -0
  80. package/dist/render/fill.js.map +1 -0
  81. package/dist/render/keyframe-player.d.ts +10 -0
  82. package/dist/render/keyframe-player.d.ts.map +1 -0
  83. package/dist/render/keyframe-player.js +65 -0
  84. package/dist/render/keyframe-player.js.map +1 -0
  85. package/dist/render/primitives/frame.d.ts +12 -0
  86. package/dist/render/primitives/frame.d.ts.map +1 -0
  87. package/dist/render/primitives/frame.js +65 -0
  88. package/dist/render/primitives/frame.js.map +1 -0
  89. package/dist/render/primitives/grid.d.ts +4 -0
  90. package/dist/render/primitives/grid.d.ts.map +1 -0
  91. package/dist/render/primitives/grid.js +14 -0
  92. package/dist/render/primitives/grid.js.map +1 -0
  93. package/dist/render/primitives/image.d.ts +5 -0
  94. package/dist/render/primitives/image.d.ts.map +1 -0
  95. package/dist/render/primitives/image.js +25 -0
  96. package/dist/render/primitives/image.js.map +1 -0
  97. package/dist/render/primitives/index.d.ts +10 -0
  98. package/dist/render/primitives/index.d.ts.map +1 -0
  99. package/dist/render/primitives/index.js +22 -0
  100. package/dist/render/primitives/index.js.map +1 -0
  101. package/dist/render/primitives/instance.d.ts +4 -0
  102. package/dist/render/primitives/instance.d.ts.map +1 -0
  103. package/dist/render/primitives/instance.js +35 -0
  104. package/dist/render/primitives/instance.js.map +1 -0
  105. package/dist/render/primitives/media.d.ts +6 -0
  106. package/dist/render/primitives/media.d.ts.map +1 -0
  107. package/dist/render/primitives/media.js +19 -0
  108. package/dist/render/primitives/media.js.map +1 -0
  109. package/dist/render/primitives/shape.d.ts +12 -0
  110. package/dist/render/primitives/shape.d.ts.map +1 -0
  111. package/dist/render/primitives/shape.js +66 -0
  112. package/dist/render/primitives/shape.js.map +1 -0
  113. package/dist/render/primitives/stack.d.ts +13 -0
  114. package/dist/render/primitives/stack.d.ts.map +1 -0
  115. package/dist/render/primitives/stack.js +45 -0
  116. package/dist/render/primitives/stack.js.map +1 -0
  117. package/dist/render/primitives/text.d.ts +6 -0
  118. package/dist/render/primitives/text.d.ts.map +1 -0
  119. package/dist/render/primitives/text.js +27 -0
  120. package/dist/render/primitives/text.js.map +1 -0
  121. package/dist/render/scope.d.ts +10 -0
  122. package/dist/render/scope.d.ts.map +1 -0
  123. package/dist/render/scope.js +27 -0
  124. package/dist/render/scope.js.map +1 -0
  125. package/dist/render/stagger-context.d.ts +9 -0
  126. package/dist/render/stagger-context.d.ts.map +1 -0
  127. package/dist/render/stagger-context.js +22 -0
  128. package/dist/render/stagger-context.js.map +1 -0
  129. package/dist/render/tree.d.ts +9 -0
  130. package/dist/render/tree.d.ts.map +1 -0
  131. package/dist/render/tree.js +139 -0
  132. package/dist/render/tree.js.map +1 -0
  133. package/dist/render/universal-wrapper.d.ts +16 -0
  134. package/dist/render/universal-wrapper.d.ts.map +1 -0
  135. package/dist/render/universal-wrapper.js +58 -0
  136. package/dist/render/universal-wrapper.js.map +1 -0
  137. package/dist/state/apply-delta.d.ts +11 -0
  138. package/dist/state/apply-delta.d.ts.map +1 -0
  139. package/dist/state/apply-delta.js +23 -0
  140. package/dist/state/apply-delta.js.map +1 -0
  141. package/dist/state/apply-snapshot.d.ts +6 -0
  142. package/dist/state/apply-snapshot.d.ts.map +1 -0
  143. package/dist/state/apply-snapshot.js +6 -0
  144. package/dist/state/apply-snapshot.js.map +1 -0
  145. package/dist/state/store.d.ts +28 -0
  146. package/dist/state/store.d.ts.map +1 -0
  147. package/dist/state/store.js +119 -0
  148. package/dist/state/store.js.map +1 -0
  149. package/dist/status-pill-DCHvrd_y.js +241 -0
  150. package/dist/status-pill-DCHvrd_y.js.map +1 -0
  151. package/dist/test-DBCtwx_I.js +210 -0
  152. package/dist/test-DBCtwx_I.js.map +1 -0
  153. package/dist/transport/reconnect.d.ts +22 -0
  154. package/dist/transport/reconnect.d.ts.map +1 -0
  155. package/dist/transport/reconnect.js +60 -0
  156. package/dist/transport/reconnect.js.map +1 -0
  157. package/dist/transport/ws.d.ts +66 -0
  158. package/dist/transport/ws.d.ts.map +1 -0
  159. package/dist/transport/ws.js +270 -0
  160. package/dist/transport/ws.js.map +1 -0
  161. package/dist/tree-CnhX02kd.js +494 -0
  162. package/dist/tree-CnhX02kd.js.map +1 -0
  163. package/dist/types.d.ts +38 -0
  164. package/dist/types.d.ts.map +1 -0
  165. package/dist/types.js +3 -0
  166. package/dist/types.js.map +1 -0
  167. package/package.json +64 -0
  168. package/src/animate/crossfade.tsx +31 -0
  169. package/src/animate/keyframes.ts +142 -0
  170. package/src/animate/transitions.ts +116 -0
  171. package/src/app.tsx +84 -0
  172. package/src/dev-entry.tsx +38 -0
  173. package/src/index.ts +24 -0
  174. package/src/internal/validate-options.ts +20 -0
  175. package/src/modes/broadcast.tsx +8 -0
  176. package/src/modes/control.tsx +17 -0
  177. package/src/modes/test.tsx +19 -0
  178. package/src/mount.ts +169 -0
  179. package/src/overlay/control.tsx +239 -0
  180. package/src/overlay/runtime-context.tsx +37 -0
  181. package/src/overlay/status-pill.tsx +37 -0
  182. package/src/overlay/test.tsx +213 -0
  183. package/src/render/bundle.ts +208 -0
  184. package/src/render/fill.tsx +163 -0
  185. package/src/render/keyframe-player.tsx +89 -0
  186. package/src/render/primitives/frame.tsx +78 -0
  187. package/src/render/primitives/grid.tsx +20 -0
  188. package/src/render/primitives/image.tsx +35 -0
  189. package/src/render/primitives/index.ts +35 -0
  190. package/src/render/primitives/instance.tsx +70 -0
  191. package/src/render/primitives/media.tsx +28 -0
  192. package/src/render/primitives/shape.tsx +135 -0
  193. package/src/render/primitives/stack.tsx +48 -0
  194. package/src/render/primitives/text.tsx +38 -0
  195. package/src/render/scope.tsx +27 -0
  196. package/src/render/stagger-context.tsx +24 -0
  197. package/src/render/tree.tsx +182 -0
  198. package/src/render/universal-wrapper.tsx +95 -0
  199. package/src/state/apply-delta.ts +24 -0
  200. package/src/state/apply-snapshot.ts +8 -0
  201. package/src/state/store.ts +141 -0
  202. package/src/transport/reconnect.ts +83 -0
  203. package/src/transport/ws.ts +359 -0
  204. package/src/types.ts +54 -0
@@ -0,0 +1,583 @@
1
+ import { batch as b, signal as d } from "@preact/signals-react";
2
+ import { createRoot as C } from "react-dom/client";
3
+ import { createContext as U, useContext as x, lazy as S, Suspense as P, createElement as q } from "react";
4
+ import { jsx as l } from "react/jsx-runtime";
5
+ import { useSignals as N } from "@preact/signals-react/runtime";
6
+ import { AnimatePresence as j, motion as W } from "framer-motion";
7
+ import { SequenceTracker as B, encodeFrame as _, input as D, WS_SUBPROTOCOLS as F, WS_SUBPROTOCOL_V1_1 as H, subscribe as z, decodeServerFrame as G, LumencastError as I } from "@lumencast/protocol";
8
+ const O = U(null);
9
+ function K({
10
+ value: t,
11
+ children: e
12
+ }) {
13
+ return /* @__PURE__ */ l(O.Provider, { value: t, children: e });
14
+ }
15
+ function Te() {
16
+ const t = x(O);
17
+ if (!t)
18
+ throw new Error(
19
+ "Lumencast overlay components must be rendered inside LumencastRuntimeProvider"
20
+ );
21
+ return t;
22
+ }
23
+ const J = S(
24
+ () => import("./broadcast-BqOhSNsY.js").then((t) => ({ default: t.BroadcastMode }))
25
+ ), Q = S(
26
+ () => import("./control-CRFn328D.js").then((t) => ({ default: t.ControlMode }))
27
+ ), X = S(() => import("./test-DBCtwx_I.js").then((t) => ({ default: t.TestMode })));
28
+ function Y({
29
+ mode: t,
30
+ store: e,
31
+ bundleSignal: s,
32
+ statusSignal: n,
33
+ crossfadeKeySignal: r,
34
+ sendInput: c
35
+ }) {
36
+ N();
37
+ const i = s.value, m = n.value, h = r.value;
38
+ if (!i) return null;
39
+ const a = t === "broadcast" ? J : t === "control" ? Q : X;
40
+ return /* @__PURE__ */ l(j, { mode: "sync", children: /* @__PURE__ */ l(
41
+ W.div,
42
+ {
43
+ initial: { opacity: 0 },
44
+ animate: { opacity: 1 },
45
+ exit: { opacity: 0 },
46
+ transition: { duration: 0.4, ease: "easeInOut" },
47
+ style: { position: "absolute", inset: 0 },
48
+ children: /* @__PURE__ */ l(
49
+ K,
50
+ {
51
+ value: {
52
+ mode: t,
53
+ store: e,
54
+ bundle: i,
55
+ status: m,
56
+ sendInput: c
57
+ },
58
+ children: /* @__PURE__ */ l(P, { fallback: null, children: /* @__PURE__ */ l(a, {}) })
59
+ }
60
+ )
61
+ },
62
+ h
63
+ ) });
64
+ }
65
+ const Z = { duration: 0 }, V = {
66
+ linear: "linear",
67
+ "cubic-in": "easeIn",
68
+ "cubic-out": "easeOut",
69
+ "cubic-in-out": "easeInOut"
70
+ };
71
+ function _e(t) {
72
+ return !t || t.kind === "none" ? Z : t.kind === "tween" ? {
73
+ type: "tween",
74
+ duration: (t.duration_ms ?? 0) / 1e3,
75
+ ease: t.ease ? V[t.ease] ?? "easeOut" : "easeOut"
76
+ } : t.kind === "spring" ? {
77
+ type: "spring",
78
+ ...t.stiffness !== void 0 ? { stiffness: t.stiffness } : {},
79
+ ...t.damping !== void 0 ? { damping: t.damping } : {}
80
+ } : {
81
+ type: "tween",
82
+ duration: (t.duration_ms ?? 400) / 1e3,
83
+ ease: "easeInOut"
84
+ };
85
+ }
86
+ function ee(t) {
87
+ if (typeof t != "object" || t === null) return;
88
+ const e = t, s = e.kind;
89
+ if (s === "snap")
90
+ return { kind: "none" };
91
+ if (s === "tween") {
92
+ const n = typeof e.duration_ms == "number" ? e.duration_ms : 0, r = te[e.easing] ?? "cubic-out";
93
+ return { kind: "tween", duration_ms: n, ease: r };
94
+ }
95
+ if (s === "spring") {
96
+ const n = { kind: "spring" };
97
+ return typeof e.stiffness == "number" && (n.stiffness = e.stiffness), typeof e.damping == "number" && (n.damping = e.damping), n;
98
+ }
99
+ }
100
+ const te = {
101
+ linear: "linear",
102
+ "ease-in": "cubic-in",
103
+ "ease-out": "cubic-out",
104
+ "ease-in-out": "cubic-in-out"
105
+ };
106
+ function se(t, e) {
107
+ b(() => {
108
+ for (const s of e.patches) {
109
+ const n = ee(s.transition);
110
+ n !== void 0 ? t.setWithTransition(s.path, s.value, n) : t.set(s.path, s.value);
111
+ }
112
+ });
113
+ }
114
+ function ne(t, e) {
115
+ t.reset(e.state);
116
+ }
117
+ class re {
118
+ signals = /* @__PURE__ */ new Map();
119
+ transitions = /* @__PURE__ */ new Map();
120
+ signal(e) {
121
+ let s = this.signals.get(e);
122
+ return s || (s = d(void 0), this.signals.set(e, s)), s;
123
+ }
124
+ transitionSignal(e) {
125
+ let s = this.transitions.get(e);
126
+ return s || (s = d(void 0), this.transitions.set(e, s)), s;
127
+ }
128
+ set(e, s) {
129
+ const n = this.signal(e);
130
+ v(n.peek(), s) || (n.value = s);
131
+ }
132
+ setWithTransition(e, s, n) {
133
+ b(() => {
134
+ const r = this.transitionSignal(e);
135
+ r.peek() !== n && (r.value = n);
136
+ const c = this.signal(e);
137
+ v(c.peek(), s) || (c.value = s);
138
+ });
139
+ }
140
+ reset(e) {
141
+ b(() => {
142
+ const s = /* @__PURE__ */ new Set();
143
+ for (const [n, r] of Object.entries(e)) {
144
+ s.add(n);
145
+ const c = this.signal(n);
146
+ v(c.peek(), r) || (c.value = r);
147
+ const i = this.transitions.get(n);
148
+ i && i.peek() !== void 0 && (i.value = void 0);
149
+ }
150
+ for (const n of this.signals.keys())
151
+ if (!s.has(n)) {
152
+ const r = this.signals.get(n);
153
+ r && r.peek() !== void 0 && (r.value = void 0);
154
+ }
155
+ });
156
+ }
157
+ toRecord() {
158
+ const e = {};
159
+ for (const [s, n] of this.signals.entries())
160
+ e[s] = n.peek();
161
+ return e;
162
+ }
163
+ }
164
+ function oe() {
165
+ return new re();
166
+ }
167
+ function v(t, e) {
168
+ if (t === e) return !0;
169
+ if (t === null || e === null || typeof t != typeof e || typeof t != "object" || Array.isArray(t) !== Array.isArray(e)) return !1;
170
+ if (Array.isArray(t) && Array.isArray(e)) {
171
+ if (t.length !== e.length) return !1;
172
+ for (let i = 0; i < t.length; i++)
173
+ if (t[i] !== e[i]) return !1;
174
+ return !0;
175
+ }
176
+ const s = t, n = e, r = Object.keys(s), c = Object.keys(n);
177
+ if (r.length !== c.length) return !1;
178
+ for (const i of r)
179
+ if (s[i] !== n[i]) return !1;
180
+ return !0;
181
+ }
182
+ const ie = /* @__PURE__ */ new Set([
183
+ "x-lumencast.color-srgb-1.0"
184
+ ]);
185
+ class ce extends Error {
186
+ code = "BUNDLE_INCOMPATIBLE";
187
+ unsupportedProfiles;
188
+ constructor(e) {
189
+ super(
190
+ `BUNDLE_INCOMPATIBLE: profile(s) not supported by this runtime: ${e.join(
191
+ ", "
192
+ )}`
193
+ ), this.name = "BundleIncompatibleError", this.unsupportedProfiles = e;
194
+ }
195
+ }
196
+ function R(t, e = ie) {
197
+ const s = t.profiles;
198
+ if (!s || s.length === 0) return;
199
+ const n = s.filter((r) => !e.has(r));
200
+ if (n.length > 0)
201
+ throw new ce(n);
202
+ }
203
+ class ae {
204
+ cache = /* @__PURE__ */ new Map();
205
+ baseUrl;
206
+ pathPrefix;
207
+ fetchImpl;
208
+ constructor(e) {
209
+ this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.pathPrefix = (e.pathPrefix ?? "/lsdp/v1/scenes").replace(/\/$/, ""), this.fetchImpl = e.fetchImpl ?? globalThis.fetch.bind(globalThis);
210
+ }
211
+ preload(e) {
212
+ R(e), this.cache.set(e.scene_version, e);
213
+ }
214
+ async get(e, s) {
215
+ const n = this.cache.get(s);
216
+ if (n) return n;
217
+ const r = `${this.baseUrl}${this.pathPrefix}/${encodeURIComponent(e)}/bundle?v=${encodeURIComponent(s)}`, c = await this.fetchImpl(r);
218
+ if (!c.ok)
219
+ throw new Error(`bundle fetch failed: ${c.status} ${c.statusText}`);
220
+ const i = await c.json();
221
+ if (i.scene_version !== s)
222
+ throw new Error(
223
+ `bundle scene_version mismatch: expected ${s}, got ${i.scene_version}`
224
+ );
225
+ return R(i), this.cache.set(s, i), i;
226
+ }
227
+ }
228
+ function ue(t) {
229
+ return new ae(t);
230
+ }
231
+ const p = {
232
+ initial: 200,
233
+ max: 5e3,
234
+ factor: 2,
235
+ jitter: 0.2
236
+ };
237
+ class le {
238
+ constructor(e, s) {
239
+ this.opts = e, this.random = s;
240
+ }
241
+ _attempt = 0;
242
+ get attempt() {
243
+ return this._attempt;
244
+ }
245
+ delayFor(e) {
246
+ if (!Number.isInteger(e) || e < 1)
247
+ throw new RangeError(`attempt must be a positive integer, got ${e}`);
248
+ this._attempt = e;
249
+ const s = Math.min(
250
+ this.opts.initial * Math.pow(this.opts.factor, e - 1),
251
+ this.opts.max
252
+ );
253
+ if (this.opts.jitter <= 0) return s;
254
+ const n = (this.random() * 2 - 1) * this.opts.jitter * s;
255
+ return Math.max(0, s + n);
256
+ }
257
+ reset() {
258
+ this._attempt = 0;
259
+ }
260
+ }
261
+ function he(t = {}) {
262
+ const e = {
263
+ initial: t.initial ?? p.initial,
264
+ max: t.max ?? p.max,
265
+ factor: t.factor ?? p.factor,
266
+ jitter: t.jitter ?? p.jitter
267
+ };
268
+ if (e.initial <= 0) throw new RangeError("initial must be > 0");
269
+ if (e.max < e.initial) throw new RangeError("max must be >= initial");
270
+ if (e.factor < 1) throw new RangeError("factor must be >= 1");
271
+ if (e.jitter < 0 || e.jitter > 1) throw new RangeError("jitter must be within [0, 1]");
272
+ return new le(e, t.random ?? Math.random);
273
+ }
274
+ class u extends Error {
275
+ recoverable;
276
+ code;
277
+ cause;
278
+ constructor(e, s, n = "INTERNAL", r) {
279
+ super(e), this.name = "TransportError", this.recoverable = s, this.code = n, this.cause = r;
280
+ }
281
+ }
282
+ class de {
283
+ status = "disconnected";
284
+ socket = null;
285
+ token;
286
+ url;
287
+ WebSocketCtor;
288
+ schedule;
289
+ seq = new B();
290
+ opts;
291
+ scheduler;
292
+ reconnectTimer = null;
293
+ active = !0;
294
+ constructor(e) {
295
+ this.opts = e, this.url = e.url, this.token = e.token;
296
+ const s = e.webSocketImpl ?? globalThis.WebSocket;
297
+ if (!s)
298
+ throw new TypeError(
299
+ "Lumencast WsClient: no WebSocket implementation found in this environment"
300
+ );
301
+ this.WebSocketCtor = s, this.schedule = he(e.reconnect), this.scheduler = e.scheduler ?? {
302
+ setTimeout: globalThis.setTimeout.bind(globalThis),
303
+ clearTimeout: globalThis.clearTimeout.bind(globalThis)
304
+ };
305
+ }
306
+ /** Open and start the connection lifecycle. Idempotent. */
307
+ start() {
308
+ this.active && (this.socket || this.status === "connecting" || this.openSocket());
309
+ }
310
+ /** Send `input` patches to the server. No-op if not connected. */
311
+ sendInput(e) {
312
+ !this.socket || this.socket.readyState !== this.WebSocketCtor.OPEN || e.length !== 0 && this.socket.send(_(D(e)));
313
+ }
314
+ /** Replace the auth token. Closes and reopens with the new token. */
315
+ setToken(e) {
316
+ this.token = e, this.active && this.socket && (this.closeSocket(), this.scheduleReconnect(!0));
317
+ }
318
+ /** Tear down for good. No more reconnect attempts. */
319
+ close() {
320
+ this.active && (this.active = !1, this.cancelReconnect(), this.closeSocket(), this.setStatus("disconnected"));
321
+ }
322
+ // --- internals --------------------------------------------------
323
+ async openSocket() {
324
+ if (!this.active) return;
325
+ this.setStatus("connecting");
326
+ let e;
327
+ try {
328
+ e = await fe(this.token);
329
+ } catch (n) {
330
+ this.opts.onTransportError?.(
331
+ new u(
332
+ `failed to resolve token: ${n.message}`,
333
+ !0,
334
+ "AUTH_DENIED",
335
+ n
336
+ )
337
+ ), this.scheduleReconnect();
338
+ return;
339
+ }
340
+ if (!this.active) return;
341
+ let s;
342
+ try {
343
+ s = new this.WebSocketCtor(this.url, [...F]);
344
+ } catch (n) {
345
+ this.opts.onTransportError?.(
346
+ new u(
347
+ `failed to open WebSocket: ${n.message}`,
348
+ !0,
349
+ "INTERNAL",
350
+ n
351
+ )
352
+ ), this.scheduleReconnect();
353
+ return;
354
+ }
355
+ 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);
356
+ }
357
+ handleOpen(e) {
358
+ if (!this.socket) return;
359
+ const n = this.socket.protocol === H && this.seq.last > 0, r = n ? this.seq.last : void 0;
360
+ n || this.seq.reset();
361
+ const c = z({
362
+ token: e,
363
+ ...this.opts.scene !== void 0 ? { scene: this.opts.scene } : {},
364
+ ...this.opts.session !== void 0 ? { session: this.opts.session } : {},
365
+ ...r !== void 0 ? { since_sequence: r } : {}
366
+ });
367
+ this.socket.send(_(c));
368
+ }
369
+ handleMessage(e) {
370
+ const s = typeof e.data == "string" ? e.data : "";
371
+ if (!s) return;
372
+ let n;
373
+ try {
374
+ n = G(s);
375
+ } catch (r) {
376
+ const c = (r instanceof I, r.message), i = r instanceof I ? r.code : "INTERNAL";
377
+ this.opts.onTransportError?.(new u(`codec: ${c}`, !0, i, r)), this.closeSocket(), this.scheduleReconnect();
378
+ return;
379
+ }
380
+ if (n !== null)
381
+ switch (n.type) {
382
+ case "snapshot": {
383
+ if (n.seq < 1) {
384
+ this.opts.onTransportError?.(
385
+ new u(`snapshot seq must be >= 1, got ${n.seq}`, !0, "VERSION_GAP")
386
+ ), this.closeSocket(), this.scheduleReconnect();
387
+ return;
388
+ }
389
+ this.seq.observeSnapshot(n.seq), this.schedule.reset(), this.setStatus("live"), this.opts.onSnapshot?.(n);
390
+ return;
391
+ }
392
+ case "delta": {
393
+ const r = this.seq.observe(n.seq);
394
+ if (r.kind === "gap") {
395
+ this.opts.onTransportError?.(
396
+ new u(
397
+ `sequence gap: expected ${this.seq.last + 1}, got ${n.seq}`,
398
+ !0,
399
+ "VERSION_GAP"
400
+ )
401
+ ), this.closeSocket(), this.scheduleReconnect();
402
+ return;
403
+ }
404
+ if (r.kind === "duplicate") return;
405
+ this.opts.onDelta?.(n);
406
+ return;
407
+ }
408
+ case "scene_changed": {
409
+ this.seq.reset(), this.opts.onSceneChanged?.(n);
410
+ return;
411
+ }
412
+ case "error": {
413
+ this.opts.onServerError?.(n), n.recoverable || this.close();
414
+ return;
415
+ }
416
+ case "pong":
417
+ return;
418
+ }
419
+ }
420
+ handleError(e) {
421
+ }
422
+ handleClose(e) {
423
+ if (this.socket = null, !this.active) {
424
+ this.setStatus("disconnected");
425
+ return;
426
+ }
427
+ if (e.code === 4401 || e.code === 4403 || e.code === 1008) {
428
+ this.opts.onTransportError?.(
429
+ new u(`server closed: ${e.code} ${e.reason}`, !1, "AUTH_DENIED")
430
+ ), this.close();
431
+ return;
432
+ }
433
+ this.scheduleReconnect();
434
+ }
435
+ scheduleReconnect(e = !1) {
436
+ if (!this.active) return;
437
+ this.cancelReconnect();
438
+ const s = (this.schedule.attempt || 0) + 1, n = e ? 0 : this.schedule.delayFor(s);
439
+ this.setStatus("disconnected"), this.reconnectTimer = this.scheduler.setTimeout(() => {
440
+ this.reconnectTimer = null, this.openSocket();
441
+ }, n);
442
+ }
443
+ cancelReconnect() {
444
+ this.reconnectTimer && (this.scheduler.clearTimeout(this.reconnectTimer), this.reconnectTimer = null);
445
+ }
446
+ closeSocket() {
447
+ if (this.socket) {
448
+ try {
449
+ this.socket.close(1e3, "client closing");
450
+ } catch {
451
+ }
452
+ this.socket = null;
453
+ }
454
+ }
455
+ setStatus(e) {
456
+ this.status !== e && (this.status = e, this.opts.onStatus?.(e));
457
+ }
458
+ }
459
+ async function fe(t) {
460
+ return typeof t == "string" ? t : await t.fetch();
461
+ }
462
+ function pe(t) {
463
+ if (!(t.target instanceof HTMLElement))
464
+ throw new TypeError("mount: `target` must be an HTMLElement");
465
+ if (typeof t.serverUrl != "string" || t.serverUrl.length === 0)
466
+ throw new TypeError("mount: `serverUrl` must be a non-empty string");
467
+ if (t.mode === "test") {
468
+ if (!t.testSession)
469
+ throw new TypeError("mount: `testSession` is required when mode === 'test'");
470
+ if (!t.scene)
471
+ throw new TypeError("mount: `scene` is required when mode === 'test'");
472
+ }
473
+ }
474
+ function Ie(t) {
475
+ pe(t), t.onStatus?.("disconnected");
476
+ const e = oe(), s = ge(t.serverUrl), n = ue({ baseUrl: s }), r = d(null), c = d("disconnected"), i = d("__initial__"), m = (o) => {
477
+ c.value = o, t.onStatus?.(o);
478
+ }, h = (o) => {
479
+ t.onError?.(o);
480
+ };
481
+ let a = !0;
482
+ const f = new de({
483
+ url: t.serverUrl,
484
+ token: t.token,
485
+ ...t.scene !== void 0 ? { scene: t.scene } : {},
486
+ ...t.testSession !== void 0 ? { session: t.testSession } : {},
487
+ onStatus: m,
488
+ onSnapshot: (o) => {
489
+ a && (A(
490
+ n,
491
+ r,
492
+ i,
493
+ o.scene_id,
494
+ o.scene_version,
495
+ () => ne(e, o),
496
+ h
497
+ ), t.onMetric?.({
498
+ name: "snapshot_received",
499
+ scene_id: o.scene_id,
500
+ path_count: Object.keys(o.state).length
501
+ }));
502
+ },
503
+ onDelta: (o) => {
504
+ if (!a) return;
505
+ const g = performance.now();
506
+ se(e, o), t.onMetric?.({
507
+ name: "delta_applied",
508
+ duration_ms: performance.now() - g
509
+ }), t.onMetric?.({ name: "delta_received", count: 1, path_count: o.patches.length });
510
+ },
511
+ onSceneChanged: (o) => {
512
+ a && t.onMetric?.({
513
+ name: "scene_changed",
514
+ from: r.value?.scene_version ?? null,
515
+ to: o.scene_version
516
+ });
517
+ },
518
+ onServerError: (o) => {
519
+ h({
520
+ code: o.code,
521
+ message: o.message,
522
+ recoverable: o.recoverable
523
+ });
524
+ },
525
+ onTransportError: (o) => {
526
+ h(me(o));
527
+ }
528
+ });
529
+ f.start();
530
+ const k = C(t.target);
531
+ return k.render(
532
+ q(Y, {
533
+ mode: t.mode,
534
+ store: e,
535
+ bundleSignal: r,
536
+ statusSignal: c,
537
+ crossfadeKeySignal: i,
538
+ sendInput: (o) => f.sendInput(o)
539
+ })
540
+ ), {
541
+ disconnect() {
542
+ a && (a = !1, f.close(), k.unmount());
543
+ },
544
+ setToken(o) {
545
+ a && f.setToken(o);
546
+ }
547
+ };
548
+ async function A(o, g, L, w, E, M, $) {
549
+ let y;
550
+ try {
551
+ y = await o.get(w, E);
552
+ } catch (T) {
553
+ $({
554
+ code: "BUNDLE_FETCH_FAILED",
555
+ message: T instanceof Error ? T.message : "render bundle fetch failed",
556
+ recoverable: !0
557
+ });
558
+ return;
559
+ }
560
+ a && (M(), g.value = y, L.value = `${w}::${E}`);
561
+ }
562
+ }
563
+ function me(t) {
564
+ return {
565
+ code: t.code,
566
+ message: t.message,
567
+ recoverable: t.recoverable
568
+ };
569
+ }
570
+ function ge(t) {
571
+ try {
572
+ const e = new URL(t);
573
+ return `${e.protocol === "wss:" ? "https:" : "http:"}//${e.host}`;
574
+ } catch {
575
+ return "";
576
+ }
577
+ }
578
+ export {
579
+ Ie as m,
580
+ _e as t,
581
+ Te as u
582
+ };
583
+ //# sourceMappingURL=index-DUhPPRvw.js.map