react-mnemonic 0.1.1-alpha.0 → 1.0.0-beta.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 +171 -85
- package/dist/index.cjs +615 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +578 -10
- package/dist/index.d.ts +578 -10
- package/dist/index.js +610 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -41,6 +41,121 @@ function MnemonicProvider({
|
|
|
41
41
|
const listeners = /* @__PURE__ */ new Map();
|
|
42
42
|
let quotaErrorLogged = false;
|
|
43
43
|
let accessErrorLogged = false;
|
|
44
|
+
const detectEnumerableStorage = () => {
|
|
45
|
+
if (!st) return false;
|
|
46
|
+
try {
|
|
47
|
+
return typeof st.length === "number" && typeof st.key === "function";
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const canEnumerateKeys = detectEnumerableStorage();
|
|
53
|
+
const isProductionRuntime = () => {
|
|
54
|
+
const env = globalThis?.process?.env?.NODE_ENV;
|
|
55
|
+
if (typeof env !== "string") {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
return env === "production";
|
|
59
|
+
};
|
|
60
|
+
const weakRefConstructor = () => {
|
|
61
|
+
const ctor = globalThis?.WeakRef;
|
|
62
|
+
return typeof ctor === "function" ? ctor : null;
|
|
63
|
+
};
|
|
64
|
+
const hasFinalizationRegistry = () => typeof globalThis?.FinalizationRegistry === "function";
|
|
65
|
+
const ensureDevToolsRoot = () => {
|
|
66
|
+
if (!enableDevTools || typeof window === "undefined") return null;
|
|
67
|
+
const weakRefSupported = weakRefConstructor() !== null;
|
|
68
|
+
const finalizationRegistrySupported = hasFinalizationRegistry();
|
|
69
|
+
const globalWindow = window;
|
|
70
|
+
const rawExisting = globalWindow.__REACT_MNEMONIC_DEVTOOLS__;
|
|
71
|
+
const root = rawExisting && typeof rawExisting === "object" ? rawExisting : {};
|
|
72
|
+
const reserved = /* @__PURE__ */ new Set(["providers", "resolve", "list", "capabilities", "__meta"]);
|
|
73
|
+
for (const key of Object.keys(root)) {
|
|
74
|
+
if (!reserved.has(key)) {
|
|
75
|
+
const descriptor = Object.getOwnPropertyDescriptor(root, key);
|
|
76
|
+
if (!descriptor || descriptor.configurable) {
|
|
77
|
+
try {
|
|
78
|
+
delete root[key];
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!root.providers || typeof root.providers !== "object") {
|
|
85
|
+
root.providers = {};
|
|
86
|
+
}
|
|
87
|
+
if (!root.capabilities || typeof root.capabilities !== "object") {
|
|
88
|
+
root.capabilities = {};
|
|
89
|
+
}
|
|
90
|
+
root.capabilities.weakRef = weakRefSupported;
|
|
91
|
+
root.capabilities.finalizationRegistry = finalizationRegistrySupported;
|
|
92
|
+
if (!root.__meta || typeof root.__meta !== "object") {
|
|
93
|
+
root.__meta = {
|
|
94
|
+
version: 0,
|
|
95
|
+
lastUpdated: Date.now(),
|
|
96
|
+
lastChange: ""
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (typeof root.__meta.version !== "number" || !Number.isFinite(root.__meta.version)) {
|
|
100
|
+
root.__meta.version = 0;
|
|
101
|
+
}
|
|
102
|
+
if (typeof root.__meta.lastUpdated !== "number" || !Number.isFinite(root.__meta.lastUpdated)) {
|
|
103
|
+
root.__meta.lastUpdated = Date.now();
|
|
104
|
+
}
|
|
105
|
+
if (typeof root.__meta.lastChange !== "string") {
|
|
106
|
+
root.__meta.lastChange = "";
|
|
107
|
+
}
|
|
108
|
+
if (typeof root.resolve !== "function") {
|
|
109
|
+
root.resolve = (ns) => {
|
|
110
|
+
const entry = root.providers[ns];
|
|
111
|
+
if (!entry || !entry.weakRef || typeof entry.weakRef.deref !== "function") return null;
|
|
112
|
+
const live = entry.weakRef.deref();
|
|
113
|
+
if (live) {
|
|
114
|
+
entry.lastSeenAt = Date.now();
|
|
115
|
+
entry.staleSince = null;
|
|
116
|
+
return live;
|
|
117
|
+
}
|
|
118
|
+
if (entry.staleSince === null) {
|
|
119
|
+
entry.staleSince = Date.now();
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (typeof root.list !== "function") {
|
|
125
|
+
root.list = () => {
|
|
126
|
+
const entries = root.providers;
|
|
127
|
+
const out = [];
|
|
128
|
+
for (const [ns, entry] of Object.entries(entries)) {
|
|
129
|
+
const live = entry && entry.weakRef && typeof entry.weakRef.deref === "function" ? entry.weakRef.deref() : void 0;
|
|
130
|
+
const available = Boolean(live);
|
|
131
|
+
if (available) {
|
|
132
|
+
entry.lastSeenAt = Date.now();
|
|
133
|
+
entry.staleSince = null;
|
|
134
|
+
} else if (entry.staleSince === null) {
|
|
135
|
+
entry.staleSince = Date.now();
|
|
136
|
+
}
|
|
137
|
+
out.push({
|
|
138
|
+
namespace: ns,
|
|
139
|
+
available,
|
|
140
|
+
registeredAt: entry.registeredAt,
|
|
141
|
+
lastSeenAt: entry.lastSeenAt,
|
|
142
|
+
staleSince: entry.staleSince
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
out.sort((a, b) => a.namespace.localeCompare(b.namespace));
|
|
146
|
+
return out;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
globalWindow.__REACT_MNEMONIC_DEVTOOLS__ = root;
|
|
150
|
+
return root;
|
|
151
|
+
};
|
|
152
|
+
const bumpDevToolsVersion = (reason) => {
|
|
153
|
+
const root = ensureDevToolsRoot();
|
|
154
|
+
if (!root) return;
|
|
155
|
+
root.__meta.version += 1;
|
|
156
|
+
root.__meta.lastUpdated = Date.now();
|
|
157
|
+
root.__meta.lastChange = `${namespace}.${reason}`;
|
|
158
|
+
};
|
|
44
159
|
const fullKey = (key) => prefix + key;
|
|
45
160
|
const emit = (key) => {
|
|
46
161
|
const set = listeners.get(key);
|
|
@@ -90,6 +205,7 @@ function MnemonicProvider({
|
|
|
90
205
|
}
|
|
91
206
|
}
|
|
92
207
|
emit(key);
|
|
208
|
+
bumpDevToolsVersion(`set:${key}`);
|
|
93
209
|
};
|
|
94
210
|
const removeRaw = (key) => {
|
|
95
211
|
cache.set(key, null);
|
|
@@ -102,6 +218,7 @@ function MnemonicProvider({
|
|
|
102
218
|
}
|
|
103
219
|
}
|
|
104
220
|
emit(key);
|
|
221
|
+
bumpDevToolsVersion(`remove:${key}`);
|
|
105
222
|
};
|
|
106
223
|
const subscribeRaw = (key, listener) => {
|
|
107
224
|
let set = listeners.get(key);
|
|
@@ -120,11 +237,14 @@ function MnemonicProvider({
|
|
|
120
237
|
};
|
|
121
238
|
const getRawSnapshot = (key) => readThrough(key);
|
|
122
239
|
const keys = () => {
|
|
123
|
-
if (!
|
|
240
|
+
if (!canEnumerateKeys || !st) return [];
|
|
124
241
|
const out = [];
|
|
125
242
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
243
|
+
const storageLength = st.length;
|
|
244
|
+
const getStorageKey = st.key;
|
|
245
|
+
if (typeof storageLength !== "number" || typeof getStorageKey !== "function") return [];
|
|
246
|
+
for (let i = 0; i < storageLength; i++) {
|
|
247
|
+
const k = getStorageKey.call(st, i);
|
|
128
248
|
if (!k) continue;
|
|
129
249
|
if (k.startsWith(prefix)) out.push(k.slice(prefix.length));
|
|
130
250
|
}
|
|
@@ -144,6 +264,7 @@ function MnemonicProvider({
|
|
|
144
264
|
};
|
|
145
265
|
const reloadFromStorage = (changedKeys) => {
|
|
146
266
|
if (!st) return;
|
|
267
|
+
let changed = false;
|
|
147
268
|
if (changedKeys !== void 0 && changedKeys.length === 0) return;
|
|
148
269
|
if (changedKeys !== void 0) {
|
|
149
270
|
for (const fk of changedKeys) {
|
|
@@ -163,11 +284,15 @@ function MnemonicProvider({
|
|
|
163
284
|
if (fresh !== cached) {
|
|
164
285
|
cache.set(key, fresh);
|
|
165
286
|
emit(key);
|
|
287
|
+
changed = true;
|
|
166
288
|
}
|
|
167
289
|
} else if (cache.has(key)) {
|
|
168
290
|
cache.delete(key);
|
|
169
291
|
}
|
|
170
292
|
}
|
|
293
|
+
if (changed) {
|
|
294
|
+
bumpDevToolsVersion("reload:granular");
|
|
295
|
+
}
|
|
171
296
|
return;
|
|
172
297
|
}
|
|
173
298
|
for (const [key, listenerSet] of listeners) {
|
|
@@ -184,6 +309,7 @@ function MnemonicProvider({
|
|
|
184
309
|
if (fresh !== cached) {
|
|
185
310
|
cache.set(key, fresh);
|
|
186
311
|
emit(key);
|
|
312
|
+
changed = true;
|
|
187
313
|
}
|
|
188
314
|
}
|
|
189
315
|
for (const key of cache.keys()) {
|
|
@@ -191,9 +317,13 @@ function MnemonicProvider({
|
|
|
191
317
|
cache.delete(key);
|
|
192
318
|
}
|
|
193
319
|
}
|
|
320
|
+
if (changed) {
|
|
321
|
+
bumpDevToolsVersion("reload:full");
|
|
322
|
+
}
|
|
194
323
|
};
|
|
195
324
|
const store2 = {
|
|
196
325
|
prefix,
|
|
326
|
+
canEnumerateKeys,
|
|
197
327
|
subscribeRaw,
|
|
198
328
|
getRawSnapshot,
|
|
199
329
|
setRaw: writeRaw,
|
|
@@ -205,56 +335,86 @@ function MnemonicProvider({
|
|
|
205
335
|
...schemaRegistry ? { schemaRegistry } : {}
|
|
206
336
|
};
|
|
207
337
|
if (enableDevTools && typeof window !== "undefined") {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
338
|
+
const root = ensureDevToolsRoot();
|
|
339
|
+
let infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" available via window.__REACT_MNEMONIC_DEVTOOLS__.resolve("${namespace}")`;
|
|
340
|
+
if (root) {
|
|
341
|
+
if (!root.capabilities.weakRef) {
|
|
342
|
+
infoMessage = `[Mnemonic DevTools] WeakRef is not available; registry provider "${namespace}" was not registered.`;
|
|
343
|
+
} else {
|
|
344
|
+
const existingLive = root.resolve(namespace);
|
|
345
|
+
if (existingLive) {
|
|
346
|
+
const duplicateMessage = `[Mnemonic DevTools] Duplicate provider namespace "${namespace}" detected. Each window must have at most one live MnemonicProvider per namespace.`;
|
|
347
|
+
if (!isProductionRuntime()) {
|
|
348
|
+
throw new Error(duplicateMessage);
|
|
349
|
+
}
|
|
350
|
+
console.warn(`${duplicateMessage} Keeping the first provider and ignoring the duplicate.`);
|
|
351
|
+
infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" already registered. Keeping existing provider reference.`;
|
|
352
|
+
} else {
|
|
353
|
+
const providerApi = {
|
|
354
|
+
/** Access the underlying store instance */
|
|
355
|
+
getStore: () => store2,
|
|
356
|
+
/** Dump all key-value pairs and display as a console table */
|
|
357
|
+
dump: () => {
|
|
358
|
+
const data = dump();
|
|
359
|
+
console.table(
|
|
360
|
+
Object.entries(data).map(([key, value]) => ({
|
|
361
|
+
key,
|
|
362
|
+
value,
|
|
363
|
+
decoded: (() => {
|
|
364
|
+
try {
|
|
365
|
+
return JSON.parse(value);
|
|
366
|
+
} catch {
|
|
367
|
+
return value;
|
|
368
|
+
}
|
|
369
|
+
})()
|
|
370
|
+
}))
|
|
371
|
+
);
|
|
372
|
+
return data;
|
|
373
|
+
},
|
|
374
|
+
/** Get a decoded value by key */
|
|
375
|
+
get: (key) => {
|
|
376
|
+
const raw = readThrough(key);
|
|
377
|
+
if (raw == null) return void 0;
|
|
220
378
|
try {
|
|
221
|
-
return JSON.parse(
|
|
379
|
+
return JSON.parse(raw);
|
|
222
380
|
} catch {
|
|
223
|
-
return
|
|
381
|
+
return raw;
|
|
224
382
|
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
383
|
+
},
|
|
384
|
+
/** Set a value by key (automatically JSON-encoded) */
|
|
385
|
+
set: (key, value) => {
|
|
386
|
+
writeRaw(key, JSON.stringify(value));
|
|
387
|
+
},
|
|
388
|
+
/** Remove a key from storage */
|
|
389
|
+
remove: (key) => removeRaw(key),
|
|
390
|
+
/** Clear all keys in this namespace */
|
|
391
|
+
clear: () => {
|
|
392
|
+
for (const k of keys()) {
|
|
393
|
+
removeRaw(k);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
/** List all keys in this namespace */
|
|
397
|
+
keys
|
|
398
|
+
};
|
|
399
|
+
const WeakRefCtor = weakRefConstructor();
|
|
400
|
+
if (!WeakRefCtor) {
|
|
401
|
+
infoMessage = `[Mnemonic DevTools] WeakRef became unavailable while registering "${namespace}".`;
|
|
402
|
+
} else {
|
|
403
|
+
store2.__devToolsProviderApiHold = providerApi;
|
|
404
|
+
root.providers[namespace] = {
|
|
405
|
+
namespace,
|
|
406
|
+
weakRef: new WeakRefCtor(providerApi),
|
|
407
|
+
registeredAt: Date.now(),
|
|
408
|
+
lastSeenAt: Date.now(),
|
|
409
|
+
staleSince: null
|
|
410
|
+
};
|
|
411
|
+
bumpDevToolsVersion("registry:namespace-registered");
|
|
412
|
+
infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" available via window.__REACT_MNEMONIC_DEVTOOLS__.resolve("${namespace}")`;
|
|
413
|
+
}
|
|
250
414
|
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
};
|
|
255
|
-
console.info(
|
|
256
|
-
`[Mnemonic DevTools] Namespace "${namespace}" available at window.__REACT_MNEMONIC_DEVTOOLS__.${namespace}`
|
|
257
|
-
);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
console.info(infoMessage);
|
|
258
418
|
}
|
|
259
419
|
return store2;
|
|
260
420
|
}, [namespace, storage, enableDevTools, schemaMode, schemaRegistry]);
|
|
@@ -596,7 +756,7 @@ function inferJsonSchema(sample) {
|
|
|
596
756
|
// src/Mnemonic/use.ts
|
|
597
757
|
function useMnemonicKey(key, options) {
|
|
598
758
|
const api = useMnemonic();
|
|
599
|
-
const { defaultValue, onMount, onChange, listenCrossTab, codec: codecOpt, schema } = options;
|
|
759
|
+
const { defaultValue, onMount, onChange, listenCrossTab, codec: codecOpt, schema, reconcile } = options;
|
|
600
760
|
const codec = codecOpt ?? JSONCodec;
|
|
601
761
|
const schemaMode = api.schemaMode;
|
|
602
762
|
const schemaRegistry = api.schemaRegistry;
|
|
@@ -695,6 +855,112 @@ function useMnemonicKey(key, options) {
|
|
|
695
855
|
},
|
|
696
856
|
[schemaRegistry, registryCache, key]
|
|
697
857
|
);
|
|
858
|
+
const encodeForWrite = react.useCallback(
|
|
859
|
+
(nextValue) => {
|
|
860
|
+
const explicitVersion = schema?.version;
|
|
861
|
+
const latestSchema = getLatestSchemaForKey();
|
|
862
|
+
const explicitSchema = explicitVersion !== void 0 ? getSchemaForVersion(explicitVersion) : void 0;
|
|
863
|
+
let targetSchema = explicitSchema;
|
|
864
|
+
if (!targetSchema) {
|
|
865
|
+
if (explicitVersion !== void 0) {
|
|
866
|
+
if (schemaMode !== "strict") {
|
|
867
|
+
targetSchema = latestSchema;
|
|
868
|
+
}
|
|
869
|
+
} else {
|
|
870
|
+
targetSchema = latestSchema;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (!targetSchema) {
|
|
874
|
+
if (explicitVersion !== void 0 && schemaMode === "strict") {
|
|
875
|
+
throw new SchemaError(
|
|
876
|
+
"WRITE_SCHEMA_REQUIRED",
|
|
877
|
+
`Write requires schema for key "${key}" in strict mode`
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
const envelope2 = {
|
|
881
|
+
version: 0,
|
|
882
|
+
payload: codec.encode(nextValue)
|
|
883
|
+
};
|
|
884
|
+
return JSON.stringify(envelope2);
|
|
885
|
+
}
|
|
886
|
+
let valueToStore = nextValue;
|
|
887
|
+
const writeMigration = schemaRegistry?.getWriteMigration?.(key, targetSchema.version);
|
|
888
|
+
if (writeMigration) {
|
|
889
|
+
try {
|
|
890
|
+
valueToStore = writeMigration.migrate(valueToStore);
|
|
891
|
+
} catch (err) {
|
|
892
|
+
throw err instanceof SchemaError ? err : new SchemaError("MIGRATION_FAILED", `Write-time migration failed for key "${key}"`, err);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
validateAgainstSchema(valueToStore, targetSchema.schema);
|
|
896
|
+
const envelope = {
|
|
897
|
+
version: targetSchema.version,
|
|
898
|
+
payload: valueToStore
|
|
899
|
+
};
|
|
900
|
+
return JSON.stringify(envelope);
|
|
901
|
+
},
|
|
902
|
+
[
|
|
903
|
+
schema?.version,
|
|
904
|
+
key,
|
|
905
|
+
schemaMode,
|
|
906
|
+
codec,
|
|
907
|
+
schemaRegistry,
|
|
908
|
+
validateAgainstSchema,
|
|
909
|
+
getLatestSchemaForKey,
|
|
910
|
+
getSchemaForVersion
|
|
911
|
+
]
|
|
912
|
+
);
|
|
913
|
+
const applyReconcile = react.useCallback(
|
|
914
|
+
({
|
|
915
|
+
value: value2,
|
|
916
|
+
rewriteRaw,
|
|
917
|
+
pendingSchema,
|
|
918
|
+
persistedVersion,
|
|
919
|
+
latestVersion,
|
|
920
|
+
serializeForPersist,
|
|
921
|
+
derivePendingSchema
|
|
922
|
+
}) => {
|
|
923
|
+
if (!reconcile) {
|
|
924
|
+
const result = { value: value2 };
|
|
925
|
+
if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
|
|
926
|
+
if (pendingSchema !== void 0) result.pendingSchema = pendingSchema;
|
|
927
|
+
return result;
|
|
928
|
+
}
|
|
929
|
+
const context = {
|
|
930
|
+
key,
|
|
931
|
+
persistedVersion,
|
|
932
|
+
...latestVersion === void 0 ? {} : { latestVersion }
|
|
933
|
+
};
|
|
934
|
+
let baselineSerialized;
|
|
935
|
+
if (serializeForPersist) {
|
|
936
|
+
try {
|
|
937
|
+
baselineSerialized = serializeForPersist(value2);
|
|
938
|
+
} catch {
|
|
939
|
+
baselineSerialized = rewriteRaw;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
try {
|
|
943
|
+
const reconciled = reconcile(value2, context);
|
|
944
|
+
const nextPendingSchema = derivePendingSchema ? derivePendingSchema(reconciled) : pendingSchema;
|
|
945
|
+
if (!serializeForPersist) {
|
|
946
|
+
const result2 = { value: reconciled };
|
|
947
|
+
if (rewriteRaw !== void 0) result2.rewriteRaw = rewriteRaw;
|
|
948
|
+
if (nextPendingSchema !== void 0) result2.pendingSchema = nextPendingSchema;
|
|
949
|
+
return result2;
|
|
950
|
+
}
|
|
951
|
+
const nextSerialized = serializeForPersist(reconciled);
|
|
952
|
+
const nextRewriteRaw = baselineSerialized === void 0 || nextSerialized !== baselineSerialized ? nextSerialized : rewriteRaw;
|
|
953
|
+
const result = { value: reconciled };
|
|
954
|
+
if (nextRewriteRaw !== void 0) result.rewriteRaw = nextRewriteRaw;
|
|
955
|
+
if (nextPendingSchema !== void 0) result.pendingSchema = nextPendingSchema;
|
|
956
|
+
return result;
|
|
957
|
+
} catch (err) {
|
|
958
|
+
const typedErr = err instanceof SchemaError ? err : new SchemaError("RECONCILE_FAILED", `Reconciliation failed for key "${key}"`, err);
|
|
959
|
+
return { value: getFallback(typedErr) };
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
[getFallback, key, reconcile]
|
|
963
|
+
);
|
|
698
964
|
const decodeForRead = react.useCallback(
|
|
699
965
|
(rawText) => {
|
|
700
966
|
if (rawText == null) return { value: getFallback() };
|
|
@@ -730,21 +996,26 @@ function useMnemonicKey(key, options) {
|
|
|
730
996
|
}
|
|
731
997
|
try {
|
|
732
998
|
const decoded2 = typeof envelope.payload === "string" ? decodeStringPayload(envelope.payload, codec) : envelope.payload;
|
|
733
|
-
const
|
|
734
|
-
const inferred = {
|
|
999
|
+
const inferSchemaForValue = (value2) => ({
|
|
735
1000
|
key,
|
|
736
1001
|
version: 1,
|
|
737
|
-
schema:
|
|
738
|
-
};
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
payload: decoded2
|
|
742
|
-
};
|
|
743
|
-
return {
|
|
1002
|
+
schema: inferJsonSchema(value2)
|
|
1003
|
+
});
|
|
1004
|
+
const inferred = inferSchemaForValue(decoded2);
|
|
1005
|
+
return applyReconcile({
|
|
744
1006
|
value: decoded2,
|
|
745
1007
|
pendingSchema: inferred,
|
|
746
|
-
rewriteRaw: JSON.stringify(
|
|
747
|
-
|
|
1008
|
+
rewriteRaw: JSON.stringify({
|
|
1009
|
+
version: inferred.version,
|
|
1010
|
+
payload: decoded2
|
|
1011
|
+
}),
|
|
1012
|
+
persistedVersion: envelope.version,
|
|
1013
|
+
serializeForPersist: (value2) => JSON.stringify({
|
|
1014
|
+
version: inferred.version,
|
|
1015
|
+
payload: value2
|
|
1016
|
+
}),
|
|
1017
|
+
derivePendingSchema: inferSchemaForValue
|
|
1018
|
+
});
|
|
748
1019
|
} catch (err) {
|
|
749
1020
|
const typedErr = err instanceof SchemaError || err instanceof CodecError ? err : new SchemaError("TYPE_MISMATCH", `Autoschema inference failed for key "${key}"`, err);
|
|
750
1021
|
return { value: getFallback(typedErr) };
|
|
@@ -752,11 +1023,21 @@ function useMnemonicKey(key, options) {
|
|
|
752
1023
|
}
|
|
753
1024
|
if (!schemaForVersion) {
|
|
754
1025
|
if (typeof envelope.payload !== "string") {
|
|
755
|
-
return {
|
|
1026
|
+
return applyReconcile({
|
|
1027
|
+
value: envelope.payload,
|
|
1028
|
+
persistedVersion: envelope.version,
|
|
1029
|
+
...latestSchema ? { latestVersion: latestSchema.version } : {},
|
|
1030
|
+
serializeForPersist: encodeForWrite
|
|
1031
|
+
});
|
|
756
1032
|
}
|
|
757
1033
|
try {
|
|
758
1034
|
const decoded2 = decodeStringPayload(envelope.payload, codec);
|
|
759
|
-
return {
|
|
1035
|
+
return applyReconcile({
|
|
1036
|
+
value: decoded2,
|
|
1037
|
+
persistedVersion: envelope.version,
|
|
1038
|
+
...latestSchema ? { latestVersion: latestSchema.version } : {},
|
|
1039
|
+
serializeForPersist: encodeForWrite
|
|
1040
|
+
});
|
|
760
1041
|
} catch (err) {
|
|
761
1042
|
const typedErr = err instanceof SchemaError || err instanceof CodecError ? err : new CodecError(`Codec decode failed for key "${key}"`, err);
|
|
762
1043
|
return { value: getFallback(typedErr) };
|
|
@@ -771,7 +1052,12 @@ function useMnemonicKey(key, options) {
|
|
|
771
1052
|
return { value: getFallback(typedErr) };
|
|
772
1053
|
}
|
|
773
1054
|
if (!latestSchema || envelope.version >= latestSchema.version) {
|
|
774
|
-
return {
|
|
1055
|
+
return applyReconcile({
|
|
1056
|
+
value: current,
|
|
1057
|
+
persistedVersion: envelope.version,
|
|
1058
|
+
...latestSchema ? { latestVersion: latestSchema.version } : {},
|
|
1059
|
+
serializeForPersist: encodeForWrite
|
|
1060
|
+
});
|
|
775
1061
|
}
|
|
776
1062
|
const path = getMigrationPathForKey(envelope.version, latestSchema.version);
|
|
777
1063
|
if (!path) {
|
|
@@ -790,22 +1076,26 @@ function useMnemonicKey(key, options) {
|
|
|
790
1076
|
migrated = step.migrate(migrated);
|
|
791
1077
|
}
|
|
792
1078
|
validateAgainstSchema(migrated, latestSchema.schema);
|
|
793
|
-
|
|
794
|
-
version: latestSchema.version,
|
|
795
|
-
payload: migrated
|
|
796
|
-
};
|
|
797
|
-
return {
|
|
1079
|
+
return applyReconcile({
|
|
798
1080
|
value: migrated,
|
|
799
|
-
rewriteRaw: JSON.stringify(
|
|
800
|
-
|
|
1081
|
+
rewriteRaw: JSON.stringify({
|
|
1082
|
+
version: latestSchema.version,
|
|
1083
|
+
payload: migrated
|
|
1084
|
+
}),
|
|
1085
|
+
persistedVersion: envelope.version,
|
|
1086
|
+
latestVersion: latestSchema.version,
|
|
1087
|
+
serializeForPersist: encodeForWrite
|
|
1088
|
+
});
|
|
801
1089
|
} catch (err) {
|
|
802
1090
|
const typedErr = err instanceof SchemaError || err instanceof CodecError ? err : new SchemaError("MIGRATION_FAILED", `Migration failed for key "${key}"`, err);
|
|
803
1091
|
return { value: getFallback(typedErr) };
|
|
804
1092
|
}
|
|
805
1093
|
},
|
|
806
1094
|
[
|
|
1095
|
+
applyReconcile,
|
|
807
1096
|
codec,
|
|
808
1097
|
decodeStringPayload,
|
|
1098
|
+
encodeForWrite,
|
|
809
1099
|
getFallback,
|
|
810
1100
|
key,
|
|
811
1101
|
parseEnvelope,
|
|
@@ -817,61 +1107,6 @@ function useMnemonicKey(key, options) {
|
|
|
817
1107
|
validateAgainstSchema
|
|
818
1108
|
]
|
|
819
1109
|
);
|
|
820
|
-
const encodeForWrite = react.useCallback(
|
|
821
|
-
(nextValue) => {
|
|
822
|
-
const explicitVersion = schema?.version;
|
|
823
|
-
const latestSchema = getLatestSchemaForKey();
|
|
824
|
-
const explicitSchema = explicitVersion !== void 0 ? getSchemaForVersion(explicitVersion) : void 0;
|
|
825
|
-
let targetSchema = explicitSchema;
|
|
826
|
-
if (!targetSchema) {
|
|
827
|
-
if (explicitVersion !== void 0) {
|
|
828
|
-
if (schemaMode !== "strict") {
|
|
829
|
-
targetSchema = latestSchema;
|
|
830
|
-
}
|
|
831
|
-
} else {
|
|
832
|
-
targetSchema = latestSchema;
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
if (!targetSchema) {
|
|
836
|
-
if (explicitVersion !== void 0 && schemaMode === "strict") {
|
|
837
|
-
throw new SchemaError(
|
|
838
|
-
"WRITE_SCHEMA_REQUIRED",
|
|
839
|
-
`Write requires schema for key "${key}" in strict mode`
|
|
840
|
-
);
|
|
841
|
-
}
|
|
842
|
-
const envelope2 = {
|
|
843
|
-
version: 0,
|
|
844
|
-
payload: codec.encode(nextValue)
|
|
845
|
-
};
|
|
846
|
-
return JSON.stringify(envelope2);
|
|
847
|
-
}
|
|
848
|
-
let valueToStore = nextValue;
|
|
849
|
-
const writeMigration = schemaRegistry?.getWriteMigration?.(key, targetSchema.version);
|
|
850
|
-
if (writeMigration) {
|
|
851
|
-
try {
|
|
852
|
-
valueToStore = writeMigration.migrate(valueToStore);
|
|
853
|
-
} catch (err) {
|
|
854
|
-
throw err instanceof SchemaError ? err : new SchemaError("MIGRATION_FAILED", `Write-time migration failed for key "${key}"`, err);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
validateAgainstSchema(valueToStore, targetSchema.schema);
|
|
858
|
-
const envelope = {
|
|
859
|
-
version: targetSchema.version,
|
|
860
|
-
payload: valueToStore
|
|
861
|
-
};
|
|
862
|
-
return JSON.stringify(envelope);
|
|
863
|
-
},
|
|
864
|
-
[
|
|
865
|
-
schema?.version,
|
|
866
|
-
key,
|
|
867
|
-
schemaMode,
|
|
868
|
-
codec,
|
|
869
|
-
schemaRegistry,
|
|
870
|
-
validateAgainstSchema,
|
|
871
|
-
getLatestSchemaForKey,
|
|
872
|
-
getSchemaForVersion
|
|
873
|
-
]
|
|
874
|
-
);
|
|
875
1110
|
const raw = react.useSyncExternalStore(
|
|
876
1111
|
(listener) => api.subscribeRaw(key, listener),
|
|
877
1112
|
() => api.getRawSnapshot(key),
|
|
@@ -983,6 +1218,254 @@ function useMnemonicKey(key, options) {
|
|
|
983
1218
|
[value, set, reset, remove]
|
|
984
1219
|
);
|
|
985
1220
|
}
|
|
1221
|
+
function uniqueKeys(keys) {
|
|
1222
|
+
return [...new Set(keys)];
|
|
1223
|
+
}
|
|
1224
|
+
function useMnemonicRecovery(options = {}) {
|
|
1225
|
+
const api = useMnemonic();
|
|
1226
|
+
const { onRecover } = options;
|
|
1227
|
+
const namespace = react.useMemo(() => api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix, [api.prefix]);
|
|
1228
|
+
const emitRecovery = react.useCallback(
|
|
1229
|
+
(action, clearedKeys) => {
|
|
1230
|
+
const event = {
|
|
1231
|
+
action,
|
|
1232
|
+
namespace,
|
|
1233
|
+
clearedKeys
|
|
1234
|
+
};
|
|
1235
|
+
onRecover?.(event);
|
|
1236
|
+
},
|
|
1237
|
+
[namespace, onRecover]
|
|
1238
|
+
);
|
|
1239
|
+
const listKeys = react.useCallback(() => api.keys(), [api]);
|
|
1240
|
+
const clearResolvedKeys = react.useCallback(
|
|
1241
|
+
(action, keys) => {
|
|
1242
|
+
const clearedKeys = uniqueKeys(keys);
|
|
1243
|
+
for (const key of clearedKeys) {
|
|
1244
|
+
api.removeRaw(key);
|
|
1245
|
+
}
|
|
1246
|
+
emitRecovery(action, clearedKeys);
|
|
1247
|
+
return clearedKeys;
|
|
1248
|
+
},
|
|
1249
|
+
[api, emitRecovery]
|
|
1250
|
+
);
|
|
1251
|
+
const clearKeys = react.useCallback(
|
|
1252
|
+
(keys) => clearResolvedKeys("clear-keys", keys),
|
|
1253
|
+
[clearResolvedKeys]
|
|
1254
|
+
);
|
|
1255
|
+
const clearAll = react.useCallback(() => {
|
|
1256
|
+
if (!api.canEnumerateKeys) {
|
|
1257
|
+
throw new Error(
|
|
1258
|
+
"clearAll requires an enumerable storage backend. Use clearKeys([...]) with an explicit key list instead."
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
return clearResolvedKeys("clear-all", api.keys());
|
|
1262
|
+
}, [api, clearResolvedKeys]);
|
|
1263
|
+
const clearMatching = react.useCallback(
|
|
1264
|
+
(predicate) => {
|
|
1265
|
+
if (!api.canEnumerateKeys) {
|
|
1266
|
+
throw new Error(
|
|
1267
|
+
"clearMatching requires an enumerable storage backend. Use clearKeys([...]) with an explicit key list instead."
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
return clearResolvedKeys(
|
|
1271
|
+
"clear-matching",
|
|
1272
|
+
api.keys().filter((key) => predicate(key))
|
|
1273
|
+
);
|
|
1274
|
+
},
|
|
1275
|
+
[api, clearResolvedKeys]
|
|
1276
|
+
);
|
|
1277
|
+
return react.useMemo(
|
|
1278
|
+
() => ({
|
|
1279
|
+
namespace,
|
|
1280
|
+
canEnumerateKeys: api.canEnumerateKeys,
|
|
1281
|
+
listKeys,
|
|
1282
|
+
clearAll,
|
|
1283
|
+
clearKeys,
|
|
1284
|
+
clearMatching
|
|
1285
|
+
}),
|
|
1286
|
+
[namespace, api.canEnumerateKeys, listKeys, clearAll, clearKeys, clearMatching]
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// src/Mnemonic/schema-registry.ts
|
|
1291
|
+
function schemaVersionKey(key, version) {
|
|
1292
|
+
return `${key}:${version}`;
|
|
1293
|
+
}
|
|
1294
|
+
function migrationVersionKey(key, fromVersion) {
|
|
1295
|
+
return `${key}:${fromVersion}`;
|
|
1296
|
+
}
|
|
1297
|
+
function validateVersion(value, label) {
|
|
1298
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
1299
|
+
throw new SchemaError("MIGRATION_GRAPH_INVALID", `${label} must be a non-negative integer`);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function createSchemaRegistry(options = {}) {
|
|
1303
|
+
const { schemas = [], migrations = [] } = options;
|
|
1304
|
+
const schemasByKeyAndVersion = /* @__PURE__ */ new Map();
|
|
1305
|
+
const latestSchemaByKey = /* @__PURE__ */ new Map();
|
|
1306
|
+
const writeMigrationsByKeyAndVersion = /* @__PURE__ */ new Map();
|
|
1307
|
+
const migrationsByKeyAndFromVersion = /* @__PURE__ */ new Map();
|
|
1308
|
+
for (const schema of schemas) {
|
|
1309
|
+
validateVersion(schema.version, `Schema version for key "${schema.key}"`);
|
|
1310
|
+
const id = schemaVersionKey(schema.key, schema.version);
|
|
1311
|
+
if (schemasByKeyAndVersion.has(id)) {
|
|
1312
|
+
throw new SchemaError(
|
|
1313
|
+
"SCHEMA_REGISTRATION_CONFLICT",
|
|
1314
|
+
`Duplicate schema registered for key "${schema.key}" version ${schema.version}`
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
schemasByKeyAndVersion.set(id, schema);
|
|
1318
|
+
const currentLatest = latestSchemaByKey.get(schema.key);
|
|
1319
|
+
if (!currentLatest || schema.version > currentLatest.version) {
|
|
1320
|
+
latestSchemaByKey.set(schema.key, schema);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
for (const migration of migrations) {
|
|
1324
|
+
validateVersion(migration.fromVersion, `Migration fromVersion for key "${migration.key}"`);
|
|
1325
|
+
validateVersion(migration.toVersion, `Migration toVersion for key "${migration.key}"`);
|
|
1326
|
+
if (migration.toVersion < migration.fromVersion) {
|
|
1327
|
+
throw new SchemaError(
|
|
1328
|
+
"MIGRATION_GRAPH_INVALID",
|
|
1329
|
+
`Backward migration "${migration.key}" ${migration.fromVersion} -> ${migration.toVersion} is not supported`
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
if (migration.fromVersion === migration.toVersion) {
|
|
1333
|
+
const id = schemaVersionKey(migration.key, migration.fromVersion);
|
|
1334
|
+
if (writeMigrationsByKeyAndVersion.has(id)) {
|
|
1335
|
+
throw new SchemaError(
|
|
1336
|
+
"MIGRATION_GRAPH_INVALID",
|
|
1337
|
+
`Duplicate write migration registered for key "${migration.key}" version ${migration.fromVersion}`
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
writeMigrationsByKeyAndVersion.set(id, migration);
|
|
1341
|
+
continue;
|
|
1342
|
+
}
|
|
1343
|
+
const edgeKey = migrationVersionKey(migration.key, migration.fromVersion);
|
|
1344
|
+
if (migrationsByKeyAndFromVersion.has(edgeKey)) {
|
|
1345
|
+
const existing = migrationsByKeyAndFromVersion.get(edgeKey);
|
|
1346
|
+
throw new SchemaError(
|
|
1347
|
+
"MIGRATION_GRAPH_INVALID",
|
|
1348
|
+
`Ambiguous migration graph for key "${migration.key}" at version ${migration.fromVersion}: ${existing.fromVersion} -> ${existing.toVersion} conflicts with ${migration.fromVersion} -> ${migration.toVersion}`
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
migrationsByKeyAndFromVersion.set(edgeKey, migration);
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
getSchema(key, version) {
|
|
1355
|
+
return schemasByKeyAndVersion.get(schemaVersionKey(key, version));
|
|
1356
|
+
},
|
|
1357
|
+
getLatestSchema(key) {
|
|
1358
|
+
return latestSchemaByKey.get(key);
|
|
1359
|
+
},
|
|
1360
|
+
getMigrationPath(key, fromVersion, toVersion) {
|
|
1361
|
+
if (fromVersion === toVersion) return [];
|
|
1362
|
+
if (toVersion < fromVersion) return null;
|
|
1363
|
+
const path = [];
|
|
1364
|
+
let currentVersion = fromVersion;
|
|
1365
|
+
while (currentVersion < toVersion) {
|
|
1366
|
+
const next = migrationsByKeyAndFromVersion.get(migrationVersionKey(key, currentVersion));
|
|
1367
|
+
if (!next) return null;
|
|
1368
|
+
path.push(next);
|
|
1369
|
+
currentVersion = next.toVersion;
|
|
1370
|
+
}
|
|
1371
|
+
return currentVersion === toVersion ? path : null;
|
|
1372
|
+
},
|
|
1373
|
+
getWriteMigration(key, version) {
|
|
1374
|
+
return writeMigrationsByKeyAndVersion.get(schemaVersionKey(key, version));
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/Mnemonic/structural-migrations.ts
|
|
1380
|
+
function resolveHelpers(helpers) {
|
|
1381
|
+
if (helpers) return helpers;
|
|
1382
|
+
return {
|
|
1383
|
+
getId: (node) => node.id,
|
|
1384
|
+
getChildren: (node) => node.children,
|
|
1385
|
+
withChildren: (node, children) => ({ ...node, children }),
|
|
1386
|
+
withId: (node, id) => ({ ...node, id })
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
function findNodeById(root, id, helpers) {
|
|
1390
|
+
const tree = resolveHelpers(helpers);
|
|
1391
|
+
if (tree.getId(root) === id) return root;
|
|
1392
|
+
for (const child of tree.getChildren(root) ?? []) {
|
|
1393
|
+
const match = findNodeById(child, id, tree);
|
|
1394
|
+
if (match) return match;
|
|
1395
|
+
}
|
|
1396
|
+
return void 0;
|
|
1397
|
+
}
|
|
1398
|
+
function insertChildIfMissing(root, parentId, child, helpers) {
|
|
1399
|
+
const tree = resolveHelpers(helpers);
|
|
1400
|
+
const childId = tree.getId(child);
|
|
1401
|
+
const visit = (node) => {
|
|
1402
|
+
if (tree.getId(node) === parentId) {
|
|
1403
|
+
const children2 = [...tree.getChildren(node) ?? []];
|
|
1404
|
+
if (children2.some((existing) => tree.getId(existing) === childId)) {
|
|
1405
|
+
return [node, false];
|
|
1406
|
+
}
|
|
1407
|
+
return [tree.withChildren(node, [...children2, child]), true];
|
|
1408
|
+
}
|
|
1409
|
+
const children = tree.getChildren(node);
|
|
1410
|
+
if (!children?.length) return [node, false];
|
|
1411
|
+
let inserted = false;
|
|
1412
|
+
let changed = false;
|
|
1413
|
+
const nextChildren = children.map((existingChild) => {
|
|
1414
|
+
if (inserted) return existingChild;
|
|
1415
|
+
const [nextChild, didInsert] = visit(existingChild);
|
|
1416
|
+
inserted || (inserted = didInsert);
|
|
1417
|
+
changed || (changed = nextChild !== existingChild);
|
|
1418
|
+
return nextChild;
|
|
1419
|
+
});
|
|
1420
|
+
if (!changed) return [node, inserted];
|
|
1421
|
+
return [tree.withChildren(node, nextChildren), inserted];
|
|
1422
|
+
};
|
|
1423
|
+
return visit(root)[0];
|
|
1424
|
+
}
|
|
1425
|
+
function renameNode(root, currentId, nextId, helpers) {
|
|
1426
|
+
const tree = resolveHelpers(helpers);
|
|
1427
|
+
if (currentId === nextId) return root;
|
|
1428
|
+
if (!findNodeById(root, currentId, tree)) return root;
|
|
1429
|
+
if (findNodeById(root, nextId, tree)) return root;
|
|
1430
|
+
const visit = (node) => {
|
|
1431
|
+
let nextNode = tree.getId(node) === currentId ? tree.withId(node, nextId) : node;
|
|
1432
|
+
const children = tree.getChildren(nextNode);
|
|
1433
|
+
if (!children?.length) return nextNode;
|
|
1434
|
+
let changed = nextNode !== node;
|
|
1435
|
+
const nextChildren = children.map((child) => {
|
|
1436
|
+
const nextChild = visit(child);
|
|
1437
|
+
changed || (changed = nextChild !== child);
|
|
1438
|
+
return nextChild;
|
|
1439
|
+
});
|
|
1440
|
+
if (!changed) return node;
|
|
1441
|
+
return tree.withChildren(nextNode, nextChildren);
|
|
1442
|
+
};
|
|
1443
|
+
return visit(root);
|
|
1444
|
+
}
|
|
1445
|
+
function dedupeChildrenBy(root, getKey, helpers) {
|
|
1446
|
+
const tree = resolveHelpers(helpers);
|
|
1447
|
+
const visit = (node) => {
|
|
1448
|
+
const children = tree.getChildren(node);
|
|
1449
|
+
if (!children?.length) return node;
|
|
1450
|
+
let changed = false;
|
|
1451
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1452
|
+
const nextChildren = [];
|
|
1453
|
+
for (const child of children) {
|
|
1454
|
+
const normalizedChild = visit(child);
|
|
1455
|
+
changed || (changed = normalizedChild !== child);
|
|
1456
|
+
const key = getKey(normalizedChild);
|
|
1457
|
+
if (seen.has(key)) {
|
|
1458
|
+
changed = true;
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
seen.add(key);
|
|
1462
|
+
nextChildren.push(normalizedChild);
|
|
1463
|
+
}
|
|
1464
|
+
if (!changed && nextChildren.length === children.length) return node;
|
|
1465
|
+
return tree.withChildren(node, nextChildren);
|
|
1466
|
+
};
|
|
1467
|
+
return visit(root);
|
|
1468
|
+
}
|
|
986
1469
|
|
|
987
1470
|
exports.CodecError = CodecError;
|
|
988
1471
|
exports.JSONCodec = JSONCodec;
|
|
@@ -990,7 +1473,13 @@ exports.MnemonicProvider = MnemonicProvider;
|
|
|
990
1473
|
exports.SchemaError = SchemaError;
|
|
991
1474
|
exports.compileSchema = compileSchema;
|
|
992
1475
|
exports.createCodec = createCodec;
|
|
1476
|
+
exports.createSchemaRegistry = createSchemaRegistry;
|
|
1477
|
+
exports.dedupeChildrenBy = dedupeChildrenBy;
|
|
1478
|
+
exports.findNodeById = findNodeById;
|
|
1479
|
+
exports.insertChildIfMissing = insertChildIfMissing;
|
|
1480
|
+
exports.renameNode = renameNode;
|
|
993
1481
|
exports.useMnemonicKey = useMnemonicKey;
|
|
1482
|
+
exports.useMnemonicRecovery = useMnemonicRecovery;
|
|
994
1483
|
exports.validateJsonSchema = validateJsonSchema;
|
|
995
1484
|
//# sourceMappingURL=index.cjs.map
|
|
996
1485
|
//# sourceMappingURL=index.cjs.map
|