on-zero 0.4.25 → 0.4.27

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 (140) hide show
  1. package/dist/cjs/createUseQuery.cjs +28 -16
  2. package/dist/cjs/createUseQuery.native.js +42 -30
  3. package/dist/cjs/createUseQuery.native.js.map +1 -1
  4. package/dist/cjs/createZeroClient.cjs +13 -1
  5. package/dist/cjs/createZeroClient.native.js +13 -1
  6. package/dist/cjs/createZeroClient.native.js.map +1 -1
  7. package/dist/cjs/httpPull/auth.test.cjs +197 -0
  8. package/dist/cjs/httpPull/auth.test.native.js +279 -0
  9. package/dist/cjs/httpPull/auth.test.native.js.map +1 -0
  10. package/dist/cjs/httpPull/churn.test.cjs +132 -0
  11. package/dist/cjs/httpPull/churn.test.native.js +155 -0
  12. package/dist/cjs/httpPull/churn.test.native.js.map +1 -0
  13. package/dist/cjs/httpPull/fixtureSchema.cjs +76 -0
  14. package/dist/cjs/httpPull/fixtureSchema.native.js +82 -0
  15. package/dist/cjs/httpPull/fixtureSchema.native.js.map +1 -0
  16. package/dist/cjs/httpPull/fixtureServer.cjs +340 -0
  17. package/dist/cjs/httpPull/fixtureServer.native.js +534 -0
  18. package/dist/cjs/httpPull/fixtureServer.native.js.map +1 -0
  19. package/dist/cjs/httpPull/integration.test.cjs +53 -0
  20. package/dist/cjs/httpPull/integration.test.native.js +60 -0
  21. package/dist/cjs/httpPull/integration.test.native.js.map +1 -0
  22. package/dist/cjs/httpPull/rebase.test.cjs +360 -0
  23. package/dist/cjs/httpPull/rebase.test.native.js +420 -0
  24. package/dist/cjs/httpPull/rebase.test.native.js.map +1 -0
  25. package/dist/cjs/httpPull/relations.test.cjs +107 -0
  26. package/dist/cjs/httpPull/relations.test.native.js +119 -0
  27. package/dist/cjs/httpPull/relations.test.native.js.map +1 -0
  28. package/dist/cjs/httpPull/testHarness.cjs +100 -0
  29. package/dist/cjs/httpPull/testHarness.native.js +112 -0
  30. package/dist/cjs/httpPull/testHarness.native.js.map +1 -0
  31. package/dist/cjs/httpPull/transport.test.cjs +568 -0
  32. package/dist/cjs/httpPull/transport.test.native.js +655 -0
  33. package/dist/cjs/httpPull/transport.test.native.js.map +1 -0
  34. package/dist/cjs/httpPullTransport.cjs +432 -0
  35. package/dist/cjs/httpPullTransport.native.js +695 -0
  36. package/dist/cjs/httpPullTransport.native.js.map +1 -0
  37. package/dist/cjs/index.cjs +1 -0
  38. package/dist/cjs/index.native.js +1 -0
  39. package/dist/cjs/index.native.js.map +1 -1
  40. package/dist/cjs/multiInstanceNested.test.cjs +26 -0
  41. package/dist/cjs/multiInstanceNested.test.native.js +34 -0
  42. package/dist/cjs/multiInstanceNested.test.native.js.map +1 -1
  43. package/dist/esm/createUseQuery.mjs +28 -16
  44. package/dist/esm/createUseQuery.mjs.map +1 -1
  45. package/dist/esm/createUseQuery.native.js +42 -30
  46. package/dist/esm/createUseQuery.native.js.map +1 -1
  47. package/dist/esm/createZeroClient.mjs +13 -1
  48. package/dist/esm/createZeroClient.mjs.map +1 -1
  49. package/dist/esm/createZeroClient.native.js +13 -1
  50. package/dist/esm/createZeroClient.native.js.map +1 -1
  51. package/dist/esm/httpPull/auth.test.mjs +198 -0
  52. package/dist/esm/httpPull/auth.test.mjs.map +1 -0
  53. package/dist/esm/httpPull/auth.test.native.js +277 -0
  54. package/dist/esm/httpPull/auth.test.native.js.map +1 -0
  55. package/dist/esm/httpPull/churn.test.mjs +133 -0
  56. package/dist/esm/httpPull/churn.test.mjs.map +1 -0
  57. package/dist/esm/httpPull/churn.test.native.js +153 -0
  58. package/dist/esm/httpPull/churn.test.native.js.map +1 -0
  59. package/dist/esm/httpPull/fixtureSchema.mjs +50 -0
  60. package/dist/esm/httpPull/fixtureSchema.mjs.map +1 -0
  61. package/dist/esm/httpPull/fixtureSchema.native.js +53 -0
  62. package/dist/esm/httpPull/fixtureSchema.native.js.map +1 -0
  63. package/dist/esm/httpPull/fixtureServer.mjs +315 -0
  64. package/dist/esm/httpPull/fixtureServer.mjs.map +1 -0
  65. package/dist/esm/httpPull/fixtureServer.native.js +506 -0
  66. package/dist/esm/httpPull/fixtureServer.native.js.map +1 -0
  67. package/dist/esm/httpPull/integration.test.mjs +54 -0
  68. package/dist/esm/httpPull/integration.test.mjs.map +1 -0
  69. package/dist/esm/httpPull/integration.test.native.js +58 -0
  70. package/dist/esm/httpPull/integration.test.native.js.map +1 -0
  71. package/dist/esm/httpPull/rebase.test.mjs +361 -0
  72. package/dist/esm/httpPull/rebase.test.mjs.map +1 -0
  73. package/dist/esm/httpPull/rebase.test.native.js +418 -0
  74. package/dist/esm/httpPull/rebase.test.native.js.map +1 -0
  75. package/dist/esm/httpPull/relations.test.mjs +108 -0
  76. package/dist/esm/httpPull/relations.test.mjs.map +1 -0
  77. package/dist/esm/httpPull/relations.test.native.js +117 -0
  78. package/dist/esm/httpPull/relations.test.native.js.map +1 -0
  79. package/dist/esm/httpPull/testHarness.mjs +72 -0
  80. package/dist/esm/httpPull/testHarness.mjs.map +1 -0
  81. package/dist/esm/httpPull/testHarness.native.js +81 -0
  82. package/dist/esm/httpPull/testHarness.native.js.map +1 -0
  83. package/dist/esm/httpPull/transport.test.mjs +569 -0
  84. package/dist/esm/httpPull/transport.test.mjs.map +1 -0
  85. package/dist/esm/httpPull/transport.test.native.js +653 -0
  86. package/dist/esm/httpPull/transport.test.native.js.map +1 -0
  87. package/dist/esm/httpPullTransport.mjs +406 -0
  88. package/dist/esm/httpPullTransport.mjs.map +1 -0
  89. package/dist/esm/httpPullTransport.native.js +666 -0
  90. package/dist/esm/httpPullTransport.native.js.map +1 -0
  91. package/dist/esm/index.js +1 -0
  92. package/dist/esm/index.js.map +1 -1
  93. package/dist/esm/index.mjs +1 -0
  94. package/dist/esm/index.mjs.map +1 -1
  95. package/dist/esm/index.native.js +1 -0
  96. package/dist/esm/index.native.js.map +1 -1
  97. package/dist/esm/multiInstanceNested.test.mjs +27 -1
  98. package/dist/esm/multiInstanceNested.test.mjs.map +1 -1
  99. package/dist/esm/multiInstanceNested.test.native.js +35 -1
  100. package/dist/esm/multiInstanceNested.test.native.js.map +1 -1
  101. package/package.json +2 -2
  102. package/src/createUseQuery.tsx +40 -22
  103. package/src/createZeroClient.tsx +19 -0
  104. package/src/httpPull/auth.test.ts +208 -0
  105. package/src/httpPull/churn.test.ts +147 -0
  106. package/src/httpPull/fixtureSchema.ts +82 -0
  107. package/src/httpPull/fixtureServer.ts +391 -0
  108. package/src/httpPull/integration.test.ts +57 -0
  109. package/src/httpPull/rebase.test.ts +368 -0
  110. package/src/httpPull/relations.test.ts +135 -0
  111. package/src/httpPull/testHarness.ts +95 -0
  112. package/src/httpPull/transport.test.ts +577 -0
  113. package/src/httpPullTransport.ts +559 -0
  114. package/src/index.ts +1 -0
  115. package/src/multiInstanceNested.test.tsx +25 -1
  116. package/types/createUseQuery.d.ts.map +1 -1
  117. package/types/createZeroClient.d.ts +3 -1
  118. package/types/createZeroClient.d.ts.map +1 -1
  119. package/types/httpPull/auth.test.d.ts +2 -0
  120. package/types/httpPull/auth.test.d.ts.map +1 -0
  121. package/types/httpPull/churn.test.d.ts +2 -0
  122. package/types/httpPull/churn.test.d.ts.map +1 -0
  123. package/types/httpPull/fixtureSchema.d.ts +111 -0
  124. package/types/httpPull/fixtureSchema.d.ts.map +1 -0
  125. package/types/httpPull/fixtureServer.d.ts +14 -0
  126. package/types/httpPull/fixtureServer.d.ts.map +1 -0
  127. package/types/httpPull/integration.test.d.ts +2 -0
  128. package/types/httpPull/integration.test.d.ts.map +1 -0
  129. package/types/httpPull/rebase.test.d.ts +2 -0
  130. package/types/httpPull/rebase.test.d.ts.map +1 -0
  131. package/types/httpPull/relations.test.d.ts +2 -0
  132. package/types/httpPull/relations.test.d.ts.map +1 -0
  133. package/types/httpPull/testHarness.d.ts +32 -0
  134. package/types/httpPull/testHarness.d.ts.map +1 -0
  135. package/types/httpPull/transport.test.d.ts +2 -0
  136. package/types/httpPull/transport.test.d.ts.map +1 -0
  137. package/types/httpPullTransport.d.ts +13 -0
  138. package/types/httpPullTransport.d.ts.map +1 -0
  139. package/types/index.d.ts +1 -0
  140. package/types/index.d.ts.map +1 -1
