@interop/was-react 0.18.1 → 0.20.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 +4 -3
- package/dist/auth/verifyResponse.d.ts.map +1 -1
- package/dist/auth/verifyResponse.js +14 -7
- package/dist/auth/verifyResponse.js.map +1 -1
- package/dist/identity/agents.d.ts +5 -0
- package/dist/identity/agents.d.ts.map +1 -1
- package/dist/identity/agents.js +10 -3
- package/dist/identity/agents.js.map +1 -1
- package/dist/identity/seedCredential.d.ts +5 -1
- package/dist/identity/seedCredential.d.ts.map +1 -1
- package/dist/identity/seedCredential.js +15 -28
- package/dist/identity/seedCredential.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/dist/mui/ClearDataDialog.d.ts.map +1 -1
- package/dist/mui/ClearDataDialog.js +14 -12
- package/dist/mui/ClearDataDialog.js.map +1 -1
- package/dist/mui/LogoutDialog.d.ts.map +1 -1
- package/dist/mui/LogoutDialog.js +12 -8
- package/dist/mui/LogoutDialog.js.map +1 -1
- package/dist/react/hooks.d.ts +11 -7
- package/dist/react/hooks.d.ts.map +1 -1
- package/dist/react/hooks.js +14 -8
- package/dist/react/hooks.js.map +1 -1
- package/dist/session/authStore.d.ts +30 -9
- package/dist/session/authStore.d.ts.map +1 -1
- package/dist/session/authStore.js +147 -48
- package/dist/session/authStore.js.map +1 -1
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +1 -0
- package/dist/session/index.js.map +1 -1
- package/dist/session/localWipe.d.ts +144 -0
- package/dist/session/localWipe.d.ts.map +1 -0
- package/dist/session/localWipe.js +190 -0
- package/dist/session/localWipe.js.map +1 -0
- package/dist/storage/adopt.d.ts +4 -1
- package/dist/storage/adopt.d.ts.map +1 -1
- package/dist/storage/adopt.js +4 -3
- package/dist/storage/adopt.js.map +1 -1
- package/dist/storage/entityStore.d.ts.map +1 -1
- package/dist/storage/entityStore.js +3 -0
- package/dist/storage/entityStore.js.map +1 -1
- package/dist/storage/publicUrl.js +3 -3
- package/dist/storage/storageContext.d.ts +175 -0
- package/dist/storage/storageContext.d.ts.map +1 -0
- package/dist/storage/storageContext.js +327 -0
- package/dist/storage/storageContext.js.map +1 -0
- package/dist/storage/storageManager.d.ts +57 -60
- package/dist/storage/storageManager.d.ts.map +1 -1
- package/dist/storage/storageManager.js +55 -125
- package/dist/storage/storageManager.js.map +1 -1
- package/dist/storage/syncController.d.ts +10 -1
- package/dist/storage/syncController.d.ts.map +1 -1
- package/dist/storage/syncController.js +12 -4
- package/dist/storage/syncController.js.map +1 -1
- package/dist/storage/syncStatusStore.d.ts +23 -2
- package/dist/storage/syncStatusStore.d.ts.map +1 -1
- package/dist/storage/syncStatusStore.js +22 -13
- package/dist/storage/syncStatusStore.js.map +1 -1
- package/dist/storage/writerId.d.ts +36 -0
- package/dist/storage/writerId.d.ts.map +1 -0
- package/dist/storage/writerId.js +76 -0
- package/dist/storage/writerId.js.map +1 -0
- package/package.json +13 -13
- package/dist/storage/rehydrate.d.ts +0 -64
- package/dist/storage/rehydrate.d.ts.map +0 -1
- package/dist/storage/rehydrate.js +0 -132
- package/dist/storage/rehydrate.js.map +0 -1
|
@@ -1,175 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
-
*/
|
|
1
|
+
let active = null;
|
|
4
2
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* the app own the init/hydrate ordering.
|
|
3
|
+
* Makes `context` the active one (called by the session store at creation, so
|
|
4
|
+
* the facades resolve before any replica opens, again right before it opens a
|
|
5
|
+
* replica, and by {@link StorageContext.attachStore}). Idempotent for the
|
|
6
|
+
* context already active; throws while a DIFFERENT context still has a replica
|
|
7
|
+
* attached.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
13
|
-
* the per-install id, {@link setWriterId} installs the session's resolved value,
|
|
14
|
-
* and {@link stampLww} is the one place a payload's last-write-wins fields are
|
|
15
|
-
* minted, so no caller has to remember to stamp.
|
|
16
|
-
*/
|
|
17
|
-
import { uuidv7 } from 'uuidv7';
|
|
18
|
-
import { DEFAULT_STORAGE_KEY_PREFIX } from '../config.js';
|
|
19
|
-
let localStore = null;
|
|
20
|
-
let remoteStore = null;
|
|
21
|
-
/**
|
|
22
|
-
* Installs the opened store (called once by the app bootstrap).
|
|
23
|
-
*
|
|
24
|
-
* @param store {LocalStore}
|
|
9
|
+
* @param context {StorageContext}
|
|
25
10
|
* @returns {void}
|
|
26
11
|
*/
|
|
27
|
-
export function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
* The opened store, or throws if the app has not bootstrapped yet.
|
|
32
|
-
*
|
|
33
|
-
* @returns {LocalStore}
|
|
34
|
-
*/
|
|
35
|
-
export function requireStore() {
|
|
36
|
-
if (!localStore) {
|
|
37
|
-
throw new Error('LocalStore is not initialized; open it first.');
|
|
12
|
+
export function activateStorageContext(context) {
|
|
13
|
+
if (active && active !== context && active.hasStore()) {
|
|
14
|
+
throw new Error('Another storage context still has a replica attached; ' +
|
|
15
|
+
'one process hosts one live session (one provider) at a time.');
|
|
38
16
|
}
|
|
39
|
-
|
|
17
|
+
active = context;
|
|
40
18
|
}
|
|
41
19
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* @returns {boolean}
|
|
45
|
-
*/
|
|
46
|
-
export function hasStore() {
|
|
47
|
-
return localStore !== null;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Releases the held store reference (logout; the caller closes the db).
|
|
20
|
+
* Releases the active pointer if `context` holds it (a torn-down session); a
|
|
21
|
+
* no-op for any other context.
|
|
51
22
|
*
|
|
23
|
+
* @param context {StorageContext}
|
|
52
24
|
* @returns {void}
|
|
53
25
|
*/
|
|
54
|
-
export function
|
|
55
|
-
|
|
26
|
+
export function deactivateStorageContext(context) {
|
|
27
|
+
if (active === context) {
|
|
28
|
+
active = null;
|
|
29
|
+
}
|
|
56
30
|
}
|
|
57
31
|
/**
|
|
58
|
-
*
|
|
59
|
-
* has bootstrapped it from the granted zcaps).
|
|
32
|
+
* Whether a storage context is active.
|
|
60
33
|
*
|
|
61
|
-
* @
|
|
62
|
-
* @returns {void}
|
|
34
|
+
* @returns {boolean}
|
|
63
35
|
*/
|
|
64
|
-
export function
|
|
65
|
-
|
|
36
|
+
export function hasStorageContext() {
|
|
37
|
+
return active !== null;
|
|
66
38
|
}
|
|
67
39
|
/**
|
|
68
|
-
* The
|
|
69
|
-
* session is active (local-only mode, or sync has not bootstrapped yet).
|
|
40
|
+
* The active storage context, or throws if no session store has been created.
|
|
70
41
|
*
|
|
71
|
-
* @returns {
|
|
42
|
+
* @returns {StorageContext}
|
|
72
43
|
*/
|
|
73
|
-
export function
|
|
74
|
-
if (!
|
|
75
|
-
throw new Error('No
|
|
44
|
+
export function requireStorageContext() {
|
|
45
|
+
if (!active) {
|
|
46
|
+
throw new Error('No storage context is active; create the session store first.');
|
|
76
47
|
}
|
|
77
|
-
return
|
|
48
|
+
return active;
|
|
78
49
|
}
|
|
79
50
|
/**
|
|
80
|
-
*
|
|
51
|
+
* The active session's opened replica, or throws if none is open.
|
|
81
52
|
*
|
|
82
|
-
* @returns {
|
|
53
|
+
* @returns {LocalStore}
|
|
83
54
|
*/
|
|
84
|
-
export function
|
|
85
|
-
return
|
|
55
|
+
export function requireStore() {
|
|
56
|
+
return requireStorageContext().requireStore();
|
|
86
57
|
}
|
|
87
58
|
/**
|
|
88
|
-
*
|
|
59
|
+
* Whether the active session has a replica open.
|
|
89
60
|
*
|
|
90
|
-
* @returns {
|
|
61
|
+
* @returns {boolean}
|
|
91
62
|
*/
|
|
92
|
-
export function
|
|
93
|
-
|
|
63
|
+
export function hasStore() {
|
|
64
|
+
return active?.hasStore() ?? false;
|
|
94
65
|
}
|
|
95
66
|
/**
|
|
96
|
-
* The
|
|
97
|
-
*
|
|
98
|
-
* fresh on the next run.
|
|
99
|
-
*/
|
|
100
|
-
let fallbackWriterId = null;
|
|
101
|
-
/**
|
|
102
|
-
* A stable per-install writer id (the last-write-wins tiebreak stamped into
|
|
103
|
-
* every payload), persisted in localStorage under `<prefix>writerId`. In an
|
|
104
|
-
* environment without `localStorage` it falls back to a process-stable
|
|
105
|
-
* unpersisted id instead of throwing.
|
|
67
|
+
* The active session's remote store, or throws while no wallet-connected
|
|
68
|
+
* session is active.
|
|
106
69
|
*
|
|
107
|
-
*
|
|
108
|
-
* miss it adopts a value left under the pre-rename `<prefix>clientId` key and
|
|
109
|
-
* removes the old one, so an existing install keeps stamping the same id
|
|
110
|
-
* across the rename rather than looking like a second writer.
|
|
111
|
-
*
|
|
112
|
-
* @param [options] {object}
|
|
113
|
-
* @param [options.storageKeyPrefix] {string} the localStorage key prefix
|
|
114
|
-
* (defaults to {@link DEFAULT_STORAGE_KEY_PREFIX})
|
|
115
|
-
* @returns {string}
|
|
70
|
+
* @returns {WasRemoteStore}
|
|
116
71
|
*/
|
|
117
|
-
export function
|
|
118
|
-
|
|
119
|
-
const legacyKey = `${storageKeyPrefix}clientId`;
|
|
120
|
-
try {
|
|
121
|
-
let id = localStorage.getItem(writerIdKey);
|
|
122
|
-
if (!id) {
|
|
123
|
-
id = localStorage.getItem(legacyKey) || uuidv7();
|
|
124
|
-
localStorage.setItem(writerIdKey, id);
|
|
125
|
-
localStorage.removeItem(legacyKey);
|
|
126
|
-
}
|
|
127
|
-
return id;
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
fallbackWriterId ??= uuidv7();
|
|
131
|
-
return fallbackWriterId;
|
|
132
|
-
}
|
|
72
|
+
export function requireRemoteStore() {
|
|
73
|
+
return requireStorageContext().requireRemoteStore();
|
|
133
74
|
}
|
|
134
|
-
let resolvedWriterId = null;
|
|
135
75
|
/**
|
|
136
|
-
*
|
|
137
|
-
* under the app's configured `storageKeyPrefix`, before any replica opens).
|
|
76
|
+
* Whether the active session has a remote store available.
|
|
138
77
|
*
|
|
139
|
-
* @
|
|
140
|
-
* @returns {void}
|
|
78
|
+
* @returns {boolean}
|
|
141
79
|
*/
|
|
142
|
-
export function
|
|
143
|
-
|
|
80
|
+
export function hasRemoteStore() {
|
|
81
|
+
return active?.hasRemoteStore() ?? false;
|
|
144
82
|
}
|
|
145
83
|
/**
|
|
146
|
-
* The session's
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
84
|
+
* The active session's writer id, or throws if no session store exists yet.
|
|
85
|
+
* Deliberately never falls back to `getWriterId`: that would resolve under the
|
|
86
|
+
* DEFAULT key prefix, so an app with a custom `storageKeyPrefix` would silently
|
|
87
|
+
* stamp a second writer id.
|
|
150
88
|
*
|
|
151
89
|
* @returns {string}
|
|
152
90
|
*/
|
|
153
91
|
export function requireWriterId() {
|
|
154
|
-
|
|
155
|
-
throw new Error('Writer id is not resolved; create the session store first.');
|
|
156
|
-
}
|
|
157
|
-
return resolvedWriterId;
|
|
92
|
+
return requireStorageContext().writerId;
|
|
158
93
|
}
|
|
159
94
|
/**
|
|
160
|
-
* Stamps a payload with fresh last-write-wins fields
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* doc's older `updatedAt` would ride a later edit and lose the conflict.
|
|
95
|
+
* Stamps a payload with fresh last-write-wins fields under the active session
|
|
96
|
+
* (see {@link StorageContext.stampLww}); the entity-store write verbs call it
|
|
97
|
+
* on every write, and an app writing through `LocalStore` directly does too.
|
|
164
98
|
*
|
|
165
99
|
* @param payload {object}
|
|
166
100
|
* @returns {object} the payload with the LWW fields set
|
|
167
101
|
*/
|
|
168
102
|
export function stampLww(payload) {
|
|
169
|
-
return
|
|
170
|
-
...payload,
|
|
171
|
-
updatedAt: new Date().toISOString(),
|
|
172
|
-
writerId: requireWriterId()
|
|
173
|
-
};
|
|
103
|
+
return requireStorageContext().stampLww(payload);
|
|
174
104
|
}
|
|
175
105
|
//# sourceMappingURL=storageManager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storageManager.js","sourceRoot":"","sources":["../../src/storage/storageManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"storageManager.js","sourceRoot":"","sources":["../../src/storage/storageManager.ts"],"names":[],"mappings":"AAyBA,IAAI,MAAM,GAA0B,IAAI,CAAA;AAExC;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAuB;IAC5D,IAAI,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,wDAAwD;YACtD,8DAA8D,CACjE,CAAA;IACH,CAAC;IACD,MAAM,GAAG,OAAO,CAAA;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAuB;IAC9D,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,GAAG,IAAI,CAAA;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,KAAK,IAAI,CAAA;AACxB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,+DAA+D,CAChE,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,qBAAqB,EAAE,CAAC,YAAY,EAAE,CAAA;AAC/C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,MAAM,EAAE,QAAQ,EAAE,IAAI,KAAK,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,qBAAqB,EAAE,CAAC,kBAAkB,EAAE,CAAA;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,MAAM,EAAE,cAAc,EAAE,IAAI,KAAK,CAAA;AAC1C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,qBAAqB,EAAE,CAAC,QAAQ,CAAA;AACzC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAA2B,OAAU;IAC3D,OAAO,qBAAqB,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;AAClD,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { type SyncedDoc } from '../sync/index.js';
|
|
|
3
3
|
import { type WasCollectionConfig, type WasSyncConfig } from '../config.js';
|
|
4
4
|
import type { LocalStore } from './localStore.js';
|
|
5
5
|
import type { WasRemoteStore } from './wasRemoteStore.js';
|
|
6
|
+
import type { SyncStatusStore } from './syncStatusStore.js';
|
|
6
7
|
/**
|
|
7
8
|
* Whether a replication error signals expired/revoked storage access. Every WAS
|
|
8
9
|
* request the replication makes funnels through the sync port, which maps a
|
|
@@ -24,8 +25,16 @@ export declare function isAuthError(err: unknown): boolean;
|
|
|
24
25
|
*/
|
|
25
26
|
export declare class SyncController {
|
|
26
27
|
#private;
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @param options {object}
|
|
30
|
+
* @param options.collections {WasCollectionConfig[]}
|
|
31
|
+
* @param options.syncStatus {SyncStatusStore} the session's per-collection
|
|
32
|
+
* status store this controller reports into
|
|
33
|
+
* @param [options.sync] {WasSyncConfig}
|
|
34
|
+
*/
|
|
35
|
+
constructor({ collections, syncStatus, sync }: {
|
|
28
36
|
collections: WasCollectionConfig[];
|
|
37
|
+
syncStatus: SyncStatusStore;
|
|
29
38
|
sync?: WasSyncConfig;
|
|
30
39
|
});
|
|
31
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncController.d.ts","sourceRoot":"","sources":["../../src/storage/syncController.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAML,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"syncController.d.ts","sourceRoot":"","sources":["../../src/storage/syncController.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAML,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,aAAa,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAO3D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CA+BjD;AAED;;GAEG;AACH,qBAAa,cAAc;;IAazB;;;;;;OAMG;gBACS,EACV,WAAW,EACX,UAAU,EACV,IAAI,EACL,EAAE;QACD,WAAW,EAAE,mBAAmB,EAAE,CAAA;QAClC,UAAU,EAAE,eAAe,CAAA;QAC3B,IAAI,CAAC,EAAE,aAAa,CAAA;KACrB;IAMD;;;;;;;;;;;;;OAaG;IACG,KAAK,CAAC,EACV,WAAW,EACX,UAAU,EACV,cAAc,EACd,WAAW,EACZ,EAAE;QACD,WAAW,EAAE,cAAc,CAAA;QAC3B,UAAU,EAAE,UAAU,CAAA;QACtB,cAAc,CAAC,EAAE,CACf,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,KAC5B,IAAI,CAAA;QACT,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;KACzB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgIjB;;;;;OAKG;IACH,MAAM,IAAI,IAAI;IAMd;;;;;OAKG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ5B"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createWasReplication, createWasSyncPort, withFeedMasterRead, WasSyncAuthError } from '../sync/index.js';
|
|
2
2
|
import { DEFAULT_SYNC_POLL_MS } from '../config.js';
|
|
3
|
-
import { useSyncStatusStore } from './syncStatusStore.js';
|
|
4
3
|
/**
|
|
5
4
|
* Whether a replication error signals expired/revoked storage access. Every WAS
|
|
6
5
|
* request the replication makes funnels through the sync port, which maps a
|
|
@@ -48,13 +47,22 @@ export function isAuthError(err) {
|
|
|
48
47
|
export class SyncController {
|
|
49
48
|
#collections;
|
|
50
49
|
#sync;
|
|
50
|
+
#syncStatus;
|
|
51
51
|
#replications = [];
|
|
52
52
|
#onlineHandler;
|
|
53
53
|
#pollTimer;
|
|
54
54
|
#started = false;
|
|
55
55
|
#stopped = false;
|
|
56
|
-
|
|
56
|
+
/**
|
|
57
|
+
* @param options {object}
|
|
58
|
+
* @param options.collections {WasCollectionConfig[]}
|
|
59
|
+
* @param options.syncStatus {SyncStatusStore} the session's per-collection
|
|
60
|
+
* status store this controller reports into
|
|
61
|
+
* @param [options.sync] {WasSyncConfig}
|
|
62
|
+
*/
|
|
63
|
+
constructor({ collections, syncStatus, sync }) {
|
|
57
64
|
this.#collections = collections;
|
|
65
|
+
this.#syncStatus = syncStatus;
|
|
58
66
|
this.#sync = sync ?? {};
|
|
59
67
|
}
|
|
60
68
|
/**
|
|
@@ -79,7 +87,7 @@ export class SyncController {
|
|
|
79
87
|
return;
|
|
80
88
|
}
|
|
81
89
|
this.#started = true;
|
|
82
|
-
const setStatus =
|
|
90
|
+
const setStatus = this.#syncStatus.getState().setStatus;
|
|
83
91
|
const batchSize = this.#sync.batchSize;
|
|
84
92
|
const retryMs = this.#sync.retryMs;
|
|
85
93
|
const pollMs = this.#sync.pollMs ?? DEFAULT_SYNC_POLL_MS;
|
|
@@ -211,7 +219,7 @@ export class SyncController {
|
|
|
211
219
|
// bootstrap) sees the controller as terminally stopped and bails.
|
|
212
220
|
this.#stopped = true;
|
|
213
221
|
await this.#teardownReplications();
|
|
214
|
-
|
|
222
|
+
this.#syncStatus.getState().reset();
|
|
215
223
|
this.#started = false;
|
|
216
224
|
}
|
|
217
225
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncController.js","sourceRoot":"","sources":["../../src/storage/syncController.ts"],"names":[],"mappings":"AAgCA,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAGjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,oBAAoB,EAGrB,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"syncController.js","sourceRoot":"","sources":["../../src/storage/syncController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* The per-collection replication status store, mirroring the WAS per-replica
|
|
6
|
+
* sync-status vocabulary, keyed by the registry's logical collection key. One
|
|
7
|
+
* is created per {@link StorageContext} (so per session provider, never
|
|
8
|
+
* process-wide): the sync controller writes to it off the RxDB replication
|
|
9
|
+
* `active$` / `error$` streams, and `useSyncStatus` reads it through the
|
|
10
|
+
* provider. In-memory only, like the session -- reset on logout.
|
|
11
|
+
*/
|
|
12
|
+
import { type StoreApi } from 'zustand/vanilla';
|
|
1
13
|
/**
|
|
2
14
|
* A single collection's replication status:
|
|
3
15
|
* - `idle` -- configured but no cycle has run yet
|
|
@@ -6,7 +18,7 @@
|
|
|
6
18
|
* - `error` -- last cycle failed (RxDB is backing off / will retry)
|
|
7
19
|
*/
|
|
8
20
|
export type SyncStatus = 'idle' | 'syncing' | 'synced' | 'error';
|
|
9
|
-
|
|
21
|
+
interface SyncStatusState {
|
|
10
22
|
/**
|
|
11
23
|
* Keyed by the registry's LOGICAL collection key (`WasCollectionConfig.key`,
|
|
12
24
|
* e.g. `actionItems`), not the WAS wire id. Two registry entries may share one
|
|
@@ -17,7 +29,15 @@ export declare const useSyncStatusStore: import("zustand").UseBoundStore<import(
|
|
|
17
29
|
statuses: Record<string, SyncStatus>;
|
|
18
30
|
setStatus: (collectionKey: string, status: SyncStatus) => void;
|
|
19
31
|
reset: () => void;
|
|
20
|
-
}
|
|
32
|
+
}
|
|
33
|
+
export type SyncStatusStore = StoreApi<SyncStatusState>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates one session's sync status store (a vanilla zustand store; subscribe
|
|
36
|
+
* to it from React with zustand's `useStore`).
|
|
37
|
+
*
|
|
38
|
+
* @returns {SyncStatusStore}
|
|
39
|
+
*/
|
|
40
|
+
export declare function createSyncStatusStore(): SyncStatusStore;
|
|
21
41
|
/**
|
|
22
42
|
* The aggregate replication status derived from the per-collection statuses:
|
|
23
43
|
* `offline` when no replication is running (local-only), otherwise rolled up as
|
|
@@ -41,4 +61,5 @@ export declare function deriveSyncRollup(statuses: SyncStatus[]): {
|
|
|
41
61
|
label: string;
|
|
42
62
|
title: string;
|
|
43
63
|
};
|
|
64
|
+
export {};
|
|
44
65
|
//# sourceMappingURL=syncStatusStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncStatusStore.d.ts","sourceRoot":"","sources":["../../src/storage/syncStatusStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"syncStatusStore.d.ts","sourceRoot":"","sources":["../../src/storage/syncStatusStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE5D;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;AAEhE,UAAU,eAAe;IACvB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACpC,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;IAC9D,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAA;AAEvD;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CASvD;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAA;AAEnE;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG;IACxD,KAAK,EAAE,UAAU,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,CA2BA"}
|
|
@@ -2,20 +2,29 @@
|
|
|
2
2
|
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* The per-collection replication status store, mirroring the WAS per-replica
|
|
6
|
+
* sync-status vocabulary, keyed by the registry's logical collection key. One
|
|
7
|
+
* is created per {@link StorageContext} (so per session provider, never
|
|
8
|
+
* process-wide): the sync controller writes to it off the RxDB replication
|
|
9
|
+
* `active$` / `error$` streams, and `useSyncStatus` reads it through the
|
|
10
|
+
* provider. In-memory only, like the session -- reset on logout.
|
|
10
11
|
*/
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
import { createStore } from 'zustand/vanilla';
|
|
13
|
+
/**
|
|
14
|
+
* Creates one session's sync status store (a vanilla zustand store; subscribe
|
|
15
|
+
* to it from React with zustand's `useStore`).
|
|
16
|
+
*
|
|
17
|
+
* @returns {SyncStatusStore}
|
|
18
|
+
*/
|
|
19
|
+
export function createSyncStatusStore() {
|
|
20
|
+
return createStore()(set => ({
|
|
21
|
+
statuses: {},
|
|
22
|
+
setStatus: (collectionKey, status) => set(state => ({
|
|
23
|
+
statuses: { ...state.statuses, [collectionKey]: status }
|
|
24
|
+
})),
|
|
25
|
+
reset: () => set({ statuses: {} })
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
19
28
|
/**
|
|
20
29
|
* Rolls the per-collection replication statuses up to a single aggregate plus
|
|
21
30
|
* its display copy. With no collections registered it reports `offline`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncStatusStore.js","sourceRoot":"","sources":["../../src/storage/syncStatusStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"syncStatusStore.js","sourceRoot":"","sources":["../../src/storage/syncStatusStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAiB,MAAM,iBAAiB,CAAA;AA0B5D;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,WAAW,EAAmB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,CACnC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACZ,QAAQ,EAAE,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE;SACzD,CAAC,CAAC;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;KACnC,CAAC,CAAC,CAAA;AACL,CAAC;AASD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAsB;IAKrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,mDAAmD;SAC3D,CAAA;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,+DAA+D;SACvE,CAAA;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9D,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,sDAAsD;SAC9D,CAAA;IACH,CAAC;IACD,OAAO;QACL,KAAK,EAAE,QAAQ;QACf,KAAK,EAAE,QAAQ;QACf,KAAK,EAAE,oDAAoD;KAC5D,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stable per-install writer id (the last-write-wins tiebreak stamped into
|
|
3
|
+
* every payload), persisted in localStorage under `<prefix>writerId`. In an
|
|
4
|
+
* environment without `localStorage` it falls back to a process-stable
|
|
5
|
+
* unpersisted id instead of throwing.
|
|
6
|
+
*
|
|
7
|
+
* The id is an unkeyed, clearable attribution label -- never an identity. On a
|
|
8
|
+
* miss it adopts a value left under the pre-rename `<prefix>clientId` key and
|
|
9
|
+
* removes the old one, so an existing install keeps stamping the same id
|
|
10
|
+
* across the rename rather than looking like a second writer.
|
|
11
|
+
*
|
|
12
|
+
* @param [options] {object}
|
|
13
|
+
* @param [options.storageKeyPrefix] {string} the localStorage key prefix
|
|
14
|
+
* (defaults to {@link DEFAULT_STORAGE_KEY_PREFIX})
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
export declare function getWriterId({ storageKeyPrefix }?: {
|
|
18
|
+
storageKeyPrefix?: string;
|
|
19
|
+
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* Clears the persisted writer id (the clear-data grade of the wipe): removes
|
|
22
|
+
* both the current key and the pre-rename one, so nothing this library wrote
|
|
23
|
+
* survives in localStorage. Only persistence is touched; the running session's
|
|
24
|
+
* in-memory id is replaced by {@link StorageContext.resetWriterId}, because the
|
|
25
|
+
* session keeps running over its new anonymous replica and its write verbs
|
|
26
|
+
* still have to stamp.
|
|
27
|
+
*
|
|
28
|
+
* @param [options] {object}
|
|
29
|
+
* @param [options.storageKeyPrefix] {string} the localStorage key prefix
|
|
30
|
+
* (defaults to {@link DEFAULT_STORAGE_KEY_PREFIX})
|
|
31
|
+
* @returns {void}
|
|
32
|
+
*/
|
|
33
|
+
export declare function clearPersistedWriterId({ storageKeyPrefix }?: {
|
|
34
|
+
storageKeyPrefix?: string;
|
|
35
|
+
}): void;
|
|
36
|
+
//# sourceMappingURL=writerId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writerId.d.ts","sourceRoot":"","sources":["../../src/storage/writerId.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,EAC1B,gBAA6C,EAC9C,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAe7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,gBAA6C,EAC9C,GAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,CAQ3C"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Persistence of the per-install writer id: the last-write-wins tiebreak the
|
|
6
|
+
* storage context stamps into every payload. {@link getWriterId} resolves it
|
|
7
|
+
* from localStorage (minting one on a miss), {@link clearPersistedWriterId}
|
|
8
|
+
* removes it (the clear-data grade of the wipe). The in-memory value a session
|
|
9
|
+
* stamps with lives on its {@link StorageContext}; nothing here holds state
|
|
10
|
+
* beyond the no-localStorage fallback.
|
|
11
|
+
*/
|
|
12
|
+
import { uuidv7 } from 'uuidv7';
|
|
13
|
+
import { DEFAULT_STORAGE_KEY_PREFIX } from '../config.js';
|
|
14
|
+
/**
|
|
15
|
+
* The unpersisted fallback writer id for environments without `localStorage`
|
|
16
|
+
* (tests, SSR): process-stable, so every resolution within one run agrees,
|
|
17
|
+
* minted fresh on the next run.
|
|
18
|
+
*/
|
|
19
|
+
let fallbackWriterId = null;
|
|
20
|
+
/**
|
|
21
|
+
* A stable per-install writer id (the last-write-wins tiebreak stamped into
|
|
22
|
+
* every payload), persisted in localStorage under `<prefix>writerId`. In an
|
|
23
|
+
* environment without `localStorage` it falls back to a process-stable
|
|
24
|
+
* unpersisted id instead of throwing.
|
|
25
|
+
*
|
|
26
|
+
* The id is an unkeyed, clearable attribution label -- never an identity. On a
|
|
27
|
+
* miss it adopts a value left under the pre-rename `<prefix>clientId` key and
|
|
28
|
+
* removes the old one, so an existing install keeps stamping the same id
|
|
29
|
+
* across the rename rather than looking like a second writer.
|
|
30
|
+
*
|
|
31
|
+
* @param [options] {object}
|
|
32
|
+
* @param [options.storageKeyPrefix] {string} the localStorage key prefix
|
|
33
|
+
* (defaults to {@link DEFAULT_STORAGE_KEY_PREFIX})
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
export function getWriterId({ storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX } = {}) {
|
|
37
|
+
const writerIdKey = `${storageKeyPrefix}writerId`;
|
|
38
|
+
const legacyKey = `${storageKeyPrefix}clientId`;
|
|
39
|
+
try {
|
|
40
|
+
let id = localStorage.getItem(writerIdKey);
|
|
41
|
+
if (!id) {
|
|
42
|
+
id = localStorage.getItem(legacyKey) || uuidv7();
|
|
43
|
+
localStorage.setItem(writerIdKey, id);
|
|
44
|
+
localStorage.removeItem(legacyKey);
|
|
45
|
+
}
|
|
46
|
+
return id;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
fallbackWriterId ??= uuidv7();
|
|
50
|
+
return fallbackWriterId;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Clears the persisted writer id (the clear-data grade of the wipe): removes
|
|
55
|
+
* both the current key and the pre-rename one, so nothing this library wrote
|
|
56
|
+
* survives in localStorage. Only persistence is touched; the running session's
|
|
57
|
+
* in-memory id is replaced by {@link StorageContext.resetWriterId}, because the
|
|
58
|
+
* session keeps running over its new anonymous replica and its write verbs
|
|
59
|
+
* still have to stamp.
|
|
60
|
+
*
|
|
61
|
+
* @param [options] {object}
|
|
62
|
+
* @param [options.storageKeyPrefix] {string} the localStorage key prefix
|
|
63
|
+
* (defaults to {@link DEFAULT_STORAGE_KEY_PREFIX})
|
|
64
|
+
* @returns {void}
|
|
65
|
+
*/
|
|
66
|
+
export function clearPersistedWriterId({ storageKeyPrefix = DEFAULT_STORAGE_KEY_PREFIX } = {}) {
|
|
67
|
+
try {
|
|
68
|
+
localStorage.removeItem(`${storageKeyPrefix}writerId`);
|
|
69
|
+
localStorage.removeItem(`${storageKeyPrefix}clientId`);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// No localStorage in this environment: nothing was persisted to clear.
|
|
73
|
+
}
|
|
74
|
+
fallbackWriterId = null;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=writerId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writerId.js","sourceRoot":"","sources":["../../src/storage/writerId.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAEzD;;;;GAIG;AACH,IAAI,gBAAgB,GAAkB,IAAI,CAAA;AAE1C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,EAC1B,gBAAgB,GAAG,0BAA0B,KACZ,EAAE;IACnC,MAAM,WAAW,GAAG,GAAG,gBAAgB,UAAU,CAAA;IACjD,MAAM,SAAS,GAAG,GAAG,gBAAgB,UAAU,CAAA;IAC/C,IAAI,CAAC;QACH,IAAI,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QAC1C,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,MAAM,EAAE,CAAA;YAChD,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;YACrC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB,KAAK,MAAM,EAAE,CAAA;QAC7B,OAAO,gBAAgB,CAAA;IACzB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,gBAAgB,GAAG,0BAA0B,KACZ,EAAE;IACnC,IAAI,CAAC;QACH,YAAY,CAAC,UAAU,CAAC,GAAG,gBAAgB,UAAU,CAAC,CAAA;QACtD,YAAY,CAAC,UAAU,CAAC,GAAG,gBAAgB,UAAU,CAAC,CAAA;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;IACD,gBAAgB,GAAG,IAAI,CAAA;AACzB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interop/was-react",
|
|
3
3
|
"description": "React library for building 'Bring Your Own Everything' (BYOE) apps on Wallet Attached Storage: DID Auth login via CHAPI wallet, local-first encrypted storage, and background sync to a WAS server.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.20.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "pnpm run clear && tsc",
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
"types": "dist/index.d.ts",
|
|
47
47
|
"sideEffects": false,
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@interop/data-integrity-core": "^8.
|
|
50
|
-
"@interop/did-method-webvh": "^5.
|
|
51
|
-
"@interop/ed25519-signature": "^7.
|
|
52
|
-
"@interop/ezcap": "^7.4.
|
|
53
|
-
"@interop/security-document-loader": "^10.
|
|
54
|
-
"@interop/vc": "^11.0.
|
|
55
|
-
"@interop/verifier-core": "^3.5.
|
|
56
|
-
"@interop/wallet-core": "^0.
|
|
57
|
-
"@interop/was-client": "^0.
|
|
58
|
-
"@interop/webkms-client": "^14.7.
|
|
49
|
+
"@interop/data-integrity-core": "^8.7.1",
|
|
50
|
+
"@interop/did-method-webvh": "^5.6.1",
|
|
51
|
+
"@interop/ed25519-signature": "^7.2.0",
|
|
52
|
+
"@interop/ezcap": "^7.4.5",
|
|
53
|
+
"@interop/security-document-loader": "^10.1.0",
|
|
54
|
+
"@interop/vc": "^11.0.7",
|
|
55
|
+
"@interop/verifier-core": "^3.5.5",
|
|
56
|
+
"@interop/wallet-core": "^0.66.0",
|
|
57
|
+
"@interop/was-client": "^0.47.0",
|
|
58
|
+
"@interop/webkms-client": "^14.7.4",
|
|
59
59
|
"@scure/base": "^2.2.0",
|
|
60
|
-
"byoe-context": "^0.
|
|
60
|
+
"byoe-context": "^0.5.0",
|
|
61
61
|
"credential-handler-polyfill": "^4.1.0",
|
|
62
62
|
"uuidv7": "^1.2.1"
|
|
63
63
|
},
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"typescript-eslint": "^8.59.4",
|
|
111
111
|
"vite": "^8.0.14",
|
|
112
112
|
"vitest": "^4.1.7",
|
|
113
|
-
"was-teaching-server": "^0.
|
|
113
|
+
"was-teaching-server": "^0.25.1",
|
|
114
114
|
"zustand": "^5.0.12"
|
|
115
115
|
},
|
|
116
116
|
"publishConfig": {
|