on-zero 0.6.3 → 0.6.4
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.
- package/dist/cjs/createZeroClient.cjs +91 -12
- package/dist/cjs/createZeroClient.connection.test.cjs +163 -0
- package/dist/cjs/createZeroClient.connection.test.native.js +242 -0
- package/dist/cjs/createZeroClient.connection.test.native.js.map +1 -0
- package/dist/cjs/createZeroClient.native.js +99 -12
- package/dist/cjs/createZeroClient.native.js.map +1 -1
- package/dist/cjs/createZeroClient.recovery.test.cjs +52 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js +52 -0
- package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.cjs +140 -14
- package/dist/cjs/helpers/recoverZeroClient.native.js +155 -22
- package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/cjs/helpers/recoverZeroClient.test.cjs +181 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js +209 -0
- package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.native.js +1 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/multi.cjs +13 -0
- package/dist/cjs/multi.native.js +35 -0
- package/dist/cjs/multi.native.js.map +1 -1
- package/dist/cjs/multiPartition.test.cjs +42 -0
- package/dist/cjs/multiPartition.test.native.js +51 -0
- package/dist/cjs/multiPartition.test.native.js.map +1 -0
- package/dist/esm/createZeroClient.connection.test.mjs +164 -0
- package/dist/esm/createZeroClient.connection.test.mjs.map +1 -0
- package/dist/esm/createZeroClient.connection.test.native.js +240 -0
- package/dist/esm/createZeroClient.connection.test.native.js.map +1 -0
- package/dist/esm/createZeroClient.mjs +92 -13
- package/dist/esm/createZeroClient.mjs.map +1 -1
- package/dist/esm/createZeroClient.native.js +100 -13
- package/dist/esm/createZeroClient.native.js.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.mjs +52 -0
- package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
- package/dist/esm/createZeroClient.recovery.test.native.js +52 -0
- package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.mjs +140 -15
- package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.native.js +155 -23
- package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.mjs +182 -1
- package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
- package/dist/esm/helpers/recoverZeroClient.test.native.js +210 -1
- package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/multi.mjs +13 -1
- package/dist/esm/multi.mjs.map +1 -1
- package/dist/esm/multi.native.js +35 -1
- package/dist/esm/multi.native.js.map +1 -1
- package/dist/esm/multiPartition.test.mjs +43 -0
- package/dist/esm/multiPartition.test.mjs.map +1 -0
- package/dist/esm/multiPartition.test.native.js +49 -0
- package/dist/esm/multiPartition.test.native.js.map +1 -0
- package/lint/ssr-guards.js +164 -0
- package/package.json +2 -2
- package/readme.md +126 -0
- package/src/createZeroClient.connection.test.tsx +162 -0
- package/src/createZeroClient.recovery.test.tsx +68 -0
- package/src/createZeroClient.tsx +159 -13
- package/src/helpers/recoverZeroClient.test.ts +204 -1
- package/src/helpers/recoverZeroClient.ts +263 -42
- package/src/index.ts +3 -0
- package/src/multi.ts +33 -0
- package/src/multiPartition.test.ts +38 -0
- package/types/createZeroClient.connection.test.d.ts +5 -0
- package/types/createZeroClient.connection.test.d.ts.map +1 -0
- package/types/createZeroClient.d.ts +17 -0
- package/types/createZeroClient.d.ts.map +1 -1
- package/types/createZeroServer.d.ts +4 -4
- package/types/helpers/recoverZeroClient.d.ts +15 -1
- package/types/helpers/recoverZeroClient.d.ts.map +1 -1
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/multi.d.ts +1 -0
- package/types/multi.d.ts.map +1 -1
- package/types/multiPartition.test.d.ts +2 -0
- package/types/multiPartition.test.d.ts.map +1 -0
|
@@ -211,6 +211,14 @@ function createZeroClientInternal({
|
|
|
211
211
|
const usePermission = createUsePermission(useQuery);
|
|
212
212
|
const usePermissionDirect = createUsePermission(useQueryDirect);
|
|
213
213
|
let cachedZero = null;
|
|
214
|
+
const REMINT_GUARD_MS = 12e3;
|
|
215
|
+
const REMINT_MAX_ATTEMPTS = 5;
|
|
216
|
+
const REMINT_ATTEMPT_RESET_MS = 6e4;
|
|
217
|
+
const remintControl = {
|
|
218
|
+
bump: null
|
|
219
|
+
};
|
|
220
|
+
let lastRemintAt = 0;
|
|
221
|
+
let remintAttempts = 0;
|
|
214
222
|
function invalidateZeroInstance(instanceToInvalidate) {
|
|
215
223
|
if (!instanceToInvalidate) return;
|
|
216
224
|
if (cachedZero?.instance === instanceToInvalidate) {
|
|
@@ -233,6 +241,26 @@ function createZeroClientInternal({
|
|
|
233
241
|
invalidateZeroInstance(instanceToDelete);
|
|
234
242
|
}
|
|
235
243
|
}
|
|
244
|
+
async function remint(opts = {}) {
|
|
245
|
+
if (!remintControl.bump) return false;
|
|
246
|
+
const now = Date.now();
|
|
247
|
+
const sinceLast = now - lastRemintAt;
|
|
248
|
+
if (lastRemintAt > 0 && sinceLast < REMINT_GUARD_MS) return false;
|
|
249
|
+
if (sinceLast > REMINT_ATTEMPT_RESET_MS) remintAttempts = 0;
|
|
250
|
+
if (remintAttempts >= REMINT_MAX_ATTEMPTS) return false;
|
|
251
|
+
lastRemintAt = now;
|
|
252
|
+
remintAttempts += 1;
|
|
253
|
+
const {
|
|
254
|
+
dropLocalState = true
|
|
255
|
+
} = opts;
|
|
256
|
+
if (dropLocalState && latestZeroInstance) {
|
|
257
|
+
await deleteZeroInstance(latestZeroInstance).catch(() => {});
|
|
258
|
+
}
|
|
259
|
+
const bump = remintControl.bump;
|
|
260
|
+
if (!bump) return false;
|
|
261
|
+
bump();
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
236
264
|
const DISABLED_ZERO_STUB_CONNECTION_STATE = {
|
|
237
265
|
current: {
|
|
238
266
|
name: "closed"
|
|
@@ -266,6 +294,11 @@ function createZeroClientInternal({
|
|
|
266
294
|
transport,
|
|
267
295
|
pullIntervalMs = 3e4,
|
|
268
296
|
beforeReload,
|
|
297
|
+
scheduleReload,
|
|
298
|
+
guardStorage,
|
|
299
|
+
benignLogFilter,
|
|
300
|
+
refreshAuth,
|
|
301
|
+
connectionDataset,
|
|
269
302
|
disable,
|
|
270
303
|
...props
|
|
271
304
|
}) => {
|
|
@@ -287,10 +320,17 @@ function createZeroClientInternal({
|
|
|
287
320
|
can: permissionsHelpers.can
|
|
288
321
|
});
|
|
289
322
|
}, []);
|
|
323
|
+
const [remintGeneration, setRemintGeneration] = (0, import_react2.useState)(0);
|
|
324
|
+
(0, import_react2.useEffect)(() => {
|
|
325
|
+
remintControl.bump = () => setRemintGeneration(generation => generation + 1);
|
|
326
|
+
return () => {
|
|
327
|
+
remintControl.bump = null;
|
|
328
|
+
};
|
|
329
|
+
}, []);
|
|
290
330
|
const instanceKey = JSON.stringify([Object.entries({
|
|
291
331
|
kvStore: "mem",
|
|
292
332
|
...props
|
|
293
|
-
}).filter(([key, value]) => key !== "auth" && typeof value !== "function" && value !== void 0).sort(([a], [b]) => a < b ? -1 : 1), hasAuth, transport]);
|
|
333
|
+
}).filter(([key, value]) => key !== "auth" && typeof value !== "function" && value !== void 0).sort(([a], [b]) => a < b ? -1 : 1), hasAuth, transport, remintGeneration]);
|
|
294
334
|
const [instance2, setInstance] = (0, import_react2.useState)();
|
|
295
335
|
(0, import_react2.useEffect)(() => {
|
|
296
336
|
if (disable) {
|
|
@@ -317,7 +357,10 @@ function createZeroClientInternal({
|
|
|
317
357
|
const recoveryDeps = {
|
|
318
358
|
deleteLocalState: () => deleteZeroInstance(instanceRef.current),
|
|
319
359
|
zeroEvents,
|
|
320
|
-
beforeReload
|
|
360
|
+
beforeReload,
|
|
361
|
+
scheduleReload,
|
|
362
|
+
guardStorage,
|
|
363
|
+
benignLogFilter
|
|
321
364
|
};
|
|
322
365
|
const recovery = (0, import_recoverZeroClient.makeZeroRecovery)(recoveryDeps);
|
|
323
366
|
const createdInstance = new import_zero.Zero({
|
|
@@ -365,7 +408,10 @@ function createZeroClientInternal({
|
|
|
365
408
|
children: /* @__PURE__ */(0, import_jsx_runtime.jsxs)(import_react.ZeroContext.Provider, {
|
|
366
409
|
value: liveInstance ?? DISABLED_ZERO_STUB,
|
|
367
410
|
children: [liveInstance ? /* @__PURE__ */(0, import_jsx_runtime.jsx)(SetZeroInstance, {}) : null, liveInstance ? /* @__PURE__ */(0, import_jsx_runtime.jsx)(ConnectionMonitor, {
|
|
368
|
-
zeroEvents
|
|
411
|
+
zeroEvents,
|
|
412
|
+
refreshAuth,
|
|
413
|
+
exposeDataset: connectionDataset,
|
|
414
|
+
datasetCacheUrl: connectionDataset ? props.cacheURL ?? props.server : void 0
|
|
369
415
|
}) : null, children]
|
|
370
416
|
})
|
|
371
417
|
})
|
|
@@ -386,23 +432,55 @@ function createZeroClientInternal({
|
|
|
386
432
|
return null;
|
|
387
433
|
};
|
|
388
434
|
const ConnectionMonitor = (0, import_react2.memo)(({
|
|
389
|
-
zeroEvents: zeroEvents2
|
|
435
|
+
zeroEvents: zeroEvents2,
|
|
436
|
+
refreshAuth,
|
|
437
|
+
exposeDataset,
|
|
438
|
+
datasetCacheUrl
|
|
390
439
|
}) => {
|
|
440
|
+
const zeroInstance = (0, import_react.useZero)();
|
|
391
441
|
const state = (0, import_react.useConnectionState)();
|
|
392
442
|
const prevState = (0, import_react2.useRef)(state.name);
|
|
443
|
+
const staleReconnectRef = (0, import_react2.useRef)(null);
|
|
444
|
+
const needsAuthRef = (0, import_react2.useRef)(false);
|
|
393
445
|
(0, import_react2.useEffect)(() => {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
446
|
+
const name = state.name;
|
|
447
|
+
const reason = "reason" in state && typeof state.reason === "string" ? state.reason : "";
|
|
448
|
+
if (exposeDataset && typeof document !== "undefined" && document.body) {
|
|
449
|
+
document.body.dataset.zeroState = name;
|
|
450
|
+
if (datasetCacheUrl) document.body.dataset.zeroCacheUrl = datasetCacheUrl;
|
|
451
|
+
if (reason) document.body.dataset.zeroReason = reason.slice(0, 200);else delete document.body.dataset.zeroReason;
|
|
452
|
+
if (name === "connected") document.body.dataset.zeroConnected = "true";else delete document.body.dataset.zeroConnected;
|
|
453
|
+
}
|
|
454
|
+
if (name === "error" && (0, import_recoverZeroClient.isRecoverableZeroStalePokeMessage)(reason)) {
|
|
455
|
+
if (staleReconnectRef.current !== reason) {
|
|
456
|
+
staleReconnectRef.current = reason;
|
|
457
|
+
void Promise.resolve(zeroInstance.connection?.connect?.()).catch(() => {});
|
|
458
|
+
}
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
if (name !== "error") staleReconnectRef.current = null;
|
|
462
|
+
if (name === "needs-auth") {
|
|
463
|
+
if (refreshAuth && !needsAuthRef.current) {
|
|
464
|
+
needsAuthRef.current = true;
|
|
465
|
+
void refreshAuth().then(token => {
|
|
466
|
+
if (token) zeroInstance.connection?.connect?.({
|
|
467
|
+
auth: token
|
|
468
|
+
});
|
|
469
|
+
}).catch(() => {});
|
|
470
|
+
}
|
|
471
|
+
} else {
|
|
472
|
+
needsAuthRef.current = false;
|
|
473
|
+
}
|
|
474
|
+
if (name !== prevState.current) {
|
|
475
|
+
prevState.current = name;
|
|
476
|
+
if (name === "error" || name === "needs-auth") {
|
|
399
477
|
zeroEvents2.emit({
|
|
400
478
|
type: "error",
|
|
401
|
-
message
|
|
479
|
+
message: reason || name
|
|
402
480
|
});
|
|
403
481
|
}
|
|
404
482
|
}
|
|
405
|
-
}, [state, zeroEvents2]);
|
|
483
|
+
}, [state, zeroEvents2, zeroInstance, refreshAuth, exposeDataset, datasetCacheUrl]);
|
|
406
484
|
return null;
|
|
407
485
|
});
|
|
408
486
|
function preload(fnArg, paramsOrOptions, optionsArg) {
|
|
@@ -445,6 +523,7 @@ function createZeroClientInternal({
|
|
|
445
523
|
usePermissionDirect,
|
|
446
524
|
zero,
|
|
447
525
|
preload,
|
|
448
|
-
getQuery
|
|
526
|
+
getQuery,
|
|
527
|
+
remint
|
|
449
528
|
};
|
|
450
529
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var import_zero = require("@rocicorp/zero");
|
|
2
|
+
var import_react = require("react");
|
|
3
|
+
var import_client = require("react-dom/client");
|
|
4
|
+
var import_vitest = require("vitest");
|
|
5
|
+
var import_createZeroClient = require("./createZeroClient.cjs");
|
|
6
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
const fakeZero = import_vitest.vi.hoisted(() => {
|
|
8
|
+
class FakeConnectionState {
|
|
9
|
+
current;
|
|
10
|
+
listeners = /* @__PURE__ */new Set();
|
|
11
|
+
constructor(initial) {
|
|
12
|
+
this.current = initial;
|
|
13
|
+
}
|
|
14
|
+
subscribe = cb => {
|
|
15
|
+
this.listeners.add(cb);
|
|
16
|
+
return () => {
|
|
17
|
+
this.listeners.delete(cb);
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
set(next) {
|
|
21
|
+
this.current = next;
|
|
22
|
+
for (const cb of this.listeners) cb();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class FakeZero {
|
|
26
|
+
context = {};
|
|
27
|
+
connection = {
|
|
28
|
+
state: new FakeConnectionState({
|
|
29
|
+
name: "connecting"
|
|
30
|
+
}),
|
|
31
|
+
connect: import_vitest.vi.fn(async () => {})
|
|
32
|
+
};
|
|
33
|
+
delete = import_vitest.vi.fn(async () => ({
|
|
34
|
+
errors: []
|
|
35
|
+
}));
|
|
36
|
+
close = import_vitest.vi.fn();
|
|
37
|
+
run = import_vitest.vi.fn(async () => []);
|
|
38
|
+
preload = import_vitest.vi.fn(() => ({
|
|
39
|
+
cleanup: () => {},
|
|
40
|
+
complete: Promise.resolve()
|
|
41
|
+
}));
|
|
42
|
+
constructor() {
|
|
43
|
+
instances.push(this);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const instances = [];
|
|
47
|
+
return {
|
|
48
|
+
FakeZero,
|
|
49
|
+
FakeConnectionState,
|
|
50
|
+
instances
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
import_vitest.vi.mock("@rocicorp/zero", async importOriginal => {
|
|
54
|
+
const actual = await importOriginal();
|
|
55
|
+
return {
|
|
56
|
+
...actual,
|
|
57
|
+
Zero: fakeZero.FakeZero
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
61
|
+
const noteTable = (0, import_zero.table)("note").columns({
|
|
62
|
+
id: (0, import_zero.string)(),
|
|
63
|
+
body: (0, import_zero.string)()
|
|
64
|
+
}).primaryKey("id");
|
|
65
|
+
const schema = (0, import_zero.createSchema)({
|
|
66
|
+
tables: [noteTable]
|
|
67
|
+
});
|
|
68
|
+
const client = (0, import_createZeroClient.createZeroClient)({
|
|
69
|
+
schema,
|
|
70
|
+
models: {},
|
|
71
|
+
groupedQueries: {},
|
|
72
|
+
instanceName: "connection-test"
|
|
73
|
+
});
|
|
74
|
+
let container;
|
|
75
|
+
let root;
|
|
76
|
+
(0, import_vitest.beforeEach)(() => {
|
|
77
|
+
fakeZero.instances.length = 0;
|
|
78
|
+
container = document.createElement("div");
|
|
79
|
+
root = null;
|
|
80
|
+
delete document.body.dataset.zeroState;
|
|
81
|
+
delete document.body.dataset.zeroConnected;
|
|
82
|
+
delete document.body.dataset.zeroReason;
|
|
83
|
+
});
|
|
84
|
+
(0, import_vitest.afterEach)(() => {
|
|
85
|
+
if (root) (0, import_react.act)(() => root?.unmount());
|
|
86
|
+
});
|
|
87
|
+
async function mount(extraProps = {}, userID = "conn") {
|
|
88
|
+
root = (0, import_client.createRoot)(container);
|
|
89
|
+
await (0, import_react.act)(async () => {
|
|
90
|
+
root?.render(/* @__PURE__ */(0, import_jsx_runtime.jsx)(client.ProvideZero, {
|
|
91
|
+
cacheURL: "http://127.0.0.1:7788/zero",
|
|
92
|
+
userID,
|
|
93
|
+
...extraProps,
|
|
94
|
+
children: /* @__PURE__ */(0, import_jsx_runtime.jsx)("span", {
|
|
95
|
+
children: "ok"
|
|
96
|
+
})
|
|
97
|
+
}));
|
|
98
|
+
await Promise.resolve();
|
|
99
|
+
});
|
|
100
|
+
return fakeZero.instances.at(-1);
|
|
101
|
+
}
|
|
102
|
+
(0, import_vitest.test)("refreshAuth reconnects in place on needs-auth, once per transition", async () => {
|
|
103
|
+
const refreshAuth = import_vitest.vi.fn(async () => "fresh-token");
|
|
104
|
+
const instance = await mount({
|
|
105
|
+
refreshAuth
|
|
106
|
+
}, "conn-auth");
|
|
107
|
+
await (0, import_react.act)(async () => {
|
|
108
|
+
instance.connection.state.set({
|
|
109
|
+
name: "needs-auth",
|
|
110
|
+
reason: "token expired"
|
|
111
|
+
});
|
|
112
|
+
await Promise.resolve();
|
|
113
|
+
});
|
|
114
|
+
(0, import_vitest.expect)(refreshAuth).toHaveBeenCalledTimes(1);
|
|
115
|
+
await (0, import_react.act)(async () => {
|
|
116
|
+
await Promise.resolve();
|
|
117
|
+
});
|
|
118
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledWith({
|
|
119
|
+
auth: "fresh-token"
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
(0, import_vitest.test)("stale-poke error reconnects instead of surfacing a fatal error", async () => {
|
|
123
|
+
const events = [];
|
|
124
|
+
const off = client.zeroEvents.listen(event => {
|
|
125
|
+
if (event) events.push(event);
|
|
126
|
+
});
|
|
127
|
+
const instance = await mount({}, "conn-stale");
|
|
128
|
+
await (0, import_react.act)(async () => {
|
|
129
|
+
instance.connection.state.set({
|
|
130
|
+
name: "error",
|
|
131
|
+
reason: "Server returned unexpected base cookie during sync"
|
|
132
|
+
});
|
|
133
|
+
await Promise.resolve();
|
|
134
|
+
});
|
|
135
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledTimes(1);
|
|
136
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledWith();
|
|
137
|
+
(0, import_vitest.expect)(events.some(event => event.type === "error")).toBe(false);
|
|
138
|
+
off();
|
|
139
|
+
});
|
|
140
|
+
(0, import_vitest.test)("connectionDataset mirrors connection state onto the body dataset", async () => {
|
|
141
|
+
const instance = await mount({
|
|
142
|
+
connectionDataset: true
|
|
143
|
+
}, "conn-dataset");
|
|
144
|
+
await (0, import_react.act)(async () => {
|
|
145
|
+
instance.connection.state.set({
|
|
146
|
+
name: "connected"
|
|
147
|
+
});
|
|
148
|
+
await Promise.resolve();
|
|
149
|
+
});
|
|
150
|
+
(0, import_vitest.expect)(document.body.dataset.zeroState).toBe("connected");
|
|
151
|
+
(0, import_vitest.expect)(document.body.dataset.zeroConnected).toBe("true");
|
|
152
|
+
(0, import_vitest.expect)(document.body.dataset.zeroCacheUrl).toBe("http://127.0.0.1:7788/zero");
|
|
153
|
+
await (0, import_react.act)(async () => {
|
|
154
|
+
instance.connection.state.set({
|
|
155
|
+
name: "error",
|
|
156
|
+
reason: "boom"
|
|
157
|
+
});
|
|
158
|
+
await Promise.resolve();
|
|
159
|
+
});
|
|
160
|
+
(0, import_vitest.expect)(document.body.dataset.zeroState).toBe("error");
|
|
161
|
+
(0, import_vitest.expect)(document.body.dataset.zeroConnected).toBeUndefined();
|
|
162
|
+
(0, import_vitest.expect)(document.body.dataset.zeroReason).toBe("boom");
|
|
163
|
+
});
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
4
|
+
var import_zero = require("@rocicorp/zero");
|
|
5
|
+
var import_react = require("react");
|
|
6
|
+
var import_client = require("react-dom/client");
|
|
7
|
+
var import_vitest = require("vitest");
|
|
8
|
+
var import_createZeroClient = require("./createZeroClient.native.js");
|
|
9
|
+
function _class_call_check(instance, Constructor) {
|
|
10
|
+
if (!(instance instanceof Constructor)) {
|
|
11
|
+
throw new TypeError("Cannot call a class as a function");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function _defineProperties(target, props) {
|
|
15
|
+
for (var i = 0; i < props.length; i++) {
|
|
16
|
+
var descriptor = props[i];
|
|
17
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
18
|
+
descriptor.configurable = true;
|
|
19
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
20
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
24
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
25
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
26
|
+
return Constructor;
|
|
27
|
+
}
|
|
28
|
+
function _define_property(obj, key, value) {
|
|
29
|
+
if (key in obj) {
|
|
30
|
+
Object.defineProperty(obj, key, {
|
|
31
|
+
value,
|
|
32
|
+
enumerable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
writable: true
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
obj[key] = value;
|
|
38
|
+
}
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
var fakeZero = import_vitest.vi.hoisted(function () {
|
|
42
|
+
var FakeConnectionState = /* @__PURE__ */function () {
|
|
43
|
+
"use strict";
|
|
44
|
+
|
|
45
|
+
function FakeConnectionState2(initial) {
|
|
46
|
+
var _this = this;
|
|
47
|
+
_class_call_check(this, FakeConnectionState2);
|
|
48
|
+
_define_property(this, "current", void 0);
|
|
49
|
+
_define_property(this, "listeners", /* @__PURE__ */new Set());
|
|
50
|
+
_define_property(this, "subscribe", function (cb) {
|
|
51
|
+
_this.listeners.add(cb);
|
|
52
|
+
return function () {
|
|
53
|
+
_this.listeners.delete(cb);
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
this.current = initial;
|
|
57
|
+
}
|
|
58
|
+
_create_class(FakeConnectionState2, [{
|
|
59
|
+
key: "set",
|
|
60
|
+
value: function set(next) {
|
|
61
|
+
this.current = next;
|
|
62
|
+
var _iteratorNormalCompletion = true,
|
|
63
|
+
_didIteratorError = false,
|
|
64
|
+
_iteratorError = void 0;
|
|
65
|
+
try {
|
|
66
|
+
for (var _iterator = this.listeners[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
|
67
|
+
var cb = _step.value;
|
|
68
|
+
cb();
|
|
69
|
+
}
|
|
70
|
+
} catch (err) {
|
|
71
|
+
_didIteratorError = true;
|
|
72
|
+
_iteratorError = err;
|
|
73
|
+
} finally {
|
|
74
|
+
try {
|
|
75
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
76
|
+
_iterator.return();
|
|
77
|
+
}
|
|
78
|
+
} finally {
|
|
79
|
+
if (_didIteratorError) {
|
|
80
|
+
throw _iteratorError;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}]);
|
|
86
|
+
return FakeConnectionState2;
|
|
87
|
+
}();
|
|
88
|
+
var FakeZero = function FakeZero2() {
|
|
89
|
+
"use strict";
|
|
90
|
+
|
|
91
|
+
_class_call_check(this, FakeZero2);
|
|
92
|
+
_define_property(this, "context", {});
|
|
93
|
+
_define_property(this, "connection", {
|
|
94
|
+
state: new FakeConnectionState({
|
|
95
|
+
name: "connecting"
|
|
96
|
+
}),
|
|
97
|
+
connect: import_vitest.vi.fn(async function () {})
|
|
98
|
+
});
|
|
99
|
+
_define_property(this, "delete", import_vitest.vi.fn(async function () {
|
|
100
|
+
return {
|
|
101
|
+
errors: []
|
|
102
|
+
};
|
|
103
|
+
}));
|
|
104
|
+
_define_property(this, "close", import_vitest.vi.fn());
|
|
105
|
+
_define_property(this, "run", import_vitest.vi.fn(async function () {
|
|
106
|
+
return [];
|
|
107
|
+
}));
|
|
108
|
+
_define_property(this, "preload", import_vitest.vi.fn(function () {
|
|
109
|
+
return {
|
|
110
|
+
cleanup: function () {},
|
|
111
|
+
complete: Promise.resolve()
|
|
112
|
+
};
|
|
113
|
+
}));
|
|
114
|
+
instances.push(this);
|
|
115
|
+
};
|
|
116
|
+
var instances = [];
|
|
117
|
+
return {
|
|
118
|
+
FakeZero,
|
|
119
|
+
FakeConnectionState,
|
|
120
|
+
instances
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
import_vitest.vi.mock("@rocicorp/zero", async function (importOriginal) {
|
|
124
|
+
var actual = await importOriginal();
|
|
125
|
+
return {
|
|
126
|
+
...actual,
|
|
127
|
+
Zero: fakeZero.FakeZero
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
|
131
|
+
var noteTable = (0, import_zero.table)("note").columns({
|
|
132
|
+
id: (0, import_zero.string)(),
|
|
133
|
+
body: (0, import_zero.string)()
|
|
134
|
+
}).primaryKey("id");
|
|
135
|
+
var schema = (0, import_zero.createSchema)({
|
|
136
|
+
tables: [noteTable]
|
|
137
|
+
});
|
|
138
|
+
var client = (0, import_createZeroClient.createZeroClient)({
|
|
139
|
+
schema,
|
|
140
|
+
models: {},
|
|
141
|
+
groupedQueries: {},
|
|
142
|
+
instanceName: "connection-test"
|
|
143
|
+
});
|
|
144
|
+
var container;
|
|
145
|
+
var root;
|
|
146
|
+
(0, import_vitest.beforeEach)(function () {
|
|
147
|
+
fakeZero.instances.length = 0;
|
|
148
|
+
container = document.createElement("div");
|
|
149
|
+
root = null;
|
|
150
|
+
delete document.body.dataset.zeroState;
|
|
151
|
+
delete document.body.dataset.zeroConnected;
|
|
152
|
+
delete document.body.dataset.zeroReason;
|
|
153
|
+
});
|
|
154
|
+
(0, import_vitest.afterEach)(function () {
|
|
155
|
+
if (root) (0, import_react.act)(function () {
|
|
156
|
+
return root === null || root === void 0 ? void 0 : root.unmount();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
async function mount() {
|
|
160
|
+
var extraProps = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {},
|
|
161
|
+
userID = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "conn";
|
|
162
|
+
root = (0, import_client.createRoot)(container);
|
|
163
|
+
await (0, import_react.act)(async function () {
|
|
164
|
+
root === null || root === void 0 ? void 0 : root.render(/* @__PURE__ */(0, import_jsx_runtime.jsx)(client.ProvideZero, {
|
|
165
|
+
cacheURL: "http://127.0.0.1:7788/zero",
|
|
166
|
+
userID,
|
|
167
|
+
...extraProps,
|
|
168
|
+
children: /* @__PURE__ */(0, import_jsx_runtime.jsx)("span", {
|
|
169
|
+
children: "ok"
|
|
170
|
+
})
|
|
171
|
+
}));
|
|
172
|
+
await Promise.resolve();
|
|
173
|
+
});
|
|
174
|
+
return fakeZero.instances.at(-1);
|
|
175
|
+
}
|
|
176
|
+
(0, import_vitest.test)("refreshAuth reconnects in place on needs-auth, once per transition", async function () {
|
|
177
|
+
var refreshAuth = import_vitest.vi.fn(async function () {
|
|
178
|
+
return "fresh-token";
|
|
179
|
+
});
|
|
180
|
+
var instance = await mount({
|
|
181
|
+
refreshAuth
|
|
182
|
+
}, "conn-auth");
|
|
183
|
+
await (0, import_react.act)(async function () {
|
|
184
|
+
instance.connection.state.set({
|
|
185
|
+
name: "needs-auth",
|
|
186
|
+
reason: "token expired"
|
|
187
|
+
});
|
|
188
|
+
await Promise.resolve();
|
|
189
|
+
});
|
|
190
|
+
(0, import_vitest.expect)(refreshAuth).toHaveBeenCalledTimes(1);
|
|
191
|
+
await (0, import_react.act)(async function () {
|
|
192
|
+
await Promise.resolve();
|
|
193
|
+
});
|
|
194
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledWith({
|
|
195
|
+
auth: "fresh-token"
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
(0, import_vitest.test)("stale-poke error reconnects instead of surfacing a fatal error", async function () {
|
|
199
|
+
var events = [];
|
|
200
|
+
var off = client.zeroEvents.listen(function (event) {
|
|
201
|
+
if (event) events.push(event);
|
|
202
|
+
});
|
|
203
|
+
var instance = await mount({}, "conn-stale");
|
|
204
|
+
await (0, import_react.act)(async function () {
|
|
205
|
+
instance.connection.state.set({
|
|
206
|
+
name: "error",
|
|
207
|
+
reason: "Server returned unexpected base cookie during sync"
|
|
208
|
+
});
|
|
209
|
+
await Promise.resolve();
|
|
210
|
+
});
|
|
211
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledTimes(1);
|
|
212
|
+
(0, import_vitest.expect)(instance.connection.connect).toHaveBeenCalledWith();
|
|
213
|
+
(0, import_vitest.expect)(events.some(function (event) {
|
|
214
|
+
return event.type === "error";
|
|
215
|
+
})).toBe(false);
|
|
216
|
+
off();
|
|
217
|
+
});
|
|
218
|
+
(0, import_vitest.test)("connectionDataset mirrors connection state onto the body dataset", async function () {
|
|
219
|
+
var instance = await mount({
|
|
220
|
+
connectionDataset: true
|
|
221
|
+
}, "conn-dataset");
|
|
222
|
+
await (0, import_react.act)(async function () {
|
|
223
|
+
instance.connection.state.set({
|
|
224
|
+
name: "connected"
|
|
225
|
+
});
|
|
226
|
+
await Promise.resolve();
|
|
227
|
+
});
|
|
228
|
+
(0, import_vitest.expect)(document.body.dataset.zeroState).toBe("connected");
|
|
229
|
+
(0, import_vitest.expect)(document.body.dataset.zeroConnected).toBe("true");
|
|
230
|
+
(0, import_vitest.expect)(document.body.dataset.zeroCacheUrl).toBe("http://127.0.0.1:7788/zero");
|
|
231
|
+
await (0, import_react.act)(async function () {
|
|
232
|
+
instance.connection.state.set({
|
|
233
|
+
name: "error",
|
|
234
|
+
reason: "boom"
|
|
235
|
+
});
|
|
236
|
+
await Promise.resolve();
|
|
237
|
+
});
|
|
238
|
+
(0, import_vitest.expect)(document.body.dataset.zeroState).toBe("error");
|
|
239
|
+
(0, import_vitest.expect)(document.body.dataset.zeroConnected).toBeUndefined();
|
|
240
|
+
(0, import_vitest.expect)(document.body.dataset.zeroReason).toBe("boom");
|
|
241
|
+
});
|
|
242
|
+
//# sourceMappingURL=createZeroClient.connection.test.native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["import_jsx_runtime","require","import_zero","import_react","import_client","import_vitest","import_createZeroClient","_class_call_check","instance","Constructor","TypeError","_defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","key","_create_class","protoProps","staticProps","prototype","_define_property","obj","value","fakeZero","vi","hoisted","FakeConnectionState","FakeConnectionState2","initial","_this","Set","cb","listeners","add","delete","current","set","next","_iteratorNormalCompletion","_didIteratorError","_iteratorError","_iterator","Symbol","iterator","_step","done","err","return","FakeZero","FakeZero2","state","name","connect","fn","errors","cleanup","complete","Promise","resolve","instances","push","mock","importOriginal","actual","Zero","globalThis","IS_REACT_ACT_ENVIRONMENT","noteTable","table","columns","id","string","body","primaryKey","schema","createSchema","tables"],"sources":["../../src/createZeroClient.connection.test.tsx"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|