@q9labsai/chalk-client 4.0.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 (253) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +173 -0
  3. package/dist/access/base64-url.d.ts +2 -0
  4. package/dist/access/base64-url.d.ts.map +1 -0
  5. package/dist/access/episode-diagnostic-credential.d.ts +11 -0
  6. package/dist/access/episode-diagnostic-credential.d.ts.map +1 -0
  7. package/dist/access/grant.d.ts +53 -0
  8. package/dist/access/grant.d.ts.map +1 -0
  9. package/dist/access/grant.test.helpers.d.ts +10 -0
  10. package/dist/access/grant.test.helpers.d.ts.map +1 -0
  11. package/dist/access/manager.d.ts +36 -0
  12. package/dist/access/manager.d.ts.map +1 -0
  13. package/dist/chat-files/http-transport.d.ts +8 -0
  14. package/dist/chat-files/http-transport.d.ts.map +1 -0
  15. package/dist/chat-files/index.d.ts +3 -0
  16. package/dist/chat-files/index.d.ts.map +1 -0
  17. package/dist/chat-files/types.d.ts +37 -0
  18. package/dist/chat-files/types.d.ts.map +1 -0
  19. package/dist/chunk-5VXGLI3T.js +3385 -0
  20. package/dist/chunk-O22WFBKF.js +5161 -0
  21. package/dist/chunk-PBCGWE2V.js +811 -0
  22. package/dist/chunk-PBSYXPNJ.js +23 -0
  23. package/dist/chunk-QVHR3RMB.js +1229 -0
  24. package/dist/client.d.ts +6785 -0
  25. package/dist/client.d.ts.map +1 -0
  26. package/dist/collaboration/index.d.ts +3 -0
  27. package/dist/collaboration/index.d.ts.map +1 -0
  28. package/dist/collaboration/types.d.ts +94 -0
  29. package/dist/collaboration/types.d.ts.map +1 -0
  30. package/dist/collaboration/wire.d.ts +19 -0
  31. package/dist/collaboration/wire.d.ts.map +1 -0
  32. package/dist/connection/dependencies.d.ts +112 -0
  33. package/dist/connection/dependencies.d.ts.map +1 -0
  34. package/dist/connection/diagnostics.d.ts +52 -0
  35. package/dist/connection/diagnostics.d.ts.map +1 -0
  36. package/dist/connection/index.d.ts +47 -0
  37. package/dist/connection/index.d.ts.map +1 -0
  38. package/dist/connection/lifecycle.d.ts +58 -0
  39. package/dist/connection/lifecycle.d.ts.map +1 -0
  40. package/dist/connection/media-devices.d.ts +6 -0
  41. package/dist/connection/media-devices.d.ts.map +1 -0
  42. package/dist/connection/production.d.ts +13 -0
  43. package/dist/connection/production.d.ts.map +1 -0
  44. package/dist/connection/snapshot.d.ts +23 -0
  45. package/dist/connection/snapshot.d.ts.map +1 -0
  46. package/dist/connection/types.d.ts +128 -0
  47. package/dist/connection/types.d.ts.map +1 -0
  48. package/dist/effect.d.ts +19 -0
  49. package/dist/effect.d.ts.map +1 -0
  50. package/dist/effect.js +7846 -0
  51. package/dist/episode-diagnostic-runtime.test.helpers.d.ts +3 -0
  52. package/dist/episode-diagnostic-runtime.test.helpers.d.ts.map +1 -0
  53. package/dist/generated/http-api.d.ts +6658 -0
  54. package/dist/generated/http-api.d.ts.map +1 -0
  55. package/dist/generated/schemas.d.ts +12076 -0
  56. package/dist/generated/schemas.d.ts.map +1 -0
  57. package/dist/generated/sync.d.ts +3947 -0
  58. package/dist/generated/sync.d.ts.map +1 -0
  59. package/dist/generated/whiteboard-v1.d.ts +334 -0
  60. package/dist/generated/whiteboard-v1.d.ts.map +1 -0
  61. package/dist/index.d.ts +10 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +152 -0
  64. package/dist/media/client.d.ts +18 -0
  65. package/dist/media/client.d.ts.map +1 -0
  66. package/dist/media/cloudflare-sfu.d.ts +5 -0
  67. package/dist/media/cloudflare-sfu.d.ts.map +1 -0
  68. package/dist/media/index.d.ts +3 -0
  69. package/dist/media/index.d.ts.map +1 -0
  70. package/dist/media/index.js +24 -0
  71. package/dist/media/plane.d.ts +24 -0
  72. package/dist/media/plane.d.ts.map +1 -0
  73. package/dist/media/tracks.d.ts +21 -0
  74. package/dist/media/tracks.d.ts.map +1 -0
  75. package/dist/media/transport.d.ts +3 -0
  76. package/dist/media/transport.d.ts.map +1 -0
  77. package/dist/media/types.d.ts +114 -0
  78. package/dist/media/types.d.ts.map +1 -0
  79. package/dist/server/chunk-A6YMG5FM.js +61 -0
  80. package/dist/server/client.d.cts +2 -0
  81. package/dist/server/client.d.ts +3 -0
  82. package/dist/server/client.d.ts.map +1 -0
  83. package/dist/server/errors.d.cts +18 -0
  84. package/dist/server/errors.d.ts +19 -0
  85. package/dist/server/errors.d.ts.map +1 -0
  86. package/dist/server/index.cjs +551 -0
  87. package/dist/server/index.d.cts +3 -0
  88. package/dist/server/index.d.ts +4 -0
  89. package/dist/server/index.d.ts.map +1 -0
  90. package/dist/server/index.js +474 -0
  91. package/dist/server/server-only.cjs +40 -0
  92. package/dist/server/server-only.d.cts +1 -0
  93. package/dist/server/server-only.d.ts +2 -0
  94. package/dist/server/server-only.d.ts.map +1 -0
  95. package/dist/server/server-only.js +9 -0
  96. package/dist/server/transport.d.cts +12 -0
  97. package/dist/server/transport.d.ts +13 -0
  98. package/dist/server/transport.d.ts.map +1 -0
  99. package/dist/server/types.d.cts +201 -0
  100. package/dist/server/types.d.ts +202 -0
  101. package/dist/server/types.d.ts.map +1 -0
  102. package/dist/space-client/chat-controller-helpers.d.ts +15 -0
  103. package/dist/space-client/chat-controller-helpers.d.ts.map +1 -0
  104. package/dist/space-client/chat-controller.d.ts +34 -0
  105. package/dist/space-client/chat-controller.d.ts.map +1 -0
  106. package/dist/space-client/controller-effects.d.ts +45 -0
  107. package/dist/space-client/controller-effects.d.ts.map +1 -0
  108. package/dist/space-client/controller-parity.test.helpers.d.ts +150 -0
  109. package/dist/space-client/controller-parity.test.helpers.d.ts.map +1 -0
  110. package/dist/space-client/core.d.ts +52 -0
  111. package/dist/space-client/core.d.ts.map +1 -0
  112. package/dist/space-client/core.test.helpers.d.ts +14 -0
  113. package/dist/space-client/core.test.helpers.d.ts.map +1 -0
  114. package/dist/space-client/effect.d.ts +44 -0
  115. package/dist/space-client/effect.d.ts.map +1 -0
  116. package/dist/space-client/episode-diagnostic-registry.d.ts +13 -0
  117. package/dist/space-client/episode-diagnostic-registry.d.ts.map +1 -0
  118. package/dist/space-client/episode-diagnostic-render-registry.d.ts +4 -0
  119. package/dist/space-client/episode-diagnostic-render-registry.d.ts.map +1 -0
  120. package/dist/space-client/episode-diagnostic-runtime.d.ts +102 -0
  121. package/dist/space-client/episode-diagnostic-runtime.d.ts.map +1 -0
  122. package/dist/space-client/errors.d.ts +11 -0
  123. package/dist/space-client/errors.d.ts.map +1 -0
  124. package/dist/space-client/index.d.ts +5 -0
  125. package/dist/space-client/index.d.ts.map +1 -0
  126. package/dist/space-client/media-controller.d.ts +30 -0
  127. package/dist/space-client/media-controller.d.ts.map +1 -0
  128. package/dist/space-client/media-controller.test.helpers.d.ts +105 -0
  129. package/dist/space-client/media-controller.test.helpers.d.ts.map +1 -0
  130. package/dist/space-client/media-device-selection.d.ts +13 -0
  131. package/dist/space-client/media-device-selection.d.ts.map +1 -0
  132. package/dist/space-client/participants-controller.d.ts +33 -0
  133. package/dist/space-client/participants-controller.d.ts.map +1 -0
  134. package/dist/space-client/promise-facade.d.ts +12 -0
  135. package/dist/space-client/promise-facade.d.ts.map +1 -0
  136. package/dist/space-client/reactions-controller.d.ts +19 -0
  137. package/dist/space-client/reactions-controller.d.ts.map +1 -0
  138. package/dist/space-client/space-client.d.ts +5 -0
  139. package/dist/space-client/space-client.d.ts.map +1 -0
  140. package/dist/space-client/store.d.ts +29 -0
  141. package/dist/space-client/store.d.ts.map +1 -0
  142. package/dist/space-client/types.d.ts +222 -0
  143. package/dist/space-client/types.d.ts.map +1 -0
  144. package/dist/space-client/whiteboard-controller.d.ts +17 -0
  145. package/dist/space-client/whiteboard-controller.d.ts.map +1 -0
  146. package/dist/sync/browser.d.ts +9 -0
  147. package/dist/sync/browser.d.ts.map +1 -0
  148. package/dist/sync/canonical.d.ts +7 -0
  149. package/dist/sync/canonical.d.ts.map +1 -0
  150. package/dist/sync/errors.d.ts +9 -0
  151. package/dist/sync/errors.d.ts.map +1 -0
  152. package/dist/sync/index.d.ts +13 -0
  153. package/dist/sync/index.d.ts.map +1 -0
  154. package/dist/sync/index.js +51 -0
  155. package/dist/sync/react-native.d.ts +42 -0
  156. package/dist/sync/react-native.d.ts.map +1 -0
  157. package/dist/sync/types.d.ts +28 -0
  158. package/dist/sync/types.d.ts.map +1 -0
  159. package/dist/sync/v1-client.d.ts +59 -0
  160. package/dist/sync/v1-client.d.ts.map +1 -0
  161. package/dist/sync/v1-codec.d.ts +5 -0
  162. package/dist/sync/v1-codec.d.ts.map +1 -0
  163. package/dist/sync/v1-create.d.ts +12 -0
  164. package/dist/sync/v1-create.d.ts.map +1 -0
  165. package/dist/sync/v1-persistence.d.ts +10 -0
  166. package/dist/sync/v1-persistence.d.ts.map +1 -0
  167. package/dist/sync/v1-platform-persistence.d.ts +26 -0
  168. package/dist/sync/v1-platform-persistence.d.ts.map +1 -0
  169. package/dist/sync/v1-reducer.d.ts +17 -0
  170. package/dist/sync/v1-reducer.d.ts.map +1 -0
  171. package/dist/sync/v1-types.d.ts +197 -0
  172. package/dist/sync/v1-types.d.ts.map +1 -0
  173. package/dist/telemetry/attributes.d.ts +7 -0
  174. package/dist/telemetry/attributes.d.ts.map +1 -0
  175. package/dist/telemetry/client.d.ts +44 -0
  176. package/dist/telemetry/client.d.ts.map +1 -0
  177. package/dist/telemetry/delivery.d.ts +107 -0
  178. package/dist/telemetry/delivery.d.ts.map +1 -0
  179. package/dist/telemetry/exporter.d.ts +38 -0
  180. package/dist/telemetry/exporter.d.ts.map +1 -0
  181. package/dist/telemetry/index.d.ts +7 -0
  182. package/dist/telemetry/index.d.ts.map +1 -0
  183. package/dist/telemetry/index.js +48 -0
  184. package/dist/telemetry/journey.d.ts +52 -0
  185. package/dist/telemetry/journey.d.ts.map +1 -0
  186. package/dist/telemetry/random.d.ts +18 -0
  187. package/dist/telemetry/random.d.ts.map +1 -0
  188. package/dist/telemetry/rtc.d.ts +35 -0
  189. package/dist/telemetry/rtc.d.ts.map +1 -0
  190. package/dist/telemetry/storage.d.ts +22 -0
  191. package/dist/telemetry/storage.d.ts.map +1 -0
  192. package/dist/telemetry/sync.d.ts +10 -0
  193. package/dist/telemetry/sync.d.ts.map +1 -0
  194. package/dist/telemetry/test-support.d.ts +51 -0
  195. package/dist/telemetry/test-support.d.ts.map +1 -0
  196. package/dist/telemetry/trace.d.ts +18 -0
  197. package/dist/telemetry/trace.d.ts.map +1 -0
  198. package/dist/telemetry/types.d.ts +109 -0
  199. package/dist/telemetry/types.d.ts.map +1 -0
  200. package/dist/webhooks/chunk-UNMJZNTZ.js +31 -0
  201. package/dist/webhooks/errors.d.cts +8 -0
  202. package/dist/webhooks/errors.d.ts +9 -0
  203. package/dist/webhooks/errors.d.ts.map +1 -0
  204. package/dist/webhooks/generated/event-v1.d.cts +764 -0
  205. package/dist/webhooks/generated/event-v1.d.ts +765 -0
  206. package/dist/webhooks/generated/event-v1.d.ts.map +1 -0
  207. package/dist/webhooks/generated/fixtures-v1.d.cts +46 -0
  208. package/dist/webhooks/generated/fixtures-v1.d.ts +47 -0
  209. package/dist/webhooks/generated/fixtures-v1.d.ts.map +1 -0
  210. package/dist/webhooks/index.cjs +1242 -0
  211. package/dist/webhooks/index.d.cts +5 -0
  212. package/dist/webhooks/index.d.ts +6 -0
  213. package/dist/webhooks/index.d.ts.map +1 -0
  214. package/dist/webhooks/index.js +1197 -0
  215. package/dist/webhooks/processor.d.cts +21 -0
  216. package/dist/webhooks/processor.d.ts +22 -0
  217. package/dist/webhooks/processor.d.ts.map +1 -0
  218. package/dist/webhooks/server-only.cjs +36 -0
  219. package/dist/webhooks/server-only.d.cts +1 -0
  220. package/dist/webhooks/server-only.d.ts +2 -0
  221. package/dist/webhooks/server-only.d.ts.map +1 -0
  222. package/dist/webhooks/server-only.js +9 -0
  223. package/dist/webhooks/test.cjs +160 -0
  224. package/dist/webhooks/test.d.cts +42 -0
  225. package/dist/webhooks/test.d.ts +43 -0
  226. package/dist/webhooks/test.d.ts.map +1 -0
  227. package/dist/webhooks/test.js +137 -0
  228. package/dist/webhooks/types.d.cts +55 -0
  229. package/dist/webhooks/types.d.ts +56 -0
  230. package/dist/webhooks/types.d.ts.map +1 -0
  231. package/dist/webhooks/validate.d.cts +5 -0
  232. package/dist/webhooks/validate.d.ts +6 -0
  233. package/dist/webhooks/validate.d.ts.map +1 -0
  234. package/dist/webhooks/verify.d.cts +10 -0
  235. package/dist/webhooks/verify.d.ts +11 -0
  236. package/dist/webhooks/verify.d.ts.map +1 -0
  237. package/dist/whiteboard/file-http-transport.d.ts +9 -0
  238. package/dist/whiteboard/file-http-transport.d.ts.map +1 -0
  239. package/dist/whiteboard/index.d.ts +7 -0
  240. package/dist/whiteboard/index.d.ts.map +1 -0
  241. package/dist/whiteboard/types.d.ts +139 -0
  242. package/dist/whiteboard/types.d.ts.map +1 -0
  243. package/dist/whiteboard/v1-client.d.ts +18 -0
  244. package/dist/whiteboard/v1-client.d.ts.map +1 -0
  245. package/dist/whiteboard/v1-codec.d.ts +5 -0
  246. package/dist/whiteboard/v1-codec.d.ts.map +1 -0
  247. package/dist/whiteboard/v1-create.d.ts +8 -0
  248. package/dist/whiteboard/v1-create.d.ts.map +1 -0
  249. package/dist/whiteboard/v1-multipart.d.ts +30 -0
  250. package/dist/whiteboard/v1-multipart.d.ts.map +1 -0
  251. package/dist/whiteboard/v1-persistence.d.ts +9 -0
  252. package/dist/whiteboard/v1-persistence.d.ts.map +1 -0
  253. package/package.json +222 -0
