statewire 0.17.1 → 0.18.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/dist/client/connection.d.ts +2 -3
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +61 -25
- package/dist/client/connection.js.map +1 -1
- package/dist/client/session.d.ts +6 -2
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +189 -40
- package/dist/client/session.js.map +1 -1
- package/dist/client/storageError.d.ts +6 -0
- package/dist/client/storageError.d.ts.map +1 -0
- package/dist/client/storageError.js +12 -0
- package/dist/client/storageError.js.map +1 -0
- package/dist/statewire.d.ts +25 -11
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js.map +1 -1
- package/dist/storage.d.ts +33 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +371 -0
- package/dist/storage.js.map +1 -0
- package/dist/transports/sse.d.ts +2 -0
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +3 -0
- package/dist/transports/sse.js.map +1 -1
- package/package.json +5 -1
- package/src/client/connection.ts +57 -28
- package/src/client/session.ts +262 -72
- package/src/client/storageError.ts +9 -0
- package/src/statewire.ts +31 -21
- package/src/storage.ts +601 -0
- package/src/transports/sse.ts +5 -0
package/dist/client/session.js
CHANGED
|
@@ -8,6 +8,7 @@ import { bindCommandsHost } from "../host/host.js";
|
|
|
8
8
|
import "../wire/limits.js";
|
|
9
9
|
import { DocumentStorageContext, SessionStorageContext, createMemorySessionStore } from "./sessionStore.js";
|
|
10
10
|
import { backoff } from "./timing.js";
|
|
11
|
+
import { wrapStorageError } from "./storageError.js";
|
|
11
12
|
import { TERMINAL } from "./connection.js";
|
|
12
13
|
import { randomId } from "../util/randomId.js";
|
|
13
14
|
import { useContext, useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
@@ -42,9 +43,20 @@ const sleepUntilWake = (s, delayMs) => new Promise((resolve) => {
|
|
|
42
43
|
}, delayMs);
|
|
43
44
|
s.waiters.push(waiter);
|
|
44
45
|
});
|
|
46
|
+
const storageFailed = (s, cause) => {
|
|
47
|
+
const error = wrapStorageError(cause);
|
|
48
|
+
s.storageError = error;
|
|
49
|
+
for (const entry of s.pending) entry.reject(error);
|
|
50
|
+
s.transport?.storageFailed(error);
|
|
51
|
+
};
|
|
45
52
|
const setRecord = (s, record) => {
|
|
46
53
|
s.record = record;
|
|
47
|
-
if (!s.deactivated)
|
|
54
|
+
if (!s.deactivated) try {
|
|
55
|
+
s.store.save(record);
|
|
56
|
+
} catch (cause) {
|
|
57
|
+
storageFailed(s, cause);
|
|
58
|
+
throw s.storageError;
|
|
59
|
+
}
|
|
48
60
|
};
|
|
49
61
|
const backlog = (s) => s.pending.filter((p) => p.seq > s.durableSeq).map((p) => ({
|
|
50
62
|
seq: p.seq,
|
|
@@ -70,7 +82,7 @@ const syncBacklogInner = (s) => {
|
|
|
70
82
|
};
|
|
71
83
|
const syncBacklog = (s) => {
|
|
72
84
|
if (!s.shared) return syncBacklogInner(s);
|
|
73
|
-
|
|
85
|
+
transactBackground(s, () => syncBacklogInner(s));
|
|
74
86
|
};
|
|
75
87
|
const transact = (s, fn) => {
|
|
76
88
|
if (!s.shared || s.deactivated) {
|
|
@@ -78,7 +90,7 @@ const transact = (s, fn) => {
|
|
|
78
90
|
return Promise.resolve();
|
|
79
91
|
}
|
|
80
92
|
const shared = s.shared;
|
|
81
|
-
const
|
|
93
|
+
const result = shared.txq.then(() => s.store.lock(async () => {
|
|
82
94
|
const stored = s.store.load();
|
|
83
95
|
if (stored !== null && stored.clientId !== s.record.clientId) adoptReset(s, stored);
|
|
84
96
|
else if (stored !== null) {
|
|
@@ -97,9 +109,17 @@ const transact = (s, fn) => {
|
|
|
97
109
|
}
|
|
98
110
|
}
|
|
99
111
|
fn();
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
112
|
+
const persistence = s.store.flush?.();
|
|
113
|
+
if (persistence) await persistence;
|
|
114
|
+
})).catch((cause) => {
|
|
115
|
+
storageFailed(s, cause);
|
|
116
|
+
throw s.storageError;
|
|
117
|
+
});
|
|
118
|
+
shared.txq = result.then(() => {}, () => {});
|
|
119
|
+
return result;
|
|
120
|
+
};
|
|
121
|
+
const transactBackground = (s, fn, done) => {
|
|
122
|
+
transact(s, fn).then(done, () => {});
|
|
103
123
|
};
|
|
104
124
|
const setIdle = (s, level) => {
|
|
105
125
|
if (level === s.idle) return;
|
|
@@ -136,7 +156,7 @@ const retainFailed = (s, entry, failure) => {
|
|
|
136
156
|
retainFailedInner(s, entry, failure);
|
|
137
157
|
return;
|
|
138
158
|
}
|
|
139
|
-
|
|
159
|
+
transactBackground(s, () => retainFailedInner(s, entry, failure));
|
|
140
160
|
};
|
|
141
161
|
const settleEntry = (s, entry, outcome) => {
|
|
142
162
|
s.pending = s.pending.filter((p) => p !== entry);
|
|
@@ -370,6 +390,36 @@ const publishIngested = (s) => {
|
|
|
370
390
|
wake(s);
|
|
371
391
|
};
|
|
372
392
|
const snapCtxClock = (s, ctxWm) => {
|
|
393
|
+
if (s.record.context?.recover === "version-1") {
|
|
394
|
+
const document = s.contextDocuments.documents.get(0);
|
|
395
|
+
if (s.contextDocuments.documents.size !== 1 || !document?.main) throw new Error("statewire: version-1 context recovery requires one main document at doc 0");
|
|
396
|
+
const encoded = encodeDocument(document.value);
|
|
397
|
+
const ops = [{
|
|
398
|
+
...ctxWm === 0 ? {
|
|
399
|
+
op: "mount",
|
|
400
|
+
protocol: document.protocol,
|
|
401
|
+
main: true
|
|
402
|
+
} : {
|
|
403
|
+
op: "replace",
|
|
404
|
+
path: []
|
|
405
|
+
},
|
|
406
|
+
...encoded
|
|
407
|
+
}];
|
|
408
|
+
s.ctxPending = [{
|
|
409
|
+
seq: ctxWm + 1,
|
|
410
|
+
ops,
|
|
411
|
+
posted: false
|
|
412
|
+
}];
|
|
413
|
+
setRecord(s, {
|
|
414
|
+
...s.record,
|
|
415
|
+
ctxNextSeq: ctxWm + 2,
|
|
416
|
+
context: {
|
|
417
|
+
ops: contextSnapshot(s.contextDocuments),
|
|
418
|
+
pending: s.ctxPending
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
373
423
|
if (!(s.ctxPending.every((c, i) => c.seq === ctxWm + 1 + i) && s.record.ctxNextSeq === ctxWm + s.ctxPending.length + 1)) {
|
|
374
424
|
if (ctxWm > 0) throw new Error("statewire: context history is missing; use a new client id");
|
|
375
425
|
setRecord(s, {
|
|
@@ -433,7 +483,7 @@ const handleHello = (s, { ops, syn }) => {
|
|
|
433
483
|
pump(s);
|
|
434
484
|
return;
|
|
435
485
|
}
|
|
436
|
-
|
|
486
|
+
transactBackground(s, reconcile, () => {
|
|
437
487
|
publishIngested(s);
|
|
438
488
|
pump(s);
|
|
439
489
|
});
|
|
@@ -466,10 +516,10 @@ const handleRefusal = (s, syn) => {
|
|
|
466
516
|
const cmdGap = typeof seq === "number" && firstCmd !== void 0 && firstCmd.seq > Math.max(seq, s.durableSeq) + 1;
|
|
467
517
|
const ctxGap = typeof ctxSeq === "number" && firstCtx !== void 0 && firstCtx.seq > ctxSeq + 1;
|
|
468
518
|
if (cmdGap || ctxGap) {
|
|
469
|
-
|
|
519
|
+
transactBackground(s, () => {
|
|
470
520
|
if (cmdGap) sessionLostInner(s, seq, ctxSeq ?? 0);
|
|
471
521
|
else snapCtxClock(s, ctxSeq);
|
|
472
|
-
}
|
|
522
|
+
}, () => {
|
|
473
523
|
wake(s);
|
|
474
524
|
pump(s);
|
|
475
525
|
});
|
|
@@ -491,10 +541,11 @@ const handleFinish = (s, { reason }) => {
|
|
|
491
541
|
wake(s);
|
|
492
542
|
};
|
|
493
543
|
const isFinished = (s) => s.attach === "finished";
|
|
494
|
-
const buildLanes = (s) => {
|
|
544
|
+
const buildLanes = (s, persisted = false) => {
|
|
495
545
|
const ctxEntries = [];
|
|
496
546
|
for (const entry of s.ctxPending) {
|
|
497
547
|
if (entry.posted) continue;
|
|
548
|
+
if (persisted && (s.persistedRecord?.clientId !== s.record.clientId || entry.seq >= s.persistedRecord.ctxNextSeq)) break;
|
|
498
549
|
if (ctxEntries.length >= 256) break;
|
|
499
550
|
if (ctxEntries.length > 0 && entry.seq !== ctxEntries.at(-1).seq + 1) break;
|
|
500
551
|
ctxEntries.push(entry);
|
|
@@ -502,6 +553,7 @@ const buildLanes = (s) => {
|
|
|
502
553
|
const cmdEntries = [];
|
|
503
554
|
for (const entry of s.pending) {
|
|
504
555
|
if (entry.posted) continue;
|
|
556
|
+
if (persisted && (s.persistedRecord?.clientId !== s.record.clientId || entry.seq >= s.persistedRecord.nextSeq)) break;
|
|
505
557
|
if (cmdEntries.length >= 256) break;
|
|
506
558
|
if (cmdEntries.length > 0 && entry.seq !== cmdEntries.at(-1).seq + 1) break;
|
|
507
559
|
cmdEntries.push(entry);
|
|
@@ -529,22 +581,39 @@ const takeAttachLanes = (s) => {
|
|
|
529
581
|
s.attachLaneSeqs = [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()];
|
|
530
582
|
const wanted = s.lanesOnAttach;
|
|
531
583
|
s.lanesOnAttach = false;
|
|
532
|
-
if (!wanted || !s.sessionKnown) return null;
|
|
533
|
-
const lanes = buildLanes(s);
|
|
584
|
+
if (!wanted || !s.sessionKnown || s.record.context?.recover !== void 0) return null;
|
|
585
|
+
const lanes = buildLanes(s, true);
|
|
534
586
|
if (!lanes) return null;
|
|
535
587
|
s.attachLaneSeqs = [new Set(lanes.cmdEntries.map((p) => p.seq)), new Set(lanes.ctxEntries.map((c) => c.seq))];
|
|
536
588
|
for (const entry of lanes.cmdEntries) entry.attempted = true;
|
|
537
589
|
return lanes.frame;
|
|
538
590
|
};
|
|
591
|
+
const persistBeforeSend = (s) => {
|
|
592
|
+
if (s.storageError !== void 0) throw s.storageError;
|
|
593
|
+
if (!s.hydrated) return s.ready.then(() => persistBeforeSend(s));
|
|
594
|
+
const record = s.record;
|
|
595
|
+
try {
|
|
596
|
+
const pending = s.store.flush?.();
|
|
597
|
+
if (pending) return pending.then(() => {
|
|
598
|
+
s.persistedRecord = record;
|
|
599
|
+
}, (cause) => {
|
|
600
|
+
throw wrapStorageError(cause);
|
|
601
|
+
});
|
|
602
|
+
s.persistedRecord = record;
|
|
603
|
+
} catch (cause) {
|
|
604
|
+
throw wrapStorageError(cause);
|
|
605
|
+
}
|
|
606
|
+
};
|
|
539
607
|
const pump = async (s) => {
|
|
540
608
|
if (s.pumping) return;
|
|
541
609
|
s.pumping = true;
|
|
542
610
|
try {
|
|
543
611
|
while (s.running && !isFinished(s)) {
|
|
612
|
+
if (!s.hydrated) await s.ready;
|
|
544
613
|
const transport = s.transport;
|
|
545
614
|
if (buildLanes(s) === null) return;
|
|
546
615
|
if (s.attach !== "attached" || !transport) {
|
|
547
|
-
if (transport?.connection.status === "
|
|
616
|
+
if (transport?.connection.status === "standby" && transport.connection.reason === "idle" || transport?.parked && s.pending.length > 0) transport.connection.reconnect();
|
|
548
617
|
await waitForWake(s);
|
|
549
618
|
continue;
|
|
550
619
|
}
|
|
@@ -556,6 +625,10 @@ const pump = async (s) => {
|
|
|
556
625
|
const lanes = buildLanes(s);
|
|
557
626
|
if (!lanes) continue;
|
|
558
627
|
const epoch = s.attachEpoch;
|
|
628
|
+
const persistence = persistBeforeSend(s);
|
|
629
|
+
if (persistence) await persistence;
|
|
630
|
+
if (!s.running || isFinished(s)) return;
|
|
631
|
+
if (epoch !== s.attachEpoch || s.attach !== "attached") continue;
|
|
559
632
|
for (const entry of lanes.cmdEntries) entry.attempted = true;
|
|
560
633
|
let result;
|
|
561
634
|
try {
|
|
@@ -592,22 +665,31 @@ const pump = async (s) => {
|
|
|
592
665
|
}
|
|
593
666
|
}
|
|
594
667
|
}
|
|
668
|
+
} catch (error) {
|
|
669
|
+
storageFailed(s, error);
|
|
595
670
|
} finally {
|
|
596
671
|
s.pumping = false;
|
|
597
672
|
}
|
|
598
673
|
};
|
|
599
674
|
const start = (s) => {
|
|
675
|
+
s.running = true;
|
|
676
|
+
if (!s.hydrated) {
|
|
677
|
+
s.ready.then(() => {
|
|
678
|
+
if (s.running) start(s);
|
|
679
|
+
}, () => {});
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
600
682
|
if (s.shared) {
|
|
601
683
|
s.shared.unsubscribe = s.store.subscribe(() => {
|
|
602
|
-
|
|
684
|
+
transactBackground(s, () => consumeVerdicts(s));
|
|
603
685
|
});
|
|
604
686
|
s.running = true;
|
|
605
|
-
|
|
687
|
+
transactBackground(s, () => {
|
|
606
688
|
if (s.store.load() === null) s.store.save(s.record);
|
|
607
689
|
s.recordPersisted = true;
|
|
608
690
|
adoptStored(s);
|
|
609
691
|
consumeVerdicts(s);
|
|
610
|
-
}
|
|
692
|
+
}, () => void pump(s));
|
|
611
693
|
return;
|
|
612
694
|
}
|
|
613
695
|
if (!s.recordPersisted) {
|
|
@@ -685,7 +767,7 @@ const enqueue = (s, command, params, resolve, reject) => {
|
|
|
685
767
|
}).then(() => {
|
|
686
768
|
wake(s);
|
|
687
769
|
pump(s);
|
|
688
|
-
});
|
|
770
|
+
}, reject);
|
|
689
771
|
};
|
|
690
772
|
const adoptStored = (s) => {
|
|
691
773
|
const known = new Set(s.pending.map((p) => p.seq));
|
|
@@ -718,6 +800,16 @@ const adoptStored = (s) => {
|
|
|
718
800
|
s.pending.sort((a, b) => a.seq - b.seq);
|
|
719
801
|
};
|
|
720
802
|
const sendCommand = (s, method, params, protocol = s.options.protocol ?? "default") => {
|
|
803
|
+
if (!s.hydrated) {
|
|
804
|
+
const result = s.ready.then(() => sendCommand(s, method, params, protocol));
|
|
805
|
+
result.catch(() => {});
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
if (s.storageError !== void 0) {
|
|
809
|
+
const result = Promise.reject(s.storageError);
|
|
810
|
+
result.catch(() => {});
|
|
811
|
+
return result;
|
|
812
|
+
}
|
|
721
813
|
if (!s.running) return rejectedSend({
|
|
722
814
|
fate: "aborted",
|
|
723
815
|
cause: "unmount"
|
|
@@ -761,7 +853,7 @@ const discardFailed = (s, entry) => {
|
|
|
761
853
|
return;
|
|
762
854
|
}
|
|
763
855
|
if (findFailed(s, entry) === void 0) throw unknownFailed(entry);
|
|
764
|
-
|
|
856
|
+
transactBackground(s, () => {
|
|
765
857
|
if (findFailed(s, entry) !== void 0) takeFailed(s, entry);
|
|
766
858
|
});
|
|
767
859
|
};
|
|
@@ -840,6 +932,7 @@ const persistContext = (s) => {
|
|
|
840
932
|
...s.record,
|
|
841
933
|
context: {
|
|
842
934
|
ops,
|
|
935
|
+
...s.record.context?.recover === void 0 ? {} : { recover: s.record.context.recover },
|
|
843
936
|
pending: s.ctxPending.map(({ seq, ops }) => ({
|
|
844
937
|
seq,
|
|
845
938
|
ops
|
|
@@ -848,6 +941,14 @@ const persistContext = (s) => {
|
|
|
848
941
|
});
|
|
849
942
|
};
|
|
850
943
|
const changeContext = (s, build) => {
|
|
944
|
+
if (!s.hydrated) {
|
|
945
|
+
s.ready.then(() => changeContext(s, build)).catch((cause) => {
|
|
946
|
+
const error = wrapStorageError(cause);
|
|
947
|
+
s.storageError = error;
|
|
948
|
+
s.transport?.storageFailed(error);
|
|
949
|
+
});
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
851
952
|
if (!s.running || isFinished(s)) return;
|
|
852
953
|
const submit = () => {
|
|
853
954
|
if (!s.running || isFinished(s)) return;
|
|
@@ -881,7 +982,7 @@ const changeContext = (s, build) => {
|
|
|
881
982
|
submit();
|
|
882
983
|
wake(s);
|
|
883
984
|
pump(s);
|
|
884
|
-
} else
|
|
985
|
+
} else transactBackground(s, submit, () => {
|
|
885
986
|
wake(s);
|
|
886
987
|
pump(s);
|
|
887
988
|
});
|
|
@@ -943,6 +1044,32 @@ const storedCommandCompatible = (command, current) => {
|
|
|
943
1044
|
const offer = current.protocols.find((p) => p.name === command.protocol);
|
|
944
1045
|
return produced !== void 0 && offer !== void 0 && inRange(produced.version, offer);
|
|
945
1046
|
};
|
|
1047
|
+
const loadSessionRecord = (store, options) => {
|
|
1048
|
+
let stored = store.load();
|
|
1049
|
+
if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
|
|
1050
|
+
const current = {
|
|
1051
|
+
wire: options.wireVersion ?? { version: "2026-09-07" },
|
|
1052
|
+
protocols: protocolOffers(options)
|
|
1053
|
+
};
|
|
1054
|
+
if (stored !== null && !stored.commands.every((command) => storedCommandCompatible(command, current))) {
|
|
1055
|
+
if (!store.migrate) throw new Error("statewire: stored commands require a storage migration");
|
|
1056
|
+
stored = store.migrate(stored, current);
|
|
1057
|
+
if (stored !== null && !stored.commands.every((command) => storedCommandCompatible(command, current))) throw new Error("statewire: migrated commands are incompatible");
|
|
1058
|
+
if (stored !== null) store.save(stored);
|
|
1059
|
+
}
|
|
1060
|
+
if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
|
|
1061
|
+
const record = stored ?? {
|
|
1062
|
+
clientId: randomId(),
|
|
1063
|
+
nextSeq: 1,
|
|
1064
|
+
ctxNextSeq: 1,
|
|
1065
|
+
commands: []
|
|
1066
|
+
};
|
|
1067
|
+
if (stored === null) store.save(record);
|
|
1068
|
+
return {
|
|
1069
|
+
record,
|
|
1070
|
+
stored
|
|
1071
|
+
};
|
|
1072
|
+
};
|
|
946
1073
|
const useStatewireSession = (options) => {
|
|
947
1074
|
const [defaultStore] = useState(createMemorySessionStore);
|
|
948
1075
|
const mounted = useContext(SessionStorageContext);
|
|
@@ -951,26 +1078,15 @@ const useStatewireSession = (options) => {
|
|
|
951
1078
|
const store = options.sessionStore ?? mounted ?? defaultStore;
|
|
952
1079
|
if (store.lock === void 0 !== (store.subscribe === void 0)) throw new Error("statewire: session storage must provide lock and subscribe together");
|
|
953
1080
|
const [s] = useState(() => {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
stored = store.migrate(stored, current);
|
|
963
|
-
if (stored !== null && !stored.commands.every((command) => storedCommandCompatible(command, current))) throw new Error("statewire: migrated commands are incompatible");
|
|
964
|
-
if (stored !== null) store.save(stored);
|
|
965
|
-
}
|
|
966
|
-
if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
|
|
967
|
-
const record = stored ?? {
|
|
968
|
-
clientId: randomId(),
|
|
969
|
-
nextSeq: 1,
|
|
970
|
-
ctxNextSeq: 1,
|
|
971
|
-
commands: []
|
|
1081
|
+
const { record, stored } = store.ready === void 0 ? loadSessionRecord(store, options) : {
|
|
1082
|
+
record: {
|
|
1083
|
+
clientId: randomId(),
|
|
1084
|
+
nextSeq: 1,
|
|
1085
|
+
ctxNextSeq: 1,
|
|
1086
|
+
commands: []
|
|
1087
|
+
},
|
|
1088
|
+
stored: null
|
|
972
1089
|
};
|
|
973
|
-
if (stored === null) store.save(record);
|
|
974
1090
|
const session = {
|
|
975
1091
|
options,
|
|
976
1092
|
selection: void 0,
|
|
@@ -983,6 +1099,7 @@ const useStatewireSession = (options) => {
|
|
|
983
1099
|
}, stored.context.ops),
|
|
984
1100
|
record,
|
|
985
1101
|
ctx: {
|
|
1102
|
+
beforeAttach: () => persistBeforeSend(session),
|
|
986
1103
|
get clientId() {
|
|
987
1104
|
return session.record.clientId;
|
|
988
1105
|
},
|
|
@@ -995,7 +1112,11 @@ const useStatewireSession = (options) => {
|
|
|
995
1112
|
onDetach: () => handleDetach(session),
|
|
996
1113
|
onFinish: (args_1) => handleFinish(session, args_1)
|
|
997
1114
|
},
|
|
998
|
-
recordPersisted:
|
|
1115
|
+
recordPersisted: store.ready === void 0,
|
|
1116
|
+
hydrated: store.ready === void 0,
|
|
1117
|
+
ready: void 0,
|
|
1118
|
+
storageError: void 0,
|
|
1119
|
+
persistedRecord: store.ready === void 0 ? record : null,
|
|
999
1120
|
store,
|
|
1000
1121
|
documentStore,
|
|
1001
1122
|
shared: store.lock !== void 0 ? {
|
|
@@ -1049,6 +1170,34 @@ const useStatewireSession = (options) => {
|
|
|
1049
1170
|
notify: () => {},
|
|
1050
1171
|
commands: createMethodProxy((method, params) => sendCommand(session, method, params))
|
|
1051
1172
|
};
|
|
1173
|
+
if (store.ready !== void 0) {
|
|
1174
|
+
session.ready = store.ready.then(() => {
|
|
1175
|
+
const { record: record_0 } = loadSessionRecord(store, session.options);
|
|
1176
|
+
session.record = record_0;
|
|
1177
|
+
session.contextDocuments = record_0.context === void 0 ? {
|
|
1178
|
+
mode: "mounted",
|
|
1179
|
+
documents: /* @__PURE__ */ new Map()
|
|
1180
|
+
} : applyDocumentOps({
|
|
1181
|
+
mode: "mounted",
|
|
1182
|
+
documents: /* @__PURE__ */ new Map()
|
|
1183
|
+
}, record_0.context.ops);
|
|
1184
|
+
session.ctxOps = record_0.context?.ops;
|
|
1185
|
+
session.ctxPending = record_0.context?.pending.map((entry) => ({
|
|
1186
|
+
...entry,
|
|
1187
|
+
posted: false
|
|
1188
|
+
})) ?? [];
|
|
1189
|
+
session.recordPersisted = true;
|
|
1190
|
+
session.hydrated = true;
|
|
1191
|
+
if (session.running) session.notify();
|
|
1192
|
+
});
|
|
1193
|
+
session.ready = session.ready.catch((cause) => {
|
|
1194
|
+
const error = wrapStorageError(cause);
|
|
1195
|
+
session.storageError = error;
|
|
1196
|
+
session.transport?.storageFailed(error);
|
|
1197
|
+
throw error;
|
|
1198
|
+
});
|
|
1199
|
+
session.ready.catch(() => {});
|
|
1200
|
+
}
|
|
1052
1201
|
bindCommandsHost(session.commands, { setListener: (listener_0) => {
|
|
1053
1202
|
session.lifecycle = listener_0;
|
|
1054
1203
|
} });
|