@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,60 @@
1
+ // Exponential backoff schedule for the WS reconnect loop.
2
+ //
3
+ // Aggressive at first (200 ms, 400 ms, 800 ms…) then capped at 5 s so a
4
+ // sustained outage doesn't hammer the gateway. Jittered to avoid thundering
5
+ // herds when several Lumencast instances reconnect together (e.g. a CEF
6
+ // host + a webview waking from suspend at the same time).
7
+ //
8
+ // The reference schedule in LSDP/1 §7 is "0 ms, 500 ms, 1 s, 2 s, 4 s, 8 s,
9
+ // 15 s, 30 s, 60 s cap". This implementation defaults are tighter; both are
10
+ // MAY-bounded by the spec.
11
+ const DEFAULTS = {
12
+ initial: 200,
13
+ max: 5_000,
14
+ factor: 2,
15
+ jitter: 0.2,
16
+ };
17
+ class ScheduleImpl {
18
+ opts;
19
+ random;
20
+ _attempt = 0;
21
+ constructor(opts, random) {
22
+ this.opts = opts;
23
+ this.random = random;
24
+ }
25
+ get attempt() {
26
+ return this._attempt;
27
+ }
28
+ delayFor(attempt) {
29
+ if (!Number.isInteger(attempt) || attempt < 1) {
30
+ throw new RangeError(`attempt must be a positive integer, got ${attempt}`);
31
+ }
32
+ this._attempt = attempt;
33
+ const base = Math.min(this.opts.initial * Math.pow(this.opts.factor, attempt - 1), this.opts.max);
34
+ if (this.opts.jitter <= 0)
35
+ return base;
36
+ const offset = (this.random() * 2 - 1) * this.opts.jitter * base;
37
+ return Math.max(0, base + offset);
38
+ }
39
+ reset() {
40
+ this._attempt = 0;
41
+ }
42
+ }
43
+ export function createReconnectSchedule(opts = {}) {
44
+ const merged = {
45
+ initial: opts.initial ?? DEFAULTS.initial,
46
+ max: opts.max ?? DEFAULTS.max,
47
+ factor: opts.factor ?? DEFAULTS.factor,
48
+ jitter: opts.jitter ?? DEFAULTS.jitter,
49
+ };
50
+ if (merged.initial <= 0)
51
+ throw new RangeError("initial must be > 0");
52
+ if (merged.max < merged.initial)
53
+ throw new RangeError("max must be >= initial");
54
+ if (merged.factor < 1)
55
+ throw new RangeError("factor must be >= 1");
56
+ if (merged.jitter < 0 || merged.jitter > 1)
57
+ throw new RangeError("jitter must be within [0, 1]");
58
+ return new ScheduleImpl(merged, opts.random ?? Math.random);
59
+ }
60
+ //# sourceMappingURL=reconnect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconnect.js","sourceRoot":"","sources":["../../src/transport/reconnect.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,wEAAwE;AACxE,0DAA0D;AAC1D,EAAE;AACF,4EAA4E;AAC5E,4EAA4E;AAC5E,2BAA2B;AAe3B,MAAM,QAAQ,GAAuD;IACnE,OAAO,EAAE,GAAG;IACZ,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,CAAC;IACT,MAAM,EAAE,GAAG;CACZ,CAAC;AAWF,MAAM,YAAY;IAGG;IACA;IAHX,QAAQ,GAAG,CAAC,CAAC;IACrB,YACmB,IAAwD,EACxD,MAAoB;QADpB,SAAI,GAAJ,IAAI,CAAoD;QACxD,WAAM,GAAN,MAAM,CAAc;IACpC,CAAC;IAEJ,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,QAAQ,CAAC,OAAe;QACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,UAAU,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC,EAC3D,IAAI,CAAC,IAAI,CAAC,GAAG,CACd,CAAC;QACF,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACvC,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACjE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;IACpB,CAAC;CACF;AAED,MAAM,UAAU,uBAAuB,CAAC,OAAiC,EAAE;IACzE,MAAM,MAAM,GAAG;QACb,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;QACzC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;QACtC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;KACvC,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,CAAC,CAAC;IACrE,IAAI,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,wBAAwB,CAAC,CAAC;IAChF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,qBAAqB,CAAC,CAAC;IACnE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;IACjG,OAAO,IAAI,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { type DeltaFrame, type ErrorCode, type ErrorFrame, type Patch, type SceneChangedFrame, type SnapshotFrame } from "@lumencast/protocol";
2
+ import type { LumencastToken } from "../types.js";
3
+ import { type ReconnectScheduleOptions } from "./reconnect.js";
4
+ export type ConnectionStatus = "disconnected" | "connecting" | "live";
5
+ export interface WsClientOptions {
6
+ url: string;
7
+ token: LumencastToken;
8
+ /** Optional scene identifier (test mode). */
9
+ scene?: string;
10
+ /** Optional session identifier (test mode). */
11
+ session?: string;
12
+ /** Override the WebSocket constructor (for tests / non-browser hosts). */
13
+ webSocketImpl?: typeof WebSocket;
14
+ /** Reconnect tuning. */
15
+ reconnect?: ReconnectScheduleOptions;
16
+ /** Inject scheduler for tests. */
17
+ scheduler?: {
18
+ setTimeout: typeof globalThis.setTimeout;
19
+ clearTimeout: typeof globalThis.clearTimeout;
20
+ };
21
+ onStatus?: (status: ConnectionStatus) => void;
22
+ onSnapshot?: (frame: SnapshotFrame) => void;
23
+ onDelta?: (frame: DeltaFrame) => void;
24
+ onSceneChanged?: (frame: SceneChangedFrame) => void;
25
+ onServerError?: (frame: ErrorFrame) => void;
26
+ /** Wire-level / codec / unrecoverable errors. */
27
+ onTransportError?: (err: TransportError) => void;
28
+ }
29
+ export declare class TransportError extends Error {
30
+ readonly recoverable: boolean;
31
+ readonly code: ErrorCode;
32
+ readonly cause?: unknown;
33
+ constructor(message: string, recoverable: boolean, code?: ErrorCode, cause?: unknown);
34
+ }
35
+ export declare class WsClient {
36
+ private status;
37
+ private socket;
38
+ private token;
39
+ private readonly url;
40
+ private readonly WebSocketCtor;
41
+ private readonly schedule;
42
+ private readonly seq;
43
+ private readonly opts;
44
+ private readonly scheduler;
45
+ private reconnectTimer;
46
+ private active;
47
+ constructor(opts: WsClientOptions);
48
+ /** Open and start the connection lifecycle. Idempotent. */
49
+ start(): void;
50
+ /** Send `input` patches to the server. No-op if not connected. */
51
+ sendInput(patches: Patch[]): void;
52
+ /** Replace the auth token. Closes and reopens with the new token. */
53
+ setToken(token: LumencastToken): void;
54
+ /** Tear down for good. No more reconnect attempts. */
55
+ close(): void;
56
+ private openSocket;
57
+ private handleOpen;
58
+ private handleMessage;
59
+ private handleError;
60
+ private handleClose;
61
+ private scheduleReconnect;
62
+ private cancelReconnect;
63
+ private closeSocket;
64
+ private setStatus;
65
+ }
66
+ //# sourceMappingURL=ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,270 @@
1
+ // LSDP/1 WebSocket client.
2
+ //
3
+ // Lifecycle (LSDP/1 §6):
4
+ // 1. open() — opens the WS with subprotocol `lsdp.v1`
5
+ // 2. on open: send `subscribe` with the resolved token (and scene + session
6
+ // for test mode)
7
+ // 3. server replies `snapshot` (seq=1) → emit onSnapshot
8
+ // 4. subsequent `delta` / `scene_changed` / `error` / `pong` are dispatched
9
+ // 5. on a sequence gap → close + reconnect (fresh snapshot)
10
+ // 6. on close → reconnect with backoff, unless close was triggered by close()
11
+ // 7. setToken() opens a parallel WS with the new token; once its snapshot
12
+ // lands, atomically swap and close the old socket — no rendering gap
13
+ import { decodeServerFrame, encodeFrame, LumencastError, SequenceTracker, WS_SUBPROTOCOL_V1_1, WS_SUBPROTOCOLS, input as inputFrame, subscribe as subscribeFrame, } from "@lumencast/protocol";
14
+ import { createReconnectSchedule, } from "./reconnect.js";
15
+ export class TransportError extends Error {
16
+ recoverable;
17
+ code;
18
+ cause;
19
+ constructor(message, recoverable, code = "INTERNAL", cause) {
20
+ super(message);
21
+ this.name = "TransportError";
22
+ this.recoverable = recoverable;
23
+ this.code = code;
24
+ this.cause = cause;
25
+ }
26
+ }
27
+ export class WsClient {
28
+ status = "disconnected";
29
+ socket = null;
30
+ token;
31
+ url;
32
+ WebSocketCtor;
33
+ schedule;
34
+ seq = new SequenceTracker();
35
+ opts;
36
+ scheduler;
37
+ reconnectTimer = null;
38
+ active = true;
39
+ constructor(opts) {
40
+ this.opts = opts;
41
+ this.url = opts.url;
42
+ this.token = opts.token;
43
+ const ctor = opts.webSocketImpl ?? globalThis.WebSocket;
44
+ if (!ctor) {
45
+ throw new TypeError("Lumencast WsClient: no WebSocket implementation found in this environment");
46
+ }
47
+ this.WebSocketCtor = ctor;
48
+ this.schedule = createReconnectSchedule(opts.reconnect);
49
+ this.scheduler = opts.scheduler ?? {
50
+ setTimeout: globalThis.setTimeout.bind(globalThis),
51
+ clearTimeout: globalThis.clearTimeout.bind(globalThis),
52
+ };
53
+ }
54
+ /** Open and start the connection lifecycle. Idempotent. */
55
+ start() {
56
+ if (!this.active)
57
+ return;
58
+ if (this.socket || this.status === "connecting")
59
+ return;
60
+ void this.openSocket();
61
+ }
62
+ /** Send `input` patches to the server. No-op if not connected. */
63
+ sendInput(patches) {
64
+ if (!this.socket || this.socket.readyState !== this.WebSocketCtor.OPEN)
65
+ return;
66
+ if (patches.length === 0)
67
+ return;
68
+ this.socket.send(encodeFrame(inputFrame(patches)));
69
+ }
70
+ /** Replace the auth token. Closes and reopens with the new token. */
71
+ setToken(token) {
72
+ this.token = token;
73
+ if (!this.active)
74
+ return;
75
+ if (this.socket) {
76
+ this.closeSocket();
77
+ this.scheduleReconnect(true);
78
+ }
79
+ }
80
+ /** Tear down for good. No more reconnect attempts. */
81
+ close() {
82
+ if (!this.active)
83
+ return;
84
+ this.active = false;
85
+ this.cancelReconnect();
86
+ this.closeSocket();
87
+ this.setStatus("disconnected");
88
+ }
89
+ // --- internals --------------------------------------------------
90
+ async openSocket() {
91
+ if (!this.active)
92
+ return;
93
+ this.setStatus("connecting");
94
+ let resolvedToken;
95
+ try {
96
+ resolvedToken = await resolveToken(this.token);
97
+ }
98
+ catch (err) {
99
+ this.opts.onTransportError?.(new TransportError(`failed to resolve token: ${err.message}`, true, "AUTH_DENIED", err));
100
+ this.scheduleReconnect();
101
+ return;
102
+ }
103
+ if (!this.active)
104
+ return;
105
+ let socket;
106
+ try {
107
+ // Advertise both 1.1 (preferred) and 1.0 (fallback) ; the server
108
+ // picks one. Spread to a mutable array — the WebSocket constructor
109
+ // type expects string[].
110
+ socket = new this.WebSocketCtor(this.url, [...WS_SUBPROTOCOLS]);
111
+ }
112
+ catch (err) {
113
+ this.opts.onTransportError?.(new TransportError(`failed to open WebSocket: ${err.message}`, true, "INTERNAL", err));
114
+ this.scheduleReconnect();
115
+ return;
116
+ }
117
+ this.socket = socket;
118
+ socket.onopen = () => this.handleOpen(resolvedToken);
119
+ socket.onmessage = (event) => this.handleMessage(event);
120
+ socket.onerror = (event) => this.handleError(event);
121
+ socket.onclose = (event) => this.handleClose(event);
122
+ }
123
+ handleOpen(token) {
124
+ if (!this.socket)
125
+ return;
126
+ // LSDP/1.1 §4.1, §18 — if we have a previously-observed seq AND the
127
+ // negotiated subprotocol is 1.1, request an incremental resume.
128
+ // The server will EITHER ship buffered deltas (cache stays valid)
129
+ // OR a fresh snapshot which we rebase via observeSnapshot.
130
+ const subprotocol = this.socket.protocol;
131
+ const canResume = subprotocol === WS_SUBPROTOCOL_V1_1 && this.seq.last > 0;
132
+ const sinceSequence = canResume ? this.seq.last : undefined;
133
+ if (!canResume) {
134
+ // Fresh subscription (no resume) — reset the tracker baseline.
135
+ this.seq.reset();
136
+ }
137
+ const frame = subscribeFrame({
138
+ token,
139
+ ...(this.opts.scene !== undefined ? { scene: this.opts.scene } : {}),
140
+ ...(this.opts.session !== undefined ? { session: this.opts.session } : {}),
141
+ ...(sinceSequence !== undefined ? { since_sequence: sinceSequence } : {}),
142
+ });
143
+ this.socket.send(encodeFrame(frame));
144
+ }
145
+ handleMessage(event) {
146
+ const data = typeof event.data === "string" ? event.data : "";
147
+ if (!data)
148
+ return;
149
+ let frame;
150
+ try {
151
+ frame = decodeServerFrame(data);
152
+ }
153
+ catch (err) {
154
+ const message = err instanceof LumencastError ? err.message : err.message;
155
+ const code = err instanceof LumencastError ? err.code : "INTERNAL";
156
+ this.opts.onTransportError?.(new TransportError(`codec: ${message}`, true, code, err));
157
+ this.closeSocket();
158
+ this.scheduleReconnect();
159
+ return;
160
+ }
161
+ if (frame === null)
162
+ return; // unknown frame type — forward-compat ignore
163
+ switch (frame.type) {
164
+ case "snapshot": {
165
+ // LSDP/1.1 §18.1.1 — snapshot rebases the tracker to its seq
166
+ // value. This is the ONLY valid way to set or change the
167
+ // tracker's baseline (handles fresh sub, scene_changed, and
168
+ // back-pressure recovery uniformly).
169
+ if (frame.seq < 1) {
170
+ this.opts.onTransportError?.(new TransportError(`snapshot seq must be >= 1, got ${frame.seq}`, true, "VERSION_GAP"));
171
+ this.closeSocket();
172
+ this.scheduleReconnect();
173
+ return;
174
+ }
175
+ this.seq.observeSnapshot(frame.seq);
176
+ this.schedule.reset();
177
+ this.setStatus("live");
178
+ this.opts.onSnapshot?.(frame);
179
+ return;
180
+ }
181
+ case "delta": {
182
+ const obs = this.seq.observe(frame.seq);
183
+ if (obs.kind === "gap") {
184
+ this.opts.onTransportError?.(new TransportError(`sequence gap: expected ${this.seq.last + 1}, got ${frame.seq}`, true, "VERSION_GAP"));
185
+ this.closeSocket();
186
+ this.scheduleReconnect();
187
+ return;
188
+ }
189
+ if (obs.kind === "duplicate")
190
+ return; // silent drop per LSDP/1 §5
191
+ this.opts.onDelta?.(frame);
192
+ return;
193
+ }
194
+ case "scene_changed": {
195
+ // The next snapshot will rebase the tracker via observeSnapshot.
196
+ // Reset here so the tracker doesn't fault on the SceneChanged's
197
+ // own seq (which advances prev's counter one final step).
198
+ this.seq.reset();
199
+ this.opts.onSceneChanged?.(frame);
200
+ return;
201
+ }
202
+ case "error": {
203
+ this.opts.onServerError?.(frame);
204
+ if (!frame.recoverable)
205
+ this.close();
206
+ return;
207
+ }
208
+ case "pong":
209
+ return;
210
+ }
211
+ }
212
+ handleError(_event) {
213
+ // The browser does not give us a real reason — `close` will follow.
214
+ }
215
+ handleClose(event) {
216
+ this.socket = null;
217
+ if (!this.active) {
218
+ this.setStatus("disconnected");
219
+ return;
220
+ }
221
+ if (event.code === 4401 || event.code === 4403 || event.code === 1008) {
222
+ // Auth-related close codes: not recoverable without operator intervention.
223
+ this.opts.onTransportError?.(new TransportError(`server closed: ${event.code} ${event.reason}`, false, "AUTH_DENIED"));
224
+ this.close();
225
+ return;
226
+ }
227
+ this.scheduleReconnect();
228
+ }
229
+ scheduleReconnect(immediate = false) {
230
+ if (!this.active)
231
+ return;
232
+ this.cancelReconnect();
233
+ const attempt = (this.schedule.attempt || 0) + 1;
234
+ const delay = immediate ? 0 : this.schedule.delayFor(attempt);
235
+ this.setStatus("disconnected");
236
+ this.reconnectTimer = this.scheduler.setTimeout(() => {
237
+ this.reconnectTimer = null;
238
+ void this.openSocket();
239
+ }, delay);
240
+ }
241
+ cancelReconnect() {
242
+ if (this.reconnectTimer) {
243
+ this.scheduler.clearTimeout(this.reconnectTimer);
244
+ this.reconnectTimer = null;
245
+ }
246
+ }
247
+ closeSocket() {
248
+ if (this.socket) {
249
+ try {
250
+ this.socket.close(1000, "client closing");
251
+ }
252
+ catch {
253
+ // ignore
254
+ }
255
+ this.socket = null;
256
+ }
257
+ }
258
+ setStatus(next) {
259
+ if (this.status === next)
260
+ return;
261
+ this.status = next;
262
+ this.opts.onStatus?.(next);
263
+ }
264
+ }
265
+ async function resolveToken(token) {
266
+ if (typeof token === "string")
267
+ return token;
268
+ return await token.fetch();
269
+ }
270
+ //# sourceMappingURL=ws.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../../src/transport/ws.ts"],"names":[],"mappings":"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"}