@@ -0,0 +1,3385 @@
1
+ import {
2
+ syncTelemetryCorrelation
3
+ } from "./chunk-PBSYXPNJ.js";
4
+
5
+ // src/sync/canonical.ts
6
+ var encoder = new TextEncoder();
7
+ function canonicalJson(value) {
8
+ return serialize(value);
9
+ }
10
+ function canonicalJsonBytes(value) {
11
+ return canonicalJsonBytesFromUnknown(value);
12
+ }
13
+ function canonicalJsonBytesFromUnknown(value) {
14
+ return encoder.encode(serialize(value));
15
+ }
16
+ function serialize(value) {
17
+ if (value === null) return "null";
18
+ if (Array.isArray(value)) return `[${value.map(serialize).join(",")}]`;
19
+ if (typeof value === "object") return serializeObject(value);
20
+ return serializeScalar(value);
21
+ }
22
+ function serializeScalar(value) {
23
+ switch (typeof value) {
24
+ case "string":
25
+ return serializeString(value);
26
+ case "number":
27
+ return serializeNumber(value);
28
+ case "boolean":
29
+ return JSON.stringify(value);
30
+ default:
31
+ throw new TypeError("canonical JSON only supports JSON values");
32
+ }
33
+ }
34
+ function serializeString(value) {
35
+ assertWellFormedUnicode(value);
36
+ return JSON.stringify(value);
37
+ }
38
+ function serializeNumber(value) {
39
+ if (!Number.isFinite(value)) {
40
+ throw new TypeError("canonical JSON does not support non-finite numbers");
41
+ }
42
+ return JSON.stringify(value);
43
+ }
44
+ function serializeObject(value) {
45
+ const prototype = Object.getPrototypeOf(value);
46
+ if (prototype !== Object.prototype && prototype !== null) throw new TypeError("canonical JSON only supports plain objects");
47
+ const keys = Object.keys(value).sort(compareUnicodeCodeUnits);
48
+ return `{${keys.map((key) => `${serialize(key)}:${serialize(Reflect.get(value, key))}`).join(",")}}`;
49
+ }
50
+ function compareUnicodeCodeUnits(left, right) {
51
+ return left < right ? -1 : left > right ? 1 : 0;
52
+ }
53
+ function assertWellFormedUnicode(value) {
54
+ for (let index = 0; index < value.length; index += 1) {
55
+ const code = value.charCodeAt(index);
56
+ if (!isSurrogate(code)) {
57
+ continue;
58
+ }
59
+ const next = value.charCodeAt(index + 1);
60
+ if (isSurrogatePair(code, next)) {
61
+ index += 1;
62
+ continue;
63
+ }
64
+ throw new TypeError("canonical JSON does not support unpaired UTF-16 surrogates");
65
+ }
66
+ }
67
+ function isSurrogate(code) {
68
+ return code >= 55296 && code <= 57343;
69
+ }
70
+ function isSurrogatePair(code, next) {
71
+ return code <= 56319 && next >= 56320 && next <= 57343;
72
+ }
73
+
74
+ // src/sync/errors.ts
75
+ var SyncBrowserCapabilityError = class extends Error {
76
+ _tag = "SyncBrowserCapabilityError";
77
+ constructor(capability) {
78
+ super(`${capability} is unavailable in this runtime`);
79
+ this.name = "SyncBrowserCapabilityError";
80
+ }
81
+ };
82
+ var SyncReactNativeCapabilityError = class extends Error {
83
+ _tag = "SyncReactNativeCapabilityError";
84
+ constructor(capability) {
85
+ super(`React Native ${capability} is unavailable in this runtime`);
86
+ this.name = "SyncReactNativeCapabilityError";
87
+ }
88
+ };
89
+
90
+ // src/sync/browser.ts
91
+ function createBrowserWebSocketFactory(WebSocketConstructor) {
92
+ return {
93
+ connect(url) {
94
+ const Constructor = WebSocketConstructor ?? globalThis.WebSocket;
95
+ if (!Constructor) {
96
+ throw new SyncBrowserCapabilityError("WebSocket");
97
+ }
98
+ return new BrowserSyncSocket(new Constructor(url));
99
+ }
100
+ };
101
+ }
102
+ function createBrowserSyncLifecycle(environment = browserLifecycleEnvironment()) {
103
+ return {
104
+ subscribe(listener) {
105
+ const online = () => listener("online");
106
+ const offline = () => listener("offline");
107
+ environment.window.addEventListener("online", online);
108
+ environment.window.addEventListener("offline", offline);
109
+ listener(environment.navigator?.onLine ?? true ? "online" : "offline");
110
+ return () => {
111
+ environment.window.removeEventListener("online", online);
112
+ environment.window.removeEventListener("offline", offline);
113
+ };
114
+ }
115
+ };
116
+ }
117
+ var BrowserSyncSocket = class {
118
+ #socket;
119
+ onopen = null;
120
+ onmessage = null;
121
+ onclose = null;
122
+ onerror = null;
123
+ constructor(socket) {
124
+ this.#socket = socket;
125
+ this.#socket.addEventListener("open", () => this.onopen?.());
126
+ this.#socket.addEventListener("message", (event) => this.onmessage?.({ data: event.data }));
127
+ this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code }));
128
+ this.#socket.addEventListener("error", () => this.onerror?.());
129
+ }
130
+ send(data) {
131
+ this.#socket.send(data);
132
+ }
133
+ close(code, reason) {
134
+ this.#socket.close(code, reason);
135
+ }
136
+ };
137
+ function browserLifecycleEnvironment() {
138
+ if (typeof globalThis.window === "undefined" || typeof globalThis.navigator === "undefined") {
139
+ throw new SyncBrowserCapabilityError("browser lifecycle");
140
+ }
141
+ return { window: globalThis.window, navigator: globalThis.navigator };
142
+ }
143
+
144
+ // src/sync/react-native.ts
145
+ function createReactNativeWebSocketFactory(WebSocketConstructor) {
146
+ return {
147
+ connect(url) {
148
+ if (WebSocketConstructor) {
149
+ return new ReactNativeSyncSocket(new WebSocketConstructor(url));
150
+ }
151
+ if (!globalThis.WebSocket) {
152
+ throw new SyncReactNativeCapabilityError("WebSocket");
153
+ }
154
+ return new BrowserFallbackSyncSocket(new globalThis.WebSocket(url));
155
+ }
156
+ };
157
+ }
158
+ function createReactNativeSyncLifecycle(environment) {
159
+ return {
160
+ subscribe(listener) {
161
+ const appState = environment.appState.addEventListener("change", (state) => listener(state === "active" ? "active" : "inactive"));
162
+ const network = environment.networkInfo?.addEventListener((state) => listener(isNetworkOnline(state) ? "online" : "offline"));
163
+ listener(environment.appState.currentState === "active" ? "active" : "inactive");
164
+ return () => {
165
+ unsubscribe(appState);
166
+ if (network) {
167
+ unsubscribe(network);
168
+ }
169
+ };
170
+ }
171
+ };
172
+ }
173
+ var ReactNativeSyncSocket = class {
174
+ #socket;
175
+ onopen = null;
176
+ onmessage = null;
177
+ onclose = null;
178
+ onerror = null;
179
+ constructor(socket) {
180
+ this.#socket = socket;
181
+ this.#socket.onopen = () => this.onopen?.();
182
+ this.#socket.onmessage = (event) => this.onmessage?.({ data: event.data });
183
+ this.#socket.onclose = (event) => this.onclose?.({ code: typeof event.code === "number" ? event.code : 1006 });
184
+ this.#socket.onerror = () => this.onerror?.();
185
+ }
186
+ send(data) {
187
+ this.#socket.send(data);
188
+ }
189
+ close(code, reason) {
190
+ this.#socket.close(code, reason);
191
+ }
192
+ };
193
+ var BrowserFallbackSyncSocket = class {
194
+ #socket;
195
+ onopen = null;
196
+ onmessage = null;
197
+ onclose = null;
198
+ onerror = null;
199
+ constructor(socket) {
200
+ this.#socket = socket;
201
+ this.#socket.addEventListener("open", () => this.onopen?.());
202
+ this.#socket.addEventListener("message", (event) => this.onmessage?.({ data: event.data }));
203
+ this.#socket.addEventListener("close", (event) => this.onclose?.({ code: event.code }));
204
+ this.#socket.addEventListener("error", () => this.onerror?.());
205
+ }
206
+ send(data) {
207
+ this.#socket.send(data);
208
+ }
209
+ close(code, reason) {
210
+ this.#socket.close(code, reason);
211
+ }
212
+ };
213
+ function isNetworkOnline(state) {
214
+ return state.isConnected !== false && state.isInternetReachable !== false;
215
+ }
216
+ function unsubscribe(subscription) {
217
+ if (typeof subscription === "function") {
218
+ subscription();
219
+ } else {
220
+ subscription.remove();
221
+ }
222
+ }
223
+
224
+ // src/generated/sync.ts
225
+ import { Schema } from "effect";
226
+ var SyncProtocolMetadata = {
227
+ version: 1,
228
+ protocol: {
229
+ field: "protocol",
230
+ value: 1,
231
+ transport: "websocket-json-text",
232
+ route: "/v1/sync"
233
+ },
234
+ directions: {
235
+ clientToServer: "client-to-server",
236
+ serverToClient: "server-to-client"
237
+ },
238
+ phases: [
239
+ {
240
+ id: "awaiting_hello",
241
+ accepts: ["hello", "ping"],
242
+ hello: {
243
+ transitionsTo: "recovering",
244
+ deadlineMs: 5e3
245
+ }
246
+ },
247
+ {
248
+ id: "recovering",
249
+ accepts: ["recovery_ack", "ping"],
250
+ recoveryComplete: {
251
+ transitionsTo: "live"
252
+ }
253
+ },
254
+ {
255
+ id: "live",
256
+ accepts: ["command", "live_target", "directed_request", "delivery_ack", "request_ack", "reaction_send", "chat_send", "chat_page_request", "chat_read_set", "ping"],
257
+ heartbeat: {
258
+ intervalMs: 2e4,
259
+ missedDeadlinesBeforeClose: 2
260
+ }
261
+ },
262
+ {
263
+ id: "terminal",
264
+ transitionsTo: "closed"
265
+ },
266
+ {
267
+ id: "draining",
268
+ transitionsTo: "closed"
269
+ }
270
+ ],
271
+ streams: {
272
+ control: {
273
+ required: true,
274
+ authority: "postgres",
275
+ version: "revision-and-digest",
276
+ cursor: "controlCursor",
277
+ recovery: ["snapshot", "bounded_exact_replay", "up_to_date", "terminal"]
278
+ },
279
+ media: {
280
+ required: true,
281
+ authority: "media-plane-observation",
282
+ version: "projection-id-and-exact-next-sequence",
283
+ cursor: null,
284
+ recovery: ["replace_latest_snapshot"]
285
+ },
286
+ presence: {
287
+ required: true,
288
+ authority: "sync-live-projection",
289
+ version: "projection-id-and-exact-next-sequence",
290
+ cursor: null,
291
+ recovery: ["replace_latest_snapshot"]
292
+ },
293
+ requests: {
294
+ required: true,
295
+ authority: "directed-live-delivery",
296
+ version: "none",
297
+ cursor: null,
298
+ recovery: ["none"]
299
+ }
300
+ },
301
+ correlation: {
302
+ optionalTopLevelFields: {
303
+ journey_id: {
304
+ kind: "string",
305
+ minBytes: 36,
306
+ maxBytes: 36,
307
+ format: "chalk-journey-id",
308
+ pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
309
+ },
310
+ traceparent: {
311
+ kind: "string",
312
+ minBytes: 55,
313
+ maxBytes: 55,
314
+ format: "w3c-traceparent",
315
+ pattern: "^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$"
316
+ },
317
+ tracestate: {
318
+ kind: "string",
319
+ minBytes: 1,
320
+ maxBytes: 512,
321
+ format: "w3c-tracestate",
322
+ pattern: "^[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256}(,[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256})*$"
323
+ }
324
+ },
325
+ acceptedOn: {
326
+ hello: "client-to-server",
327
+ serverFrames: "server-to-client"
328
+ },
329
+ upgradeHeaders: ["x-chalk-journey-id", "traceparent", "tracestate"],
330
+ rule: "propagate_from_first_observed_layer_to_every_downstream_frame"
331
+ },
332
+ externalIntents: [
333
+ "admit_participant",
334
+ "deny_admission",
335
+ "admission_request_expired",
336
+ "mute_participant",
337
+ "stop_participant_camera",
338
+ "stop_participant_screen_share",
339
+ "remove_participant",
340
+ "start_recording",
341
+ "stop_recording",
342
+ "participant_leave",
343
+ "start_episode",
344
+ "extend_episode",
345
+ "end_episode",
346
+ "tenant_set_deadline",
347
+ "tenant_end_episode",
348
+ "maximum_duration_expired"
349
+ ],
350
+ limits: {
351
+ decodedInboundFrameBytes: 65536,
352
+ correlationReservedBytes: 1160,
353
+ tokenBytes: 8192,
354
+ commandIdMinBytes: 16,
355
+ commandIdMaxBytes: 64,
356
+ requestIdMinBytes: 16,
357
+ requestIdMaxBytes: 64,
358
+ decodedCommandPayloadBytes: 16384,
359
+ encodedLiveEventBytes: 32768,
360
+ replayPageMaxEvents: 128,
361
+ replayPageEncodedBytes: 262144,
362
+ completeReplayMaxEvents: 2048,
363
+ completeReplayEncodedBytes: 2097152,
364
+ snapshotEncodedBytes: 1048576,
365
+ projectionSnapshotEncodedBytes: 1048576,
366
+ projectionMaxItems: 1500,
367
+ directedRequestTtlMs: 3e4,
368
+ directedRequestsPerActorTarget: 4,
369
+ collaborationFrameBytes: 32768,
370
+ collaborationQueueMaxFrames: 256,
371
+ collaborationBurstMax: 8,
372
+ chatMessageUtf8Bytes: 16384,
373
+ chatMessageUnicodeScalars: 4e3,
374
+ chatAttachmentMaxItems: 5,
375
+ chatAttachmentFileNameUtf8Bytes: 255,
376
+ chatAttachmentMaxBytes: 26214400,
377
+ chatPageMaxMessages: 100,
378
+ chatPageEncodedBytes: 131072,
379
+ reactionTtlMs: 5e3,
380
+ reactionRateWindowMs: 1e4,
381
+ reactionRateMax: 10,
382
+ protocolErrorDetailBytes: 1024
383
+ },
384
+ collaboration: {
385
+ extension: "collaboration_v1",
386
+ capabilities: ["sendReaction", "sendChat"],
387
+ reactions: ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F389}"],
388
+ attachmentMimeTypes: [
389
+ "image/png",
390
+ "image/jpeg",
391
+ "image/gif",
392
+ "image/webp",
393
+ "application/pdf",
394
+ "text/plain",
395
+ "application/msword",
396
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
397
+ "application/vnd.ms-excel",
398
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
399
+ "application/vnd.ms-powerpoint",
400
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
401
+ "application/vnd.oasis.opendocument.text",
402
+ "application/vnd.oasis.opendocument.spreadsheet",
403
+ "application/vnd.oasis.opendocument.presentation"
404
+ ],
405
+ chatCursor: {
406
+ exactFields: ["after_sequence", "retained_floor_sequence"],
407
+ afterSequence: "nullableUnsignedDecimal",
408
+ retainedFloorSequence: "nullableUnsignedDecimal"
409
+ },
410
+ helloExtension: {
411
+ exactFields: ["name", "chat_cursor"]
412
+ },
413
+ welcomeExtension: {
414
+ exactFields: ["name", "capabilities", "participant_capabilities", "chat_head_sequence", "retained_floor_sequence", "read_receipts"]
415
+ },
416
+ clientFrames: {
417
+ sendReaction: {
418
+ type: "reaction_send",
419
+ exactFields: ["type", "operation_id", "reaction"]
420
+ },
421
+ sendChat: {
422
+ type: "chat_send",
423
+ exactFields: ["type", "client_message_id", "text", "attachment_ids"]
424
+ },
425
+ readChatPage: {
426
+ type: "chat_page_request",
427
+ exactFields: ["type", "request_id", "direction", "cursor_sequence", "limit"],
428
+ directions: ["older", "newer"]
429
+ },
430
+ setChatRead: {
431
+ type: "chat_read_set",
432
+ exactFields: ["type", "request_id", "sequence"]
433
+ }
434
+ },
435
+ serverFrames: {
436
+ reaction: {
437
+ type: "reaction",
438
+ exactFields: ["type", "event_id", "participant_id", "display_name", "reaction", "occurred_at", "expires_at"]
439
+ },
440
+ reactionResult: {
441
+ type: "reaction_result",
442
+ acceptedFields: ["type", "operation_id", "outcome", "reaction"],
443
+ rejectedFields: ["type", "operation_id", "outcome", "error_code"],
444
+ outcomes: ["accepted", "rejected"]
445
+ },
446
+ chatMessage: {
447
+ type: "chat_message",
448
+ exactFields: ["type", "message_id", "client_message_id", "sequence", "participant_id", "display_name", "text", "attachments", "created_at"]
449
+ },
450
+ chatSendResult: {
451
+ type: "chat_send_result",
452
+ acceptedFields: ["type", "client_message_id", "outcome", "message"],
453
+ rejectedFields: ["type", "client_message_id", "outcome", "error_code"],
454
+ outcomes: ["accepted", "rejected"]
455
+ },
456
+ chatPage: {
457
+ type: "chat_page",
458
+ loadedFields: ["type", "request_id", "outcome", "messages", "has_more", "head_sequence", "retained_floor_sequence"],
459
+ resetFields: ["type", "request_id", "outcome", "retained_floor_sequence"],
460
+ outcomes: ["loaded", "cursor_reset"]
461
+ },
462
+ chatHead: {
463
+ type: "chat_head",
464
+ exactFields: ["type", "head_sequence", "retained_floor_sequence"]
465
+ },
466
+ chatReadReceipt: {
467
+ type: "chat_read_receipt",
468
+ exactFields: ["type", "participant_id", "participant_generation", "sequence", "read_at"]
469
+ },
470
+ chatReadResult: {
471
+ type: "chat_read_result",
472
+ acceptedFields: ["type", "request_id", "outcome", "participant_id", "participant_generation", "sequence", "read_at"],
473
+ rejectedFields: ["type", "request_id", "outcome", "error_code"],
474
+ outcomes: ["accepted", "rejected"]
475
+ }
476
+ },
477
+ errorCodes: ["capability_denied", "invalid_payload", "rate_limited", "overloaded", "episode_ended", "participant_stale", "client_message_id_conflict", "attachment_not_found", "attachment_not_ready", "attachment_already_claimed", "attachment_quota_exceeded", "dependency_unavailable"]
478
+ },
479
+ continuity: {
480
+ cursor: {
481
+ field: "streams.control.cursor",
482
+ resume: "events_after_cursor_when_digest_matches",
483
+ stream: "control"
484
+ },
485
+ events: {
486
+ baseRevisionField: "base_revision",
487
+ revisionField: "revision",
488
+ rule: "revision_equals_base_revision_plus_one",
489
+ stream: "control"
490
+ },
491
+ snapshotFallback: {
492
+ when: ["cursor_missing", "cursor_future", "cursor_malformed", "cursor_expired", "cursor_unavailable", "cursor_same_revision_digest_mismatch"],
493
+ welcomeMode: "snapshot"
494
+ },
495
+ replay: {
496
+ pageAcknowledgement: "recovery_ack",
497
+ pageCompletion: "recovery_complete_after_acknowledged_head",
498
+ liveEventsAfter: "recovery_complete",
499
+ maxEvents: 2048,
500
+ maxEncodedBytes: 2097152
501
+ }
502
+ },
503
+ idempotency: {
504
+ key: "command_id",
505
+ outcomes: ["committed", "satisfied", "rejected"],
506
+ scope: "participant",
507
+ duplicate: "reuses_original_semantic_outcome",
508
+ conflict: "preserves_original_receipt"
509
+ },
510
+ closeCodes: [
511
+ {
512
+ code: 1e3,
513
+ connection: "closed",
514
+ reasons: ["terminal event acknowledged", "terminal recovery drained"]
515
+ },
516
+ {
517
+ code: 1008,
518
+ connection: "closed",
519
+ reasons: ["invalid token", "policy violation"]
520
+ },
521
+ {
522
+ code: 1009,
523
+ connection: "closed",
524
+ reasons: ["malformed frame", "oversized frame"]
525
+ },
526
+ {
527
+ code: 1012,
528
+ connection: "closed",
529
+ reasons: ["service restart", "server draining", "terminal acknowledgement timeout"]
530
+ }
531
+ ]
532
+ };
533
+ var SyncProtocolLimits = SyncProtocolMetadata.limits;
534
+ var SyncCloseCodes = SyncProtocolMetadata.closeCodes;
535
+ var textEncoder = new TextEncoder();
536
+ function encodedSyncFrameBytes(frame) {
537
+ return textEncoder.encode(JSON.stringify(frame)).byteLength;
538
+ }
539
+ function boundedUtf8String(maxBytes, minBytes = 0) {
540
+ return Schema.String.check(
541
+ Schema.makeFilter((value) => {
542
+ const bytes = textEncoder.encode(value).byteLength;
543
+ return bytes >= minBytes && bytes <= maxBytes ? void 0 : { path: [], issue: "must fit the UTF-8 byte bounds" };
544
+ })
545
+ );
546
+ }
547
+ function boundedFrame(maxBytes) {
548
+ return Schema.makeFilter((frame) => encodedSyncFrameBytes(frame) <= maxBytes ? void 0 : { path: [], issue: "must fit the encoded byte limit" });
549
+ }
550
+ function isObject(value) {
551
+ return typeof value === "object" && value !== null && !Array.isArray(value);
552
+ }
553
+ function exactObject(value, keys) {
554
+ return isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
555
+ }
556
+ var syncCorrelationKeys = ["journey_id", "traceparent", "tracestate"];
557
+ function completeSyncCorrelation(value) {
558
+ return isObject(value) && syncCorrelationKeys.every((key) => Object.hasOwn(value, key));
559
+ }
560
+ function boundedServerFrame(maxBytes) {
561
+ return Schema.makeFilter((frame) => {
562
+ const budget = completeSyncCorrelation(frame) ? maxBytes : maxBytes - SyncProtocolLimits.correlationReservedBytes;
563
+ return encodedSyncFrameBytes(frame) <= budget ? void 0 : { path: [], issue: "must fit the encoded byte limit including correlation reserve" };
564
+ });
565
+ }
566
+ var syncJourneyIdPattern = new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", "iu");
567
+ var syncTraceparentPattern = new RegExp("^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$", "u");
568
+ var syncTracestatePattern = new RegExp("^[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256}(,[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256})*$", "u");
569
+ function boundedCorrelationString(value, minBytes, maxBytes) {
570
+ return typeof value === "string" && textEncoder.encode(value).byteLength >= minBytes && textEncoder.encode(value).byteLength <= maxBytes;
571
+ }
572
+ function validSyncCorrelation(value) {
573
+ if (!isObject(value)) return false;
574
+ const journeyId = value.journey_id;
575
+ const traceparent = value.traceparent;
576
+ const tracestate = value.tracestate;
577
+ return (journeyId === void 0 || boundedCorrelationString(journeyId, 36, 36) && syncJourneyIdPattern.test(journeyId) && !/^0{8}-0{4}-0{4}-0{4}-0{12}$/u.test(journeyId)) && (traceparent === void 0 || boundedCorrelationString(traceparent, 55, 55) && syncTraceparentPattern.test(traceparent) && !/^00-0{32}-[0-9a-f]{16}-[0-9a-f]{2}$/u.test(traceparent) && !/^00-[0-9a-f]{32}-0{16}-[0-9a-f]{2}$/u.test(traceparent)) && (tracestate === void 0 || boundedCorrelationString(tracestate, 1, 512) && syncTracestatePattern.test(tracestate));
578
+ }
579
+ function exactObjectWithCorrelation(value, keys) {
580
+ return validSyncCorrelation(value) && isObject(value) && Object.keys(value).length >= keys.length && keys.every((key) => Object.hasOwn(value, key)) && Object.keys(value).every((key) => keys.includes(key) || syncCorrelationKeys.includes(key));
581
+ }
582
+ function serverExactKeys(keys) {
583
+ return Schema.makeFilter((value) => exactObjectWithCorrelation(value, keys) ? void 0 : { path: [], issue: "must not contain unknown or missing fields" });
584
+ }
585
+ function exactKeys(keys) {
586
+ return Schema.makeFilter((value) => exactObject(value, keys) ? void 0 : { path: [], issue: "must not contain unknown or missing fields" });
587
+ }
588
+ function uniqueStrings(value) {
589
+ return Array.isArray(value) && value.every((item) => typeof item === "string") && new Set(value).size === value.length;
590
+ }
591
+ function sameStrings(left, right) {
592
+ return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => value === right[index]);
593
+ }
594
+ function strictCursor(value) {
595
+ return exactObject(value, ["revision", "state_schema_version", "state_digest"]);
596
+ }
597
+ function strictCommand(value) {
598
+ if (!exactObject(value, ["type", "command_id", "name", "payload"]) || !isObject(value.payload)) return false;
599
+ switch (value.name) {
600
+ case "set_hand_raised":
601
+ return exactObject(value.payload, ["raised"]);
602
+ case "set_display_name":
603
+ return exactObject(value.payload, ["display_name"]);
604
+ case "set_admission_policy":
605
+ return exactObject(value.payload, ["policy"]);
606
+ case "assign_roles":
607
+ return exactObject(value.payload, ["participant_id", "role"]);
608
+ default:
609
+ return false;
610
+ }
611
+ }
612
+ function strictCollaborationsHelloExtension(value) {
613
+ return exactObject(value, ["name", "chat_cursor"]) && value.name === "collaboration_v1" && exactObject(value.chat_cursor, ["after_sequence", "retained_floor_sequence"]);
614
+ }
615
+ function strictHello(value) {
616
+ const base = exactObjectWithCorrelation(value, ["type", "protocol", "token", "streams"]);
617
+ const extended = exactObjectWithCorrelation(value, ["type", "protocol", "token", "streams", "extensions"]) && Array.isArray(value.extensions) && value.extensions.length === 1 && strictCollaborationsHelloExtension(value.extensions[0]);
618
+ if (!base && !extended || !exactObject(value.streams, ["control", "media", "presence", "requests"])) return false;
619
+ const streams = value.streams;
620
+ return exactObject(streams.control, ["cursor"]) && (streams.control.cursor === null || strictCursor(streams.control.cursor)) && exactObject(streams.media, ["cursor"]) && streams.media.cursor === null && exactObject(streams.presence, ["cursor"]) && streams.presence.cursor === null && exactObject(streams.requests, ["cursor"]) && streams.requests.cursor === null;
621
+ }
622
+ function strictChatMessage(value) {
623
+ return exactObjectWithCorrelation(value, ["type", "message_id", "client_message_id", "sequence", "participant_id", "display_name", "text", "attachments", "created_at"]) && Array.isArray(value.attachments) && value.attachments.every(strictChatAttachment);
624
+ }
625
+ function strictChatAttachment(value) {
626
+ return exactObject(value, ["attachment_id", "file_name", "mime_type", "byte_length"]);
627
+ }
628
+ function strictReaction(value) {
629
+ return exactObjectWithCorrelation(value, ["type", "event_id", "participant_id", "display_name", "reaction", "occurred_at", "expires_at"]);
630
+ }
631
+ function strictOperation(value) {
632
+ if (!exactObject(value, ["type", "command_id", "name", "payload"]) || !isObject(value.payload)) return false;
633
+ switch (value.name) {
634
+ case "admit_participant":
635
+ return exactObject(value.payload, ["admission_request_id"]);
636
+ case "deny_admission":
637
+ return exactObject(value.payload, ["admission_request_id"]);
638
+ case "mute_participant":
639
+ return exactObject(value.payload, ["participant_id"]);
640
+ case "stop_participant_camera":
641
+ return exactObject(value.payload, ["participant_id"]);
642
+ case "stop_participant_screen_share":
643
+ return exactObject(value.payload, ["participant_id"]);
644
+ case "remove_participant":
645
+ return exactObject(value.payload, ["participant_id"]);
646
+ case "start_recording":
647
+ return exactObject(value.payload, ["recording_id"]);
648
+ case "stop_recording":
649
+ return exactObject(value.payload, ["recording_id"]);
650
+ case "participant_leave":
651
+ return exactObject(value.payload, []);
652
+ case "start_episode":
653
+ return exactObject(value.payload, []);
654
+ case "extend_episode":
655
+ return exactObject(value.payload, ["extension_seconds"]);
656
+ case "end_episode":
657
+ return exactObject(value.payload, []);
658
+ default:
659
+ return false;
660
+ }
661
+ }
662
+ function strictClientFrame(value) {
663
+ if (!isObject(value)) return false;
664
+ switch (value.type) {
665
+ case "hello":
666
+ return strictHello(value);
667
+ case "command":
668
+ return strictCommand(value);
669
+ case "operation":
670
+ return strictOperation(value);
671
+ case "live_target":
672
+ return exactObject(value, ["type", "operation_id", "name", "enabled"]);
673
+ case "directed_request":
674
+ return exactObject(value, ["type", "request_id", "name", "target_participant_id"]);
675
+ case "request_ack":
676
+ return exactObject(value, ["type", "request_id"]);
677
+ case "reaction_send":
678
+ return exactObject(value, ["type", "operation_id", "reaction"]);
679
+ case "chat_send":
680
+ return exactObject(value, ["type", "client_message_id", "text", "attachment_ids"]);
681
+ case "chat_page_request":
682
+ return exactObject(value, ["type", "request_id", "direction", "cursor_sequence", "limit"]);
683
+ case "chat_read_set":
684
+ return exactObject(value, ["type", "request_id", "sequence"]);
685
+ case "delivery_ack":
686
+ return exactObject(value, ["type", "stream", "revision", "state_digest"]);
687
+ case "recovery_ack":
688
+ return exactObject(value, ["type", "recovery_id", "revision", "state_digest"]);
689
+ case "ping":
690
+ return exactObject(value, ["type"]);
691
+ default:
692
+ return false;
693
+ }
694
+ }
695
+ function strictSnapshot(value) {
696
+ if (!exactObject(value, ["control_revision", "state_schema_version", "state_digest", "status", "admission_policy", "deadline_at_ms", "deadline_generation", "role_capabilities", "recording", "participants", "admission_requests"]) || !isObject(value.role_capabilities) || value.recording !== null && !exactObject(value.recording, ["recording_id", "status", "failure_code"]) || !Array.isArray(value.participants) || !value.participants.every((participant) => exactObject(participant, ["participant_id", "display_name", "hand_raised", "admission_revision", "role", "capabilities"])) || !Array.isArray(value.admission_requests) || !value.admission_requests.every((request) => exactObject(request, ["admission_request_id", "participant_id", "display_name", "role", "expires_at_ms"])))
697
+ return false;
698
+ const roleCapabilities = value.role_capabilities;
699
+ if (!isObject(roleCapabilities) || Object.keys(roleCapabilities).length === 0 || !Object.values(roleCapabilities).every((capabilities) => Array.isArray(capabilities) && uniqueStrings(capabilities) && capabilities.length <= 23)) return false;
700
+ if (value.recording !== null && value.recording.status === "failed" !== (value.recording.failure_code !== null)) return false;
701
+ const participantIds = /* @__PURE__ */ new Set();
702
+ for (const participant of value.participants) {
703
+ if (typeof participant.role !== "string" || participantIds.has(participant.participant_id) || !sameStrings(participant.capabilities, roleCapabilities[participant.role])) return false;
704
+ participantIds.add(participant.participant_id);
705
+ }
706
+ const requestIds = /* @__PURE__ */ new Set();
707
+ const candidateIds = /* @__PURE__ */ new Set();
708
+ for (const request of value.admission_requests) {
709
+ if (typeof request.role !== "string" || !Object.prototype.hasOwnProperty.call(roleCapabilities, request.role) || requestIds.has(request.admission_request_id) || candidateIds.has(request.participant_id) || participantIds.has(request.participant_id)) return false;
710
+ requestIds.add(request.admission_request_id);
711
+ candidateIds.add(request.participant_id);
712
+ }
713
+ if (value.status === "ended") return value.participants.length === 0 && value.admission_requests.length === 0 && value.recording === null;
714
+ return true;
715
+ }
716
+ function strictEvent(value) {
717
+ if (!isObject(value.payload)) return false;
718
+ const common = ["type", "stream", "name", "event_id", "base_revision", "revision", "schema_version", "resulting_state_digest", "payload"];
719
+ switch (value.name) {
720
+ case "participant_joined":
721
+ return exactObject(value.payload, ["participant_id", "display_name", "role", "admission_revision"]) && exactObjectWithCorrelation(value, [...common, "lifecycle_intent_id"]);
722
+ case "participant_left":
723
+ return exactObject(value.payload, ["participant_id", "reason"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
724
+ case "episode_started":
725
+ return exactObject(value.payload, ["episode_id"]) && exactObjectWithCorrelation(value, [...common, "lifecycle_intent_id"]);
726
+ case "episode_ended":
727
+ return exactObject(value.payload, ["reason"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
728
+ case "hand_raised":
729
+ return exactObject(value.payload, ["participant_id"]) && exactObjectWithCorrelation(value, [...common, "command_id"]);
730
+ case "hand_lowered":
731
+ return exactObject(value.payload, ["participant_id"]) && exactObjectWithCorrelation(value, [...common, "command_id"]);
732
+ case "participant_display_name_changed":
733
+ return exactObject(value.payload, ["participant_id", "display_name"]) && exactObjectWithCorrelation(value, [...common, "command_id"]);
734
+ case "admission_policy_changed":
735
+ return exactObject(value.payload, ["policy"]) && exactObjectWithCorrelation(value, [...common, "command_id"]);
736
+ case "role_assigned":
737
+ return exactObject(value.payload, ["participant_id", "role"]) && exactObjectWithCorrelation(value, [...common, "command_id"]);
738
+ case "deadline_changed":
739
+ return exactObject(value.payload, ["deadline_at_ms", "deadline_generation"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
740
+ case "admission_requested":
741
+ return exactObject(value.payload, ["admission_request_id", "participant_id", "display_name", "role", "expires_at_ms"]) && exactObjectWithCorrelation(value, [...common, "lifecycle_intent_id"]);
742
+ case "admission_denied":
743
+ return exactObject(value.payload, ["admission_request_id"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
744
+ case "admission_expired":
745
+ return exactObject(value.payload, ["admission_request_id"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
746
+ case "participant_microphone_stopped":
747
+ return exactObject(value.payload, ["participant_id"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
748
+ case "participant_camera_stopped":
749
+ return exactObject(value.payload, ["participant_id"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
750
+ case "participant_screen_share_stopped":
751
+ return exactObject(value.payload, ["participant_id"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
752
+ case "recording_status_changed":
753
+ return exactObject(value.payload, ["recording_id", "status", "failure_code"]) && exactObjectWithCorrelation(value, [...common, "external_operation_id"]);
754
+ default:
755
+ return false;
756
+ }
757
+ }
758
+ function strictProjectionItem(value, stream) {
759
+ if (stream === "media") return exactObject(value, ["participant_id", "source", "enabled", "publication_id"]);
760
+ if (stream === "presence") return exactObject(value, ["participant_id", "state", "speaking", "active_speaker"]);
761
+ return false;
762
+ }
763
+ function strictProjection(value) {
764
+ if (value.type === "projection_snapshot") return exactObjectWithCorrelation(value, ["type", "stream", "projection_id", "sequence", "items"]) && Array.isArray(value.items) && value.items.every((item) => strictProjectionItem(item, value.stream));
765
+ return exactObjectWithCorrelation(value, ["type", "stream", "projection_id", "sequence", "item"]) && strictProjectionItem(value.item, value.stream);
766
+ }
767
+ function strictWelcome(value) {
768
+ const base = ["type", "protocol", "participant_id", "participant_generation", "recovery_id", "head", "mode"];
769
+ const extension = Array.isArray(value.extensions) && value.extensions.length === 1 ? value.extensions[0] : void 0;
770
+ const extensionValid = isObject(extension) && extension.name === "collaboration_v1" && exactObject(extension, ["name", "capabilities", "participant_capabilities", "chat_head_sequence", "retained_floor_sequence", "read_receipts"]) && Array.isArray(extension.read_receipts);
771
+ const fields = extensionValid ? [...base, "extensions"] : base;
772
+ if (!strictCursor(value.head)) return false;
773
+ if (value.mode === "snapshot") return exactObjectWithCorrelation(value, [...fields, "snapshot"]) && strictSnapshot(value.snapshot);
774
+ if (value.mode === "terminal") return exactObjectWithCorrelation(value, [...fields, "reason"]);
775
+ return (value.mode === "replay" || value.mode === "up_to_date") && exactObjectWithCorrelation(value, fields);
776
+ }
777
+ function serverFrameWithinLimit(value) {
778
+ if (!isObject(value)) return false;
779
+ const limit = value.type === "welcome" && value.mode === "snapshot" ? SyncProtocolLimits.snapshotEncodedBytes : value.type === "replay_page" ? SyncProtocolLimits.replayPageEncodedBytes : value.type === "event" ? SyncProtocolLimits.encodedLiveEventBytes : value.type === "projection_snapshot" ? SyncProtocolLimits.projectionSnapshotEncodedBytes : value.type === "projection_event" ? SyncProtocolLimits.encodedLiveEventBytes : value.type === "reaction" ? SyncProtocolLimits.collaborationFrameBytes : value.type === "chat_message" ? SyncProtocolLimits.collaborationFrameBytes : value.type === "chat_page" && value.outcome === "loaded" ? SyncProtocolLimits.chatPageEncodedBytes : void 0;
780
+ if (limit === void 0) return true;
781
+ const budget = completeSyncCorrelation(value) ? limit : limit - SyncProtocolLimits.correlationReservedBytes;
782
+ return encodedSyncFrameBytes(value) <= budget;
783
+ }
784
+ function strictServerFrame(value) {
785
+ if (!isObject(value) || !validSyncCorrelation(value)) return false;
786
+ switch (value.type) {
787
+ case "welcome":
788
+ return strictWelcome(value);
789
+ case "replay_page":
790
+ return exactObjectWithCorrelation(value, ["type", "recovery_id", "first_revision", "last_revision", "events"]) && Array.isArray(value.events) && value.events.every((event) => isObject(event) && strictEvent(event));
791
+ case "recovery_complete":
792
+ return exactObjectWithCorrelation(value, ["type", "recovery_id", "head"]) && strictCursor(value.head);
793
+ case "event":
794
+ return strictEvent(value);
795
+ case "ack":
796
+ return value.outcome === "committed" ? exactObjectWithCorrelation(value, ["type", "command_id", "delivery", "outcome", "event_id", "revision", "state_digest"]) : value.outcome === "satisfied" ? exactObjectWithCorrelation(value, ["type", "command_id", "delivery", "outcome", "revision", "state_digest"]) : value.outcome === "rejected" ? exactObjectWithCorrelation(value, ["type", "command_id", "delivery", "outcome", "reason"]) : value.outcome === "command_id_conflict" && exactObjectWithCorrelation(value, ["type", "command_id", "delivery", "outcome", "reason"]);
797
+ case "projection_snapshot":
798
+ case "projection_event":
799
+ return strictProjection(value);
800
+ case "live_target_result":
801
+ return exactObjectWithCorrelation(value, ["type", "operation_id", "name", "outcome", "error_code"]);
802
+ case "directed_request":
803
+ return exactObjectWithCorrelation(value, ["type", "request_id", "name", "actor_participant_id", "expires_at_ms"]);
804
+ case "directed_request_result":
805
+ return exactObjectWithCorrelation(value, ["type", "request_id", "result"]);
806
+ case "reaction":
807
+ return strictReaction(value);
808
+ case "reaction_result":
809
+ return value.outcome === "accepted" ? exactObjectWithCorrelation(value, ["type", "operation_id", "outcome", "reaction"]) && strictReaction(value.reaction) : value.outcome === "rejected" && exactObjectWithCorrelation(value, ["type", "operation_id", "outcome", "error_code"]);
810
+ case "chat_message":
811
+ return strictChatMessage(value);
812
+ case "chat_send_result":
813
+ return value.outcome === "accepted" ? exactObjectWithCorrelation(value, ["type", "client_message_id", "outcome", "message"]) && strictChatMessage(value.message) : value.outcome === "rejected" && exactObjectWithCorrelation(value, ["type", "client_message_id", "outcome", "error_code"]);
814
+ case "chat_page":
815
+ return value.outcome === "loaded" ? exactObjectWithCorrelation(value, ["type", "request_id", "outcome", "messages", "has_more", "head_sequence", "retained_floor_sequence"]) && Array.isArray(value.messages) && value.messages.every(strictChatMessage) : value.outcome === "cursor_reset" && exactObjectWithCorrelation(value, ["type", "request_id", "outcome", "retained_floor_sequence"]);
816
+ case "chat_head":
817
+ return exactObjectWithCorrelation(value, ["type", "head_sequence", "retained_floor_sequence"]);
818
+ case "chat_read_receipt":
819
+ return exactObjectWithCorrelation(value, ["type", "participant_id", "participant_generation", "sequence", "read_at"]);
820
+ case "chat_read_result":
821
+ return value.outcome === "accepted" ? exactObjectWithCorrelation(value, ["type", "request_id", "outcome", "participant_id", "participant_generation", "sequence", "read_at"]) : value.outcome === "rejected" && exactObjectWithCorrelation(value, ["type", "request_id", "outcome", "error_code"]);
822
+ case "retryable_error":
823
+ return exactObjectWithCorrelation(value, ["type", "command_id", "code"]);
824
+ case "error":
825
+ return exactObjectWithCorrelation(value, ["type", "code", "detail"]);
826
+ case "pong":
827
+ return exactObjectWithCorrelation(value, ["type"]);
828
+ default:
829
+ return false;
830
+ }
831
+ }
832
+ var NonNegativeIntegerSchema = Schema.Number.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0));
833
+ var PositiveIntegerSchema = Schema.Number.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(1));
834
+ var UuidSchema = Schema.String.check(Schema.makeFilter((value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value) ? void 0 : { path: [], issue: "must be an RFC 4122 UUID" }));
835
+ var JourneyIdSchema = UuidSchema.check(Schema.makeFilter((value) => !/^0{8}-0{4}-0{4}-0{4}-0{12}$/u.test(value) ? void 0 : { path: [], issue: "must be a non-zero Chalk journey UUID" }));
836
+ var TraceparentSchema = boundedUtf8String(55, 55).check(
837
+ Schema.makeFilter((value) => /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/u.test(value) && !/^00-0{32}-[0-9a-f]{16}-[0-9a-f]{2}$/u.test(value) && !/^00-[0-9a-f]{32}-0{16}-[0-9a-f]{2}$/u.test(value) ? void 0 : { path: [], issue: "must be a valid non-zero W3C traceparent" })
838
+ );
839
+ var TracestateSchema = boundedUtf8String(512, 1).check(
840
+ Schema.makeFilter((value) => new RegExp("^[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256}(,[a-z][a-z0-9_*\\-/]{0,255}=[\\x21-\\x2b\\x2d-\\x3c\\x3e-\\x7e]{1,256})*$", "u").test(value) ? void 0 : { path: [], issue: "must be a valid bounded W3C tracestate" })
841
+ );
842
+ var SyncCorrelationFieldsSchema = Schema.Struct({ journey_id: Schema.optional(JourneyIdSchema), traceparent: Schema.optional(TraceparentSchema), tracestate: Schema.optional(TracestateSchema) });
843
+ var HelloCorrelationFields = { journey_id: Schema.optional(JourneyIdSchema), traceparent: Schema.optional(TraceparentSchema), tracestate: Schema.optional(TracestateSchema) };
844
+ var ServerCorrelationFields = { ...HelloCorrelationFields };
845
+ var StateDigestSchema = Schema.String.check(Schema.makeFilter((value) => /^[0-9a-f]{64}$/u.test(value) ? void 0 : { path: [], issue: "must be a lowercase hexadecimal SHA-256 digest" }));
846
+ var UnsignedDecimalSchema = Schema.String.check(Schema.makeFilter((value) => /^(?:0|[1-9][0-9]*)$/u.test(value) ? void 0 : { path: [], issue: "must be an unsigned decimal integer" }));
847
+ var CommandIdSchema = boundedUtf8String(64).check(Schema.makeFilter((value) => textEncoder.encode(value).byteLength >= 16 ? void 0 : { path: [], issue: "must meet the command ID minimum byte length" }));
848
+ var RequestIdSchema = boundedUtf8String(64).check(Schema.makeFilter((value) => textEncoder.encode(value).byteLength >= 16 ? void 0 : { path: [], issue: "must meet the request ID minimum byte length" }));
849
+ var ControlCursorSchema = Schema.Struct({ revision: NonNegativeIntegerSchema, state_schema_version: PositiveIntegerSchema, state_digest: StateDigestSchema }).check(exactKeys(["revision", "state_schema_version", "state_digest"]));
850
+ var CapabilitySchema = Schema.Union([
851
+ Schema.Literal("publishAudio"),
852
+ Schema.Literal("publishVideo"),
853
+ Schema.Literal("publishScreen"),
854
+ Schema.Literal("subscribe"),
855
+ Schema.Literal("raiseHand"),
856
+ Schema.Literal("renameSelf"),
857
+ Schema.Literal("sendChat"),
858
+ Schema.Literal("sendReaction"),
859
+ Schema.Literal("drawWhiteboard"),
860
+ Schema.Literal("manageWhiteboard"),
861
+ Schema.Literal("manageAdmission"),
862
+ Schema.Literal("assignRoles"),
863
+ Schema.Literal("muteOthers"),
864
+ Schema.Literal("stopVideoOthers"),
865
+ Schema.Literal("stopScreenOthers"),
866
+ Schema.Literal("requestMediaOthers"),
867
+ Schema.Literal("removeParticipant"),
868
+ Schema.Literal("manageRecording"),
869
+ Schema.Literal("startEpisode"),
870
+ Schema.Literal("extendEpisode"),
871
+ Schema.Literal("endEpisode"),
872
+ Schema.Literal("manageMembers"),
873
+ Schema.Literal("clearSpaceContent")
874
+ ]);
875
+ var RoleSchema = boundedUtf8String(64, 1).check(Schema.makeFilter((value) => value === value.trim() ? void 0 : { path: [], issue: "role names must not have surrounding whitespace" }));
876
+ var TerminalRecoveryReasonSchema = Schema.Union([Schema.Literal("episode_ended"), Schema.Literal("participant_inactive"), Schema.Literal("stale_participant_generation")]);
877
+ var RejectionReasonSchema = Schema.Union([
878
+ Schema.Literal("episode_ended"),
879
+ Schema.Literal("participant_inactive"),
880
+ Schema.Literal("stale_participant_generation"),
881
+ Schema.Literal("capability_denied"),
882
+ Schema.Literal("invalid_state"),
883
+ Schema.Literal("invalid_target"),
884
+ Schema.Literal("role_not_eligible"),
885
+ Schema.Literal("screen_share_in_use"),
886
+ Schema.Literal("recording_in_progress"),
887
+ Schema.Literal("command_id_conflict"),
888
+ Schema.Literal("external_operation_failed")
889
+ ]);
890
+ var RetryableErrorCodeSchema = Schema.Union([Schema.Literal("overloaded"), Schema.Literal("server_draining"), Schema.Literal("dependency_unavailable"), Schema.Literal("decision_unavailable"), Schema.Literal("external_operation_pending")]);
891
+ var ProtocolErrorCodeSchema = Schema.Union([Schema.Literal("protocol_error"), Schema.Literal("invalid_frame"), Schema.Literal("unsupported_protocol")]);
892
+ var ParticipantSchema = Schema.Struct({
893
+ participant_id: UuidSchema,
894
+ display_name: boundedUtf8String(256, 1),
895
+ hand_raised: Schema.Boolean,
896
+ admission_revision: PositiveIntegerSchema,
897
+ role: RoleSchema,
898
+ capabilities: Schema.Array(CapabilitySchema).check(
899
+ Schema.isMaxLength(23),
900
+ Schema.makeFilter((capabilities) => uniqueStrings(capabilities) ? void 0 : { path: [], issue: "must contain unique capabilities" })
901
+ )
902
+ }).check(exactKeys(["participant_id", "display_name", "hand_raised", "admission_revision", "role", "capabilities"]));
903
+ var AdmissionRequestSchema = Schema.Struct({ admission_request_id: UuidSchema, participant_id: UuidSchema, display_name: boundedUtf8String(256, 1), role: RoleSchema, expires_at_ms: PositiveIntegerSchema }).check(
904
+ exactKeys(["admission_request_id", "participant_id", "display_name", "role", "expires_at_ms"])
905
+ );
906
+ var UniqueCapabilityArraySchema = Schema.Array(CapabilitySchema).check(
907
+ Schema.isMaxLength(23),
908
+ Schema.makeFilter((capabilities) => uniqueStrings(capabilities) ? void 0 : { path: [], issue: "must contain unique capabilities" })
909
+ );
910
+ var RoleCapabilitiesSchema = Schema.Record(RoleSchema, UniqueCapabilityArraySchema);
911
+ var RecordingSchema = Schema.Struct({ recording_id: UuidSchema, status: Schema.Union([Schema.Literal("starting"), Schema.Literal("recording"), Schema.Literal("stopping"), Schema.Literal("stopped"), Schema.Literal("failed")]), failure_code: Schema.NullOr(boundedUtf8String(96, 1)) }).check(
912
+ exactKeys(["recording_id", "status", "failure_code"]),
913
+ Schema.makeFilter((recording) => recording.status === "failed" === (recording.failure_code !== null) ? void 0 : { path: ["failure_code"], issue: "must be non-null exactly when recording status is failed" })
914
+ );
915
+ var SnapshotSchema = Schema.Struct({
916
+ control_revision: NonNegativeIntegerSchema,
917
+ state_schema_version: PositiveIntegerSchema,
918
+ state_digest: StateDigestSchema,
919
+ status: Schema.Union([Schema.Literal("active"), Schema.Literal("ended")]),
920
+ admission_policy: Schema.Union([Schema.Literal("open"), Schema.Literal("knock"), Schema.Literal("members_only")]),
921
+ deadline_at_ms: PositiveIntegerSchema,
922
+ deadline_generation: PositiveIntegerSchema,
923
+ role_capabilities: RoleCapabilitiesSchema,
924
+ recording: Schema.NullOr(RecordingSchema),
925
+ participants: Schema.Array(ParticipantSchema).check(Schema.isMaxLength(500)),
926
+ admission_requests: Schema.Array(AdmissionRequestSchema).check(Schema.isMaxLength(500))
927
+ }).check(
928
+ Schema.makeFilter((snapshot) => strictSnapshot(snapshot) ? void 0 : { path: [], issue: "must satisfy durable control snapshot invariants" }),
929
+ boundedFrame(1048576)
930
+ );
931
+ var NullCursorStreamSchema = Schema.Struct({ cursor: Schema.Null }).check(exactKeys(["cursor"]));
932
+ var StreamsSchema = Schema.Struct({ control: Schema.Struct({ cursor: Schema.NullOr(ControlCursorSchema) }).check(exactKeys(["cursor"])), media: NullCursorStreamSchema, presence: NullCursorStreamSchema, requests: NullCursorStreamSchema });
933
+ var HelloFrameSchema = Schema.Struct({ type: Schema.Literal("hello"), protocol: Schema.Literal(1), token: boundedUtf8String(8192), streams: StreamsSchema, ...HelloCorrelationFields }).check(boundedFrame(65536));
934
+ var ChatCursorSchema = Schema.Struct({ after_sequence: Schema.NullOr(UnsignedDecimalSchema), retained_floor_sequence: Schema.NullOr(UnsignedDecimalSchema) }).check(exactKeys(["after_sequence", "retained_floor_sequence"]));
935
+ var CollaborationHelloExtensionSchema = Schema.Struct({ name: Schema.Literal("collaboration_v1"), chat_cursor: ChatCursorSchema }).check(exactKeys(["name", "chat_cursor"]));
936
+ var ExtendedHelloFrameSchema = Schema.Struct({ type: Schema.Literal("hello"), protocol: Schema.Literal(1), token: boundedUtf8String(8192), streams: StreamsSchema, extensions: Schema.Tuple([CollaborationHelloExtensionSchema]), ...HelloCorrelationFields }).check(boundedFrame(65536));
937
+ var DeliveryAckFrameSchema = Schema.Struct({ type: Schema.Literal("delivery_ack"), stream: Schema.Literal("control"), revision: PositiveIntegerSchema, state_digest: StateDigestSchema });
938
+ var RecoveryAckFrameSchema = Schema.Struct({ type: Schema.Literal("recovery_ack"), recovery_id: UuidSchema, revision: NonNegativeIntegerSchema, state_digest: StateDigestSchema });
939
+ var SetHandRaisedCommandFrameSchema = Schema.Struct({ type: Schema.Literal("command"), command_id: CommandIdSchema, name: Schema.Literal("set_hand_raised"), payload: Schema.Struct({ raised: Schema.Boolean }) }).check(boundedFrame(65536));
940
+ var SetDisplayNameCommandFrameSchema = Schema.Struct({
941
+ type: Schema.Literal("command"),
942
+ command_id: CommandIdSchema,
943
+ name: Schema.Literal("set_display_name"),
944
+ payload: Schema.Struct({ display_name: boundedUtf8String(256, 1).check(Schema.makeFilter((value) => value.length > 0 && value === value.trim() ? void 0 : { path: [], issue: "must be non-empty without surrounding whitespace" })) })
945
+ }).check(boundedFrame(65536));
946
+ var SetAdmissionPolicyCommandFrameSchema = Schema.Struct({
947
+ type: Schema.Literal("command"),
948
+ command_id: CommandIdSchema,
949
+ name: Schema.Literal("set_admission_policy"),
950
+ payload: Schema.Struct({ policy: Schema.Union([Schema.Literal("open"), Schema.Literal("knock"), Schema.Literal("members_only")]) })
951
+ }).check(boundedFrame(65536));
952
+ var AssignRolesCommandFrameSchema = Schema.Struct({
953
+ type: Schema.Literal("command"),
954
+ command_id: CommandIdSchema,
955
+ name: Schema.Literal("assign_roles"),
956
+ payload: Schema.Struct({ participant_id: UuidSchema, role: boundedUtf8String(64, 1).check(Schema.makeFilter((value) => value.length > 0 && value === value.trim() ? void 0 : { path: [], issue: "must be non-empty without surrounding whitespace" })) })
957
+ }).check(boundedFrame(65536));
958
+ var AdmitParticipantOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("admit_participant"), payload: Schema.Struct({ admission_request_id: UuidSchema }) }).check(boundedFrame(65536));
959
+ var DenyAdmissionOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("deny_admission"), payload: Schema.Struct({ admission_request_id: UuidSchema }) }).check(boundedFrame(65536));
960
+ var MuteParticipantOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("mute_participant"), payload: Schema.Struct({ participant_id: UuidSchema }) }).check(boundedFrame(65536));
961
+ var StopParticipantCameraOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("stop_participant_camera"), payload: Schema.Struct({ participant_id: UuidSchema }) }).check(boundedFrame(65536));
962
+ var StopParticipantScreenShareOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("stop_participant_screen_share"), payload: Schema.Struct({ participant_id: UuidSchema }) }).check(boundedFrame(65536));
963
+ var RemoveParticipantOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("remove_participant"), payload: Schema.Struct({ participant_id: UuidSchema }) }).check(boundedFrame(65536));
964
+ var StartRecordingOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("start_recording"), payload: Schema.Struct({ recording_id: UuidSchema }) }).check(boundedFrame(65536));
965
+ var StopRecordingOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("stop_recording"), payload: Schema.Struct({ recording_id: UuidSchema }) }).check(boundedFrame(65536));
966
+ var ParticipantLeaveOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("participant_leave"), payload: Schema.Struct({}) }).check(boundedFrame(65536));
967
+ var StartEpisodeOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("start_episode"), payload: Schema.Struct({}) }).check(boundedFrame(65536));
968
+ var ExtendEpisodeOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("extend_episode"), payload: Schema.Struct({ extension_seconds: PositiveIntegerSchema }) }).check(boundedFrame(65536));
969
+ var EndEpisodeOperationFrameSchema = Schema.Struct({ type: Schema.Literal("operation"), command_id: CommandIdSchema, name: Schema.Literal("end_episode"), payload: Schema.Struct({}) }).check(boundedFrame(65536));
970
+ var LiveTargetNameSchema = Schema.Union([Schema.Literal("set_microphone_enabled"), Schema.Literal("set_camera_enabled"), Schema.Literal("set_screen_share_enabled")]);
971
+ var LiveTargetFrameSchema = Schema.Struct({ type: Schema.Literal("live_target"), operation_id: RequestIdSchema, name: LiveTargetNameSchema, enabled: Schema.Boolean });
972
+ var DirectedRequestNameSchema = Schema.Union([Schema.Literal("request_unmute"), Schema.Literal("request_start_camera")]);
973
+ var DirectedRequestSendFrameSchema = Schema.Struct({ type: Schema.Literal("directed_request"), request_id: RequestIdSchema, name: DirectedRequestNameSchema, target_participant_id: UuidSchema });
974
+ var RequestAckFrameSchema = Schema.Struct({ type: Schema.Literal("request_ack"), request_id: RequestIdSchema });
975
+ var ReactionSchema = Schema.Union([Schema.Literal("\u{1F44D}"), Schema.Literal("\u2764\uFE0F"), Schema.Literal("\u{1F602}"), Schema.Literal("\u{1F62E}"), Schema.Literal("\u{1F622}"), Schema.Literal("\u{1F389}")]);
976
+ var ReactionSendFrameSchema = Schema.Struct({ type: Schema.Literal("reaction_send"), operation_id: RequestIdSchema, reaction: ReactionSchema }).check(boundedFrame(SyncProtocolLimits.collaborationFrameBytes));
977
+ var ChatTextSchema = boundedUtf8String(16384).check(Schema.makeFilter((value) => Array.from(value).length <= 4e3 ? void 0 : { path: ["text"], issue: "must fit the Unicode scalar limit" }));
978
+ var ChatAttachmentMimeTypeSchema = Schema.Union([
979
+ Schema.Literal("image/png"),
980
+ Schema.Literal("image/jpeg"),
981
+ Schema.Literal("image/gif"),
982
+ Schema.Literal("image/webp"),
983
+ Schema.Literal("application/pdf"),
984
+ Schema.Literal("text/plain"),
985
+ Schema.Literal("application/msword"),
986
+ Schema.Literal("application/vnd.openxmlformats-officedocument.wordprocessingml.document"),
987
+ Schema.Literal("application/vnd.ms-excel"),
988
+ Schema.Literal("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
989
+ Schema.Literal("application/vnd.ms-powerpoint"),
990
+ Schema.Literal("application/vnd.openxmlformats-officedocument.presentationml.presentation"),
991
+ Schema.Literal("application/vnd.oasis.opendocument.text"),
992
+ Schema.Literal("application/vnd.oasis.opendocument.spreadsheet"),
993
+ Schema.Literal("application/vnd.oasis.opendocument.presentation")
994
+ ]);
995
+ var ChatAttachmentIdSchema = Schema.Array(UuidSchema).check(
996
+ Schema.isMaxLength(SyncProtocolLimits.chatAttachmentMaxItems),
997
+ Schema.makeFilter((ids) => uniqueStrings(ids) ? void 0 : { path: ["attachment_ids"], issue: "must contain unique attachment IDs" })
998
+ );
999
+ var ChatSendFrameSchema = Schema.Struct({ type: Schema.Literal("chat_send"), client_message_id: RequestIdSchema, text: ChatTextSchema, attachment_ids: ChatAttachmentIdSchema }).check(
1000
+ Schema.makeFilter((frame) => frame.text.length > 0 || frame.attachment_ids.length > 0 ? void 0 : { path: [], issue: "must contain text or at least one attachment" }),
1001
+ boundedFrame(SyncProtocolLimits.collaborationFrameBytes)
1002
+ );
1003
+ var ChatReadSetFrameSchema = Schema.Struct({ type: Schema.Literal("chat_read_set"), request_id: RequestIdSchema, sequence: UnsignedDecimalSchema }).check(boundedFrame(SyncProtocolLimits.collaborationFrameBytes));
1004
+ var ChatPageDirectionSchema = Schema.Union([Schema.Literal("older"), Schema.Literal("newer")]);
1005
+ var ChatPageRequestFrameSchema = Schema.Struct({ type: Schema.Literal("chat_page_request"), request_id: RequestIdSchema, direction: ChatPageDirectionSchema, cursor_sequence: Schema.NullOr(UnsignedDecimalSchema), limit: PositiveIntegerSchema }).check(
1006
+ Schema.makeFilter((frame) => frame.limit <= SyncProtocolLimits.chatPageMaxMessages ? void 0 : { path: ["limit"], issue: "must fit the chat page limit" }),
1007
+ boundedFrame(SyncProtocolLimits.collaborationFrameBytes)
1008
+ );
1009
+ var ParticipantJoinedLifecycleIntentIdEventVariantSchema = Schema.Struct({
1010
+ type: Schema.Literal("event"),
1011
+ stream: Schema.Literal("control"),
1012
+ name: Schema.Literal("participant_joined"),
1013
+ event_id: UuidSchema,
1014
+ base_revision: NonNegativeIntegerSchema,
1015
+ revision: PositiveIntegerSchema,
1016
+ schema_version: PositiveIntegerSchema,
1017
+ resulting_state_digest: StateDigestSchema,
1018
+ payload: Schema.Struct({
1019
+ participant_id: UuidSchema,
1020
+ display_name: boundedUtf8String(256, 1),
1021
+ role: boundedUtf8String(64, 1).check(Schema.makeFilter((value) => value.length > 0 && value === value.trim() ? void 0 : { path: [], issue: "must be non-empty without surrounding whitespace" })),
1022
+ admission_revision: PositiveIntegerSchema
1023
+ }),
1024
+ lifecycle_intent_id: UuidSchema,
1025
+ ...ServerCorrelationFields
1026
+ }).check(
1027
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1028
+ boundedFrame(32768)
1029
+ );
1030
+ var ParticipantLeftExternalOperationIdEventVariantSchema = Schema.Struct({
1031
+ type: Schema.Literal("event"),
1032
+ stream: Schema.Literal("control"),
1033
+ name: Schema.Literal("participant_left"),
1034
+ event_id: UuidSchema,
1035
+ base_revision: NonNegativeIntegerSchema,
1036
+ revision: PositiveIntegerSchema,
1037
+ schema_version: PositiveIntegerSchema,
1038
+ resulting_state_digest: StateDigestSchema,
1039
+ payload: Schema.Struct({ participant_id: UuidSchema, reason: Schema.Union([Schema.Literal("left"), Schema.Literal("removed")]) }),
1040
+ external_operation_id: UuidSchema,
1041
+ ...ServerCorrelationFields
1042
+ }).check(
1043
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1044
+ boundedFrame(32768)
1045
+ );
1046
+ var EpisodeStartedLifecycleIntentIdEventVariantSchema = Schema.Struct({
1047
+ type: Schema.Literal("event"),
1048
+ stream: Schema.Literal("control"),
1049
+ name: Schema.Literal("episode_started"),
1050
+ event_id: UuidSchema,
1051
+ base_revision: NonNegativeIntegerSchema,
1052
+ revision: PositiveIntegerSchema,
1053
+ schema_version: PositiveIntegerSchema,
1054
+ resulting_state_digest: StateDigestSchema,
1055
+ payload: Schema.Struct({ episode_id: UuidSchema }),
1056
+ lifecycle_intent_id: UuidSchema,
1057
+ ...ServerCorrelationFields
1058
+ }).check(
1059
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1060
+ boundedFrame(32768)
1061
+ );
1062
+ var EpisodeEndedExternalOperationIdEventVariantSchema = Schema.Struct({
1063
+ type: Schema.Literal("event"),
1064
+ stream: Schema.Literal("control"),
1065
+ name: Schema.Literal("episode_ended"),
1066
+ event_id: UuidSchema,
1067
+ base_revision: NonNegativeIntegerSchema,
1068
+ revision: PositiveIntegerSchema,
1069
+ schema_version: PositiveIntegerSchema,
1070
+ resulting_state_digest: StateDigestSchema,
1071
+ payload: Schema.Struct({ reason: Schema.Union([Schema.Literal("ended_by_participant"), Schema.Literal("tenant_recovery"), Schema.Literal("maximum_duration")]) }),
1072
+ external_operation_id: UuidSchema,
1073
+ ...ServerCorrelationFields
1074
+ }).check(
1075
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1076
+ boundedFrame(32768)
1077
+ );
1078
+ var HandRaisedCommandIdEventVariantSchema = Schema.Struct({
1079
+ type: Schema.Literal("event"),
1080
+ stream: Schema.Literal("control"),
1081
+ name: Schema.Literal("hand_raised"),
1082
+ event_id: UuidSchema,
1083
+ base_revision: NonNegativeIntegerSchema,
1084
+ revision: PositiveIntegerSchema,
1085
+ schema_version: PositiveIntegerSchema,
1086
+ resulting_state_digest: StateDigestSchema,
1087
+ payload: Schema.Struct({ participant_id: UuidSchema }),
1088
+ command_id: CommandIdSchema,
1089
+ ...ServerCorrelationFields
1090
+ }).check(
1091
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1092
+ boundedFrame(32768)
1093
+ );
1094
+ var HandLoweredCommandIdEventVariantSchema = Schema.Struct({
1095
+ type: Schema.Literal("event"),
1096
+ stream: Schema.Literal("control"),
1097
+ name: Schema.Literal("hand_lowered"),
1098
+ event_id: UuidSchema,
1099
+ base_revision: NonNegativeIntegerSchema,
1100
+ revision: PositiveIntegerSchema,
1101
+ schema_version: PositiveIntegerSchema,
1102
+ resulting_state_digest: StateDigestSchema,
1103
+ payload: Schema.Struct({ participant_id: UuidSchema }),
1104
+ command_id: CommandIdSchema,
1105
+ ...ServerCorrelationFields
1106
+ }).check(
1107
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1108
+ boundedFrame(32768)
1109
+ );
1110
+ var ParticipantDisplayNameChangedCommandIdEventVariantSchema = Schema.Struct({
1111
+ type: Schema.Literal("event"),
1112
+ stream: Schema.Literal("control"),
1113
+ name: Schema.Literal("participant_display_name_changed"),
1114
+ event_id: UuidSchema,
1115
+ base_revision: NonNegativeIntegerSchema,
1116
+ revision: PositiveIntegerSchema,
1117
+ schema_version: PositiveIntegerSchema,
1118
+ resulting_state_digest: StateDigestSchema,
1119
+ payload: Schema.Struct({ participant_id: UuidSchema, display_name: boundedUtf8String(256, 1) }),
1120
+ command_id: CommandIdSchema,
1121
+ ...ServerCorrelationFields
1122
+ }).check(
1123
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1124
+ boundedFrame(32768)
1125
+ );
1126
+ var AdmissionPolicyChangedCommandIdEventVariantSchema = Schema.Struct({
1127
+ type: Schema.Literal("event"),
1128
+ stream: Schema.Literal("control"),
1129
+ name: Schema.Literal("admission_policy_changed"),
1130
+ event_id: UuidSchema,
1131
+ base_revision: NonNegativeIntegerSchema,
1132
+ revision: PositiveIntegerSchema,
1133
+ schema_version: PositiveIntegerSchema,
1134
+ resulting_state_digest: StateDigestSchema,
1135
+ payload: Schema.Struct({ policy: Schema.Union([Schema.Literal("open"), Schema.Literal("knock"), Schema.Literal("members_only")]) }),
1136
+ command_id: CommandIdSchema,
1137
+ ...ServerCorrelationFields
1138
+ }).check(
1139
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1140
+ boundedFrame(32768)
1141
+ );
1142
+ var RoleAssignedCommandIdEventVariantSchema = Schema.Struct({
1143
+ type: Schema.Literal("event"),
1144
+ stream: Schema.Literal("control"),
1145
+ name: Schema.Literal("role_assigned"),
1146
+ event_id: UuidSchema,
1147
+ base_revision: NonNegativeIntegerSchema,
1148
+ revision: PositiveIntegerSchema,
1149
+ schema_version: PositiveIntegerSchema,
1150
+ resulting_state_digest: StateDigestSchema,
1151
+ payload: Schema.Struct({ participant_id: UuidSchema, role: boundedUtf8String(64, 1).check(Schema.makeFilter((value) => value.length > 0 && value === value.trim() ? void 0 : { path: [], issue: "must be non-empty without surrounding whitespace" })) }),
1152
+ command_id: CommandIdSchema,
1153
+ ...ServerCorrelationFields
1154
+ }).check(
1155
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1156
+ boundedFrame(32768)
1157
+ );
1158
+ var DeadlineChangedExternalOperationIdEventVariantSchema = Schema.Struct({
1159
+ type: Schema.Literal("event"),
1160
+ stream: Schema.Literal("control"),
1161
+ name: Schema.Literal("deadline_changed"),
1162
+ event_id: UuidSchema,
1163
+ base_revision: NonNegativeIntegerSchema,
1164
+ revision: PositiveIntegerSchema,
1165
+ schema_version: PositiveIntegerSchema,
1166
+ resulting_state_digest: StateDigestSchema,
1167
+ payload: Schema.Struct({ deadline_at_ms: PositiveIntegerSchema, deadline_generation: PositiveIntegerSchema }),
1168
+ external_operation_id: UuidSchema,
1169
+ ...ServerCorrelationFields
1170
+ }).check(
1171
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1172
+ boundedFrame(32768)
1173
+ );
1174
+ var AdmissionRequestedLifecycleIntentIdEventVariantSchema = Schema.Struct({
1175
+ type: Schema.Literal("event"),
1176
+ stream: Schema.Literal("control"),
1177
+ name: Schema.Literal("admission_requested"),
1178
+ event_id: UuidSchema,
1179
+ base_revision: NonNegativeIntegerSchema,
1180
+ revision: PositiveIntegerSchema,
1181
+ schema_version: PositiveIntegerSchema,
1182
+ resulting_state_digest: StateDigestSchema,
1183
+ payload: Schema.Struct({
1184
+ admission_request_id: UuidSchema,
1185
+ participant_id: UuidSchema,
1186
+ display_name: boundedUtf8String(256, 1),
1187
+ role: boundedUtf8String(64, 1).check(Schema.makeFilter((value) => value.length > 0 && value === value.trim() ? void 0 : { path: [], issue: "must be non-empty without surrounding whitespace" })),
1188
+ expires_at_ms: PositiveIntegerSchema
1189
+ }),
1190
+ lifecycle_intent_id: UuidSchema,
1191
+ ...ServerCorrelationFields
1192
+ }).check(
1193
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1194
+ boundedFrame(32768)
1195
+ );
1196
+ var AdmissionDeniedExternalOperationIdEventVariantSchema = Schema.Struct({
1197
+ type: Schema.Literal("event"),
1198
+ stream: Schema.Literal("control"),
1199
+ name: Schema.Literal("admission_denied"),
1200
+ event_id: UuidSchema,
1201
+ base_revision: NonNegativeIntegerSchema,
1202
+ revision: PositiveIntegerSchema,
1203
+ schema_version: PositiveIntegerSchema,
1204
+ resulting_state_digest: StateDigestSchema,
1205
+ payload: Schema.Struct({ admission_request_id: UuidSchema }),
1206
+ external_operation_id: UuidSchema,
1207
+ ...ServerCorrelationFields
1208
+ }).check(
1209
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1210
+ boundedFrame(32768)
1211
+ );
1212
+ var AdmissionExpiredExternalOperationIdEventVariantSchema = Schema.Struct({
1213
+ type: Schema.Literal("event"),
1214
+ stream: Schema.Literal("control"),
1215
+ name: Schema.Literal("admission_expired"),
1216
+ event_id: UuidSchema,
1217
+ base_revision: NonNegativeIntegerSchema,
1218
+ revision: PositiveIntegerSchema,
1219
+ schema_version: PositiveIntegerSchema,
1220
+ resulting_state_digest: StateDigestSchema,
1221
+ payload: Schema.Struct({ admission_request_id: UuidSchema }),
1222
+ external_operation_id: UuidSchema,
1223
+ ...ServerCorrelationFields
1224
+ }).check(
1225
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1226
+ boundedFrame(32768)
1227
+ );
1228
+ var ParticipantMicrophoneStoppedExternalOperationIdEventVariantSchema = Schema.Struct({
1229
+ type: Schema.Literal("event"),
1230
+ stream: Schema.Literal("control"),
1231
+ name: Schema.Literal("participant_microphone_stopped"),
1232
+ event_id: UuidSchema,
1233
+ base_revision: NonNegativeIntegerSchema,
1234
+ revision: PositiveIntegerSchema,
1235
+ schema_version: PositiveIntegerSchema,
1236
+ resulting_state_digest: StateDigestSchema,
1237
+ payload: Schema.Struct({ participant_id: UuidSchema }),
1238
+ external_operation_id: UuidSchema,
1239
+ ...ServerCorrelationFields
1240
+ }).check(
1241
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1242
+ boundedFrame(32768)
1243
+ );
1244
+ var ParticipantCameraStoppedExternalOperationIdEventVariantSchema = Schema.Struct({
1245
+ type: Schema.Literal("event"),
1246
+ stream: Schema.Literal("control"),
1247
+ name: Schema.Literal("participant_camera_stopped"),
1248
+ event_id: UuidSchema,
1249
+ base_revision: NonNegativeIntegerSchema,
1250
+ revision: PositiveIntegerSchema,
1251
+ schema_version: PositiveIntegerSchema,
1252
+ resulting_state_digest: StateDigestSchema,
1253
+ payload: Schema.Struct({ participant_id: UuidSchema }),
1254
+ external_operation_id: UuidSchema,
1255
+ ...ServerCorrelationFields
1256
+ }).check(
1257
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1258
+ boundedFrame(32768)
1259
+ );
1260
+ var ParticipantScreenShareStoppedExternalOperationIdEventVariantSchema = Schema.Struct({
1261
+ type: Schema.Literal("event"),
1262
+ stream: Schema.Literal("control"),
1263
+ name: Schema.Literal("participant_screen_share_stopped"),
1264
+ event_id: UuidSchema,
1265
+ base_revision: NonNegativeIntegerSchema,
1266
+ revision: PositiveIntegerSchema,
1267
+ schema_version: PositiveIntegerSchema,
1268
+ resulting_state_digest: StateDigestSchema,
1269
+ payload: Schema.Struct({ participant_id: UuidSchema }),
1270
+ external_operation_id: UuidSchema,
1271
+ ...ServerCorrelationFields
1272
+ }).check(
1273
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1274
+ boundedFrame(32768)
1275
+ );
1276
+ var RecordingStatusChangedExternalOperationIdEventVariantSchema = Schema.Struct({
1277
+ type: Schema.Literal("event"),
1278
+ stream: Schema.Literal("control"),
1279
+ name: Schema.Literal("recording_status_changed"),
1280
+ event_id: UuidSchema,
1281
+ base_revision: NonNegativeIntegerSchema,
1282
+ revision: PositiveIntegerSchema,
1283
+ schema_version: PositiveIntegerSchema,
1284
+ resulting_state_digest: StateDigestSchema,
1285
+ payload: Schema.Struct({ recording_id: UuidSchema, status: Schema.Union([Schema.Literal("starting"), Schema.Literal("recording"), Schema.Literal("stopping"), Schema.Literal("stopped"), Schema.Literal("failed")]), failure_code: Schema.NullOr(boundedUtf8String(96, 1)) }),
1286
+ external_operation_id: UuidSchema,
1287
+ ...ServerCorrelationFields
1288
+ }).check(
1289
+ Schema.makeFilter((frame) => frame.revision === frame.base_revision + 1 ? void 0 : { path: ["revision"], issue: "revision must equal base_revision + 1" }),
1290
+ boundedFrame(32768)
1291
+ );
1292
+ var ParticipantJoinedEventFrameSchema = ParticipantJoinedLifecycleIntentIdEventVariantSchema;
1293
+ var ParticipantLeftEventFrameSchema = ParticipantLeftExternalOperationIdEventVariantSchema;
1294
+ var EpisodeStartedEventFrameSchema = EpisodeStartedLifecycleIntentIdEventVariantSchema;
1295
+ var EpisodeEndedEventFrameSchema = EpisodeEndedExternalOperationIdEventVariantSchema;
1296
+ var HandRaisedEventFrameSchema = HandRaisedCommandIdEventVariantSchema;
1297
+ var HandLoweredEventFrameSchema = HandLoweredCommandIdEventVariantSchema;
1298
+ var ParticipantDisplayNameChangedEventFrameSchema = ParticipantDisplayNameChangedCommandIdEventVariantSchema;
1299
+ var AdmissionPolicyChangedEventFrameSchema = AdmissionPolicyChangedCommandIdEventVariantSchema;
1300
+ var RoleAssignedEventFrameSchema = RoleAssignedCommandIdEventVariantSchema;
1301
+ var DeadlineChangedEventFrameSchema = DeadlineChangedExternalOperationIdEventVariantSchema;
1302
+ var AdmissionRequestedEventFrameSchema = AdmissionRequestedLifecycleIntentIdEventVariantSchema;
1303
+ var AdmissionDeniedEventFrameSchema = AdmissionDeniedExternalOperationIdEventVariantSchema;
1304
+ var AdmissionExpiredEventFrameSchema = AdmissionExpiredExternalOperationIdEventVariantSchema;
1305
+ var ParticipantMicrophoneStoppedEventFrameSchema = ParticipantMicrophoneStoppedExternalOperationIdEventVariantSchema;
1306
+ var ParticipantCameraStoppedEventFrameSchema = ParticipantCameraStoppedExternalOperationIdEventVariantSchema;
1307
+ var ParticipantScreenShareStoppedEventFrameSchema = ParticipantScreenShareStoppedExternalOperationIdEventVariantSchema;
1308
+ var RecordingStatusChangedEventFrameSchema = RecordingStatusChangedExternalOperationIdEventVariantSchema;
1309
+ var EventFrameSchema = Schema.Union([
1310
+ ParticipantJoinedEventFrameSchema,
1311
+ ParticipantLeftEventFrameSchema,
1312
+ EpisodeStartedEventFrameSchema,
1313
+ EpisodeEndedEventFrameSchema,
1314
+ HandRaisedEventFrameSchema,
1315
+ HandLoweredEventFrameSchema,
1316
+ ParticipantDisplayNameChangedEventFrameSchema,
1317
+ AdmissionPolicyChangedEventFrameSchema,
1318
+ RoleAssignedEventFrameSchema,
1319
+ DeadlineChangedEventFrameSchema,
1320
+ AdmissionRequestedEventFrameSchema,
1321
+ AdmissionDeniedEventFrameSchema,
1322
+ AdmissionExpiredEventFrameSchema,
1323
+ ParticipantMicrophoneStoppedEventFrameSchema,
1324
+ ParticipantCameraStoppedEventFrameSchema,
1325
+ ParticipantScreenShareStoppedEventFrameSchema,
1326
+ RecordingStatusChangedEventFrameSchema
1327
+ ]);
1328
+ var CollaborationCapabilitySchema = Schema.Union([Schema.Literal("sendReaction"), Schema.Literal("sendChat")]);
1329
+ var CollaborationCapabilitiesSchema = Schema.Array(CollaborationCapabilitySchema).check(
1330
+ Schema.isMaxLength(2),
1331
+ Schema.makeFilter((capabilities) => uniqueStrings(capabilities) ? void 0 : { path: [], issue: "must contain unique collaboration capabilities" })
1332
+ );
1333
+ var ChatReadReceiptSchema = Schema.Struct({ participant_id: UuidSchema, participant_generation: PositiveIntegerSchema, sequence: UnsignedDecimalSchema, read_at: boundedUtf8String(64, 1) }).check(exactKeys(["participant_id", "participant_generation", "sequence", "read_at"]));
1334
+ var CollaborationWelcomeExtensionSchema = Schema.Struct({
1335
+ name: Schema.Literal("collaboration_v1"),
1336
+ capabilities: CollaborationCapabilitiesSchema,
1337
+ participant_capabilities: Schema.Record(UuidSchema, CollaborationCapabilitiesSchema),
1338
+ chat_head_sequence: Schema.NullOr(UnsignedDecimalSchema),
1339
+ retained_floor_sequence: Schema.NullOr(UnsignedDecimalSchema),
1340
+ read_receipts: Schema.Array(ChatReadReceiptSchema).check(Schema.isMaxLength(500))
1341
+ }).check(exactKeys(["name", "capabilities", "participant_capabilities", "chat_head_sequence", "retained_floor_sequence", "read_receipts"]));
1342
+ var WelcomeBase = { type: Schema.Literal("welcome"), protocol: Schema.Literal(1), participant_id: UuidSchema, participant_generation: PositiveIntegerSchema, recovery_id: UuidSchema, head: ControlCursorSchema };
1343
+ var ExtendedWelcomeBase = { ...WelcomeBase, extensions: Schema.Tuple([CollaborationWelcomeExtensionSchema]) };
1344
+ var WelcomeSnapshotFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("snapshot"), snapshot: SnapshotSchema, ...ServerCorrelationFields }).check(boundedServerFrame(SyncProtocolLimits.snapshotEncodedBytes));
1345
+ var WelcomeReplayFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("replay"), ...ServerCorrelationFields });
1346
+ var WelcomeUpToDateFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("up_to_date"), ...ServerCorrelationFields });
1347
+ var WelcomeTerminalFrameSchema = Schema.Struct({ ...WelcomeBase, mode: Schema.Literal("terminal"), reason: TerminalRecoveryReasonSchema, ...ServerCorrelationFields });
1348
+ var ExtendedWelcomeSnapshotFrameSchema = Schema.Struct({ ...ExtendedWelcomeBase, mode: Schema.Literal("snapshot"), snapshot: SnapshotSchema, ...ServerCorrelationFields }).check(boundedServerFrame(SyncProtocolLimits.snapshotEncodedBytes));
1349
+ var ExtendedWelcomeReplayFrameSchema = Schema.Struct({ ...ExtendedWelcomeBase, mode: Schema.Literal("replay"), ...ServerCorrelationFields });
1350
+ var ExtendedWelcomeUpToDateFrameSchema = Schema.Struct({ ...ExtendedWelcomeBase, mode: Schema.Literal("up_to_date"), ...ServerCorrelationFields });
1351
+ var ExtendedWelcomeTerminalFrameSchema = Schema.Struct({ ...ExtendedWelcomeBase, mode: Schema.Literal("terminal"), reason: TerminalRecoveryReasonSchema, ...ServerCorrelationFields });
1352
+ var WelcomeFrameSchema = Schema.Union([
1353
+ ExtendedWelcomeSnapshotFrameSchema,
1354
+ ExtendedWelcomeReplayFrameSchema,
1355
+ ExtendedWelcomeUpToDateFrameSchema,
1356
+ ExtendedWelcomeTerminalFrameSchema,
1357
+ WelcomeSnapshotFrameSchema,
1358
+ WelcomeReplayFrameSchema,
1359
+ WelcomeUpToDateFrameSchema,
1360
+ WelcomeTerminalFrameSchema
1361
+ ]);
1362
+ var ReplayPageFrameSchema = Schema.Struct({
1363
+ type: Schema.Literal("replay_page"),
1364
+ recovery_id: UuidSchema,
1365
+ first_revision: PositiveIntegerSchema,
1366
+ last_revision: PositiveIntegerSchema,
1367
+ events: Schema.Array(EventFrameSchema).check(Schema.isMaxLength(SyncProtocolLimits.replayPageMaxEvents)),
1368
+ ...ServerCorrelationFields
1369
+ }).check(
1370
+ Schema.makeFilter((frame) => {
1371
+ const first = frame.events[0];
1372
+ const last = frame.events.at(-1);
1373
+ const budget = completeSyncCorrelation(frame) ? SyncProtocolLimits.replayPageEncodedBytes : SyncProtocolLimits.replayPageEncodedBytes - SyncProtocolLimits.correlationReservedBytes;
1374
+ return encodedSyncFrameBytes(frame) <= budget && first !== void 0 && last !== void 0 && first.revision === frame.first_revision && last.revision === frame.last_revision && frame.events.every((event, index) => index === 0 || event.base_revision === frame.events[index - 1].revision) ? void 0 : { path: [], issue: "must declare one bounded contiguous replay page" };
1375
+ })
1376
+ );
1377
+ var RecoveryCompleteFrameSchema = Schema.Struct({ type: Schema.Literal("recovery_complete"), recovery_id: UuidSchema, head: ControlCursorSchema, ...ServerCorrelationFields });
1378
+ var AckDeliverySchema = Schema.Union([Schema.Literal("original"), Schema.Literal("duplicate")]);
1379
+ var CommittedAckFrameSchema = Schema.Struct({ type: Schema.Literal("ack"), command_id: CommandIdSchema, delivery: AckDeliverySchema, outcome: Schema.Literal("committed"), event_id: UuidSchema, revision: PositiveIntegerSchema, state_digest: StateDigestSchema, ...ServerCorrelationFields });
1380
+ var SatisfiedAckFrameSchema = Schema.Struct({ type: Schema.Literal("ack"), command_id: CommandIdSchema, delivery: AckDeliverySchema, outcome: Schema.Literal("satisfied"), revision: NonNegativeIntegerSchema, state_digest: StateDigestSchema, ...ServerCorrelationFields });
1381
+ var RejectedAckFrameSchema = Schema.Struct({ type: Schema.Literal("ack"), command_id: CommandIdSchema, delivery: AckDeliverySchema, outcome: Schema.Literal("rejected"), reason: RejectionReasonSchema, ...ServerCorrelationFields });
1382
+ var CommandIdConflictAckFrameSchema = Schema.Struct({ type: Schema.Literal("ack"), command_id: CommandIdSchema, delivery: AckDeliverySchema, outcome: Schema.Literal("command_id_conflict"), reason: Schema.Literal("command_id_conflict"), ...ServerCorrelationFields });
1383
+ var MediaProjectionItemSchema = Schema.Struct({ participant_id: UuidSchema, source: Schema.Union([Schema.Literal("microphone"), Schema.Literal("camera"), Schema.Literal("screen")]), enabled: Schema.Boolean, publication_id: Schema.NullOr(boundedUtf8String(256, 1)) }).check(
1384
+ Schema.makeFilter((item) => item.enabled === (item.publication_id !== null) ? void 0 : { path: [], issue: "enabled must equal whether publication_id is non-null" })
1385
+ );
1386
+ var PresenceProjectionItemSchema = Schema.Struct({ participant_id: UuidSchema, state: Schema.Union([Schema.Literal("connected"), Schema.Literal("disconnected")]), speaking: Schema.Boolean, active_speaker: Schema.Boolean }).check(
1387
+ Schema.makeFilter((item) => item.state !== "disconnected" || !item.speaking && !item.active_speaker ? void 0 : { path: [], issue: "disconnected presence cannot be speaking or active speaker" })
1388
+ );
1389
+ var MediaProjectionSnapshotFrameSchema = Schema.Struct({
1390
+ type: Schema.Literal("projection_snapshot"),
1391
+ stream: Schema.Literal("media"),
1392
+ projection_id: UuidSchema,
1393
+ sequence: Schema.Literal(0),
1394
+ items: Schema.Array(MediaProjectionItemSchema).check(Schema.isMaxLength(1500)),
1395
+ ...ServerCorrelationFields
1396
+ }).check(boundedServerFrame(SyncProtocolLimits.projectionSnapshotEncodedBytes));
1397
+ var PresenceProjectionSnapshotFrameSchema = Schema.Struct({
1398
+ type: Schema.Literal("projection_snapshot"),
1399
+ stream: Schema.Literal("presence"),
1400
+ projection_id: UuidSchema,
1401
+ sequence: Schema.Literal(0),
1402
+ items: Schema.Array(PresenceProjectionItemSchema).check(Schema.isMaxLength(500)),
1403
+ ...ServerCorrelationFields
1404
+ }).check(boundedServerFrame(SyncProtocolLimits.projectionSnapshotEncodedBytes));
1405
+ var MediaProjectionEventFrameSchema = Schema.Struct({ type: Schema.Literal("projection_event"), stream: Schema.Literal("media"), projection_id: UuidSchema, sequence: PositiveIntegerSchema, item: MediaProjectionItemSchema, ...ServerCorrelationFields }).check(
1406
+ boundedServerFrame(SyncProtocolLimits.encodedLiveEventBytes)
1407
+ );
1408
+ var PresenceProjectionEventFrameSchema = Schema.Struct({ type: Schema.Literal("projection_event"), stream: Schema.Literal("presence"), projection_id: UuidSchema, sequence: PositiveIntegerSchema, item: PresenceProjectionItemSchema, ...ServerCorrelationFields }).check(
1409
+ boundedServerFrame(SyncProtocolLimits.encodedLiveEventBytes)
1410
+ );
1411
+ var ProjectionFrameSchema = Schema.Union([MediaProjectionSnapshotFrameSchema, PresenceProjectionSnapshotFrameSchema, MediaProjectionEventFrameSchema, PresenceProjectionEventFrameSchema]);
1412
+ var LiveTargetOutcomeSchema = Schema.Union([Schema.Literal("confirmed"), Schema.Literal("satisfied"), Schema.Literal("retryable_failure"), Schema.Literal("terminal_failure"), Schema.Literal("ambiguous")]);
1413
+ var LiveTargetResultFrameSchema = Schema.Struct({
1414
+ type: Schema.Literal("live_target_result"),
1415
+ operation_id: RequestIdSchema,
1416
+ name: LiveTargetNameSchema,
1417
+ outcome: LiveTargetOutcomeSchema,
1418
+ error_code: Schema.NullOr(boundedUtf8String(SyncProtocolLimits.protocolErrorDetailBytes, 1)),
1419
+ ...ServerCorrelationFields
1420
+ });
1421
+ var DirectedRequestDeliverFrameSchema = Schema.Struct({ type: Schema.Literal("directed_request"), request_id: RequestIdSchema, name: DirectedRequestNameSchema, actor_participant_id: UuidSchema, expires_at_ms: PositiveIntegerSchema, ...ServerCorrelationFields });
1422
+ var DirectedRequestResultSchema = Schema.Union([Schema.Literal("delivered"), Schema.Literal("target_unavailable"), Schema.Literal("expired"), Schema.Literal("rejected"), Schema.Literal("rate_limited")]);
1423
+ var DirectedRequestResultFrameSchema = Schema.Struct({ type: Schema.Literal("directed_request_result"), request_id: RequestIdSchema, result: DirectedRequestResultSchema, ...ServerCorrelationFields });
1424
+ var ReactionEventFrameSchema = Schema.Struct({
1425
+ type: Schema.Literal("reaction"),
1426
+ event_id: UuidSchema,
1427
+ participant_id: UuidSchema,
1428
+ display_name: boundedUtf8String(256, 1),
1429
+ reaction: ReactionSchema,
1430
+ occurred_at: boundedUtf8String(64, 1),
1431
+ expires_at: boundedUtf8String(64, 1),
1432
+ ...ServerCorrelationFields
1433
+ }).check(boundedFrame(SyncProtocolLimits.collaborationFrameBytes));
1434
+ var CollaborationErrorCodeSchema = Schema.Union([
1435
+ Schema.Literal("capability_denied"),
1436
+ Schema.Literal("invalid_payload"),
1437
+ Schema.Literal("rate_limited"),
1438
+ Schema.Literal("overloaded"),
1439
+ Schema.Literal("episode_ended"),
1440
+ Schema.Literal("participant_stale"),
1441
+ Schema.Literal("client_message_id_conflict"),
1442
+ Schema.Literal("attachment_not_found"),
1443
+ Schema.Literal("attachment_not_ready"),
1444
+ Schema.Literal("attachment_already_claimed"),
1445
+ Schema.Literal("attachment_quota_exceeded"),
1446
+ Schema.Literal("dependency_unavailable")
1447
+ ]);
1448
+ var AcceptedReactionResultFrameSchema = Schema.Struct({ type: Schema.Literal("reaction_result"), operation_id: RequestIdSchema, outcome: Schema.Literal("accepted"), reaction: ReactionEventFrameSchema, ...ServerCorrelationFields });
1449
+ var RejectedReactionResultFrameSchema = Schema.Struct({ type: Schema.Literal("reaction_result"), operation_id: RequestIdSchema, outcome: Schema.Literal("rejected"), error_code: CollaborationErrorCodeSchema, ...ServerCorrelationFields });
1450
+ var ReactionResultFrameSchema = Schema.Union([AcceptedReactionResultFrameSchema, RejectedReactionResultFrameSchema]);
1451
+ var ChatAttachmentSchema = Schema.Struct({ attachment_id: UuidSchema, file_name: boundedUtf8String(SyncProtocolLimits.chatAttachmentFileNameUtf8Bytes, 1), mime_type: ChatAttachmentMimeTypeSchema, byte_length: PositiveIntegerSchema }).check(
1452
+ Schema.makeFilter((attachment) => attachment.byte_length <= SyncProtocolLimits.chatAttachmentMaxBytes ? void 0 : { path: ["byte_length"], issue: "must fit the attachment byte limit" }),
1453
+ exactKeys(["attachment_id", "file_name", "mime_type", "byte_length"])
1454
+ );
1455
+ var ChatMessageFrameSchema = Schema.Struct({
1456
+ type: Schema.Literal("chat_message"),
1457
+ message_id: UuidSchema,
1458
+ client_message_id: RequestIdSchema,
1459
+ sequence: UnsignedDecimalSchema,
1460
+ participant_id: UuidSchema,
1461
+ display_name: boundedUtf8String(256, 1),
1462
+ text: ChatTextSchema,
1463
+ attachments: Schema.Array(ChatAttachmentSchema).check(Schema.isMaxLength(SyncProtocolLimits.chatAttachmentMaxItems)),
1464
+ created_at: boundedUtf8String(64, 1),
1465
+ ...ServerCorrelationFields
1466
+ }).check(
1467
+ Schema.makeFilter((frame) => frame.text.length > 0 || frame.attachments.length > 0 ? void 0 : { path: [], issue: "must contain text or at least one attachment" }),
1468
+ boundedFrame(SyncProtocolLimits.collaborationFrameBytes)
1469
+ );
1470
+ var AnyChatMessageFrameSchema = ChatMessageFrameSchema;
1471
+ var AcceptedChatSendResultFrameSchema = Schema.Struct({ type: Schema.Literal("chat_send_result"), client_message_id: RequestIdSchema, outcome: Schema.Literal("accepted"), message: ChatMessageFrameSchema, ...ServerCorrelationFields });
1472
+ var RejectedChatSendResultFrameSchema = Schema.Struct({ type: Schema.Literal("chat_send_result"), client_message_id: RequestIdSchema, outcome: Schema.Literal("rejected"), error_code: CollaborationErrorCodeSchema, ...ServerCorrelationFields });
1473
+ var ChatSendResultFrameSchema = Schema.Union([AcceptedChatSendResultFrameSchema, RejectedChatSendResultFrameSchema]);
1474
+ var LoadedChatPageFrameSchema = Schema.Struct({
1475
+ type: Schema.Literal("chat_page"),
1476
+ request_id: RequestIdSchema,
1477
+ outcome: Schema.Literal("loaded"),
1478
+ messages: Schema.Array(AnyChatMessageFrameSchema).check(Schema.isMaxLength(SyncProtocolLimits.chatPageMaxMessages)),
1479
+ has_more: Schema.Boolean,
1480
+ head_sequence: Schema.NullOr(UnsignedDecimalSchema),
1481
+ retained_floor_sequence: Schema.NullOr(UnsignedDecimalSchema),
1482
+ ...ServerCorrelationFields
1483
+ }).check(boundedServerFrame(SyncProtocolLimits.chatPageEncodedBytes));
1484
+ var ResetChatPageFrameSchema = Schema.Struct({ type: Schema.Literal("chat_page"), request_id: RequestIdSchema, outcome: Schema.Literal("cursor_reset"), retained_floor_sequence: UnsignedDecimalSchema, ...ServerCorrelationFields });
1485
+ var ChatPageFrameSchema = Schema.Union([LoadedChatPageFrameSchema, ResetChatPageFrameSchema]);
1486
+ var ChatHeadFrameSchema = Schema.Struct({ type: Schema.Literal("chat_head"), head_sequence: Schema.NullOr(UnsignedDecimalSchema), retained_floor_sequence: Schema.NullOr(UnsignedDecimalSchema), ...ServerCorrelationFields });
1487
+ var ChatReadReceiptFrameSchema = Schema.Struct({ type: Schema.Literal("chat_read_receipt"), participant_id: UuidSchema, participant_generation: PositiveIntegerSchema, sequence: UnsignedDecimalSchema, read_at: boundedUtf8String(64, 1), ...ServerCorrelationFields }).check(
1488
+ serverExactKeys(["type", "participant_id", "participant_generation", "sequence", "read_at"])
1489
+ );
1490
+ var AcceptedChatReadResultFrameSchema = Schema.Struct({
1491
+ type: Schema.Literal("chat_read_result"),
1492
+ request_id: RequestIdSchema,
1493
+ outcome: Schema.Literal("accepted"),
1494
+ participant_id: UuidSchema,
1495
+ participant_generation: PositiveIntegerSchema,
1496
+ sequence: UnsignedDecimalSchema,
1497
+ read_at: boundedUtf8String(64, 1),
1498
+ ...ServerCorrelationFields
1499
+ });
1500
+ var RejectedChatReadResultFrameSchema = Schema.Struct({ type: Schema.Literal("chat_read_result"), request_id: RequestIdSchema, outcome: Schema.Literal("rejected"), error_code: CollaborationErrorCodeSchema, ...ServerCorrelationFields });
1501
+ var ChatReadResultFrameSchema = Schema.Union([AcceptedChatReadResultFrameSchema, RejectedChatReadResultFrameSchema]);
1502
+ var RetryableErrorFrameSchema = Schema.Struct({ type: Schema.Literal("retryable_error"), command_id: CommandIdSchema, code: RetryableErrorCodeSchema, ...ServerCorrelationFields });
1503
+ var ErrorFrameSchema = Schema.Struct({ type: Schema.Literal("error"), code: ProtocolErrorCodeSchema, detail: boundedUtf8String(1024), ...ServerCorrelationFields });
1504
+ var PingFrameSchema = Schema.Struct({ type: Schema.Literal("ping") });
1505
+ var PongFrameSchema = Schema.Struct({ type: Schema.Literal("pong"), ...ServerCorrelationFields });
1506
+ var SyncV1ClientFrameSchema = Schema.Unknown.check(Schema.makeFilter((frame) => strictClientFrame(frame) ? void 0 : { path: [], issue: "must not contain unknown or missing fields" })).pipe(
1507
+ Schema.decodeTo(
1508
+ Schema.Union([
1509
+ ExtendedHelloFrameSchema,
1510
+ HelloFrameSchema,
1511
+ SetHandRaisedCommandFrameSchema,
1512
+ SetDisplayNameCommandFrameSchema,
1513
+ SetAdmissionPolicyCommandFrameSchema,
1514
+ AssignRolesCommandFrameSchema,
1515
+ AdmitParticipantOperationFrameSchema,
1516
+ DenyAdmissionOperationFrameSchema,
1517
+ MuteParticipantOperationFrameSchema,
1518
+ StopParticipantCameraOperationFrameSchema,
1519
+ StopParticipantScreenShareOperationFrameSchema,
1520
+ RemoveParticipantOperationFrameSchema,
1521
+ StartRecordingOperationFrameSchema,
1522
+ StopRecordingOperationFrameSchema,
1523
+ ParticipantLeaveOperationFrameSchema,
1524
+ StartEpisodeOperationFrameSchema,
1525
+ ExtendEpisodeOperationFrameSchema,
1526
+ EndEpisodeOperationFrameSchema,
1527
+ LiveTargetFrameSchema,
1528
+ DirectedRequestSendFrameSchema,
1529
+ RequestAckFrameSchema,
1530
+ ReactionSendFrameSchema,
1531
+ ChatSendFrameSchema,
1532
+ ChatPageRequestFrameSchema,
1533
+ ChatReadSetFrameSchema,
1534
+ DeliveryAckFrameSchema,
1535
+ RecoveryAckFrameSchema,
1536
+ PingFrameSchema
1537
+ ])
1538
+ )
1539
+ ).check(boundedFrame(SyncProtocolLimits.decodedInboundFrameBytes));
1540
+ var SyncV1ServerFrameSchema = Schema.Unknown.check(Schema.makeFilter((frame) => strictServerFrame(frame) ? void 0 : { path: [], issue: "must not contain unknown or missing fields" })).pipe(
1541
+ Schema.decodeTo(
1542
+ Schema.Union([
1543
+ WelcomeFrameSchema,
1544
+ ReplayPageFrameSchema,
1545
+ RecoveryCompleteFrameSchema,
1546
+ EventFrameSchema,
1547
+ CommittedAckFrameSchema,
1548
+ SatisfiedAckFrameSchema,
1549
+ RejectedAckFrameSchema,
1550
+ CommandIdConflictAckFrameSchema,
1551
+ ProjectionFrameSchema,
1552
+ LiveTargetResultFrameSchema,
1553
+ DirectedRequestDeliverFrameSchema,
1554
+ DirectedRequestResultFrameSchema,
1555
+ ReactionEventFrameSchema,
1556
+ ReactionResultFrameSchema,
1557
+ ChatMessageFrameSchema,
1558
+ ChatSendResultFrameSchema,
1559
+ ChatPageFrameSchema,
1560
+ ChatHeadFrameSchema,
1561
+ ChatReadReceiptFrameSchema,
1562
+ ChatReadResultFrameSchema,
1563
+ RetryableErrorFrameSchema,
1564
+ ErrorFrameSchema,
1565
+ PongFrameSchema
1566
+ ])
1567
+ )
1568
+ ).check(Schema.makeFilter((frame) => serverFrameWithinLimit(frame) ? void 0 : { path: [], issue: "must fit the encoded byte limit including correlation reserve" }));
1569
+ function encodeSyncFrame(frame) {
1570
+ return JSON.stringify(frame);
1571
+ }
1572
+
1573
+ // src/collaboration/wire.ts
1574
+ function reactionFromFrame(frame) {
1575
+ return {
1576
+ eventId: frame.event_id,
1577
+ participantId: frame.participant_id,
1578
+ displayName: frame.display_name,
1579
+ reaction: frame.reaction,
1580
+ occurredAt: frame.occurred_at,
1581
+ expiresAt: frame.expires_at
1582
+ };
1583
+ }
1584
+ function chatMessageFromFrame(frame) {
1585
+ return {
1586
+ messageId: frame.message_id,
1587
+ clientMessageId: frame.client_message_id,
1588
+ sequence: frame.sequence,
1589
+ participantId: frame.participant_id,
1590
+ displayName: frame.display_name,
1591
+ text: frame.text,
1592
+ createdAt: frame.created_at,
1593
+ attachments: "attachments" in frame ? frame.attachments.map((attachment) => ({
1594
+ attachmentId: attachment.attachment_id,
1595
+ fileName: attachment.file_name,
1596
+ mimeType: attachment.mime_type,
1597
+ byteLength: attachment.byte_length
1598
+ })) : []
1599
+ };
1600
+ }
1601
+ function chatReadReceiptFromFrame(frame) {
1602
+ return {
1603
+ participantId: frame.participant_id,
1604
+ participantGeneration: frame.participant_generation,
1605
+ readThroughSequence: frame.sequence,
1606
+ readAt: frame.read_at
1607
+ };
1608
+ }
1609
+
1610
+ // src/sync/v1-codec.ts
1611
+ import { Schema as Schema2 } from "effect";
1612
+ function encodeV1ClientFrame(frame) {
1613
+ return encodeSyncFrame(Schema2.decodeUnknownSync(SyncV1ClientFrameSchema)(frame));
1614
+ }
1615
+ function decodeV1ServerFrame(wire) {
1616
+ return Schema2.decodeUnknownSync(SyncV1ServerFrameSchema)(JSON.parse(wire));
1617
+ }
1618
+ function decodeV1ClientFrame(value) {
1619
+ return Schema2.decodeUnknownSync(SyncV1ClientFrameSchema)(value);
1620
+ }
1621
+
1622
+ // src/sync/v1-persistence.ts
1623
+ var InMemoryV1PendingTargetStore = class {
1624
+ #commands = /* @__PURE__ */ new Map();
1625
+ constructor(commands = []) {
1626
+ for (const command of commands) this.#commands.set(command.commandId, structuredClone(command));
1627
+ }
1628
+ async load() {
1629
+ return [...this.#commands.values()].map((command) => structuredClone(command)).sort(comparePending);
1630
+ }
1631
+ async put(command) {
1632
+ this.#commands.set(command.commandId, structuredClone(command));
1633
+ }
1634
+ async remove(commandId) {
1635
+ this.#commands.delete(commandId);
1636
+ }
1637
+ };
1638
+ function compareV1PendingTargets(left, right) {
1639
+ return comparePending(left, right);
1640
+ }
1641
+ function comparePending(left, right) {
1642
+ return left.createdAt - right.createdAt || left.commandId.localeCompare(right.commandId);
1643
+ }
1644
+
1645
+ // src/sync/v1-reducer.ts
1646
+ import { sha256 } from "@noble/hashes/sha2.js";
1647
+ var encoder2 = new TextEncoder();
1648
+ var digestPrefix = encoder2.encode("chalk-sync-state-v1");
1649
+ var V1ReplicaError = class extends Error {
1650
+ constructor(message) {
1651
+ super(message);
1652
+ this.name = "V1ReplicaError";
1653
+ }
1654
+ };
1655
+ async function restoreV1Snapshot(snapshot) {
1656
+ const state = snapshotToState(snapshot);
1657
+ assertV1ControlSemantics(state);
1658
+ await assertDigest(state);
1659
+ return state;
1660
+ }
1661
+ async function applyV1Event(state, event) {
1662
+ if (event.revision <= state.revision) throw new V1ReplicaError("duplicate control event requires retained client evidence");
1663
+ if (state.status === "ended") throw new V1ReplicaError("ended control state cannot advance");
1664
+ if (event.base_revision !== state.revision || event.revision !== state.revision + 1) throw new V1ReplicaError("control event is not exact-next");
1665
+ if (event.schema_version !== state.stateSchemaVersion) throw new V1ReplicaError("control event schema version changed");
1666
+ const next = reduceEvent(state, event);
1667
+ const candidate = { ...next, revision: event.revision, stateDigest: event.resulting_state_digest };
1668
+ assertV1ControlSemantics(candidate);
1669
+ await assertDigest(candidate);
1670
+ return candidate;
1671
+ }
1672
+ function optimisticV1Control(state, actorId, commands) {
1673
+ return commands.reduce((current, command) => applyOptimistic(current, actorId, command), state);
1674
+ }
1675
+ function snapshotToState(snapshot) {
1676
+ const roleCapabilities = Object.fromEntries(Object.entries(snapshot.role_capabilities).map(([role, capabilities]) => [role, [...capabilities]]));
1677
+ return {
1678
+ revision: snapshot.control_revision,
1679
+ stateSchemaVersion: snapshot.state_schema_version,
1680
+ stateDigest: snapshot.state_digest,
1681
+ status: snapshot.status,
1682
+ admissionPolicy: snapshot.admission_policy,
1683
+ deadlineAtMs: snapshot.deadline_at_ms,
1684
+ deadlineGeneration: snapshot.deadline_generation,
1685
+ roleCapabilities,
1686
+ recording: snapshot.recording && { recordingId: snapshot.recording.recording_id, status: snapshot.recording.status, failureCode: snapshot.recording.failure_code },
1687
+ participants: snapshot.participants.map((participant) => ({
1688
+ participantId: participant.participant_id,
1689
+ displayName: participant.display_name,
1690
+ handRaised: participant.hand_raised,
1691
+ admissionRevision: participant.admission_revision,
1692
+ role: participant.role,
1693
+ // The canonical wire contract carries one requested/assigned role. Keep
1694
+ // the former list-shaped alias for consumers that still render it.
1695
+ eligibleRoles: [participant.role],
1696
+ capabilities: [...participant.capabilities]
1697
+ })),
1698
+ admissionRequests: snapshot.admission_requests.map((request) => ({
1699
+ admissionRequestId: request.admission_request_id,
1700
+ participantId: request.participant_id,
1701
+ displayName: request.display_name,
1702
+ initialRole: request.role,
1703
+ eligibleRoles: [request.role],
1704
+ expiresAtMs: request.expires_at_ms
1705
+ }))
1706
+ };
1707
+ }
1708
+ function assertV1ControlSemantics(state) {
1709
+ const participantIds = /* @__PURE__ */ new Set();
1710
+ for (const participant of state.participants) {
1711
+ if (participantIds.has(participant.participantId)) throw new V1ReplicaError("duplicate participant ID");
1712
+ participantIds.add(participant.participantId);
1713
+ const capabilities = state.roleCapabilities[participant.role];
1714
+ if (!capabilities) throw new V1ReplicaError("participant role has no capability bundle");
1715
+ if (!sameStrings2(participant.capabilities, capabilities)) throw new V1ReplicaError("participant capabilities do not match the durable role map");
1716
+ if (participant.displayName !== participant.displayName.trim() || participant.displayName.length === 0) throw new V1ReplicaError("participant display name has surrounding whitespace");
1717
+ }
1718
+ if (state.status === "ended" && (state.participants.length !== 0 || state.admissionRequests.length !== 0 || state.recording !== null)) {
1719
+ throw new V1ReplicaError("ended control state retains active Episode state");
1720
+ }
1721
+ const requestIds = /* @__PURE__ */ new Set();
1722
+ const pendingParticipantIds = /* @__PURE__ */ new Set();
1723
+ for (const request of state.admissionRequests) {
1724
+ if (requestIds.has(request.admissionRequestId)) throw new V1ReplicaError("duplicate admission request ID");
1725
+ if (pendingParticipantIds.has(request.participantId) || participantIds.has(request.participantId)) throw new V1ReplicaError("active and pending participant IDs overlap");
1726
+ requestIds.add(request.admissionRequestId);
1727
+ pendingParticipantIds.add(request.participantId);
1728
+ if (request.displayName !== request.displayName.trim() || request.displayName.length === 0) throw new V1ReplicaError("admission display name has surrounding whitespace");
1729
+ }
1730
+ if (state.recording?.status === "failed" ? state.recording.failureCode === null : state.recording?.failureCode !== null && state.recording !== null) {
1731
+ throw new V1ReplicaError("recording failure code does not match its status");
1732
+ }
1733
+ }
1734
+ async function computeV1StateDigest(state) {
1735
+ const version = new Uint8Array(4);
1736
+ new DataView(version.buffer).setUint32(0, state.stateSchemaVersion, false);
1737
+ const bytes = joinBytes(digestPrefix, version, canonicalJsonBytesFromUnknown(durableProjection(state)));
1738
+ return Array.from(sha256(bytes), (byte) => byte.toString(16).padStart(2, "0")).join("");
1739
+ }
1740
+ function durableProjection(state) {
1741
+ return {
1742
+ admission_policy: state.admissionPolicy,
1743
+ admission_requests: state.admissionRequests.map((request) => ({
1744
+ admission_request_id: request.admissionRequestId,
1745
+ display_name: request.displayName,
1746
+ expires_at_ms: request.expiresAtMs,
1747
+ participant_id: request.participantId,
1748
+ role: request.initialRole
1749
+ })),
1750
+ control_revision: state.revision,
1751
+ deadline_at_ms: state.deadlineAtMs,
1752
+ deadline_generation: state.deadlineGeneration,
1753
+ participants: [...state.participants].sort((left, right) => left.participantId.localeCompare(right.participantId)).map((participant) => ({
1754
+ admission_revision: participant.admissionRevision,
1755
+ capabilities: state.roleCapabilities[participant.role],
1756
+ display_name: participant.displayName,
1757
+ hand_raised: participant.handRaised,
1758
+ participant_id: participant.participantId,
1759
+ role: participant.role
1760
+ })),
1761
+ recording: state.recording && { failure_code: state.recording.failureCode, recording_id: state.recording.recordingId, status: state.recording.status },
1762
+ role_capabilities: state.roleCapabilities,
1763
+ state_schema_version: state.stateSchemaVersion,
1764
+ status: state.status
1765
+ };
1766
+ }
1767
+ async function assertDigest(state) {
1768
+ if (await computeV1StateDigest(state) !== state.stateDigest) throw new V1ReplicaError("control state digest mismatch");
1769
+ }
1770
+ function reduceEvent(state, event) {
1771
+ switch (event.name) {
1772
+ case "participant_joined": {
1773
+ if (state.participants.some((participant2) => participant2.participantId === event.payload.participant_id)) throw new V1ReplicaError("duplicate participant join");
1774
+ const participant = participantFromJoin(state, event.payload);
1775
+ return {
1776
+ ...state,
1777
+ participants: [...state.participants, participant],
1778
+ admissionRequests: state.admissionRequests.filter((request) => request.participantId !== participant.participantId)
1779
+ };
1780
+ }
1781
+ case "participant_left":
1782
+ return removeParticipant(state, event.payload.participant_id);
1783
+ case "episode_started":
1784
+ return state;
1785
+ case "episode_ended":
1786
+ return { ...state, status: "ended", participants: [], admissionRequests: [], recording: null };
1787
+ case "hand_raised":
1788
+ case "hand_lowered":
1789
+ return updateParticipant(state, event.payload.participant_id, (participant) => ({ ...participant, handRaised: event.name === "hand_raised" }));
1790
+ case "participant_display_name_changed":
1791
+ return updateParticipant(state, event.payload.participant_id, (participant) => ({ ...participant, displayName: event.payload.display_name }));
1792
+ case "admission_policy_changed":
1793
+ return { ...state, admissionPolicy: event.payload.policy };
1794
+ case "role_assigned":
1795
+ return updateParticipant(state, event.payload.participant_id, (participant) => withDerivedRole(state, participant, event.payload.role));
1796
+ case "admission_requested":
1797
+ return { ...state, admissionRequests: [...state.admissionRequests, admissionRequestFromEvent(event.payload)] };
1798
+ case "admission_denied":
1799
+ case "admission_expired":
1800
+ return removeAdmissionRequest(state, event.payload.admission_request_id);
1801
+ case "recording_status_changed":
1802
+ return transitionRecording(state, event.payload);
1803
+ case "deadline_changed":
1804
+ if (event.payload.deadline_generation !== state.deadlineGeneration + 1) throw new V1ReplicaError("deadline generation is not exact-next");
1805
+ return { ...state, deadlineAtMs: event.payload.deadline_at_ms, deadlineGeneration: event.payload.deadline_generation };
1806
+ case "participant_microphone_stopped":
1807
+ case "participant_camera_stopped":
1808
+ case "participant_screen_share_stopped":
1809
+ requireParticipant(state, event.payload.participant_id);
1810
+ return state;
1811
+ }
1812
+ }
1813
+ function applyOptimistic(state, actorId, command) {
1814
+ switch (command.name) {
1815
+ case "set_hand_raised":
1816
+ return updateParticipant(state, actorId, (participant) => ({ ...participant, handRaised: command.payload.raised }), false);
1817
+ case "set_display_name":
1818
+ return updateParticipant(state, actorId, (participant) => ({ ...participant, displayName: command.payload.display_name }), false);
1819
+ case "set_admission_policy":
1820
+ return { ...state, admissionPolicy: command.payload.policy };
1821
+ case "assign_roles":
1822
+ return updateParticipant(state, command.payload.participant_id, (participant) => withDerivedRole(state, participant, command.payload.role), false);
1823
+ }
1824
+ }
1825
+ function participantFromJoin(state, payload) {
1826
+ const capabilities = state.roleCapabilities[payload.role];
1827
+ if (!capabilities) throw new V1ReplicaError("participant join references an unknown role");
1828
+ return {
1829
+ participantId: payload.participant_id,
1830
+ displayName: payload.display_name,
1831
+ handRaised: false,
1832
+ admissionRevision: payload.admission_revision,
1833
+ role: payload.role,
1834
+ eligibleRoles: [payload.role],
1835
+ capabilities: [...capabilities]
1836
+ };
1837
+ }
1838
+ function admissionRequestFromEvent(payload) {
1839
+ return {
1840
+ admissionRequestId: payload.admission_request_id,
1841
+ participantId: payload.participant_id,
1842
+ displayName: payload.display_name,
1843
+ initialRole: payload.role,
1844
+ eligibleRoles: [payload.role],
1845
+ expiresAtMs: payload.expires_at_ms
1846
+ };
1847
+ }
1848
+ function withDerivedRole(state, participant, role) {
1849
+ const capabilities = state.roleCapabilities[role];
1850
+ if (!capabilities) throw new V1ReplicaError("role assignment references an unknown role");
1851
+ return { ...participant, role, capabilities: [...capabilities] };
1852
+ }
1853
+ function updateParticipant(state, participantId, update, required = true) {
1854
+ let found = false;
1855
+ const participants = state.participants.map((participant) => {
1856
+ if (participant.participantId !== participantId) return participant;
1857
+ found = true;
1858
+ return update(participant);
1859
+ });
1860
+ if (required && !found) throw new V1ReplicaError("control event references an unknown participant");
1861
+ return found ? { ...state, participants } : state;
1862
+ }
1863
+ function removeParticipant(state, participantId) {
1864
+ const participants = state.participants.filter((participant) => participant.participantId !== participantId);
1865
+ if (participants.length === state.participants.length) throw new V1ReplicaError("control event references an unknown participant");
1866
+ return { ...state, participants };
1867
+ }
1868
+ function requireParticipant(state, participantId) {
1869
+ const participant = state.participants.find((candidate) => candidate.participantId === participantId);
1870
+ if (!participant) throw new V1ReplicaError("control event references an unknown participant");
1871
+ return participant;
1872
+ }
1873
+ function removeAdmissionRequest(state, admissionRequestId) {
1874
+ const admissionRequests = state.admissionRequests.filter((request) => request.admissionRequestId !== admissionRequestId);
1875
+ if (admissionRequests.length === state.admissionRequests.length) throw new V1ReplicaError("control event references an unknown admission request");
1876
+ return { ...state, admissionRequests };
1877
+ }
1878
+ function transitionRecording(state, payload) {
1879
+ const current = state.recording;
1880
+ if (payload.status === "starting") {
1881
+ if (current !== null && current.status !== "stopped" && current.status !== "failed") throw new V1ReplicaError("Recording is already active");
1882
+ return { ...state, recording: recordingFromPayload(payload) };
1883
+ }
1884
+ if (!current || current.recordingId !== payload.recording_id) throw new V1ReplicaError("Recording transition changed identity");
1885
+ const allowed = current.status === "starting" && (payload.status === "recording" || payload.status === "failed") || current.status === "recording" && (payload.status === "stopping" || payload.status === "failed") || current.status === "stopping" && (payload.status === "stopped" || payload.status === "failed");
1886
+ if (!allowed) throw new V1ReplicaError("illegal Recording status transition");
1887
+ return { ...state, recording: recordingFromPayload(payload) };
1888
+ }
1889
+ function recordingFromPayload(payload) {
1890
+ return { recordingId: payload.recording_id, status: payload.status, failureCode: payload.failure_code };
1891
+ }
1892
+ function joinBytes(...parts) {
1893
+ const output = new Uint8Array(parts.reduce((total, part) => total + part.byteLength, 0));
1894
+ let offset = 0;
1895
+ for (const part of parts) {
1896
+ output.set(part, offset);
1897
+ offset += part.byteLength;
1898
+ }
1899
+ return output;
1900
+ }
1901
+ function sameStrings2(left, right) {
1902
+ return left.length === right.length && left.every((value, index) => value === right[index]);
1903
+ }
1904
+
1905
+ // src/sync/v1-client.ts
1906
+ var encoder3 = new TextEncoder();
1907
+ var MAX_IN_FLIGHT = 256;
1908
+ var MAX_PENDING_BYTES = 1024 * 1024;
1909
+ var MAX_PENDING_AGE_MS = 24 * 60 * 60 * 1e3;
1910
+ var MAX_REPLAY_EVENTS = SyncProtocolLimits.completeReplayMaxEvents;
1911
+ var MAX_REPLAY_BYTES = SyncProtocolLimits.completeReplayEncodedBytes;
1912
+ var MAX_RETRIES = 3;
1913
+ var MAX_LIVE_SERVER_RETRIES = 16;
1914
+ var LIVE_TARGET_RETRY_BUDGET_MS = 15e3;
1915
+ var MAX_LIVE_TARGET_RETRY_DELAY_MS = 1e3;
1916
+ var MAX_PROJECTION_EVENT_EVIDENCE = 256;
1917
+ var OPERATION_PENDING_POLL_INTERVAL_MS = 1e3;
1918
+ var CLIENT_RESTART_CLOSE_CODE = 4e3;
1919
+ var MAX_COLLABORATION_REQUESTS_IN_FLIGHT = 64;
1920
+ var V1SyncError = class extends Error {
1921
+ constructor(message, code) {
1922
+ super(message);
1923
+ this.code = code;
1924
+ this.name = "V1SyncError";
1925
+ }
1926
+ code;
1927
+ };
1928
+ var V1SyncClient = class {
1929
+ #options;
1930
+ #store;
1931
+ #listeners = /* @__PURE__ */ new Set();
1932
+ #requestListeners = /* @__PURE__ */ new Set();
1933
+ #collaborationListeners = /* @__PURE__ */ new Set();
1934
+ #pendingTargets = /* @__PURE__ */ new Map();
1935
+ #reservedCommandIds = /* @__PURE__ */ new Set();
1936
+ #commands = /* @__PURE__ */ new Map();
1937
+ #acknowledgements = /* @__PURE__ */ new Map();
1938
+ #pendingRemovals = /* @__PURE__ */ new Map();
1939
+ #controlHeads = /* @__PURE__ */ new Map();
1940
+ #controlEvents = /* @__PURE__ */ new Map();
1941
+ #liveTargets = /* @__PURE__ */ new Map();
1942
+ #requests = /* @__PURE__ */ new Map();
1943
+ #reactions = /* @__PURE__ */ new Map();
1944
+ #chatSends = /* @__PURE__ */ new Map();
1945
+ #chatPages = /* @__PURE__ */ new Map();
1946
+ #chatReads = /* @__PURE__ */ new Map();
1947
+ #commandRetryTimers = /* @__PURE__ */ new Map();
1948
+ #liveRetryTimers = /* @__PURE__ */ new Map();
1949
+ #liveDeadlineTimers = /* @__PURE__ */ new Map();
1950
+ #pendingRemovalRetryTimers = /* @__PURE__ */ new Map();
1951
+ #mediaEventEvidence = /* @__PURE__ */ new Map();
1952
+ #presenceEventEvidence = /* @__PURE__ */ new Map();
1953
+ #phase = { phase: "idle" };
1954
+ #socket = null;
1955
+ #control = null;
1956
+ #media = null;
1957
+ #presence = null;
1958
+ #participantId = null;
1959
+ #participantGeneration = null;
1960
+ #recovery = null;
1961
+ #started = false;
1962
+ #startupGeneration = 0;
1963
+ #connectionGeneration = 0;
1964
+ #reconnectTimer;
1965
+ #heartbeatTimer;
1966
+ #missedHeartbeats = 0;
1967
+ #unsubscribeLifecycle;
1968
+ #inbound = Promise.resolve();
1969
+ #transportAvailable = true;
1970
+ #online = true;
1971
+ #active = true;
1972
+ #unsubscribeLocalMedia;
1973
+ #unsubscribeRemoteMedia;
1974
+ #localPublications = [];
1975
+ #remotePublications = [];
1976
+ #collaboration;
1977
+ #participantCollaborationCapabilities = {};
1978
+ #chatAfterSequence;
1979
+ #requestedCollaborationVersion;
1980
+ #localMedia = { microphone: "unknown", camera: "unknown", screen: "unknown" };
1981
+ constructor(options) {
1982
+ assertV1Url(options.url);
1983
+ this.#options = options;
1984
+ this.#store = options.pendingStore ?? new InMemoryV1PendingTargetStore();
1985
+ const cursor = options.collaboration === false ? { afterSequence: null, retainedFloorSequence: null } : options.collaboration?.chatCursor ?? { afterSequence: null, retainedFloorSequence: null };
1986
+ this.#chatAfterSequence = cursor.afterSequence;
1987
+ this.#requestedCollaborationVersion = options.collaboration === false ? 0 : 1;
1988
+ this.#collaboration = {
1989
+ negotiated: false,
1990
+ version: null,
1991
+ capabilities: [],
1992
+ chatHeadSequence: null,
1993
+ retainedFloorSequence: cursor.retainedFloorSequence,
1994
+ readReceipts: []
1995
+ };
1996
+ }
1997
+ async start() {
1998
+ if (this.#started) return;
1999
+ this.#started = true;
2000
+ const startupGeneration = ++this.#startupGeneration;
2001
+ let stored;
2002
+ try {
2003
+ stored = await this.#store.load();
2004
+ } catch (error) {
2005
+ if (startupGeneration === this.#startupGeneration) {
2006
+ this.#started = false;
2007
+ }
2008
+ throw error;
2009
+ }
2010
+ if (!this.#started || startupGeneration !== this.#startupGeneration) return;
2011
+ const storedCommandIds = new Set(stored.map((pending) => pending.commandId));
2012
+ for (const commandId of this.#pendingTargets.keys()) {
2013
+ if (storedCommandIds.has(commandId) || this.#commands.has(commandId)) continue;
2014
+ this.#pendingTargets.delete(commandId);
2015
+ }
2016
+ for (const commandId of this.#pendingRemovals.keys()) {
2017
+ if (storedCommandIds.has(commandId)) continue;
2018
+ this.#pendingRemovals.delete(commandId);
2019
+ this.#clearPendingRemovalRetryTimer(commandId);
2020
+ }
2021
+ for (const pending of [...stored].sort(compareV1PendingTargets)) {
2022
+ if (this.#pendingRemovals.has(pending.commandId)) {
2023
+ void this.#removePersistedTarget(pending.commandId, pending);
2024
+ } else if (this.#commands.has(pending.commandId)) {
2025
+ this.#pendingTargets.set(pending.commandId, pending);
2026
+ } else {
2027
+ this.#pendingTargets.delete(pending.commandId);
2028
+ this.#restorePending(pending);
2029
+ }
2030
+ }
2031
+ this.#subscribeMediaPlane(this.#options.mediaPlane);
2032
+ this.#unsubscribeLifecycle = this.#options.lifecycle?.subscribe((event) => this.#handleLifecycle(event));
2033
+ this.#connect();
2034
+ }
2035
+ stop() {
2036
+ this.#started = false;
2037
+ this.#startupGeneration += 1;
2038
+ this.#unsubscribeLifecycle?.();
2039
+ this.#unsubscribeLifecycle = void 0;
2040
+ this.#clearReconnect();
2041
+ this.#clearHeartbeat();
2042
+ this.#clearRetryTimers();
2043
+ this.#clearPendingRemovalRetryTimers();
2044
+ this.#unsubscribeMediaPlane();
2045
+ this.#socket?.close(1e3, "client stopped");
2046
+ this.#socket = null;
2047
+ this.#phase = { phase: "stopped" };
2048
+ this.#rejectEphemeral("client_stopped");
2049
+ this.#rejectCollaboration("client_stopped");
2050
+ this.#collaboration = { ...this.#collaboration, negotiated: false, version: null, capabilities: [], readReceipts: [] };
2051
+ this.#participantCollaborationCapabilities = {};
2052
+ this.#localPublications = [];
2053
+ this.#remotePublications = [];
2054
+ for (const source of ["microphone", "camera", "screen"]) this.#localMedia[source] = "unknown";
2055
+ for (const deferred of this.#commands.values()) rejectDeferred(deferred, new V1SyncError("client_stopped", "client_stopped"));
2056
+ this.#commands.clear();
2057
+ this.#acknowledgements.clear();
2058
+ this.#emit();
2059
+ }
2060
+ getSnapshot() {
2061
+ const pendingCommands = [...this.#pendingTargets.values()].sort(compareV1PendingTargets).map((pending) => pending.command);
2062
+ const optimisticControl = this.#control && this.#participantId ? optimisticV1Control(this.#control, this.#participantId, pendingCommands) : this.#control;
2063
+ return {
2064
+ connection: { ...this.#phase },
2065
+ participantId: this.#participantId,
2066
+ participantGeneration: this.#participantGeneration,
2067
+ control: this.#control,
2068
+ optimisticControl,
2069
+ media: copyProjection(this.#media),
2070
+ presence: copyProjection(this.#presence),
2071
+ mediaPlane: { local: this.#localPublications.map(copyPublication), remote: this.#remotePublications.map(copyPublication) },
2072
+ localMedia: { ...this.#localMedia },
2073
+ pendingCommandCount: this.#pendingTargets.size
2074
+ };
2075
+ }
2076
+ subscribe(listener) {
2077
+ this.#listeners.add(listener);
2078
+ listener(this.getSnapshot());
2079
+ return () => this.#listeners.delete(listener);
2080
+ }
2081
+ onDirectedRequest(listener) {
2082
+ this.#requestListeners.add(listener);
2083
+ return () => this.#requestListeners.delete(listener);
2084
+ }
2085
+ getCollaborationExtensionState() {
2086
+ return { ...this.#collaboration, capabilities: [...this.#collaboration.capabilities], readReceipts: this.#collaboration.readReceipts.map((receipt) => ({ ...receipt })) };
2087
+ }
2088
+ getParticipantCollaborationCapabilities() {
2089
+ return Object.fromEntries(Object.entries(this.#participantCollaborationCapabilities).map(([participantId, capabilities]) => [participantId, [...capabilities]]));
2090
+ }
2091
+ subscribeCollaboration(listener) {
2092
+ this.#collaborationListeners.add(listener);
2093
+ return () => this.#collaborationListeners.delete(listener);
2094
+ }
2095
+ sendReaction(reaction) {
2096
+ this.#assertCollaborationReady("sendReaction");
2097
+ this.#assertCollaborationCapacity();
2098
+ const operationId = this.#nextCollaborationRequestId();
2099
+ const frame = { type: "reaction_send", operation_id: operationId, reaction };
2100
+ encodeV1ClientFrame(frame);
2101
+ const promise = new Promise((resolve, reject) => this.#reactions.set(operationId, { resolve, reject, settled: false }));
2102
+ this.#send(frame);
2103
+ return promise;
2104
+ }
2105
+ sendChatMessage(input) {
2106
+ this.#assertCollaborationReady("sendChat");
2107
+ this.#assertCollaborationCapacity();
2108
+ const clientMessageId = input.clientMessageId ?? this.#nextCollaborationRequestId();
2109
+ this.#assertCollaborationRequestIdAvailable(clientMessageId);
2110
+ const attachments = input.attachments ?? [];
2111
+ const frame = { type: "chat_send", client_message_id: clientMessageId, text: input.text, attachment_ids: attachments.map((attachment) => attachment.attachmentId) };
2112
+ encodeV1ClientFrame(frame);
2113
+ const promise = new Promise((resolve, reject) => this.#chatSends.set(clientMessageId, { resolve, reject, settled: false }));
2114
+ this.#send(frame);
2115
+ return promise;
2116
+ }
2117
+ markChatRead(sequence) {
2118
+ this.#assertCollaborationReady();
2119
+ if (this.#collaboration.version !== 1) throw new V1SyncError("durable chat read receipts require collaboration_v1", "collaboration_unavailable");
2120
+ this.#assertCollaborationCapacity();
2121
+ const requestId = this.#nextCollaborationRequestId();
2122
+ const frame = { type: "chat_read_set", request_id: requestId, sequence };
2123
+ encodeV1ClientFrame(frame);
2124
+ const promise = new Promise((resolve, reject) => this.#chatReads.set(requestId, { resolve, reject, settled: false }));
2125
+ this.#send(frame);
2126
+ return promise;
2127
+ }
2128
+ readChatPage(input) {
2129
+ this.#assertCollaborationReady();
2130
+ this.#assertCollaborationCapacity();
2131
+ if (input.beforeSequence !== void 0 && input.afterSequence !== void 0) throw new V1SyncError("a chat page cannot declare both cursors", "invalid_payload");
2132
+ const requestId = this.#nextCollaborationRequestId();
2133
+ const frame = {
2134
+ type: "chat_page_request",
2135
+ request_id: requestId,
2136
+ direction: input.afterSequence === void 0 ? "older" : "newer",
2137
+ cursor_sequence: input.afterSequence ?? input.beforeSequence ?? null,
2138
+ limit: input.limit
2139
+ };
2140
+ encodeV1ClientFrame(frame);
2141
+ const promise = new Promise((resolve, reject) => this.#chatPages.set(requestId, { resolve, reject, settled: false }));
2142
+ this.#send(frame);
2143
+ return promise;
2144
+ }
2145
+ setHandRaised(raised, options) {
2146
+ return this.#sendTarget({ name: "set_hand_raised", payload: { raised } }, options);
2147
+ }
2148
+ setDisplayName(displayName, options) {
2149
+ return this.#sendTarget({ name: "set_display_name", payload: { display_name: displayName } }, options);
2150
+ }
2151
+ setAdmissionPolicy(policy, options) {
2152
+ return this.#sendTarget({ name: "set_admission_policy", payload: { policy } }, options);
2153
+ }
2154
+ assignRole(participantId, role, options) {
2155
+ return this.#sendTarget({ name: "assign_roles", payload: { participant_id: participantId, role } }, options);
2156
+ }
2157
+ admit(admissionRequestId, options) {
2158
+ return this.#sendOperation("admit_participant", { admission_request_id: admissionRequestId }, options);
2159
+ }
2160
+ deny(admissionRequestId, options) {
2161
+ return this.#sendOperation("deny_admission", { admission_request_id: admissionRequestId }, options);
2162
+ }
2163
+ muteParticipant(participantId, options) {
2164
+ return this.#sendOperation("mute_participant", { participant_id: participantId }, options);
2165
+ }
2166
+ stopParticipantCamera(participantId, options) {
2167
+ return this.#sendOperation("stop_participant_camera", { participant_id: participantId }, options);
2168
+ }
2169
+ stopParticipantScreenShare(participantId, options) {
2170
+ return this.#sendOperation("stop_participant_screen_share", { participant_id: participantId }, options);
2171
+ }
2172
+ removeParticipant(participantId, options) {
2173
+ return this.#sendOperation("remove_participant", { participant_id: participantId }, options);
2174
+ }
2175
+ startRecording(options) {
2176
+ const recordingId = options?.recordingId ?? this.#nextRequestId();
2177
+ return this.#sendOperation("start_recording", { recording_id: recordingId }, options).then((result) => ({ recordingId, result }));
2178
+ }
2179
+ stopRecording(recordingId, options) {
2180
+ return this.#sendOperation("stop_recording", { recording_id: recordingId }, options);
2181
+ }
2182
+ leave(options) {
2183
+ return this.#sendOperation("participant_leave", {}, options);
2184
+ }
2185
+ endEpisode(options) {
2186
+ return this.#sendOperation("end_episode", {}, options);
2187
+ }
2188
+ extendEpisode(minutes, options) {
2189
+ if (!Number.isSafeInteger(minutes) || minutes < 1) throw new V1SyncError("episode extension must be a positive whole number of minutes", "invalid_payload");
2190
+ return this.#sendOperation("extend_episode", { extension_seconds: minutes * 60 }, options);
2191
+ }
2192
+ setMicrophoneEnabled(enabled, options) {
2193
+ return this.#sendLiveTarget("set_microphone_enabled", "microphone", enabled, options);
2194
+ }
2195
+ setCameraEnabled(enabled, options) {
2196
+ return this.#sendLiveTarget("set_camera_enabled", "camera", enabled, options);
2197
+ }
2198
+ setScreenShareEnabled(enabled, options) {
2199
+ return this.#sendLiveTarget("set_screen_share_enabled", "screen", enabled, options);
2200
+ }
2201
+ requestUnmute(participantId, options) {
2202
+ return this.#sendDirectedRequest("request_unmute", participantId, options);
2203
+ }
2204
+ requestStartCamera(participantId, options) {
2205
+ return this.#sendDirectedRequest("request_start_camera", participantId, options);
2206
+ }
2207
+ async #sendTarget(command, options) {
2208
+ this.#assertCapacity();
2209
+ const commandId = options?.commandId ?? this.#nextCommandId();
2210
+ if (this.#commands.has(commandId) || this.#pendingTargets.has(commandId) || this.#pendingRemovals.has(commandId) || this.#reservedCommandIds.has(commandId)) throw new V1SyncError("command ID is already pending", "command_id_conflict");
2211
+ const frame = { type: "command", command_id: commandId, name: command.name, payload: command.payload };
2212
+ encodeV1ClientFrame(frame);
2213
+ const pending = { commandId, command, createdAt: this.#now(), bytes: encoder3.encode(JSON.stringify(frame)).byteLength };
2214
+ if (this.#pendingBytes() + pending.bytes > (this.#options.maxPendingBytes ?? MAX_PENDING_BYTES)) throw new V1SyncError("pending target byte capacity exceeded", "capacity");
2215
+ this.#reservedCommandIds.add(commandId);
2216
+ try {
2217
+ await this.#store.put(pending);
2218
+ this.#pendingTargets.set(commandId, pending);
2219
+ const promise = this.#registerCommand(commandId, frame, true, pending.createdAt);
2220
+ this.#sendIfLive(frame);
2221
+ this.#emit();
2222
+ return promise;
2223
+ } finally {
2224
+ this.#reservedCommandIds.delete(commandId);
2225
+ }
2226
+ }
2227
+ #sendOperation(name, payload, options) {
2228
+ this.#assertCapacity();
2229
+ const commandId = options?.commandId ?? this.#nextCommandId();
2230
+ if (this.#commands.has(commandId) || this.#pendingTargets.has(commandId) || this.#pendingRemovals.has(commandId) || this.#reservedCommandIds.has(commandId)) throw new V1SyncError("command ID is already pending", "command_id_conflict");
2231
+ const frame = { type: "operation", command_id: commandId, name, payload };
2232
+ encodeV1ClientFrame(frame);
2233
+ const promise = this.#registerCommand(commandId, frame, false, this.#now());
2234
+ this.#sendIfLive(frame);
2235
+ return promise;
2236
+ }
2237
+ #sendLiveTarget(name, source, enabled, options) {
2238
+ this.#assertCapacity();
2239
+ if (this.#phase.phase !== "live" || !this.#participantId) return Promise.reject(new V1SyncError("self-media targets require a live participant", "not_live"));
2240
+ if (!this.#options.mediaPlane) return Promise.reject(new V1SyncError("a client MediaPlane adapter is required for self-media targets", "media_plane_unavailable"));
2241
+ const operationId = options?.requestId ?? this.#nextRequestId();
2242
+ if (this.#liveTargets.has(operationId) || this.#requests.has(operationId)) throw new V1SyncError("request ID is already pending", "request_id_conflict");
2243
+ const frame = { type: "live_target", operation_id: operationId, name, enabled };
2244
+ encodeV1ClientFrame(frame);
2245
+ let deferred;
2246
+ const promise = new Promise((resolve, reject) => {
2247
+ deferred = {
2248
+ resolve,
2249
+ reject,
2250
+ settled: false,
2251
+ frame,
2252
+ createdAt: this.#now(),
2253
+ serverRetries: 0,
2254
+ localRetries: 0,
2255
+ localInFlight: false,
2256
+ source,
2257
+ enabled
2258
+ };
2259
+ this.#liveTargets.set(operationId, deferred);
2260
+ });
2261
+ const deadlineTimer = this.#clock().setTimeout(() => {
2262
+ this.#liveDeadlineTimers.delete(operationId);
2263
+ if (this.#liveTargets.get(operationId) === deferred) this.#failLiveTarget(operationId, deferred, new V1SyncError("self-media target confirmation timed out", "retry_exhausted"));
2264
+ }, LIVE_TARGET_RETRY_BUDGET_MS);
2265
+ this.#liveDeadlineTimers.set(operationId, deadlineTimer);
2266
+ this.#localMedia[source] = "requesting";
2267
+ this.#sendIfLive(frame);
2268
+ this.#emit();
2269
+ return promise;
2270
+ }
2271
+ #sendDirectedRequest(name, participantId, options) {
2272
+ this.#assertCapacity();
2273
+ if (this.#phase.phase !== "live") return Promise.reject(new V1SyncError("directed requests are live-only and are never queued for replay", "not_live"));
2274
+ const requestId = options?.requestId ?? this.#nextRequestId();
2275
+ if (this.#requests.has(requestId) || this.#liveTargets.has(requestId)) throw new V1SyncError("request ID is already pending", "request_id_conflict");
2276
+ const frame = { type: "directed_request", request_id: requestId, name, target_participant_id: participantId };
2277
+ encodeV1ClientFrame(frame);
2278
+ const promise = new Promise((resolve, reject) => this.#requests.set(requestId, { resolve, reject, settled: false, frame }));
2279
+ this.#send(frame);
2280
+ return promise;
2281
+ }
2282
+ #registerCommand(commandId, frame, durableTarget, createdAt) {
2283
+ if (this.#commands.has(commandId)) throw new V1SyncError("command ID is already pending", "command_id_conflict");
2284
+ return new Promise((resolve, reject) => this.#commands.set(commandId, { resolve, reject, settled: false, frame, retries: 0, durableTarget, createdAt }));
2285
+ }
2286
+ #connect() {
2287
+ if (!this.#started || !this.#transportAvailable || this.#socket) return;
2288
+ this.#phase = { phase: "connecting" };
2289
+ this.#emit();
2290
+ const socket = this.#options.webSocket.connect(this.#options.url);
2291
+ const connectionGeneration = ++this.#connectionGeneration;
2292
+ this.#socket = socket;
2293
+ socket.onopen = () => void this.#authenticate(socket);
2294
+ socket.onmessage = (event) => {
2295
+ this.#inbound = this.#inbound.then(() => this.#receive(socket, event.data));
2296
+ };
2297
+ socket.onclose = () => {
2298
+ this.#clock().setTimeout(() => {
2299
+ if (connectionGeneration !== this.#connectionGeneration) return;
2300
+ this.#inbound = this.#inbound.then(() => this.#disconnected(socket));
2301
+ }, 0);
2302
+ };
2303
+ socket.onerror = () => socket.close(CLIENT_RESTART_CLOSE_CODE, "transport error");
2304
+ }
2305
+ async #authenticate(socket) {
2306
+ try {
2307
+ const token = await this.#options.token();
2308
+ if (socket !== this.#socket) return;
2309
+ this.#phase = { phase: "recovering" };
2310
+ const hello = {
2311
+ type: "hello",
2312
+ protocol: 1,
2313
+ token,
2314
+ streams: {
2315
+ control: { cursor: this.#control && { revision: this.#control.revision, state_schema_version: this.#control.stateSchemaVersion, state_digest: this.#control.stateDigest } },
2316
+ media: { cursor: null },
2317
+ presence: { cursor: null },
2318
+ requests: { cursor: null }
2319
+ },
2320
+ ...this.#options.telemetry ? syncTelemetryCorrelation(this.#options.telemetry) : {}
2321
+ };
2322
+ if (this.#requestedCollaborationVersion === 0) {
2323
+ this.#send(hello);
2324
+ } else {
2325
+ const chat_cursor = {
2326
+ after_sequence: this.#chatAfterSequence,
2327
+ retained_floor_sequence: this.#collaboration.retainedFloorSequence
2328
+ };
2329
+ this.#send({ ...hello, extensions: [{ name: "collaboration_v1", chat_cursor }] });
2330
+ }
2331
+ this.#emit();
2332
+ } catch {
2333
+ socket.close(CLIENT_RESTART_CLOSE_CODE, "authentication failed");
2334
+ }
2335
+ }
2336
+ async #receive(socket, data) {
2337
+ if (socket !== this.#socket) return;
2338
+ try {
2339
+ if (typeof data !== "string" || encoder3.encode(data).byteLength > SyncProtocolLimits.snapshotEncodedBytes) throw new V1ReplicaError("invalid inbound frame size");
2340
+ await this.#handleFrame(decodeV1ServerFrame(data));
2341
+ } catch {
2342
+ this.#recover("invalid_frame");
2343
+ }
2344
+ }
2345
+ async #handleFrame(frame) {
2346
+ switch (frame.type) {
2347
+ case "welcome":
2348
+ await this.#welcome(frame);
2349
+ return;
2350
+ case "replay_page":
2351
+ await this.#replay(frame);
2352
+ return;
2353
+ case "recovery_complete":
2354
+ this.#completeRecovery(frame);
2355
+ return;
2356
+ case "projection_snapshot":
2357
+ this.#replaceProjection(frame);
2358
+ return;
2359
+ case "projection_event":
2360
+ this.#applyProjection(frame);
2361
+ return;
2362
+ case "event":
2363
+ this.#requireLive();
2364
+ if (frame.revision <= this.#requireControl().revision) {
2365
+ if (this.#controlEvents.get(frame.revision) !== frameSignature(frame)) throw new V1ReplicaError("conflicting or unprovable duplicate control event");
2366
+ } else {
2367
+ this.#control = await applyV1Event(this.#requireControl(), frame);
2368
+ this.#rememberControlHead(this.#control.revision, this.#control.stateDigest);
2369
+ this.#rememberControlEvent(frame);
2370
+ }
2371
+ await this.#settleTerminalLifecycleCommands(frame);
2372
+ await this.#settleProvenCommands();
2373
+ {
2374
+ const control = this.#requireControl();
2375
+ this.#send({ type: "delivery_ack", stream: "control", revision: control.revision, state_digest: control.stateDigest });
2376
+ }
2377
+ this.#emit();
2378
+ return;
2379
+ case "ack":
2380
+ this.#requireLive();
2381
+ await this.#ack(frame);
2382
+ return;
2383
+ case "retryable_error":
2384
+ this.#requireLive();
2385
+ this.#retryCommand(frame.command_id, frame.code);
2386
+ return;
2387
+ case "live_target_result":
2388
+ this.#liveTargetResult(frame);
2389
+ return;
2390
+ case "directed_request_result":
2391
+ this.#requestResult(frame);
2392
+ return;
2393
+ case "directed_request":
2394
+ this.#directedRequest(frame);
2395
+ return;
2396
+ case "reaction":
2397
+ this.#requireLive();
2398
+ this.#requireCollaborationNegotiated();
2399
+ this.#emitCollaboration({ type: "reaction", reaction: reactionFromFrame(frame) });
2400
+ return;
2401
+ case "reaction_result":
2402
+ this.#reactionResult(frame);
2403
+ return;
2404
+ case "chat_message":
2405
+ this.#requireCollaborationNegotiated();
2406
+ this.#observeChatMessage(frame);
2407
+ return;
2408
+ case "chat_send_result":
2409
+ this.#chatSendResult(frame);
2410
+ return;
2411
+ case "chat_page":
2412
+ this.#chatPageResult(frame);
2413
+ return;
2414
+ case "chat_head":
2415
+ this.#requireCollaborationNegotiated();
2416
+ this.#collaboration = {
2417
+ ...this.#collaboration,
2418
+ chatHeadSequence: frame.head_sequence,
2419
+ retainedFloorSequence: frame.retained_floor_sequence
2420
+ };
2421
+ this.#emit();
2422
+ return;
2423
+ case "chat_read_receipt":
2424
+ this.#requireLive();
2425
+ this.#requireCollaborationVersion(1);
2426
+ {
2427
+ const receipt = chatReadReceiptFromFrame(frame);
2428
+ this.#rememberChatReadReceipt(receipt);
2429
+ this.#emitCollaboration({ type: "chat_read_receipt", receipt });
2430
+ }
2431
+ return;
2432
+ case "chat_read_result":
2433
+ this.#chatReadResult(frame);
2434
+ return;
2435
+ case "error":
2436
+ throw new V1ReplicaError(frame.code);
2437
+ case "pong":
2438
+ this.#requireLive();
2439
+ this.#missedHeartbeats = 0;
2440
+ return;
2441
+ }
2442
+ }
2443
+ async #welcome(frame) {
2444
+ if (this.#phase.phase !== "recovering" || this.#recovery) throw new V1ReplicaError("unexpected welcome");
2445
+ if ("extensions" in frame) {
2446
+ const extension = frame.extensions[0];
2447
+ const version = 1;
2448
+ if (this.#requestedCollaborationVersion !== version) throw new V1ReplicaError("collaboration welcome version does not match the requested extension");
2449
+ this.#collaboration = {
2450
+ negotiated: true,
2451
+ version,
2452
+ capabilities: [...extension.capabilities],
2453
+ chatHeadSequence: extension.chat_head_sequence,
2454
+ retainedFloorSequence: extension.retained_floor_sequence,
2455
+ readReceipts: "read_receipts" in extension ? extension.read_receipts.map(chatReadReceiptFromWire) : []
2456
+ };
2457
+ this.#participantCollaborationCapabilities = copyCollaborationCapabilities(extension.participant_capabilities);
2458
+ } else {
2459
+ this.#requestedCollaborationVersion = 0;
2460
+ this.#collaboration = { ...this.#collaboration, negotiated: false, version: null, capabilities: [], readReceipts: [] };
2461
+ this.#participantCollaborationCapabilities = {};
2462
+ }
2463
+ this.#participantId = frame.participant_id;
2464
+ this.#participantGeneration = frame.participant_generation;
2465
+ this.#updateLocalMediaStates();
2466
+ if (frame.mode === "terminal") {
2467
+ await this.#settleTerminalRecoveryCommands(frame);
2468
+ this.#phase = { phase: "terminal", terminalReason: frame.reason };
2469
+ this.#socket?.close(1e3, "terminal recovery");
2470
+ this.#emit();
2471
+ return;
2472
+ }
2473
+ if (frame.mode === "snapshot") {
2474
+ this.#control = await restoreV1Snapshot(frame.snapshot);
2475
+ this.#controlHeads.clear();
2476
+ this.#controlEvents.clear();
2477
+ this.#rememberControlHead(this.#control.revision, this.#control.stateDigest);
2478
+ }
2479
+ if (frame.mode === "replay" && (!this.#control || this.#control.revision >= frame.head.revision)) throw new V1ReplicaError("invalid replay welcome");
2480
+ if (frame.mode === "up_to_date" && !sameHead(this.#control, frame.head)) throw new V1ReplicaError("up-to-date head mismatch");
2481
+ if (frame.mode === "snapshot" && !sameHead(this.#control, frame.head)) throw new V1ReplicaError("snapshot head mismatch");
2482
+ this.#recovery = { id: frame.recovery_id, head: frame.head, replayEvents: 0, replayBytes: 0, controlComplete: false };
2483
+ if (frame.mode !== "replay") this.#ackRecovery();
2484
+ this.#emit();
2485
+ }
2486
+ async #replay(frame) {
2487
+ const recovery = this.#requireRecovery();
2488
+ if (frame.recovery_id !== recovery.id || frame.first_revision !== this.#requireControl().revision + 1) throw new V1ReplicaError("replay page is not exact-next");
2489
+ recovery.replayEvents += frame.events.length;
2490
+ recovery.replayBytes += encoder3.encode(JSON.stringify(frame.events)).byteLength;
2491
+ if (recovery.replayEvents > MAX_REPLAY_EVENTS || recovery.replayBytes > MAX_REPLAY_BYTES) throw new V1ReplicaError("replay exceeds client bounds");
2492
+ for (const event of frame.events) {
2493
+ this.#control = await applyV1Event(this.#requireControl(), event);
2494
+ this.#rememberControlHead(this.#control.revision, this.#control.stateDigest);
2495
+ this.#rememberControlEvent(event);
2496
+ }
2497
+ this.#ackRecovery();
2498
+ this.#emit();
2499
+ }
2500
+ #completeRecovery(frame) {
2501
+ const recovery = this.#requireRecovery();
2502
+ if (frame.recovery_id !== recovery.id || !sameHead(this.#control, frame.head) || !sameRawHead(recovery.head, frame.head)) throw new V1ReplicaError("recovery completed at the wrong head");
2503
+ recovery.controlComplete = true;
2504
+ this.#enterLiveIfReady();
2505
+ }
2506
+ #replaceProjection(frame) {
2507
+ if (this.#phase.phase !== "recovering" && this.#phase.phase !== "live") throw new V1ReplicaError("projection snapshot arrived in the wrong phase");
2508
+ if (frame.stream === "media") {
2509
+ this.#media = { projectionId: frame.projection_id, sequence: 0, items: frame.items.map(mediaItem) };
2510
+ this.#mediaEventEvidence.clear();
2511
+ } else {
2512
+ this.#presence = { projectionId: frame.projection_id, sequence: 0, items: frame.items.map(presenceItem) };
2513
+ this.#presenceEventEvidence.clear();
2514
+ }
2515
+ this.#enterLiveIfReady();
2516
+ this.#emit();
2517
+ }
2518
+ #applyProjection(frame) {
2519
+ this.#requireLive();
2520
+ if (frame.stream === "media") {
2521
+ if (this.#acceptProjectionDuplicate(this.#media, this.#mediaEventEvidence, frame)) return;
2522
+ this.#media = updateProjection(this.#media, frame.projection_id, frame.sequence, mediaItem(frame.item), mediaKey);
2523
+ rememberBoundedEvidence(this.#mediaEventEvidence, frame.sequence, frameSignature(frame), MAX_PROJECTION_EVENT_EVIDENCE);
2524
+ } else {
2525
+ if (this.#acceptProjectionDuplicate(this.#presence, this.#presenceEventEvidence, frame)) return;
2526
+ this.#presence = updateProjection(this.#presence, frame.projection_id, frame.sequence, presenceItem(frame.item), (item) => item.participantId);
2527
+ rememberBoundedEvidence(this.#presenceEventEvidence, frame.sequence, frameSignature(frame), MAX_PROJECTION_EVENT_EVIDENCE);
2528
+ }
2529
+ this.#emit();
2530
+ }
2531
+ async #ack(frame) {
2532
+ const deferred = this.#commands.get(frame.command_id);
2533
+ if (!deferred) return;
2534
+ if (frame.outcome === "rejected" || frame.outcome === "command_id_conflict") {
2535
+ await this.#finishCommand(frame.command_id, frame);
2536
+ return;
2537
+ }
2538
+ if (isTerminalLifecycleOperation(deferred.frame)) {
2539
+ await this.#finishCommand(frame.command_id, frame);
2540
+ return;
2541
+ }
2542
+ if (!this.#ackHeadIsProven(frame)) {
2543
+ const previous = this.#acknowledgements.get(frame.command_id);
2544
+ if (previous && JSON.stringify(previous) !== JSON.stringify(frame)) throw new V1ReplicaError("conflicting duplicate command ACK");
2545
+ this.#acknowledgements.set(frame.command_id, frame);
2546
+ return;
2547
+ }
2548
+ await this.#finishCommand(frame.command_id, frame);
2549
+ }
2550
+ async #settleProvenCommands() {
2551
+ for (const commandId of this.#commands.keys()) {
2552
+ const ack = this.#acknowledgements.get(commandId);
2553
+ if (ack && this.#ackHeadIsProven(ack)) await this.#finishCommand(commandId, ack);
2554
+ }
2555
+ }
2556
+ async #settleTerminalLifecycleCommands(frame) {
2557
+ const operationName = frame.name === "episode_ended" ? "end_episode" : frame.name === "participant_left" && frame.payload.participant_id === this.#participantId ? "participant_leave" : null;
2558
+ if (!operationName) return;
2559
+ for (const [commandId, deferred] of this.#commands) {
2560
+ if (deferred.frame.type !== "operation" || deferred.frame.name !== operationName) continue;
2561
+ await this.#finishCommand(commandId, {
2562
+ type: "ack",
2563
+ command_id: commandId,
2564
+ delivery: "duplicate",
2565
+ outcome: "satisfied",
2566
+ revision: frame.revision,
2567
+ state_digest: frame.resulting_state_digest
2568
+ });
2569
+ }
2570
+ }
2571
+ async #settleTerminalRecoveryCommands(frame) {
2572
+ const satisfiedOperations = /* @__PURE__ */ new Set();
2573
+ if (frame.reason === "episode_ended") {
2574
+ satisfiedOperations.add("end_episode");
2575
+ satisfiedOperations.add("participant_leave");
2576
+ } else if (frame.reason === "participant_inactive") {
2577
+ satisfiedOperations.add("participant_leave");
2578
+ }
2579
+ for (const [commandId, deferred] of this.#commands) {
2580
+ if (deferred.frame.type !== "operation" || !satisfiedOperations.has(deferred.frame.name)) continue;
2581
+ await this.#finishCommand(commandId, {
2582
+ type: "ack",
2583
+ command_id: commandId,
2584
+ delivery: "duplicate",
2585
+ outcome: "satisfied",
2586
+ revision: frame.head.revision,
2587
+ state_digest: frame.head.state_digest
2588
+ });
2589
+ }
2590
+ }
2591
+ #retryCommand(commandId, code) {
2592
+ const deferred = this.#commands.get(commandId);
2593
+ if (!deferred || this.#commandRetryTimers.has(commandId)) return;
2594
+ if (code === "external_operation_pending") {
2595
+ this.#pollPendingOperation(commandId, deferred);
2596
+ return;
2597
+ }
2598
+ if (deferred.retries >= MAX_RETRIES) {
2599
+ rejectDeferred(deferred, new V1SyncError(code, "retry_exhausted"));
2600
+ if (!deferred.durableTarget) this.#commands.delete(commandId);
2601
+ return;
2602
+ }
2603
+ deferred.retries += 1;
2604
+ const timer = this.#clock().setTimeout(() => {
2605
+ this.#commandRetryTimers.delete(commandId);
2606
+ if (this.#commands.get(commandId) === deferred) this.#sendIfLive(deferred.frame);
2607
+ }, this.#options.retryDelayMs ?? 100);
2608
+ this.#commandRetryTimers.set(commandId, timer);
2609
+ }
2610
+ #pollPendingOperation(commandId, deferred) {
2611
+ const remainingAge = (this.#options.maxOperationPendingAgeMs ?? MAX_PENDING_AGE_MS) - (this.#now() - deferred.createdAt);
2612
+ if (remainingAge <= 0) {
2613
+ this.#expirePendingOperation(commandId, deferred);
2614
+ return;
2615
+ }
2616
+ const timer = this.#clock().setTimeout(
2617
+ () => {
2618
+ this.#commandRetryTimers.delete(commandId);
2619
+ if (this.#commands.get(commandId) !== deferred) return;
2620
+ if (this.#now() - deferred.createdAt >= (this.#options.maxOperationPendingAgeMs ?? MAX_PENDING_AGE_MS)) {
2621
+ this.#expirePendingOperation(commandId, deferred);
2622
+ return;
2623
+ }
2624
+ this.#sendIfLive(deferred.frame);
2625
+ },
2626
+ Math.min(OPERATION_PENDING_POLL_INTERVAL_MS, remainingAge)
2627
+ );
2628
+ this.#commandRetryTimers.set(commandId, timer);
2629
+ }
2630
+ #expirePendingOperation(commandId, deferred) {
2631
+ if (this.#commands.get(commandId) !== deferred) return;
2632
+ this.#commands.delete(commandId);
2633
+ this.#acknowledgements.delete(commandId);
2634
+ this.#clearCommandRetryTimer(commandId);
2635
+ let pending;
2636
+ if (deferred.durableTarget) {
2637
+ pending = this.#pendingTargets.get(commandId);
2638
+ this.#pendingTargets.delete(commandId);
2639
+ if (pending) this.#pendingRemovals.set(commandId, pending);
2640
+ }
2641
+ rejectDeferred(deferred, new V1SyncError("external operation remained pending beyond its maximum age", "operation_pending_timeout"));
2642
+ this.#emit();
2643
+ if (pending) void this.#removePersistedTarget(commandId, pending);
2644
+ }
2645
+ #liveTargetResult(frame) {
2646
+ this.#requireLive();
2647
+ const deferred = this.#liveTargets.get(frame.operation_id);
2648
+ if (!deferred || deferred.frame.name !== frame.name) return;
2649
+ if (deferred.serverResultSignature) {
2650
+ if (deferred.serverResultSignature !== frameSignature(frame)) throw new V1ReplicaError("conflicting duplicate live-target result");
2651
+ return;
2652
+ }
2653
+ if (frame.outcome === "retryable_failure") {
2654
+ this.#retryLiveServer(frame.operation_id, deferred, frame.error_code ?? frame.outcome);
2655
+ return;
2656
+ }
2657
+ if (frame.outcome !== "confirmed" && frame.outcome !== "satisfied") {
2658
+ this.#failLiveTarget(frame.operation_id, deferred, new V1SyncError(frame.error_code ?? frame.outcome, frame.outcome));
2659
+ return;
2660
+ }
2661
+ deferred.serverResult = { ...frame, outcome: frame.outcome };
2662
+ deferred.serverResultSignature = frameSignature(frame);
2663
+ this.#clearLiveRetryTimer(frame.operation_id);
2664
+ this.#clearLiveDeadlineTimer(frame.operation_id);
2665
+ this.#executeLocalMediaTarget(frame.operation_id, deferred);
2666
+ }
2667
+ #retryLiveServer(operationId, deferred, errorCode) {
2668
+ if (this.#liveRetryTimers.has(operationId)) return;
2669
+ const remainingBudget = LIVE_TARGET_RETRY_BUDGET_MS - (this.#now() - deferred.createdAt);
2670
+ if (deferred.serverRetries >= MAX_LIVE_SERVER_RETRIES || remainingBudget <= 0) {
2671
+ this.#failLiveTarget(operationId, deferred, new V1SyncError(errorCode, "retry_exhausted"));
2672
+ return;
2673
+ }
2674
+ deferred.serverRetries += 1;
2675
+ const baseDelay = this.#options.retryDelayMs ?? 100;
2676
+ const delay = Math.min(remainingBudget, MAX_LIVE_TARGET_RETRY_DELAY_MS, baseDelay * 2 ** Math.min(deferred.serverRetries - 1, 4));
2677
+ this.#scheduleLiveRetry(operationId, () => this.#sendIfLive(deferred.frame), delay);
2678
+ }
2679
+ #executeLocalMediaTarget(operationId, deferred) {
2680
+ const mediaPlane = this.#options.mediaPlane;
2681
+ const participantId = this.#participantId;
2682
+ if (!mediaPlane || !participantId || deferred.localInFlight || this.#liveTargets.get(operationId) !== deferred) return;
2683
+ deferred.localInFlight = true;
2684
+ let result;
2685
+ try {
2686
+ result = mediaPlane.setLocalPublicationTarget({ operationId, participantId, source: deferred.source, enabled: deferred.enabled });
2687
+ } catch {
2688
+ this.#localMediaResult(operationId, deferred, { outcome: "ambiguous", errorCode: "media_plane_exception" });
2689
+ return;
2690
+ }
2691
+ void result.then((outcome) => this.#localMediaResult(operationId, deferred, validMediaPlaneResult(outcome) ? outcome : { outcome: "ambiguous", errorCode: "invalid_media_plane_result" })).catch(() => this.#localMediaResult(operationId, deferred, { outcome: "ambiguous", errorCode: "media_plane_exception" }));
2692
+ }
2693
+ #localMediaResult(operationId, deferred, result) {
2694
+ if (this.#liveTargets.get(operationId) !== deferred) return;
2695
+ deferred.localInFlight = false;
2696
+ if (result.outcome === "retryable_failure") {
2697
+ if (deferred.localRetries >= MAX_RETRIES) {
2698
+ this.#failLiveTarget(operationId, deferred, new V1SyncError(result.errorCode ?? result.outcome, "retry_exhausted"));
2699
+ return;
2700
+ }
2701
+ deferred.localRetries += 1;
2702
+ this.#scheduleLiveRetry(operationId, () => this.#executeLocalMediaTarget(operationId, deferred));
2703
+ return;
2704
+ }
2705
+ if (result.outcome !== "confirmed" && result.outcome !== "satisfied") {
2706
+ this.#failLiveTarget(operationId, deferred, new V1SyncError(result.errorCode ?? result.outcome, result.outcome));
2707
+ return;
2708
+ }
2709
+ const serverResult = deferred.serverResult;
2710
+ if (!serverResult) throw new V1ReplicaError("local MediaPlane completed before server authorization");
2711
+ this.#liveTargets.delete(operationId);
2712
+ this.#clearLiveRetryTimer(operationId);
2713
+ this.#clearLiveDeadlineTimer(operationId);
2714
+ this.#localMedia[deferred.source] = deferred.enabled ? "enabled" : "disabled";
2715
+ resolveDeferred(deferred, { operationId, name: deferred.frame.name, serverOutcome: serverResult.outcome, mediaPlaneOutcome: result.outcome });
2716
+ this.#emit();
2717
+ }
2718
+ #scheduleLiveRetry(operationId, retry, delay = this.#options.retryDelayMs ?? 100) {
2719
+ const timer = this.#clock().setTimeout(() => {
2720
+ this.#liveRetryTimers.delete(operationId);
2721
+ retry();
2722
+ }, delay);
2723
+ this.#liveRetryTimers.set(operationId, timer);
2724
+ }
2725
+ #failLiveTarget(operationId, deferred, error) {
2726
+ this.#liveTargets.delete(operationId);
2727
+ this.#clearLiveRetryTimer(operationId);
2728
+ this.#clearLiveDeadlineTimer(operationId);
2729
+ this.#localMedia[deferred.source] = "failed";
2730
+ rejectDeferred(deferred, error);
2731
+ this.#emit();
2732
+ }
2733
+ #requestResult(frame) {
2734
+ this.#requireLive();
2735
+ const deferred = this.#requests.get(frame.request_id);
2736
+ if (!deferred) return;
2737
+ this.#requests.delete(frame.request_id);
2738
+ resolveDeferred(deferred, frame);
2739
+ }
2740
+ #directedRequest(frame) {
2741
+ this.#requireLive();
2742
+ if (frame.expires_at_ms <= this.#now()) return;
2743
+ this.#send({ type: "request_ack", request_id: frame.request_id });
2744
+ for (const listener of this.#requestListeners) listener(frame);
2745
+ }
2746
+ #reactionResult(frame) {
2747
+ this.#requireLive();
2748
+ this.#requireCollaborationNegotiated();
2749
+ const deferred = this.#reactions.get(frame.operation_id);
2750
+ if (!deferred) return;
2751
+ this.#reactions.delete(frame.operation_id);
2752
+ if (frame.outcome === "accepted") {
2753
+ resolveDeferred(deferred, reactionFromFrame(frame.reaction));
2754
+ } else {
2755
+ rejectDeferred(deferred, new V1SyncError(frame.error_code, frame.error_code));
2756
+ }
2757
+ }
2758
+ #chatSendResult(frame) {
2759
+ this.#requireLive();
2760
+ this.#requireCollaborationNegotiated();
2761
+ const deferred = this.#chatSends.get(frame.client_message_id);
2762
+ if (!deferred) return;
2763
+ this.#chatSends.delete(frame.client_message_id);
2764
+ if (frame.outcome === "accepted") {
2765
+ this.#assertChatMessageVersion(frame.message);
2766
+ const message = chatMessageFromFrame(frame.message);
2767
+ this.#rememberChatSequence(message.sequence);
2768
+ resolveDeferred(deferred, message);
2769
+ } else {
2770
+ rejectDeferred(deferred, new V1SyncError(frame.error_code, frame.error_code));
2771
+ }
2772
+ }
2773
+ #chatPageResult(frame) {
2774
+ this.#requireCollaborationNegotiated();
2775
+ const deferred = this.#chatPages.get(frame.request_id);
2776
+ if (!deferred) return;
2777
+ this.#chatPages.delete(frame.request_id);
2778
+ if (frame.outcome === "cursor_reset") {
2779
+ this.#collaboration = { ...this.#collaboration, retainedFloorSequence: frame.retained_floor_sequence };
2780
+ const result = { status: "cursor_reset", retainedFloorSequence: frame.retained_floor_sequence };
2781
+ this.#emitCollaboration({ type: "chat_cursor_reset", retainedFloorSequence: frame.retained_floor_sequence });
2782
+ resolveDeferred(deferred, result);
2783
+ return;
2784
+ }
2785
+ this.#collaboration = {
2786
+ ...this.#collaboration,
2787
+ chatHeadSequence: frame.head_sequence,
2788
+ retainedFloorSequence: frame.retained_floor_sequence
2789
+ };
2790
+ for (const message of frame.messages) {
2791
+ this.#assertChatMessageVersion(message);
2792
+ this.#observeChatMessage(message);
2793
+ }
2794
+ resolveDeferred(deferred, { status: "loaded", count: frame.messages.length, hasOlder: frame.has_more });
2795
+ }
2796
+ #observeChatMessage(frame) {
2797
+ this.#assertChatMessageVersion(frame);
2798
+ const message = chatMessageFromFrame(frame);
2799
+ this.#rememberChatSequence(message.sequence);
2800
+ this.#emitCollaboration({ type: "chat_message", message });
2801
+ }
2802
+ #chatReadResult(frame) {
2803
+ this.#requireLive();
2804
+ this.#requireCollaborationVersion(1);
2805
+ const deferred = this.#chatReads.get(frame.request_id);
2806
+ if (!deferred) return;
2807
+ this.#chatReads.delete(frame.request_id);
2808
+ if (frame.outcome === "accepted") {
2809
+ const receipt = chatReadReceiptFromFrame(frame);
2810
+ this.#rememberChatReadReceipt(receipt);
2811
+ resolveDeferred(deferred, receipt);
2812
+ } else {
2813
+ rejectDeferred(deferred, new V1SyncError(frame.error_code, frame.error_code));
2814
+ }
2815
+ }
2816
+ #assertChatMessageVersion(frame) {
2817
+ const version = this.#collaboration.version;
2818
+ if (version === 1 && !("attachments" in frame)) throw new V1ReplicaError("collaboration_v1 received a chat message without attachments");
2819
+ }
2820
+ #rememberChatReadReceipt(receipt) {
2821
+ const existing = this.#collaboration.readReceipts.find((candidate) => candidate.participantId === receipt.participantId && candidate.participantGeneration === receipt.participantGeneration);
2822
+ if (existing && compareUnsignedDecimals(existing.readThroughSequence, receipt.readThroughSequence) >= 0) return;
2823
+ this.#collaboration = {
2824
+ ...this.#collaboration,
2825
+ readReceipts: [...this.#collaboration.readReceipts.filter((candidate) => candidate.participantId !== receipt.participantId || candidate.participantGeneration !== receipt.participantGeneration), receipt]
2826
+ };
2827
+ }
2828
+ #rememberChatSequence(sequence) {
2829
+ if (this.#chatAfterSequence === null || compareUnsignedDecimals(sequence, this.#chatAfterSequence) > 0) this.#chatAfterSequence = sequence;
2830
+ if (this.#collaboration.chatHeadSequence === null || compareUnsignedDecimals(sequence, this.#collaboration.chatHeadSequence) > 0) {
2831
+ this.#collaboration = { ...this.#collaboration, chatHeadSequence: sequence };
2832
+ }
2833
+ }
2834
+ #emitCollaboration(event) {
2835
+ for (const listener of this.#collaborationListeners) listener(event);
2836
+ }
2837
+ async #finishCommand(commandId, result) {
2838
+ const deferred = this.#commands.get(commandId);
2839
+ if (!deferred) return;
2840
+ this.#commands.delete(commandId);
2841
+ this.#clearCommandRetryTimer(commandId);
2842
+ this.#acknowledgements.delete(commandId);
2843
+ let pending;
2844
+ if (deferred.durableTarget) {
2845
+ pending = this.#pendingTargets.get(commandId);
2846
+ this.#pendingTargets.delete(commandId);
2847
+ if (pending) this.#pendingRemovals.set(commandId, pending);
2848
+ }
2849
+ if (result.outcome === "rejected" || result.outcome === "command_id_conflict") rejectDeferred(deferred, new V1SyncError(result.reason, result.outcome));
2850
+ else resolveDeferred(deferred, result);
2851
+ this.#emit();
2852
+ if (pending) void this.#removePersistedTarget(commandId, pending);
2853
+ }
2854
+ #enterLiveIfReady() {
2855
+ if (!this.#recovery?.controlComplete || !this.#media || !this.#presence) return;
2856
+ this.#recovery = null;
2857
+ this.#phase = { phase: "live" };
2858
+ this.#missedHeartbeats = 0;
2859
+ for (const pending of this.#commands.values()) {
2860
+ pending.retries = 0;
2861
+ this.#send(pending.frame);
2862
+ }
2863
+ for (const pending of this.#liveTargets.values()) {
2864
+ pending.serverRetries = 0;
2865
+ if (pending.serverResult) this.#executeLocalMediaTarget(pending.frame.operation_id, pending);
2866
+ else this.#send(pending.frame);
2867
+ }
2868
+ this.#startHeartbeat();
2869
+ this.#emit();
2870
+ }
2871
+ #ackRecovery() {
2872
+ const recovery = this.#requireRecovery();
2873
+ const control = this.#requireControl();
2874
+ this.#send({ type: "recovery_ack", recovery_id: recovery.id, revision: control.revision, state_digest: control.stateDigest });
2875
+ }
2876
+ #restorePending(pending) {
2877
+ if (this.#pendingTargets.size + this.#pendingRemovals.size >= this.#maxPending() || this.#now() - pending.createdAt > (this.#options.maxPendingAgeMs ?? MAX_PENDING_AGE_MS) || this.#pendingBytes() + pending.bytes > (this.#options.maxPendingBytes ?? MAX_PENDING_BYTES)) {
2878
+ void this.#removePersistedTarget(pending.commandId, pending);
2879
+ return;
2880
+ }
2881
+ const frame = { type: "command", command_id: pending.commandId, name: pending.command.name, payload: pending.command.payload };
2882
+ encodeV1ClientFrame(frame);
2883
+ this.#pendingTargets.set(pending.commandId, pending);
2884
+ this.#commands.set(pending.commandId, { resolve: () => void 0, reject: () => void 0, settled: true, frame, retries: 0, durableTarget: true, createdAt: pending.createdAt });
2885
+ }
2886
+ async #removePersistedTarget(commandId, pending) {
2887
+ this.#pendingRemovals.set(commandId, pending);
2888
+ try {
2889
+ await this.#store.remove(commandId);
2890
+ if (this.#pendingRemovals.get(commandId) !== pending) return;
2891
+ this.#pendingRemovals.delete(commandId);
2892
+ this.#clearPendingRemovalRetryTimer(commandId);
2893
+ } catch {
2894
+ if (this.#pendingRemovals.get(commandId) !== pending) return;
2895
+ this.#schedulePendingRemovalRetry(commandId, pending);
2896
+ }
2897
+ }
2898
+ #schedulePendingRemovalRetry(commandId, pending) {
2899
+ if (!this.#started || this.#pendingRemovalRetryTimers.has(commandId)) return;
2900
+ const timer = this.#clock().setTimeout(() => {
2901
+ this.#pendingRemovalRetryTimers.delete(commandId);
2902
+ void this.#removePersistedTarget(commandId, pending);
2903
+ }, this.#options.retryDelayMs ?? 100);
2904
+ this.#pendingRemovalRetryTimers.set(commandId, timer);
2905
+ }
2906
+ #ackHeadIsProven(ack) {
2907
+ return this.#controlHeads.get(ack.revision) === ack.state_digest;
2908
+ }
2909
+ #rememberControlHead(revision, digest) {
2910
+ this.#controlHeads.set(revision, digest);
2911
+ if (this.#controlHeads.size <= MAX_REPLAY_EVENTS) return;
2912
+ const oldest = this.#controlHeads.keys().next().value;
2913
+ if (oldest !== void 0) this.#controlHeads.delete(oldest);
2914
+ }
2915
+ #rememberControlEvent(event) {
2916
+ rememberBoundedEvidence(this.#controlEvents, event.revision, frameSignature(event), MAX_REPLAY_EVENTS);
2917
+ }
2918
+ #acceptProjectionDuplicate(projection, evidence, frame) {
2919
+ if (!projection || frame.projection_id !== projection.projectionId || frame.sequence > projection.sequence) return false;
2920
+ if (evidence.get(frame.sequence) !== frameSignature(frame)) throw new V1ReplicaError("conflicting or unprovable duplicate projection event");
2921
+ return true;
2922
+ }
2923
+ #disconnected(socket) {
2924
+ if (socket !== this.#socket) return;
2925
+ this.#socket = null;
2926
+ this.#recovery = null;
2927
+ this.#clearHeartbeat();
2928
+ this.#clearRetryTimers();
2929
+ this.#media = null;
2930
+ this.#presence = null;
2931
+ this.#rejectRequests("disconnected_before_delivery");
2932
+ this.#rejectCollaboration("disconnected_before_delivery");
2933
+ this.#collaboration = { ...this.#collaboration, negotiated: false, version: null, capabilities: [], readReceipts: [] };
2934
+ this.#participantCollaborationCapabilities = {};
2935
+ if (!this.#started || !this.#transportAvailable || this.#phase.phase === "terminal") return;
2936
+ this.#phase = { phase: "connecting" };
2937
+ this.#emit();
2938
+ this.#clearReconnect();
2939
+ this.#reconnectTimer = this.#clock().setTimeout(() => {
2940
+ this.#reconnectTimer = void 0;
2941
+ this.#connect();
2942
+ }, this.#options.reconnectDelayMs ?? 250);
2943
+ }
2944
+ #recover(reason) {
2945
+ const socket = this.#socket;
2946
+ if (!socket) return;
2947
+ socket.close(CLIENT_RESTART_CLOSE_CODE, reason);
2948
+ this.#disconnected(socket);
2949
+ }
2950
+ #handleLifecycle(event) {
2951
+ if (event === "online" || event === "offline") this.#online = event === "online";
2952
+ else this.#active = event === "active";
2953
+ this.#transportAvailable = this.#online && this.#active;
2954
+ if (!this.#transportAvailable) this.#socket?.close(CLIENT_RESTART_CLOSE_CODE, "lifecycle unavailable");
2955
+ else this.#connect();
2956
+ }
2957
+ #rejectEphemeral(code) {
2958
+ this.#rejectRequests(code);
2959
+ for (const deferred of this.#liveTargets.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2960
+ this.#liveTargets.clear();
2961
+ }
2962
+ #rejectCollaboration(code) {
2963
+ for (const deferred of this.#reactions.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2964
+ for (const deferred of this.#chatSends.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2965
+ for (const deferred of this.#chatPages.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2966
+ for (const deferred of this.#chatReads.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2967
+ this.#reactions.clear();
2968
+ this.#chatSends.clear();
2969
+ this.#chatPages.clear();
2970
+ this.#chatReads.clear();
2971
+ }
2972
+ #rejectRequests(code) {
2973
+ for (const deferred of this.#requests.values()) rejectDeferred(deferred, new V1SyncError(code, code));
2974
+ this.#requests.clear();
2975
+ }
2976
+ #sendIfLive(frame) {
2977
+ if (this.#phase.phase === "live") this.#send(frame);
2978
+ }
2979
+ #send(frame) {
2980
+ this.#socket?.send(encodeV1ClientFrame(frame));
2981
+ }
2982
+ #requireLive() {
2983
+ if (this.#phase.phase !== "live") throw new V1ReplicaError("live frame arrived before four-stream recovery completed");
2984
+ }
2985
+ #requireCollaborationNegotiated() {
2986
+ if (!this.#collaboration.negotiated) throw new V1ReplicaError("collaboration frame arrived without a negotiated extension");
2987
+ }
2988
+ #requireCollaborationVersion(version) {
2989
+ this.#requireCollaborationNegotiated();
2990
+ if (this.#collaboration.version !== version) throw new V1ReplicaError(`collaboration_v1 frame arrived on a different extension version`);
2991
+ }
2992
+ #requireControl() {
2993
+ if (!this.#control) throw new V1ReplicaError("control replica is unavailable");
2994
+ return this.#control;
2995
+ }
2996
+ #requireRecovery() {
2997
+ if (!this.#recovery || this.#phase.phase !== "recovering") throw new V1ReplicaError("recovery frame arrived outside recovery");
2998
+ return this.#recovery;
2999
+ }
3000
+ #assertCapacity() {
3001
+ if (this.#commands.size + this.#pendingRemovals.size + this.#reservedCommandIds.size + this.#liveTargets.size + this.#requests.size >= this.#maxPending()) throw new V1SyncError("in-flight request capacity exceeded", "capacity");
3002
+ }
3003
+ #assertCollaborationReady(capability) {
3004
+ if (!this.#collaboration.negotiated) throw new V1SyncError("collaboration is unavailable", "collaboration_unavailable");
3005
+ if (this.#phase.phase !== "live") throw new V1SyncError("collaboration requires a live connection", "not_live");
3006
+ if (capability && !this.#collaboration.capabilities.includes(capability)) throw new V1SyncError("collaboration capability denied", "capability_denied");
3007
+ }
3008
+ #assertCollaborationCapacity() {
3009
+ const maximum = Math.min(this.#options.maxPendingCollaborationRequests ?? MAX_COLLABORATION_REQUESTS_IN_FLIGHT, MAX_COLLABORATION_REQUESTS_IN_FLIGHT);
3010
+ if (this.#reactions.size + this.#chatSends.size + this.#chatPages.size + this.#chatReads.size >= maximum) throw new V1SyncError("collaboration in-flight capacity exceeded", "capacity");
3011
+ }
3012
+ #assertCollaborationRequestIdAvailable(id) {
3013
+ if (this.#reactions.has(id) || this.#chatSends.has(id) || this.#chatPages.has(id) || this.#chatReads.has(id)) throw new V1SyncError("collaboration request ID is already pending", "request_id_conflict");
3014
+ }
3015
+ #nextCollaborationRequestId() {
3016
+ const id = this.#nextRequestId();
3017
+ this.#assertCollaborationRequestIdAvailable(id);
3018
+ return id;
3019
+ }
3020
+ #maxPending() {
3021
+ return Math.min(this.#options.maxPendingCommands ?? MAX_IN_FLIGHT, MAX_IN_FLIGHT);
3022
+ }
3023
+ #pendingBytes() {
3024
+ return [...this.#pendingTargets.values(), ...this.#pendingRemovals.values()].reduce((total, pending) => total + pending.bytes, 0);
3025
+ }
3026
+ #nextCommandId() {
3027
+ return this.#options.ids?.next() ?? crypto.randomUUID();
3028
+ }
3029
+ #nextRequestId() {
3030
+ return this.#options.requestIds?.next() ?? crypto.randomUUID();
3031
+ }
3032
+ #clock() {
3033
+ return this.#options.clock ?? {
3034
+ now: Date.now,
3035
+ setTimeout: (callback, milliseconds) => globalThis.setTimeout(callback, milliseconds),
3036
+ clearTimeout: (handle) => globalThis.clearTimeout(handle)
3037
+ };
3038
+ }
3039
+ #now() {
3040
+ return this.#clock().now();
3041
+ }
3042
+ #clearReconnect() {
3043
+ if (this.#reconnectTimer === void 0) return;
3044
+ this.#clock().clearTimeout(this.#reconnectTimer);
3045
+ this.#reconnectTimer = void 0;
3046
+ }
3047
+ #subscribeMediaPlane(mediaPlane) {
3048
+ if (!mediaPlane) return;
3049
+ try {
3050
+ this.#unsubscribeLocalMedia = mediaPlane.observeLocalPublications((publications) => this.#replaceMediaPlanePublications("local", publications));
3051
+ this.#unsubscribeRemoteMedia = mediaPlane.observeRemotePublications((publications) => this.#replaceMediaPlanePublications("remote", publications));
3052
+ } catch {
3053
+ this.#unsubscribeMediaPlane();
3054
+ this.#started = false;
3055
+ throw new V1SyncError("unable to observe the client MediaPlane", "media_plane_unavailable");
3056
+ }
3057
+ }
3058
+ #unsubscribeMediaPlane() {
3059
+ this.#unsubscribeLocalMedia?.();
3060
+ this.#unsubscribeRemoteMedia?.();
3061
+ this.#unsubscribeLocalMedia = void 0;
3062
+ this.#unsubscribeRemoteMedia = void 0;
3063
+ }
3064
+ #replaceMediaPlanePublications(kind, publications) {
3065
+ if (publications.length > SyncProtocolLimits.projectionMaxItems || !publications.every(validMediaPublication)) return;
3066
+ const copy = publications.map(copyPublication);
3067
+ if (kind === "local") {
3068
+ this.#localPublications = copy;
3069
+ this.#updateLocalMediaStates();
3070
+ } else {
3071
+ this.#remotePublications = copy;
3072
+ }
3073
+ this.#emit();
3074
+ }
3075
+ #updateLocalMediaStates() {
3076
+ if (!this.#participantId) return;
3077
+ for (const source of ["microphone", "camera", "screen"]) {
3078
+ const publication = this.#localPublications.find((candidate) => candidate.source === source && candidate.participantId === this.#participantId);
3079
+ this.#localMedia[source] = publication?.enabled ? "enabled" : "disabled";
3080
+ }
3081
+ }
3082
+ #clearRetryTimers() {
3083
+ for (const timer of this.#commandRetryTimers.values()) this.#clock().clearTimeout(timer);
3084
+ for (const timer of this.#liveRetryTimers.values()) this.#clock().clearTimeout(timer);
3085
+ for (const timer of this.#liveDeadlineTimers.values()) this.#clock().clearTimeout(timer);
3086
+ this.#commandRetryTimers.clear();
3087
+ this.#liveRetryTimers.clear();
3088
+ this.#liveDeadlineTimers.clear();
3089
+ }
3090
+ #clearPendingRemovalRetryTimers() {
3091
+ for (const timer of this.#pendingRemovalRetryTimers.values()) this.#clock().clearTimeout(timer);
3092
+ this.#pendingRemovalRetryTimers.clear();
3093
+ }
3094
+ #clearPendingRemovalRetryTimer(commandId) {
3095
+ const timer = this.#pendingRemovalRetryTimers.get(commandId);
3096
+ if (timer === void 0) return;
3097
+ this.#clock().clearTimeout(timer);
3098
+ this.#pendingRemovalRetryTimers.delete(commandId);
3099
+ }
3100
+ #clearLiveRetryTimer(operationId) {
3101
+ const timer = this.#liveRetryTimers.get(operationId);
3102
+ if (timer === void 0) return;
3103
+ this.#clock().clearTimeout(timer);
3104
+ this.#liveRetryTimers.delete(operationId);
3105
+ }
3106
+ #clearLiveDeadlineTimer(operationId) {
3107
+ const timer = this.#liveDeadlineTimers.get(operationId);
3108
+ if (timer === void 0) return;
3109
+ this.#clock().clearTimeout(timer);
3110
+ this.#liveDeadlineTimers.delete(operationId);
3111
+ }
3112
+ #clearCommandRetryTimer(commandId) {
3113
+ const timer = this.#commandRetryTimers.get(commandId);
3114
+ if (timer === void 0) return;
3115
+ this.#clock().clearTimeout(timer);
3116
+ this.#commandRetryTimers.delete(commandId);
3117
+ }
3118
+ #startHeartbeat() {
3119
+ this.#clearHeartbeat();
3120
+ this.#heartbeatTimer = this.#clock().setTimeout(() => {
3121
+ this.#heartbeatTimer = void 0;
3122
+ if (this.#phase.phase !== "live") return;
3123
+ this.#missedHeartbeats += 1;
3124
+ if (this.#missedHeartbeats > 2) {
3125
+ this.#socket?.close(CLIENT_RESTART_CLOSE_CODE, "heartbeat timeout");
3126
+ return;
3127
+ }
3128
+ this.#send({ type: "ping" });
3129
+ this.#startHeartbeat();
3130
+ }, 2e4);
3131
+ }
3132
+ #clearHeartbeat() {
3133
+ if (this.#heartbeatTimer === void 0) return;
3134
+ this.#clock().clearTimeout(this.#heartbeatTimer);
3135
+ this.#heartbeatTimer = void 0;
3136
+ }
3137
+ #emit() {
3138
+ const snapshot = this.getSnapshot();
3139
+ for (const listener of this.#listeners) listener(snapshot);
3140
+ }
3141
+ };
3142
+ function updateProjection(projection, projectionId, sequence, item, key) {
3143
+ if (!projection || projection.projectionId !== projectionId) throw new V1ReplicaError("projection event has no matching replace snapshot");
3144
+ if (sequence !== projection.sequence + 1) throw new V1ReplicaError("projection event is not exact-next");
3145
+ const itemKey = key(item);
3146
+ return { projectionId, sequence, items: [...projection.items.filter((candidate) => key(candidate) !== itemKey), item] };
3147
+ }
3148
+ function mediaItem(item) {
3149
+ return { participantId: item.participant_id, source: item.source, enabled: item.enabled, publicationId: item.publication_id };
3150
+ }
3151
+ function presenceItem(item) {
3152
+ return { participantId: item.participant_id, state: item.state, speaking: item.speaking, activeSpeaker: item.active_speaker };
3153
+ }
3154
+ function mediaKey(item) {
3155
+ return `${item.participantId}:${item.source}`;
3156
+ }
3157
+ function sameHead(control, head) {
3158
+ return control !== null && control.revision === head.revision && control.stateSchemaVersion === head.state_schema_version && control.stateDigest === head.state_digest;
3159
+ }
3160
+ function sameRawHead(left, right) {
3161
+ return left.revision === right.revision && left.state_schema_version === right.state_schema_version && left.state_digest === right.state_digest;
3162
+ }
3163
+ function copyProjection(projection) {
3164
+ return projection && { ...projection, items: projection.items.map((item) => ({ ...item })) };
3165
+ }
3166
+ function frameSignature(frame) {
3167
+ return new TextDecoder().decode(canonicalJsonBytesFromUnknown(frame));
3168
+ }
3169
+ function copyCollaborationCapabilities(capabilities) {
3170
+ return Object.fromEntries(Object.entries(capabilities).map(([participantId, values]) => [participantId, [...values]]));
3171
+ }
3172
+ function chatReadReceiptFromWire(receipt) {
3173
+ return {
3174
+ participantId: receipt.participant_id,
3175
+ participantGeneration: receipt.participant_generation,
3176
+ readThroughSequence: receipt.sequence,
3177
+ readAt: receipt.read_at
3178
+ };
3179
+ }
3180
+ function compareUnsignedDecimals(left, right) {
3181
+ if (left.length !== right.length) return left.length - right.length;
3182
+ return left.localeCompare(right);
3183
+ }
3184
+ function rememberBoundedEvidence(evidence, sequence, signature, capacity) {
3185
+ evidence.set(sequence, signature);
3186
+ if (evidence.size <= capacity) return;
3187
+ const oldest = evidence.keys().next().value;
3188
+ if (oldest !== void 0) evidence.delete(oldest);
3189
+ }
3190
+ function resolveDeferred(deferred, value) {
3191
+ if (deferred.settled) return;
3192
+ deferred.settled = true;
3193
+ deferred.resolve(value);
3194
+ }
3195
+ function rejectDeferred(deferred, error) {
3196
+ if (deferred.settled) return;
3197
+ deferred.settled = true;
3198
+ deferred.reject(error);
3199
+ }
3200
+ function copyPublication(publication) {
3201
+ return { ...publication };
3202
+ }
3203
+ function validMediaPublication(publication) {
3204
+ return typeof publication.participantId === "string" && publication.participantId.length > 0 && (publication.source === "microphone" || publication.source === "camera" || publication.source === "screen") && typeof publication.enabled === "boolean" && (publication.publicationId === null || typeof publication.publicationId === "string") && publication.enabled === (publication.publicationId !== null);
3205
+ }
3206
+ function validMediaPlaneResult(result) {
3207
+ return (result.outcome === "confirmed" || result.outcome === "satisfied" || result.outcome === "retryable_failure" || result.outcome === "terminal_failure" || result.outcome === "ambiguous") && (result.errorCode === null || typeof result.errorCode === "string");
3208
+ }
3209
+ function isTerminalLifecycleOperation(frame) {
3210
+ return frame.type === "operation" && (frame.name === "participant_leave" || frame.name === "end_episode");
3211
+ }
3212
+ function assertV1Url(value) {
3213
+ const url = new URL(value);
3214
+ if (url.pathname !== "/v1/sync") throw new V1SyncError("SyncEngine v1 websocket URL must use /v1/sync", "invalid_url");
3215
+ }
3216
+
3217
+ // src/sync/v1-platform-persistence.ts
3218
+ var STORE_NAME = "pending_targets";
3219
+ var SCOPE_INDEX = "by_scope";
3220
+ var STORAGE_PREFIX = "chalk-sync-v1:pending-targets:";
3221
+ var IndexedDbV1PendingTargetStore = class {
3222
+ #scope;
3223
+ #databaseName;
3224
+ #indexedDb;
3225
+ #database;
3226
+ constructor(options) {
3227
+ if (!options.scope) throw new Error("v1 pending-target scope must not be empty");
3228
+ this.#scope = options.scope;
3229
+ this.#databaseName = options.databaseName ?? "chalk-sync-v1";
3230
+ this.#indexedDb = options.indexedDb ?? globalThis.indexedDB;
3231
+ }
3232
+ async load() {
3233
+ const database = await this.#open();
3234
+ const transaction = database.transaction(STORE_NAME, "readonly");
3235
+ const records = await requestResult(transaction.objectStore(STORE_NAME).index(SCOPE_INDEX).getAll(this.#scope));
3236
+ await transactionComplete(transaction);
3237
+ return records.filter(isPendingTarget).map(copyPendingTarget);
3238
+ }
3239
+ async put(command) {
3240
+ const database = await this.#open();
3241
+ const transaction = database.transaction(STORE_NAME, "readwrite");
3242
+ transaction.objectStore(STORE_NAME).put({ scope: this.#scope, ...copyPendingTarget(command) });
3243
+ await transactionComplete(transaction);
3244
+ }
3245
+ async remove(commandId) {
3246
+ const database = await this.#open();
3247
+ const transaction = database.transaction(STORE_NAME, "readwrite");
3248
+ transaction.objectStore(STORE_NAME).delete([this.#scope, commandId]);
3249
+ await transactionComplete(transaction);
3250
+ }
3251
+ #open() {
3252
+ this.#database ??= openDatabase(this.#indexedDb, this.#databaseName);
3253
+ return this.#database;
3254
+ }
3255
+ };
3256
+ var AsyncStorageV1PendingTargetStore = class {
3257
+ #storage;
3258
+ #key;
3259
+ #operations = Promise.resolve();
3260
+ constructor(options) {
3261
+ if (!options.scope) throw new Error("v1 pending-target scope must not be empty");
3262
+ this.#storage = options.storage;
3263
+ this.#key = `${STORAGE_PREFIX}${options.scope}`;
3264
+ }
3265
+ load() {
3266
+ return this.#enqueue(async () => this.#read());
3267
+ }
3268
+ put(command) {
3269
+ return this.#enqueue(async () => {
3270
+ const commands = await this.#read();
3271
+ const next = [...commands.filter((candidate) => candidate.commandId !== command.commandId), copyPendingTarget(command)];
3272
+ await this.#write(next);
3273
+ });
3274
+ }
3275
+ remove(commandId) {
3276
+ return this.#enqueue(async () => this.#write((await this.#read()).filter((command) => command.commandId !== commandId)));
3277
+ }
3278
+ #enqueue(operation) {
3279
+ const result = this.#operations.then(operation, operation);
3280
+ this.#operations = result.then(
3281
+ () => void 0,
3282
+ () => void 0
3283
+ );
3284
+ return result;
3285
+ }
3286
+ async #read() {
3287
+ const stored = await this.#storage.getItem(this.#key);
3288
+ if (stored === null) return [];
3289
+ const value = JSON.parse(stored);
3290
+ if (!Array.isArray(value)) throw new Error("v1 pending-target storage is invalid");
3291
+ return value.filter(isPendingTarget).map(copyPendingTarget);
3292
+ }
3293
+ async #write(commands) {
3294
+ if (commands.length === 0) {
3295
+ await this.#storage.removeItem(this.#key);
3296
+ return;
3297
+ }
3298
+ await this.#storage.setItem(this.#key, JSON.stringify(commands.map(copyPendingTarget)));
3299
+ }
3300
+ };
3301
+ function isPendingTarget(value) {
3302
+ if (!isRecord(value) || typeof value.commandId !== "string" || typeof value.createdAt !== "number" || typeof value.bytes !== "number" || !isTargetCommand(value.command)) return false;
3303
+ try {
3304
+ encodeV1ClientFrame({ type: "command", command_id: value.commandId, name: value.command.name, payload: value.command.payload });
3305
+ return Number.isSafeInteger(value.createdAt) && value.createdAt >= 0 && Number.isSafeInteger(value.bytes) && value.bytes > 0;
3306
+ } catch {
3307
+ return false;
3308
+ }
3309
+ }
3310
+ function isTargetCommand(value) {
3311
+ return isRecord(value) && typeof value.name === "string" && isRecord(value.payload) && ["set_hand_raised", "set_display_name", "set_admission_policy", "assign_roles"].includes(value.name);
3312
+ }
3313
+ function copyPendingTarget(command) {
3314
+ return structuredClone(command);
3315
+ }
3316
+ function isRecord(value) {
3317
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3318
+ }
3319
+ function openDatabase(indexedDb, name) {
3320
+ if (!indexedDb) return Promise.reject(new Error("IndexedDB is unavailable"));
3321
+ return new Promise((resolve, reject) => {
3322
+ const request = indexedDb.open(name, 1);
3323
+ request.onupgradeneeded = () => {
3324
+ const store = request.result.createObjectStore(STORE_NAME, { keyPath: ["scope", "commandId"] });
3325
+ store.createIndex(SCOPE_INDEX, "scope", { unique: false });
3326
+ };
3327
+ request.onsuccess = () => resolve(request.result);
3328
+ request.onerror = () => reject(new Error("unable to open v1 pending-target storage"));
3329
+ request.onblocked = () => reject(new Error("v1 pending-target storage is blocked"));
3330
+ });
3331
+ }
3332
+ function requestResult(request) {
3333
+ return new Promise((resolve, reject) => {
3334
+ request.onsuccess = () => resolve(request.result);
3335
+ request.onerror = () => reject(new Error("v1 pending-target request failed"));
3336
+ });
3337
+ }
3338
+ function transactionComplete(transaction) {
3339
+ return new Promise((resolve, reject) => {
3340
+ transaction.oncomplete = () => resolve();
3341
+ transaction.onerror = () => reject(new Error("v1 pending-target transaction failed"));
3342
+ transaction.onabort = () => reject(new Error("v1 pending-target transaction aborted"));
3343
+ });
3344
+ }
3345
+
3346
+ // src/sync/v1-create.ts
3347
+ function createV1SyncClient(options) {
3348
+ const { indexedDb, lifecycle, mediaPlane, pendingStore, persistenceScope, webSocket, ...clientOptions } = options;
3349
+ return new V1SyncClient({
3350
+ ...clientOptions,
3351
+ lifecycle: lifecycle ?? createBrowserSyncLifecycle(),
3352
+ mediaPlane,
3353
+ pendingStore: pendingStore ?? (persistenceScope ? new IndexedDbV1PendingTargetStore({ ...indexedDb, scope: persistenceScope }) : void 0),
3354
+ webSocket: webSocket ?? createBrowserWebSocketFactory()
3355
+ });
3356
+ }
3357
+
3358
+ export {
3359
+ canonicalJson,
3360
+ canonicalJsonBytes,
3361
+ SyncBrowserCapabilityError,
3362
+ SyncReactNativeCapabilityError,
3363
+ createBrowserWebSocketFactory,
3364
+ createBrowserSyncLifecycle,
3365
+ createReactNativeWebSocketFactory,
3366
+ createReactNativeSyncLifecycle,
3367
+ reactionFromFrame,
3368
+ chatMessageFromFrame,
3369
+ chatReadReceiptFromFrame,
3370
+ encodeV1ClientFrame,
3371
+ decodeV1ServerFrame,
3372
+ decodeV1ClientFrame,
3373
+ InMemoryV1PendingTargetStore,
3374
+ V1ReplicaError,
3375
+ restoreV1Snapshot,
3376
+ applyV1Event,
3377
+ optimisticV1Control,
3378
+ assertV1ControlSemantics,
3379
+ computeV1StateDigest,
3380
+ V1SyncError,
3381
+ V1SyncClient,
3382
+ IndexedDbV1PendingTargetStore,
3383
+ AsyncStorageV1PendingTargetStore,
3384
+ createV1SyncClient
3385
+ };