dynamodb-reactive 0.4.0 → 0.5.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.
- package/README.md +76 -51
- package/dist/{client-Zb67giI5.d.ts → client-wZQ9XC9S.d.ts} +11 -0
- package/dist/client.cjs +53 -55
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +53 -55
- package/dist/client.js.map +1 -1
- package/dist/cloudflare.cjs +95 -13
- package/dist/cloudflare.cjs.map +1 -1
- package/dist/cloudflare.d.cts +37 -3
- package/dist/cloudflare.d.ts +37 -3
- package/dist/cloudflare.js +95 -13
- package/dist/cloudflare.js.map +1 -1
- package/dist/cluster.cjs +66 -66
- package/dist/cluster.cjs.map +1 -1
- package/dist/cluster.js +66 -66
- package/dist/cluster.js.map +1 -1
- package/dist/core.cjs +1 -3
- package/dist/core.cjs.map +1 -1
- package/dist/core.js +1 -3
- package/dist/core.js.map +1 -1
- package/dist/hub.cjs +8 -5
- package/dist/hub.cjs.map +1 -1
- package/dist/hub.d.cts +3 -1
- package/dist/hub.d.ts +3 -1
- package/dist/hub.js +8 -5
- package/dist/hub.js.map +1 -1
- package/dist/index.cjs +1 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/infra.cjs +19 -33
- package/dist/infra.cjs.map +1 -1
- package/dist/infra.js +19 -33
- package/dist/infra.js.map +1 -1
- package/dist/react.cjs +56 -65
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +56 -65
- package/dist/react.js.map +1 -1
- package/dist/server.cjs +46 -139
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +46 -139
- package/dist/server.js.map +1 -1
- package/package.json +22 -24
package/dist/client.js
CHANGED
|
@@ -23,9 +23,7 @@ function canonicalize(value, seen, key, arrayItem = false, applyToJSON = true) {
|
|
|
23
23
|
if (Array.isArray(value)) {
|
|
24
24
|
const items = [];
|
|
25
25
|
for (let index = 0; index < value.length; index++) {
|
|
26
|
-
items.push(
|
|
27
|
-
canonicalize(value[index], seen, String(index), true) ?? "null"
|
|
28
|
-
);
|
|
26
|
+
items.push(canonicalize(value[index], seen, String(index), true) ?? "null");
|
|
29
27
|
}
|
|
30
28
|
return `[${items.join(",")}]`;
|
|
31
29
|
}
|
|
@@ -42,6 +40,9 @@ function canonicalize(value, seen, key, arrayItem = false, applyToJSON = true) {
|
|
|
42
40
|
seen.delete(value);
|
|
43
41
|
}
|
|
44
42
|
}
|
|
43
|
+
case "bigint":
|
|
44
|
+
case "function":
|
|
45
|
+
case "symbol":
|
|
45
46
|
default:
|
|
46
47
|
throw new TypeError(`Unsupported query input value: ${typeof value}`);
|
|
47
48
|
}
|
|
@@ -49,7 +50,6 @@ function canonicalize(value, seen, key, arrayItem = false, applyToJSON = true) {
|
|
|
49
50
|
function getQueryKey(path, input) {
|
|
50
51
|
return `${JSON.stringify(path)}:${canonicalize(input, /* @__PURE__ */ new Set(), "") ?? "undefined"}`;
|
|
51
52
|
}
|
|
52
|
-
var { applyPatch } = jsonpatch;
|
|
53
53
|
function applyPatches(document, patches) {
|
|
54
54
|
if (patches.length === 0) {
|
|
55
55
|
return document;
|
|
@@ -68,7 +68,7 @@ function applyPatches(document, patches) {
|
|
|
68
68
|
return op;
|
|
69
69
|
});
|
|
70
70
|
try {
|
|
71
|
-
const result = applyPatch(
|
|
71
|
+
const result = jsonpatch.applyPatch(
|
|
72
72
|
structuredClone(document),
|
|
73
73
|
operations,
|
|
74
74
|
true,
|
|
@@ -88,12 +88,13 @@ function error(...values) {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// ../client/src/websocket.ts
|
|
91
|
-
var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
92
91
|
function withDefaults(config) {
|
|
93
92
|
return {
|
|
94
93
|
autoReconnect: true,
|
|
95
94
|
connectionTimeout: 1e4,
|
|
96
95
|
handshakeTimeout: 1e4,
|
|
96
|
+
heartbeatInterval: 5 * 60 * 1e3,
|
|
97
|
+
heartbeatTimeout: 15e3,
|
|
97
98
|
maxReconnectAttempts: 10,
|
|
98
99
|
reconnectDelay: 1e3,
|
|
99
100
|
...config
|
|
@@ -107,6 +108,7 @@ var WebSocketManager = class {
|
|
|
107
108
|
reconnectTimer = null;
|
|
108
109
|
handshakeTimer = null;
|
|
109
110
|
heartbeatTimer = null;
|
|
111
|
+
pongTimer = null;
|
|
110
112
|
messageHandlers = /* @__PURE__ */ new Set();
|
|
111
113
|
stateHandlers = /* @__PURE__ */ new Set();
|
|
112
114
|
handshakeHandlers = /* @__PURE__ */ new Set();
|
|
@@ -206,16 +208,7 @@ var WebSocketManager = class {
|
|
|
206
208
|
};
|
|
207
209
|
nextSocket.onclose = () => {
|
|
208
210
|
if (!this.isCurrent(nextSocket, generation)) return;
|
|
209
|
-
this.
|
|
210
|
-
this.ws = null;
|
|
211
|
-
this._connectionId = null;
|
|
212
|
-
this.setState("disconnected");
|
|
213
|
-
this.invokeLifecycleCallback("onDisconnect", this.config.onDisconnect);
|
|
214
|
-
if (this.config.autoReconnect && !this.intentionalDisconnect) {
|
|
215
|
-
this.scheduleReconnect();
|
|
216
|
-
} else {
|
|
217
|
-
this.rejectWaiters(new Error("WebSocket disconnected"));
|
|
218
|
-
}
|
|
211
|
+
this.handleClose();
|
|
219
212
|
};
|
|
220
213
|
nextSocket.onerror = () => {
|
|
221
214
|
if (!this.isCurrent(nextSocket, generation)) return;
|
|
@@ -304,6 +297,7 @@ var WebSocketManager = class {
|
|
|
304
297
|
return;
|
|
305
298
|
}
|
|
306
299
|
if (message.type === "pong") {
|
|
300
|
+
this.clearPongTimer();
|
|
307
301
|
if (!this._connectionId || this.state === "connected") return;
|
|
308
302
|
this.clearHandshakeTimer();
|
|
309
303
|
this.lastConnectionError = void 0;
|
|
@@ -332,6 +326,18 @@ var WebSocketManager = class {
|
|
|
332
326
|
socket.close(4e3, "Handshake timeout");
|
|
333
327
|
}, this.config.handshakeTimeout);
|
|
334
328
|
}
|
|
329
|
+
handleClose() {
|
|
330
|
+
this.clearConnectionTimers();
|
|
331
|
+
this.ws = null;
|
|
332
|
+
this._connectionId = null;
|
|
333
|
+
this.setState("disconnected");
|
|
334
|
+
this.invokeLifecycleCallback("onDisconnect", this.config.onDisconnect);
|
|
335
|
+
if (this.config.autoReconnect && !this.intentionalDisconnect) {
|
|
336
|
+
this.scheduleReconnect();
|
|
337
|
+
} else {
|
|
338
|
+
this.rejectWaiters(new Error("WebSocket disconnected"));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
335
341
|
startHeartbeat(socket, generation) {
|
|
336
342
|
this.clearHeartbeatTimer();
|
|
337
343
|
this.heartbeatTimer = setInterval(() => {
|
|
@@ -339,7 +345,17 @@ var WebSocketManager = class {
|
|
|
339
345
|
return;
|
|
340
346
|
}
|
|
341
347
|
socket.send(JSON.stringify({ type: "ping" }));
|
|
342
|
-
|
|
348
|
+
this.pongTimer ??= setTimeout(() => {
|
|
349
|
+
this.pongTimer = null;
|
|
350
|
+
if (!this.isCurrent(socket, generation)) return;
|
|
351
|
+
const failure = new Error("WebSocket heartbeat timed out");
|
|
352
|
+
this.lastConnectionError = failure;
|
|
353
|
+
this.invokeLifecycleCallback("onError", this.config.onError, failure);
|
|
354
|
+
socket.onclose = null;
|
|
355
|
+
socket.close(4001, "Heartbeat timeout");
|
|
356
|
+
this.handleClose();
|
|
357
|
+
}, this.config.heartbeatTimeout);
|
|
358
|
+
}, this.config.heartbeatInterval);
|
|
343
359
|
}
|
|
344
360
|
isCurrent(socket, generation) {
|
|
345
361
|
return this.ws === socket && this.socketGeneration === generation;
|
|
@@ -406,9 +422,15 @@ var WebSocketManager = class {
|
|
|
406
422
|
clearInterval(this.heartbeatTimer);
|
|
407
423
|
this.heartbeatTimer = null;
|
|
408
424
|
}
|
|
425
|
+
clearPongTimer() {
|
|
426
|
+
if (!this.pongTimer) return;
|
|
427
|
+
clearTimeout(this.pongTimer);
|
|
428
|
+
this.pongTimer = null;
|
|
429
|
+
}
|
|
409
430
|
clearConnectionTimers() {
|
|
410
431
|
this.clearHandshakeTimer();
|
|
411
432
|
this.clearHeartbeatTimer();
|
|
433
|
+
this.clearPongTimer();
|
|
412
434
|
}
|
|
413
435
|
clearTimers() {
|
|
414
436
|
this.clearConnectionTimers();
|
|
@@ -508,10 +530,7 @@ var ReactiveClient = class {
|
|
|
508
530
|
this.subscriptionsByKey.set(key, shared);
|
|
509
531
|
this.subscriptionsById.set(shared.id, shared);
|
|
510
532
|
if (this.connectionState === "connected") {
|
|
511
|
-
void this.ensureRegistered(
|
|
512
|
-
shared,
|
|
513
|
-
this.wsManager.generation
|
|
514
|
-
).catch(() => void 0);
|
|
533
|
+
void this.ensureRegistered(shared, this.wsManager.generation).catch(() => void 0);
|
|
515
534
|
}
|
|
516
535
|
}
|
|
517
536
|
const leaseId = generateId();
|
|
@@ -520,9 +539,7 @@ var ReactiveClient = class {
|
|
|
520
539
|
onError: options.onError
|
|
521
540
|
});
|
|
522
541
|
if (this.connectionState === "connected" && (!shared.hasRegistered || shared.stale) && !shared.registrationPromise) {
|
|
523
|
-
void this.ensureRegistered(shared, this.wsManager.generation).catch(
|
|
524
|
-
() => void 0
|
|
525
|
-
);
|
|
542
|
+
void this.ensureRegistered(shared, this.wsManager.generation).catch(() => void 0);
|
|
526
543
|
}
|
|
527
544
|
const state = shared;
|
|
528
545
|
let released = false;
|
|
@@ -611,9 +628,7 @@ var ReactiveClient = class {
|
|
|
611
628
|
registerActiveSubscriptions(socketGeneration) {
|
|
612
629
|
for (const state of this.subscriptionsByKey.values()) {
|
|
613
630
|
if (state.active) {
|
|
614
|
-
void this.ensureRegistered(state, socketGeneration).catch(
|
|
615
|
-
() => void 0
|
|
616
|
-
);
|
|
631
|
+
void this.ensureRegistered(state, socketGeneration).catch(() => void 0);
|
|
617
632
|
}
|
|
618
633
|
}
|
|
619
634
|
}
|
|
@@ -666,9 +681,7 @@ var ReactiveClient = class {
|
|
|
666
681
|
})
|
|
667
682
|
});
|
|
668
683
|
if (!response.ok) {
|
|
669
|
-
throw new Error(
|
|
670
|
-
`Subscribe failed: ${response.status} ${response.statusText}`
|
|
671
|
-
);
|
|
684
|
+
throw new Error(`Subscribe failed: ${response.status} ${response.statusText}`);
|
|
672
685
|
}
|
|
673
686
|
const result = await response.json();
|
|
674
687
|
if (result.type === "error") {
|
|
@@ -687,12 +700,7 @@ var ReactiveClient = class {
|
|
|
687
700
|
throw cause;
|
|
688
701
|
} finally {
|
|
689
702
|
if ((!state.active || !isCurrent()) && requestIssued) {
|
|
690
|
-
void this.sendUnsubscribe(
|
|
691
|
-
registrationConnectionId,
|
|
692
|
-
state.id,
|
|
693
|
-
generation,
|
|
694
|
-
registrationId
|
|
695
|
-
);
|
|
703
|
+
void this.sendUnsubscribe(registrationConnectionId, state.id, generation, registrationId);
|
|
696
704
|
}
|
|
697
705
|
if (state.registrationPromise === request) {
|
|
698
706
|
state.registrationPromise = void 0;
|
|
@@ -797,15 +805,12 @@ var ReactiveClient = class {
|
|
|
797
805
|
return;
|
|
798
806
|
}
|
|
799
807
|
this.discardStalePatches(state);
|
|
800
|
-
|
|
801
|
-
const next = [...state.patchBuffer.values()].filter((patch) => patch.fromVersion === state.version).sort((left, right) => left.toVersion - right.toVersion)
|
|
808
|
+
for (; ; ) {
|
|
809
|
+
const next = [...state.patchBuffer.values()].filter((patch) => patch.fromVersion === state.version).sort((left, right) => left.toVersion - right.toVersion).at(0);
|
|
802
810
|
if (!next) break;
|
|
803
811
|
state.patchBuffer.delete(next.messageId);
|
|
804
812
|
try {
|
|
805
|
-
state.authoritativeData = applyPatches(
|
|
806
|
-
state.authoritativeData,
|
|
807
|
-
next.patches
|
|
808
|
-
);
|
|
813
|
+
state.authoritativeData = applyPatches(state.authoritativeData, next.patches);
|
|
809
814
|
state.version = next.toVersion;
|
|
810
815
|
state.appliedMessageIds.add(next.messageId);
|
|
811
816
|
const awaitingReconciliation = this.hasSettledLayers(state);
|
|
@@ -843,12 +848,7 @@ var ReactiveClient = class {
|
|
|
843
848
|
state.stale = true;
|
|
844
849
|
state.loading = true;
|
|
845
850
|
this.notifySubscription(state);
|
|
846
|
-
|
|
847
|
-
request = this.ensureRegistered(
|
|
848
|
-
state,
|
|
849
|
-
this.wsManager.generation,
|
|
850
|
-
true
|
|
851
|
-
).finally(() => {
|
|
851
|
+
const request = this.ensureRegistered(state, this.wsManager.generation, true).finally(() => {
|
|
852
852
|
if (state.resyncPromise === request) {
|
|
853
853
|
state.resyncPromise = void 0;
|
|
854
854
|
state.resyncGeneration = void 0;
|
|
@@ -916,7 +916,10 @@ var ReactiveClient = class {
|
|
|
916
916
|
if (options?.optimisticData === void 0) return void 0;
|
|
917
917
|
return (data) => {
|
|
918
918
|
if (!Array.isArray(data)) return data;
|
|
919
|
-
const optimistic = settled ?
|
|
919
|
+
const optimistic = settled ? (
|
|
920
|
+
// oxlint-disable-next-line typescript/prefer-nullish-coalescing -- null is a valid mutation result.
|
|
921
|
+
result === void 0 ? typeof options.optimisticData === "function" ? options.optimisticData(input, data) : options.optimisticData : result
|
|
922
|
+
) : typeof options.optimisticData === "function" ? options.optimisticData(input, data) : options.optimisticData;
|
|
920
923
|
if (settled && optimistic !== null && typeof optimistic === "object") {
|
|
921
924
|
const optimisticId = optimistic.id;
|
|
922
925
|
if (optimisticId !== void 0 && data.some(
|
|
@@ -931,12 +934,7 @@ var ReactiveClient = class {
|
|
|
931
934
|
settleMutationLayers(mutationId, input, result, options, states) {
|
|
932
935
|
for (const state of states) {
|
|
933
936
|
const layer = state.optimisticLayers.get(mutationId);
|
|
934
|
-
const updater = this.createOptimisticUpdater(
|
|
935
|
-
input,
|
|
936
|
-
options,
|
|
937
|
-
result,
|
|
938
|
-
true
|
|
939
|
-
);
|
|
937
|
+
const updater = this.createOptimisticUpdater(input, options, result, true);
|
|
940
938
|
if (!layer || !updater) continue;
|
|
941
939
|
layer.updater = updater;
|
|
942
940
|
layer.settledRevision = ++state.settlementRevision;
|