@@ -0,0 +1,432 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all) __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: () => from[key],
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
21
+ value: true
22
+ }), mod);
23
+ var httpPullTransport_exports = {};
24
+ __export(httpPullTransport_exports, {
25
+ ensureHttpPullTransport: () => ensureHttpPullTransport,
26
+ installHttpPullTransport: () => installHttpPullTransport
27
+ });
28
+ module.exports = __toCommonJS(httpPullTransport_exports);
29
+ const COOKIE_WIDTH = 20;
30
+ function installHttpPullTransport(opts) {
31
+ const previousWebSocket = globalThis.WebSocket;
32
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
33
+ if (!fetchImpl) {
34
+ throw new Error("installHttpPullTransport requires a fetch implementation");
35
+ }
36
+ const state = {
37
+ origin: new URL(opts.origin),
38
+ originString: trimTrailingSlash(new URL(opts.origin).toString()),
39
+ fetch: fetchImpl,
40
+ nativeWebSocket: previousWebSocket,
41
+ sockets: /* @__PURE__ */new Set(),
42
+ pullIntervalMs: opts.pullIntervalMs,
43
+ nextPokeID: 0
44
+ };
45
+ const Shim = class {
46
+ static CONNECTING = 0;
47
+ static OPEN = 1;
48
+ static CLOSING = 2;
49
+ static CLOSED = 3;
50
+ constructor(url, protocols) {
51
+ if (shouldIntercept(state.origin, url)) {
52
+ return new ZeroHttpSocket(state, url, protocols);
53
+ }
54
+ if (!state.nativeWebSocket) {
55
+ throw new Error(`No native WebSocket available for ${String(url)}`);
56
+ }
57
+ return new state.nativeWebSocket(url, protocols);
58
+ }
59
+ };
60
+ globalThis.WebSocket = Shim;
61
+ return {
62
+ pull: async () => {
63
+ await Promise.all([...state.sockets].map(socket => socket.pull()));
64
+ },
65
+ get connections() {
66
+ return state.sockets.size;
67
+ },
68
+ uninstall: () => {
69
+ if (globalThis.WebSocket === Shim) {
70
+ globalThis.WebSocket = previousWebSocket;
71
+ }
72
+ }
73
+ };
74
+ }
75
+ const transportsByOrigin = /* @__PURE__ */new Map();
76
+ function ensureHttpPullTransport(opts) {
77
+ const key = trimTrailingSlash(new URL(opts.origin).toString());
78
+ const existing = transportsByOrigin.get(key);
79
+ if (existing) return existing;
80
+ const transport = installHttpPullTransport(opts);
81
+ transportsByOrigin.set(key, transport);
82
+ return transport;
83
+ }
84
+ class ZeroHttpSocket {
85
+ constructor(state, url, protocols) {
86
+ this.state = state;
87
+ this.connectURL = toHttpURL(url);
88
+ this.url = String(url);
89
+ this.clientID = this.connectURL.searchParams.get("clientID") ?? "";
90
+ this.clientGroupID = this.connectURL.searchParams.get("clientGroupID") ?? "";
91
+ this.wsid = this.connectURL.searchParams.get("wsid") ?? `zero-http-${Date.now()}`;
92
+ const baseCookie = this.connectURL.searchParams.get("baseCookie");
93
+ this.cookie = baseCookie ? baseCookie : null;
94
+ const decoded = decodeSecProtocol(protocols);
95
+ this.authToken = decoded.authToken;
96
+ this.queueDesiredQueries(decoded.initConnectionMessage?.[1]);
97
+ this.state.sockets.add(this);
98
+ this.openTimer = setTimeout(() => this.open(), 0);
99
+ }
100
+ CONNECTING = 0;
101
+ OPEN = 1;
102
+ CLOSING = 2;
103
+ CLOSED = 3;
104
+ url;
105
+ readyState = this.CONNECTING;
106
+ connectURL;
107
+ authToken;
108
+ listeners = {
109
+ open: /* @__PURE__ */new Set(),
110
+ message: /* @__PURE__ */new Set(),
111
+ close: /* @__PURE__ */new Set(),
112
+ error: /* @__PURE__ */new Set()
113
+ };
114
+ clientID;
115
+ clientGroupID;
116
+ wsid;
117
+ cookie;
118
+ pendingGotQueriesPatch = [];
119
+ pullInFlight;
120
+ pullAfterCurrent = false;
121
+ pushChain = Promise.resolve();
122
+ nextLocalCookieID = 0;
123
+ openTimer;
124
+ pullTimer;
125
+ addEventListener(type, listener) {
126
+ if (listener) this.listeners[type]?.add(listener);
127
+ }
128
+ removeEventListener(type, listener) {
129
+ if (listener) this.listeners[type]?.delete(listener);
130
+ }
131
+ dispatchEvent(event) {
132
+ this.emit(event.type, event);
133
+ return true;
134
+ }
135
+ send(data) {
136
+ if (this.readyState !== this.OPEN) {
137
+ throw new Error("cannot send on a socket that is not open");
138
+ }
139
+ const message = JSON.parse(data);
140
+ switch (message[0]) {
141
+ case "initConnection":
142
+ case "changeDesiredQueries":
143
+ this.queueDesiredQueries(message[1]);
144
+ this.requestPullAfterCurrent();
145
+ return;
146
+ case "updateAuth":
147
+ this.authToken = message[1].auth;
148
+ return;
149
+ case "push":
150
+ this.enqueuePush(message[1]);
151
+ return;
152
+ case "ping":
153
+ this.emitMessage(["pong", {}]);
154
+ return;
155
+ case "pull":
156
+ this.run(this.answerMutationRecoveryPull(message[1]));
157
+ return;
158
+ case "deleteClients":
159
+ case "ackMutationResponses":
160
+ return;
161
+ default:
162
+ throw new Error(`unsupported zero-http upstream message ${message[0]}`);
163
+ }
164
+ }
165
+ close(code = 1e3, reason = "") {
166
+ if (this.readyState === this.CLOSED) return;
167
+ if (this.openTimer) clearTimeout(this.openTimer);
168
+ if (this.pullTimer) clearInterval(this.pullTimer);
169
+ this.readyState = this.CLOSED;
170
+ this.state.sockets.delete(this);
171
+ this.emit("close", {
172
+ code,
173
+ reason,
174
+ wasClean: code <= 1001
175
+ });
176
+ }
177
+ pull() {
178
+ if (this.readyState === this.CLOSED) return Promise.resolve();
179
+ if (this.pullInFlight) return this.pullInFlight;
180
+ this.pullInFlight = this.fetchPull(this.clientGroupID, this.cookie).then(response => {
181
+ if (response.unchanged) {
182
+ this.emitGotQueriesPatch(response.cookie);
183
+ return;
184
+ }
185
+ this.emitPoke(response);
186
+ }).catch(error => {
187
+ this.fail(error);
188
+ throw error;
189
+ }).finally(async () => {
190
+ const pullAgain = this.pullAfterCurrent;
191
+ this.pullAfterCurrent = false;
192
+ this.pullInFlight = void 0;
193
+ if (pullAgain && this.readyState !== this.CLOSED) await this.pull();
194
+ });
195
+ return this.pullInFlight;
196
+ }
197
+ open() {
198
+ if (this.readyState !== this.CONNECTING) return;
199
+ this.readyState = this.OPEN;
200
+ this.emit("open", {});
201
+ this.emitMessage(["connected", {
202
+ wsid: this.wsid,
203
+ timestamp: Date.now()
204
+ }]);
205
+ setTimeout(() => this.run(this.pull()), 0);
206
+ if (this.state.pullIntervalMs) {
207
+ this.pullTimer = setInterval(() => {
208
+ this.run(this.pull());
209
+ }, this.state.pullIntervalMs);
210
+ }
211
+ }
212
+ queueDesiredQueries(body) {
213
+ const desiredQueriesPatch = body?.desiredQueriesPatch;
214
+ if (!Array.isArray(desiredQueriesPatch)) return;
215
+ this.pendingGotQueriesPatch.push(...gotQueriesPatch(desiredQueriesPatch));
216
+ }
217
+ async push(body) {
218
+ const response = await this.postJSON("/push", body);
219
+ this.emitMessage(["pushResponse", response.pushResponse]);
220
+ this.requestPullAfterCurrent();
221
+ }
222
+ enqueuePush(body) {
223
+ const nextPush = this.pushChain.then(async () => {
224
+ if (this.readyState === this.CLOSED) return;
225
+ await this.push(body);
226
+ });
227
+ this.pushChain = nextPush.catch(() => {});
228
+ this.run(nextPush);
229
+ }
230
+ requestPullAfterCurrent() {
231
+ if (this.pullInFlight) {
232
+ this.pullAfterCurrent = true;
233
+ return;
234
+ }
235
+ this.run(this.pull());
236
+ }
237
+ async answerMutationRecoveryPull(body) {
238
+ const response = await this.fetchPull(body.clientGroupID, body.cookie);
239
+ const cookie = toWebSocketCookie(response.cookie);
240
+ this.emitMessage(["pull", {
241
+ requestID: body.requestID,
242
+ cookie: cookie ?? this.cookie ?? "0",
243
+ lastMutationIDChanges: response.unchanged ? {} : response.lastMutationIDChanges
244
+ }]);
245
+ }
246
+ async fetchPull(clientGroupID, cookie) {
247
+ return await this.postJSON("/pull", {
248
+ clientID: this.clientID,
249
+ clientGroupID,
250
+ cookie: toHttpCookie(cookie)
251
+ });
252
+ }
253
+ async postJSON(path, body) {
254
+ const response = await this.state.fetch(`${this.state.originString}${path}`, {
255
+ method: "POST",
256
+ headers: {
257
+ authorization: this.authToken ? `Bearer ${this.authToken}` : "",
258
+ "content-type": "application/json"
259
+ },
260
+ body: JSON.stringify(body)
261
+ });
262
+ if (!response.ok) {
263
+ throw new ZeroHttpResponseError(path, response.status);
264
+ }
265
+ return response.json();
266
+ }
267
+ run(promise) {
268
+ void promise.catch(error => this.fail(error));
269
+ }
270
+ fail(error) {
271
+ if (this.readyState === this.CLOSED) return;
272
+ if (isAuthHTTPError(error)) {
273
+ this.emitMessage(["error", {
274
+ kind: "Unauthorized",
275
+ message: error.message,
276
+ origin: "server"
277
+ }]);
278
+ if (this.readyState !== this.CLOSED) this.close(1e3, error.message);
279
+ return;
280
+ }
281
+ this.emit("error", {
282
+ error
283
+ });
284
+ this.close(1011, errorMessage(error));
285
+ }
286
+ emitPoke(response) {
287
+ const nextCookie = toWebSocketCookie(response.cookie);
288
+ if (isStaleCookie(this.cookie, response.cookie)) {
289
+ throw new Error(`zero-http pull returned stale cookie ${response.cookie} for ${this.cookie}`);
290
+ }
291
+ const pokeID = `zero-http-${++this.state.nextPokeID}`;
292
+ const gotQueries = this.pendingGotQueriesPatch;
293
+ this.pendingGotQueriesPatch = [];
294
+ this.emitMessage(["pokeStart", {
295
+ pokeID,
296
+ baseCookie: this.cookie,
297
+ schemaVersions: {
298
+ minSupportedVersion: 1,
299
+ maxSupportedVersion: 1
300
+ },
301
+ timestamp: Date.now()
302
+ }]);
303
+ this.emitMessage(["pokePart", {
304
+ pokeID,
305
+ lastMutationIDChanges: response.lastMutationIDChanges,
306
+ rowsPatch: response.rowsPatch
307
+ }]);
308
+ if (gotQueries.length > 0) {
309
+ this.emitMessage(["pokePart", {
310
+ pokeID,
311
+ gotQueriesPatch: gotQueries
312
+ }]);
313
+ }
314
+ this.emitMessage(["pokeEnd", {
315
+ pokeID,
316
+ cookie: nextCookie
317
+ }]);
318
+ this.cookie = nextCookie;
319
+ }
320
+ emitGotQueriesPatch(cookie) {
321
+ if (this.pendingGotQueriesPatch.length === 0) return;
322
+ const serverCookie = cookie ?? toHttpCookie(this.cookie);
323
+ if (serverCookie === null) return;
324
+ const nextCookie = toLocalWebSocketCookie(serverCookie, ++this.nextLocalCookieID);
325
+ const pokeID = `zero-http-${++this.state.nextPokeID}`;
326
+ const gotQueries = this.pendingGotQueriesPatch;
327
+ this.pendingGotQueriesPatch = [];
328
+ this.emitMessage(["pokeStart", {
329
+ pokeID,
330
+ baseCookie: this.cookie,
331
+ schemaVersions: {
332
+ minSupportedVersion: 1,
333
+ maxSupportedVersion: 1
334
+ },
335
+ timestamp: Date.now()
336
+ }]);
337
+ this.emitMessage(["pokePart", {
338
+ pokeID,
339
+ gotQueriesPatch: gotQueries
340
+ }]);
341
+ this.emitMessage(["pokeEnd", {
342
+ pokeID,
343
+ cookie: nextCookie
344
+ }]);
345
+ this.cookie = nextCookie;
346
+ }
347
+ emitMessage(message) {
348
+ if (this.readyState !== this.OPEN) return;
349
+ this.emit("message", {
350
+ data: JSON.stringify(message)
351
+ });
352
+ }
353
+ emit(type, event) {
354
+ const handler = this[`on${type}`];
355
+ if (typeof handler === "function") handler.call(this, event);
356
+ for (const listener of this.listeners[type]) {
357
+ if (typeof listener === "function") listener(event);else listener.handleEvent(event);
358
+ }
359
+ }
360
+ }
361
+ function shouldIntercept(origin, url) {
362
+ const candidate = toHttpURL(url);
363
+ if (candidate.origin !== origin.origin) return false;
364
+ return candidate.pathname === `${trimTrailingSlash(origin.pathname)}/sync/v51/connect`;
365
+ }
366
+ function toHttpURL(url) {
367
+ const parsed = new URL(url);
368
+ if (parsed.protocol === "ws:") parsed.protocol = "http:";
369
+ if (parsed.protocol === "wss:") parsed.protocol = "https:";
370
+ return parsed;
371
+ }
372
+ function trimTrailingSlash(value) {
373
+ return value.endsWith("/") ? value.slice(0, -1) : value;
374
+ }
375
+ function decodeSecProtocol(protocols) {
376
+ const protocol = Array.isArray(protocols) ? protocols[0] : protocols;
377
+ if (!protocol) return {};
378
+ try {
379
+ const decoded = decodeURIComponent(protocol);
380
+ const json = new TextDecoder().decode(Uint8Array.from(globalThis.atob(decoded), char => char.charCodeAt(0)));
381
+ const parsed = JSON.parse(json);
382
+ return {
383
+ authToken: parsed.authToken,
384
+ initConnectionMessage: Array.isArray(parsed.initConnectionMessage) ? parsed.initConnectionMessage : void 0
385
+ };
386
+ } catch {
387
+ return {};
388
+ }
389
+ }
390
+ function gotQueriesPatch(patch) {
391
+ const got = [];
392
+ for (const op of patch) {
393
+ if (op.op === "clear") got.push({
394
+ op: "clear"
395
+ });else if (op.hash) got.push({
396
+ op: op.op,
397
+ hash: op.hash
398
+ });
399
+ }
400
+ return got;
401
+ }
402
+ function toHttpCookie(cookie) {
403
+ if (cookie === null || cookie === "") return null;
404
+ const parsed = Number(cookie.slice(0, COOKIE_WIDTH));
405
+ if (!Number.isFinite(parsed)) {
406
+ throw new Error(`zero-http cookie is not numeric: ${cookie}`);
407
+ }
408
+ return parsed;
409
+ }
410
+ function toWebSocketCookie(cookie) {
411
+ return cookie === null ? null : String(cookie).padStart(COOKIE_WIDTH, "0");
412
+ }
413
+ function toLocalWebSocketCookie(cookie, localID) {
414
+ return `${String(cookie).padStart(COOKIE_WIDTH, "0")}#${String(localID).padStart(6, "0")}`;
415
+ }
416
+ function isStaleCookie(current, next) {
417
+ const currentNumber = toHttpCookie(current);
418
+ return currentNumber !== null && next <= currentNumber;
419
+ }
420
+ function errorMessage(error) {
421
+ return error instanceof Error ? error.message : String(error);
422
+ }
423
+ class ZeroHttpResponseError extends Error {
424
+ constructor(path, status) {
425
+ super(`zero-http ${path} failed with ${status}`);
426
+ this.path = path;
427
+ this.status = status;
428
+ }
429
+ }
430
+ function isAuthHTTPError(error) {
431
+ return error instanceof ZeroHttpResponseError && (error.status === 401 || error.status === 403);
432
+ }