react-mnemonic 1.1.0-beta0 → 1.2.0-beta1

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/core.js ADDED
@@ -0,0 +1,1313 @@
1
+ import { createContext, useMemo, useCallback, useEffect, useContext, useState, useSyncExternalStore, useRef } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/Mnemonic/provider.tsx
5
+
6
+ // src/Mnemonic/runtime.ts
7
+ function getGlobalProcess() {
8
+ return globalThis.process;
9
+ }
10
+ function getRuntimeNodeEnv() {
11
+ const runtimeProcess = getGlobalProcess();
12
+ if (runtimeProcess?.env?.NODE_ENV !== void 0) {
13
+ return runtimeProcess.env.NODE_ENV;
14
+ }
15
+ return void 0;
16
+ }
17
+ function getNativeBrowserStorages() {
18
+ const globalWindow = globalThis.window;
19
+ if (!globalWindow) return [];
20
+ const storages = [];
21
+ const addStorage = (getter) => {
22
+ try {
23
+ storages.push(getter());
24
+ } catch {
25
+ }
26
+ };
27
+ addStorage(() => globalWindow.localStorage);
28
+ addStorage(() => globalWindow.sessionStorage);
29
+ return storages;
30
+ }
31
+ var MnemonicContext = createContext(null);
32
+ function useMnemonic() {
33
+ const context = useContext(MnemonicContext);
34
+ if (!context) {
35
+ throw new Error("useMnemonic must be used within a MnemonicProvider");
36
+ }
37
+ return context;
38
+ }
39
+ function defaultBrowserStorage() {
40
+ const globalWindow = globalThis.window;
41
+ if (globalWindow === void 0) return void 0;
42
+ try {
43
+ return globalWindow.localStorage;
44
+ } catch {
45
+ return void 0;
46
+ }
47
+ }
48
+ function detectEnumerableStorage(storage) {
49
+ if (!storage) return false;
50
+ try {
51
+ return typeof storage.length === "number" && typeof storage.key === "function";
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+ function isProductionRuntime() {
57
+ const env = getRuntimeNodeEnv();
58
+ if (env === void 0) {
59
+ return true;
60
+ }
61
+ return env === "production";
62
+ }
63
+ function weakRefConstructor() {
64
+ const ctor = globalThis.WeakRef;
65
+ return typeof ctor === "function" ? ctor : null;
66
+ }
67
+ function hasFinalizationRegistry() {
68
+ return typeof globalThis.FinalizationRegistry === "function";
69
+ }
70
+ function isPromiseLike(value) {
71
+ if (value == null) return false;
72
+ if (typeof value !== "object" && typeof value !== "function") return false;
73
+ return typeof value.then === "function";
74
+ }
75
+ function getCrossTabSyncMode(requestedStorage, activeStorage) {
76
+ const isExplicitNativeBrowserStorage = activeStorage !== void 0 && requestedStorage !== void 0 && getNativeBrowserStorages().includes(activeStorage);
77
+ if (requestedStorage === void 0 && activeStorage !== void 0 || isExplicitNativeBrowserStorage) {
78
+ return "browser-storage-event";
79
+ }
80
+ if (typeof activeStorage?.onExternalChange === "function") {
81
+ return "custom-external-change";
82
+ }
83
+ return "none";
84
+ }
85
+ function getDevToolsWindow() {
86
+ return globalThis.window;
87
+ }
88
+ function sanitizeDevToolsRoot(root) {
89
+ const reserved = /* @__PURE__ */ new Set(["providers", "resolve", "list", "capabilities", "__meta"]);
90
+ for (const key of Object.keys(root)) {
91
+ if (reserved.has(key)) continue;
92
+ const descriptor = Object.getOwnPropertyDescriptor(root, key);
93
+ if (descriptor && !descriptor.configurable) continue;
94
+ try {
95
+ delete root[key];
96
+ } catch {
97
+ }
98
+ }
99
+ }
100
+ function ensureDevToolsRoot(enableDevTools) {
101
+ if (!enableDevTools) return null;
102
+ const globalWindow = getDevToolsWindow();
103
+ if (!globalWindow) return null;
104
+ const weakRefSupported = weakRefConstructor() !== null;
105
+ const finalizationRegistrySupported = hasFinalizationRegistry();
106
+ const existing = globalWindow.__REACT_MNEMONIC_DEVTOOLS__;
107
+ const root = existing && typeof existing === "object" ? existing : {};
108
+ sanitizeDevToolsRoot(root);
109
+ if (!root.providers || typeof root.providers !== "object") {
110
+ root.providers = {};
111
+ }
112
+ if (!root.capabilities || typeof root.capabilities !== "object") {
113
+ root.capabilities = {};
114
+ }
115
+ const capabilities = root.capabilities;
116
+ capabilities.weakRef = weakRefSupported;
117
+ capabilities.finalizationRegistry = finalizationRegistrySupported;
118
+ if (!root.__meta || typeof root.__meta !== "object") {
119
+ root.__meta = {
120
+ version: 0,
121
+ lastUpdated: Date.now(),
122
+ lastChange: ""
123
+ };
124
+ }
125
+ const meta = root.__meta;
126
+ if (typeof meta.version !== "number" || !Number.isFinite(meta.version)) {
127
+ meta.version = 0;
128
+ }
129
+ if (typeof meta.lastUpdated !== "number" || !Number.isFinite(meta.lastUpdated)) {
130
+ meta.lastUpdated = Date.now();
131
+ }
132
+ if (typeof meta.lastChange !== "string") {
133
+ meta.lastChange = "";
134
+ }
135
+ const providers = root.providers;
136
+ if (typeof root.resolve !== "function") {
137
+ root.resolve = (namespace) => {
138
+ const entry = providers[namespace];
139
+ if (!entry || typeof entry.weakRef?.deref !== "function") return null;
140
+ const live = entry.weakRef.deref();
141
+ if (live) {
142
+ entry.lastSeenAt = Date.now();
143
+ entry.staleSince = null;
144
+ return live;
145
+ }
146
+ entry.staleSince ?? (entry.staleSince = Date.now());
147
+ return null;
148
+ };
149
+ }
150
+ if (typeof root.list !== "function") {
151
+ root.list = () => Object.entries(providers).map(([namespace, entry]) => {
152
+ const live = typeof entry.weakRef?.deref === "function" ? entry.weakRef.deref() : void 0;
153
+ const available = Boolean(live);
154
+ if (available) {
155
+ entry.lastSeenAt = Date.now();
156
+ entry.staleSince = null;
157
+ } else {
158
+ entry.staleSince ?? (entry.staleSince = Date.now());
159
+ }
160
+ return {
161
+ namespace,
162
+ available,
163
+ registeredAt: entry.registeredAt,
164
+ lastSeenAt: entry.lastSeenAt,
165
+ staleSince: entry.staleSince
166
+ };
167
+ }).sort((left, right) => left.namespace.localeCompare(right.namespace));
168
+ }
169
+ globalWindow.__REACT_MNEMONIC_DEVTOOLS__ = root;
170
+ return root;
171
+ }
172
+ function bumpDevToolsVersion(root, namespace, reason) {
173
+ if (!root) return;
174
+ root.__meta.version += 1;
175
+ root.__meta.lastUpdated = Date.now();
176
+ root.__meta.lastChange = `${namespace}.${reason}`;
177
+ }
178
+ function decodeDevToolsValue(raw) {
179
+ try {
180
+ return JSON.parse(raw);
181
+ } catch {
182
+ return raw;
183
+ }
184
+ }
185
+ function readStorageRaw(storage, storageKey, callbacks) {
186
+ if (!storage) return null;
187
+ try {
188
+ const raw = storage.getItem(storageKey);
189
+ if (isPromiseLike(raw)) {
190
+ callbacks.onAsyncViolation("getItem", raw);
191
+ return null;
192
+ }
193
+ callbacks.onAccessSuccess();
194
+ return raw;
195
+ } catch (error) {
196
+ callbacks.onAccessError(error);
197
+ return null;
198
+ }
199
+ }
200
+ function enumerateNamespaceKeys(storage, prefix, callbacks) {
201
+ if (!storage) {
202
+ return [];
203
+ }
204
+ const keys = [];
205
+ try {
206
+ const storageLength = storage.length;
207
+ const getStorageKey = storage.key;
208
+ if (typeof storageLength !== "number" || typeof getStorageKey !== "function") {
209
+ return [];
210
+ }
211
+ for (let index = 0; index < storageLength; index++) {
212
+ const fullKey = getStorageKey.call(storage, index);
213
+ if (!fullKey?.startsWith(prefix)) continue;
214
+ keys.push(fullKey.slice(prefix.length));
215
+ }
216
+ callbacks.onAccessSuccess();
217
+ } catch (error) {
218
+ callbacks.onAccessError(error);
219
+ }
220
+ return keys;
221
+ }
222
+ function syncCacheEntryFromStorage({
223
+ key,
224
+ storageKey,
225
+ storage,
226
+ cache,
227
+ emit,
228
+ callbacks
229
+ }) {
230
+ const fresh = readStorageRaw(storage, storageKey, callbacks);
231
+ const cached = cache.get(key) ?? null;
232
+ if (fresh === cached) {
233
+ return false;
234
+ }
235
+ cache.set(key, fresh);
236
+ emit(key);
237
+ return true;
238
+ }
239
+ function reloadNamedKeysFromStorage({
240
+ changedKeys,
241
+ prefix,
242
+ storage,
243
+ listeners,
244
+ cache,
245
+ emit,
246
+ callbacks
247
+ }) {
248
+ let changed = false;
249
+ for (const fullStorageKey of changedKeys) {
250
+ if (!fullStorageKey.startsWith(prefix)) continue;
251
+ const key = fullStorageKey.slice(prefix.length);
252
+ const listenerSet = listeners.get(key);
253
+ if (listenerSet && listenerSet.size > 0) {
254
+ changed = syncCacheEntryFromStorage({
255
+ key,
256
+ storageKey: fullStorageKey,
257
+ storage,
258
+ cache,
259
+ emit,
260
+ callbacks
261
+ }) || changed;
262
+ continue;
263
+ }
264
+ if (cache.has(key)) {
265
+ cache.delete(key);
266
+ }
267
+ }
268
+ return changed;
269
+ }
270
+ function reloadSubscribedKeysFromStorage({
271
+ prefix,
272
+ storage,
273
+ listeners,
274
+ cache,
275
+ emit,
276
+ callbacks
277
+ }) {
278
+ let changed = false;
279
+ for (const [key, listenerSet] of listeners) {
280
+ if (listenerSet.size === 0) continue;
281
+ changed = syncCacheEntryFromStorage({
282
+ key,
283
+ storageKey: `${prefix}${key}`,
284
+ storage,
285
+ cache,
286
+ emit,
287
+ callbacks
288
+ }) || changed;
289
+ }
290
+ for (const key of cache.keys()) {
291
+ const listenerSet = listeners.get(key);
292
+ if (listenerSet && listenerSet.size > 0) continue;
293
+ cache.delete(key);
294
+ }
295
+ return changed;
296
+ }
297
+ function createDevToolsProviderApi({
298
+ store,
299
+ dump,
300
+ keys,
301
+ readThrough,
302
+ writeRaw,
303
+ removeRaw
304
+ }) {
305
+ return {
306
+ getStore: () => store,
307
+ dump: () => {
308
+ const data = dump();
309
+ console.table(
310
+ Object.entries(data).map(([key, value]) => ({
311
+ key,
312
+ value,
313
+ decoded: decodeDevToolsValue(value)
314
+ }))
315
+ );
316
+ return data;
317
+ },
318
+ get: (key) => {
319
+ const raw = readThrough(key);
320
+ if (raw == null) return void 0;
321
+ return decodeDevToolsValue(raw);
322
+ },
323
+ set: (key, value) => {
324
+ writeRaw(key, JSON.stringify(value));
325
+ },
326
+ remove: (key) => removeRaw(key),
327
+ clear: () => {
328
+ for (const key of keys()) {
329
+ removeRaw(key);
330
+ }
331
+ },
332
+ keys
333
+ };
334
+ }
335
+ function createReloadFromStorage({
336
+ storage,
337
+ hasAsyncContractViolation,
338
+ prefix,
339
+ listeners,
340
+ cache,
341
+ emit,
342
+ callbacks,
343
+ devToolsRoot,
344
+ namespace
345
+ }) {
346
+ return (changedKeys) => {
347
+ if (!storage || hasAsyncContractViolation()) return;
348
+ if (changedKeys?.length === 0) return;
349
+ const isFullReload = changedKeys === void 0;
350
+ const changed = isFullReload ? reloadSubscribedKeysFromStorage({
351
+ prefix,
352
+ storage,
353
+ listeners,
354
+ cache,
355
+ emit,
356
+ callbacks
357
+ }) : reloadNamedKeysFromStorage({
358
+ changedKeys,
359
+ prefix,
360
+ storage,
361
+ listeners,
362
+ cache,
363
+ emit,
364
+ callbacks
365
+ });
366
+ if (changed) {
367
+ bumpDevToolsVersion(devToolsRoot, namespace, isFullReload ? "reload:full" : "reload:granular");
368
+ }
369
+ };
370
+ }
371
+ function registerDevToolsProvider({
372
+ devToolsRoot,
373
+ namespace,
374
+ store,
375
+ dump,
376
+ keys,
377
+ readThrough,
378
+ writeRaw,
379
+ removeRaw
380
+ }) {
381
+ let infoMessage = `[Mnemonic DevTools] Namespace "${namespace}" available via window.__REACT_MNEMONIC_DEVTOOLS__.resolve("${namespace}")`;
382
+ if (!devToolsRoot.capabilities.weakRef) {
383
+ console.info(
384
+ `[Mnemonic DevTools] WeakRef is not available; registry provider "${namespace}" was not registered.`
385
+ );
386
+ return;
387
+ }
388
+ const existingLive = devToolsRoot.resolve(namespace);
389
+ if (existingLive) {
390
+ const duplicateMessage = `[Mnemonic DevTools] Duplicate provider namespace "${namespace}" detected. Each window must have at most one live MnemonicProvider per namespace.`;
391
+ if (!isProductionRuntime()) {
392
+ throw new Error(duplicateMessage);
393
+ }
394
+ console.warn(`${duplicateMessage} Keeping the first provider and ignoring the duplicate.`);
395
+ console.info(
396
+ `[Mnemonic DevTools] Namespace "${namespace}" already registered. Keeping existing provider reference.`
397
+ );
398
+ return;
399
+ }
400
+ const providerApi = createDevToolsProviderApi({
401
+ store,
402
+ dump,
403
+ keys,
404
+ readThrough,
405
+ writeRaw,
406
+ removeRaw
407
+ });
408
+ const WeakRefCtor = weakRefConstructor();
409
+ if (!WeakRefCtor) {
410
+ console.info(`[Mnemonic DevTools] WeakRef became unavailable while registering "${namespace}".`);
411
+ return;
412
+ }
413
+ store.__devToolsProviderApiHold = providerApi;
414
+ const now = Date.now();
415
+ devToolsRoot.providers[namespace] = {
416
+ namespace,
417
+ weakRef: new WeakRefCtor(providerApi),
418
+ registeredAt: now,
419
+ lastSeenAt: now,
420
+ staleSince: null
421
+ };
422
+ bumpDevToolsVersion(devToolsRoot, namespace, "registry:namespace-registered");
423
+ console.info(infoMessage);
424
+ }
425
+ function MnemonicProvider({
426
+ children,
427
+ namespace,
428
+ storage,
429
+ enableDevTools = false,
430
+ schemaMode = "default",
431
+ schemaRegistry,
432
+ ssr
433
+ }) {
434
+ if (schemaMode === "strict" && !schemaRegistry) {
435
+ throw new Error("MnemonicProvider strict mode requires schemaRegistry");
436
+ }
437
+ if (schemaMode === "autoschema" && typeof schemaRegistry?.registerSchema !== "function") {
438
+ throw new Error("MnemonicProvider autoschema mode requires schemaRegistry.registerSchema");
439
+ }
440
+ const store = useMemo(() => {
441
+ const prefix = `${namespace}.`;
442
+ const st = storage ?? defaultBrowserStorage();
443
+ const ssrHydration = ssr?.hydration ?? "immediate";
444
+ const devToolsRoot = ensureDevToolsRoot(enableDevTools);
445
+ const canEnumerateKeys = detectEnumerableStorage(st);
446
+ const crossTabSyncMode = getCrossTabSyncMode(storage, st);
447
+ const cache = /* @__PURE__ */ new Map();
448
+ const listeners = /* @__PURE__ */ new Map();
449
+ let quotaErrorLogged = false;
450
+ let accessErrorLogged = false;
451
+ let asyncContractViolationDetected = false;
452
+ const storageAccessCallbacks = {
453
+ onAccessError: (err) => logAccessError(err),
454
+ onAccessSuccess: () => {
455
+ accessErrorLogged = false;
456
+ },
457
+ onAsyncViolation: (method, thenable) => handleAsyncStorageContractViolation(method, thenable)
458
+ };
459
+ const fullKey = (key) => prefix + key;
460
+ const emit = (key) => {
461
+ const set = listeners.get(key);
462
+ if (!set) return;
463
+ for (const fn of set) fn();
464
+ };
465
+ const logAccessError = (err) => {
466
+ if (!accessErrorLogged && err instanceof DOMException && err.name !== "QuotaExceededError") {
467
+ console.error(
468
+ `[Mnemonic] Storage access error (${err.name}): ${err.message}. Data is cached in memory but may not persist.`
469
+ );
470
+ accessErrorLogged = true;
471
+ }
472
+ };
473
+ const handleAsyncStorageContractViolation = (method, thenable) => {
474
+ asyncContractViolationDetected = true;
475
+ void Promise.resolve(thenable).catch(() => void 0);
476
+ if (accessErrorLogged) return;
477
+ console.error(
478
+ `[Mnemonic] StorageLike.${method} returned a Promise. StorageLike must remain synchronous for react-mnemonic v1. Wrap async persistence behind a synchronous cache facade instead.`
479
+ );
480
+ accessErrorLogged = true;
481
+ };
482
+ const readThrough = (key) => {
483
+ if (cache.has(key)) return cache.get(key) ?? null;
484
+ if (!st || asyncContractViolationDetected) {
485
+ cache.set(key, null);
486
+ return null;
487
+ }
488
+ const raw = readStorageRaw(st, fullKey(key), storageAccessCallbacks);
489
+ cache.set(key, raw);
490
+ return raw;
491
+ };
492
+ const writeRaw = (key, raw) => {
493
+ cache.set(key, raw);
494
+ if (st && !asyncContractViolationDetected) {
495
+ try {
496
+ const result = st.setItem(fullKey(key), raw);
497
+ if (isPromiseLike(result)) {
498
+ handleAsyncStorageContractViolation("setItem", result);
499
+ } else {
500
+ quotaErrorLogged = false;
501
+ accessErrorLogged = false;
502
+ }
503
+ } catch (err) {
504
+ if (!quotaErrorLogged && err instanceof DOMException && err.name === "QuotaExceededError") {
505
+ console.error(
506
+ `[Mnemonic] Storage quota exceeded writing key "${key}". Data is cached in memory but will not persist.`
507
+ );
508
+ quotaErrorLogged = true;
509
+ }
510
+ logAccessError(err);
511
+ }
512
+ }
513
+ emit(key);
514
+ bumpDevToolsVersion(devToolsRoot, namespace, `set:${key}`);
515
+ };
516
+ const removeRaw = (key) => {
517
+ cache.set(key, null);
518
+ if (st && !asyncContractViolationDetected) {
519
+ try {
520
+ const result = st.removeItem(fullKey(key));
521
+ if (isPromiseLike(result)) {
522
+ handleAsyncStorageContractViolation("removeItem", result);
523
+ } else {
524
+ accessErrorLogged = false;
525
+ }
526
+ } catch (err) {
527
+ logAccessError(err);
528
+ }
529
+ }
530
+ emit(key);
531
+ bumpDevToolsVersion(devToolsRoot, namespace, `remove:${key}`);
532
+ };
533
+ const subscribeRaw = (key, listener) => {
534
+ let set = listeners.get(key);
535
+ if (!set) {
536
+ set = /* @__PURE__ */ new Set();
537
+ listeners.set(key, set);
538
+ }
539
+ set.add(listener);
540
+ readThrough(key);
541
+ return () => {
542
+ const s = listeners.get(key);
543
+ if (!s) return;
544
+ s.delete(listener);
545
+ if (s.size === 0) listeners.delete(key);
546
+ };
547
+ };
548
+ const getRawSnapshot = (key) => readThrough(key);
549
+ const keys = () => {
550
+ if (asyncContractViolationDetected) {
551
+ return Array.from(cache.entries()).filter(([, value]) => value != null).map(([key]) => key);
552
+ }
553
+ if (!canEnumerateKeys) return [];
554
+ return enumerateNamespaceKeys(st, prefix, storageAccessCallbacks);
555
+ };
556
+ const dump = () => {
557
+ const out = {};
558
+ for (const k of keys()) {
559
+ const raw = readThrough(k);
560
+ if (raw != null) out[k] = raw;
561
+ }
562
+ return out;
563
+ };
564
+ const reloadFromStorage = createReloadFromStorage({
565
+ storage: st,
566
+ hasAsyncContractViolation: () => asyncContractViolationDetected,
567
+ prefix,
568
+ listeners,
569
+ cache,
570
+ emit,
571
+ callbacks: storageAccessCallbacks,
572
+ devToolsRoot,
573
+ namespace
574
+ });
575
+ const store2 = {
576
+ prefix,
577
+ canEnumerateKeys,
578
+ subscribeRaw,
579
+ getRawSnapshot,
580
+ setRaw: writeRaw,
581
+ removeRaw,
582
+ keys,
583
+ dump,
584
+ reloadFromStorage,
585
+ schemaMode,
586
+ ssrHydration,
587
+ crossTabSyncMode,
588
+ ...schemaRegistry ? { schemaRegistry } : {}
589
+ };
590
+ if (devToolsRoot) {
591
+ registerDevToolsProvider({
592
+ devToolsRoot,
593
+ namespace,
594
+ store: store2,
595
+ dump,
596
+ keys,
597
+ readThrough,
598
+ writeRaw,
599
+ removeRaw
600
+ });
601
+ }
602
+ return store2;
603
+ }, [namespace, storage, enableDevTools, schemaMode, schemaRegistry, ssr?.hydration]);
604
+ useEffect(() => {
605
+ if (!storage?.onExternalChange) return;
606
+ return storage.onExternalChange((changedKeys) => store.reloadFromStorage(changedKeys));
607
+ }, [storage, store]);
608
+ return /* @__PURE__ */ jsx(MnemonicContext.Provider, { value: store, children });
609
+ }
610
+ function throwCoreProviderSchemaImportError(propName) {
611
+ throw new Error(
612
+ `[Mnemonic] MnemonicProvider from react-mnemonic/core does not support ${propName}. Import MnemonicProvider from "react-mnemonic/schema" or "react-mnemonic" for schema validation, autoschema, and migration support.`
613
+ );
614
+ }
615
+ function assertNoSchemaProps(props) {
616
+ if (props.schemaMode !== void 0) {
617
+ throwCoreProviderSchemaImportError("schemaMode");
618
+ }
619
+ if (props.schemaRegistry !== void 0) {
620
+ throwCoreProviderSchemaImportError("schemaRegistry");
621
+ }
622
+ }
623
+ function MnemonicProvider2(props) {
624
+ assertNoSchemaProps(props);
625
+ return /* @__PURE__ */ jsx(MnemonicProvider, { ...props });
626
+ }
627
+
628
+ // src/Mnemonic/codecs.ts
629
+ var CodecError = class extends Error {
630
+ /**
631
+ * Creates a new CodecError.
632
+ *
633
+ * @param message - Human-readable error description
634
+ * @param cause - Optional underlying error that caused this failure
635
+ */
636
+ constructor(message, cause) {
637
+ super(message);
638
+ this.name = "CodecError";
639
+ this.cause = cause;
640
+ Object.setPrototypeOf(this, new.target.prototype);
641
+ }
642
+ };
643
+ var JSONCodec = {
644
+ encode: (value) => JSON.stringify(value),
645
+ decode: (encoded) => JSON.parse(encoded)
646
+ };
647
+ function createCodec(encode, decode) {
648
+ return { encode, decode };
649
+ }
650
+
651
+ // src/Mnemonic/schema.ts
652
+ var SchemaError = class extends Error {
653
+ /**
654
+ * Creates a new SchemaError.
655
+ *
656
+ * @param code - Machine-readable failure category
657
+ * @param message - Human-readable error description
658
+ * @param cause - Optional underlying error
659
+ */
660
+ constructor(code, message, cause) {
661
+ super(message);
662
+ this.name = "SchemaError";
663
+ this.code = code;
664
+ this.cause = cause;
665
+ Object.setPrototypeOf(this, new.target.prototype);
666
+ }
667
+ };
668
+
669
+ // src/Mnemonic/use-shared.ts
670
+ var SSR_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol("mnemonic:ssr-snapshot");
671
+ var diagnosticContractRegistry = /* @__PURE__ */ new WeakMap();
672
+ var diagnosticWarningRegistry = /* @__PURE__ */ new WeakMap();
673
+ var diagnosticObjectIds = /* @__PURE__ */ new WeakMap();
674
+ var nextDiagnosticObjectId = 1;
675
+ function serializeEnvelope(version, payload) {
676
+ return JSON.stringify({
677
+ version,
678
+ payload
679
+ });
680
+ }
681
+ function withReadMetadata(value, rewriteRaw, extra) {
682
+ const result = { value };
683
+ if (extra !== void 0) {
684
+ Object.assign(result, extra);
685
+ }
686
+ if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
687
+ return result;
688
+ }
689
+ function isDevelopmentRuntime() {
690
+ return getRuntimeNodeEnv() === "development";
691
+ }
692
+ function getDiagnosticWarnings(api) {
693
+ let warnings = diagnosticWarningRegistry.get(api);
694
+ if (!warnings) {
695
+ warnings = /* @__PURE__ */ new Set();
696
+ diagnosticWarningRegistry.set(api, warnings);
697
+ }
698
+ return warnings;
699
+ }
700
+ function warnOnce(api, id, message) {
701
+ const warnings = getDiagnosticWarnings(api);
702
+ if (warnings.has(id)) return;
703
+ warnings.add(id);
704
+ console.warn(message);
705
+ }
706
+ function stableDiagnosticValue(value) {
707
+ if (typeof value === "function") {
708
+ const source = Function.prototype.toString.call(value).split(/\s+/).join(" ").trim();
709
+ const name = value.name || "anonymous";
710
+ return `[factory:${name}/${value.length}:${source}]`;
711
+ }
712
+ if (typeof value === "bigint") return `${value.toString()}n`;
713
+ if (typeof value === "symbol") return value.toString();
714
+ if (value === void 0) return "undefined";
715
+ try {
716
+ return JSON.stringify(value);
717
+ } catch {
718
+ const tag = Object.prototype.toString.call(value);
719
+ if (value !== null && (typeof value === "object" || typeof value === "function")) {
720
+ return `${tag}#${getDiagnosticObjectId(value)}`;
721
+ }
722
+ return tag;
723
+ }
724
+ }
725
+ function isObjectLike(value) {
726
+ return value !== null && (typeof value === "object" || typeof value === "function");
727
+ }
728
+ function objectHasOwn(value, property) {
729
+ const hasOwn = Object.hasOwn;
730
+ if (typeof hasOwn === "function") {
731
+ return hasOwn(value, property);
732
+ }
733
+ return Object.getOwnPropertyDescriptor(value, property) !== void 0;
734
+ }
735
+ function getDiagnosticObjectId(value) {
736
+ const existing = diagnosticObjectIds.get(value);
737
+ if (existing !== void 0) return existing;
738
+ const id = nextDiagnosticObjectId++;
739
+ diagnosticObjectIds.set(value, id);
740
+ return id;
741
+ }
742
+ function buildContractFingerprint({
743
+ api,
744
+ key,
745
+ defaultValue,
746
+ codecOpt,
747
+ schemaVersion,
748
+ reconcile,
749
+ listenCrossTab,
750
+ ssrOptions
751
+ }) {
752
+ const codecSignature = codecOpt == null || !isObjectLike(codecOpt) ? "default-json-codec" : `codec:${stableDiagnosticValue(codecOpt.encode)}:${stableDiagnosticValue(codecOpt.decode)}`;
753
+ const reconcileSignature = reconcile == null || !isObjectLike(reconcile) ? "no-reconcile" : `reconcile:${stableDiagnosticValue(reconcile)}`;
754
+ return JSON.stringify({
755
+ key,
756
+ defaultValue: stableDiagnosticValue(defaultValue),
757
+ codec: codecSignature,
758
+ schemaVersion: schemaVersion ?? null,
759
+ listenCrossTab: Boolean(listenCrossTab),
760
+ reconcile: reconcileSignature,
761
+ ssrHydration: ssrOptions?.hydration ?? null,
762
+ hasServerValue: ssrOptions?.serverValue !== void 0,
763
+ providerHydration: api.ssrHydration ?? null
764
+ });
765
+ }
766
+ function resolveMnemonicKeyArgs(keyOrDescriptor, options) {
767
+ if (typeof keyOrDescriptor !== "string") {
768
+ return keyOrDescriptor;
769
+ }
770
+ if (!options) {
771
+ throw new Error("useMnemonicKey requires options when called with a string key");
772
+ }
773
+ return {
774
+ key: keyOrDescriptor,
775
+ options
776
+ };
777
+ }
778
+ function useMnemonicKeyShared(keyOrDescriptor, options, schemaVersion) {
779
+ const descriptor = resolveMnemonicKeyArgs(keyOrDescriptor, options);
780
+ const key = descriptor.key;
781
+ const resolvedOptions = descriptor.options;
782
+ const api = useMnemonic();
783
+ const {
784
+ defaultValue,
785
+ onMount,
786
+ onChange,
787
+ listenCrossTab,
788
+ codec: codecOpt,
789
+ schema,
790
+ reconcile,
791
+ ssr: ssrOptions
792
+ } = resolvedOptions;
793
+ const codec = codecOpt ?? JSONCodec;
794
+ const hydrationMode = ssrOptions?.hydration ?? api.ssrHydration;
795
+ const [hasMounted, setHasMounted] = useState(hydrationMode !== "client-only");
796
+ const developmentRuntime = isDevelopmentRuntime();
797
+ const contractFingerprint = useMemo(
798
+ () => developmentRuntime ? buildContractFingerprint({
799
+ api,
800
+ key,
801
+ defaultValue,
802
+ codecOpt,
803
+ ...{} ,
804
+ reconcile,
805
+ listenCrossTab,
806
+ ssrOptions
807
+ }) : null,
808
+ [
809
+ developmentRuntime,
810
+ api,
811
+ key,
812
+ defaultValue,
813
+ codecOpt,
814
+ schemaVersion,
815
+ reconcile,
816
+ listenCrossTab,
817
+ ssrOptions?.hydration,
818
+ ssrOptions?.serverValue
819
+ ]
820
+ );
821
+ const getFallback = useCallback(
822
+ (error) => typeof defaultValue === "function" ? defaultValue(error) : defaultValue,
823
+ [defaultValue]
824
+ );
825
+ const getServerValue = useCallback(() => {
826
+ const serverValue = ssrOptions?.serverValue;
827
+ if (serverValue === void 0) {
828
+ return getFallback();
829
+ }
830
+ return typeof serverValue === "function" ? serverValue() : serverValue;
831
+ }, [getFallback, ssrOptions?.serverValue]);
832
+ const parseEnvelope = useCallback(
833
+ (rawText) => {
834
+ try {
835
+ const parsed = JSON.parse(rawText);
836
+ if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn(parsed, "payload")) {
837
+ return {
838
+ ok: false,
839
+ error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`)
840
+ };
841
+ }
842
+ return { ok: true, envelope: parsed };
843
+ } catch (err) {
844
+ return {
845
+ ok: false,
846
+ error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, err)
847
+ };
848
+ }
849
+ },
850
+ [key]
851
+ );
852
+ const decodeStringPayload = useCallback(
853
+ (payload, activeCodec) => {
854
+ try {
855
+ return activeCodec.decode(payload);
856
+ } catch (err) {
857
+ throw err instanceof CodecError ? err : new CodecError(`Codec decode failed for key "${key}"`, err);
858
+ }
859
+ },
860
+ [key]
861
+ );
862
+ const buildFallbackResult = useCallback(
863
+ (error, extra) => {
864
+ return withReadMetadata(getFallback(error), void 0, extra);
865
+ },
866
+ [getFallback]
867
+ );
868
+ return {
869
+ api,
870
+ key,
871
+ codec,
872
+ codecOpt,
873
+ schema,
874
+ reconcile,
875
+ onMount,
876
+ onChange,
877
+ listenCrossTab,
878
+ getFallback,
879
+ getServerValue,
880
+ parseEnvelope,
881
+ decodeStringPayload,
882
+ buildFallbackResult,
883
+ developmentRuntime,
884
+ contractFingerprint,
885
+ hasMounted,
886
+ setHasMounted,
887
+ hydrationMode,
888
+ ssrOptions
889
+ };
890
+ }
891
+ function useApplyReconcile({
892
+ key,
893
+ reconcile,
894
+ buildFallbackResult
895
+ }) {
896
+ return useCallback(
897
+ ({
898
+ value,
899
+ rewriteRaw,
900
+ extra,
901
+ persistedVersion,
902
+ latestVersion,
903
+ serializeForPersist,
904
+ deriveExtra
905
+ }) => {
906
+ if (!reconcile) {
907
+ return withReadMetadata(value, rewriteRaw, extra);
908
+ }
909
+ const context = {
910
+ key,
911
+ persistedVersion
912
+ };
913
+ if (latestVersion !== void 0) {
914
+ context.latestVersion = latestVersion;
915
+ }
916
+ const baselineSerialized = (() => {
917
+ try {
918
+ return serializeForPersist(value);
919
+ } catch {
920
+ return rewriteRaw;
921
+ }
922
+ })();
923
+ try {
924
+ const reconciled = reconcile(value, context);
925
+ const nextExtra = deriveExtra ? deriveExtra(reconciled, extra) : extra;
926
+ const nextSerialized = serializeForPersist(reconciled);
927
+ const nextRewriteRaw = baselineSerialized === void 0 || nextSerialized !== baselineSerialized ? nextSerialized : rewriteRaw;
928
+ return withReadMetadata(reconciled, nextRewriteRaw, nextExtra);
929
+ } catch (err) {
930
+ const typedErr = err instanceof SchemaError ? err : new SchemaError("RECONCILE_FAILED", `Reconciliation failed for key "${key}"`, err);
931
+ return buildFallbackResult(typedErr, extra);
932
+ }
933
+ },
934
+ [buildFallbackResult, key, reconcile]
935
+ );
936
+ }
937
+ function useMnemonicKeyState(shared, config) {
938
+ const {
939
+ api,
940
+ key,
941
+ codecOpt,
942
+ schema,
943
+ onMount,
944
+ onChange,
945
+ listenCrossTab,
946
+ getFallback,
947
+ getServerValue,
948
+ developmentRuntime,
949
+ contractFingerprint,
950
+ hasMounted,
951
+ setHasMounted,
952
+ hydrationMode,
953
+ ssrOptions
954
+ } = shared;
955
+ const { decodeForRead, encodeForWrite, additionalDevWarnings, onDecodedEffect } = config;
956
+ const getServerRawSnapshot = useCallback(
957
+ () => ssrOptions?.serverValue === void 0 ? null : SSR_SNAPSHOT_TOKEN,
958
+ [ssrOptions?.serverValue]
959
+ );
960
+ const deferStorageRead = hydrationMode === "client-only" && !hasMounted;
961
+ const subscribe = useCallback(
962
+ (listener) => {
963
+ if (deferStorageRead) {
964
+ return () => void 0;
965
+ }
966
+ return api.subscribeRaw(key, listener);
967
+ },
968
+ [api, deferStorageRead, key]
969
+ );
970
+ const raw = useSyncExternalStore(
971
+ subscribe,
972
+ () => deferStorageRead ? getServerRawSnapshot() : api.getRawSnapshot(key),
973
+ getServerRawSnapshot
974
+ );
975
+ const decoded = useMemo(() => {
976
+ if (raw === SSR_SNAPSHOT_TOKEN) {
977
+ return withReadMetadata(getServerValue());
978
+ }
979
+ return decodeForRead(raw);
980
+ }, [decodeForRead, getServerValue, raw]);
981
+ const value = decoded.value;
982
+ useEffect(() => {
983
+ if (!developmentRuntime) return;
984
+ const globalWindow = globalThis.window;
985
+ if (listenCrossTab && (api.crossTabSyncMode ?? "none") === "none" && globalWindow !== void 0) {
986
+ warnOnce(
987
+ api,
988
+ `listenCrossTab:${key}`,
989
+ `[Mnemonic] useMnemonicKey("${key}") enabled listenCrossTab, but the active storage backend may not be able to notify external changes. If you're using a custom Storage-like wrapper around localStorage, ensure it forwards browser "storage" events or implements storage.onExternalChange(...); otherwise, use localStorage or implement storage.onExternalChange(...) on your custom backend.`
990
+ );
991
+ }
992
+ additionalDevWarnings?.({
993
+ api,
994
+ key,
995
+ listenCrossTab,
996
+ codecOpt,
997
+ schema,
998
+ warnOnce: (id, message) => warnOnce(api, id, message)
999
+ });
1000
+ let keyContracts = diagnosticContractRegistry.get(api);
1001
+ if (!keyContracts) {
1002
+ keyContracts = /* @__PURE__ */ new Map();
1003
+ diagnosticContractRegistry.set(api, keyContracts);
1004
+ }
1005
+ if (contractFingerprint === null) {
1006
+ return;
1007
+ }
1008
+ const previousContract = keyContracts.get(key);
1009
+ if (previousContract === void 0) {
1010
+ keyContracts.set(key, contractFingerprint);
1011
+ return;
1012
+ }
1013
+ if (previousContract === contractFingerprint) {
1014
+ return;
1015
+ }
1016
+ warnOnce(
1017
+ api,
1018
+ `contract-conflict:${key}`,
1019
+ `[Mnemonic] Conflicting useMnemonicKey contracts detected for key "${key}" in namespace "${api.prefix.slice(0, -1)}". Reuse a shared descriptor with defineMnemonicKey(...) or align defaultValue/codec/schema/reconcile options so every consumer describes the same persisted contract.`
1020
+ );
1021
+ }, [
1022
+ additionalDevWarnings,
1023
+ api,
1024
+ key,
1025
+ developmentRuntime,
1026
+ contractFingerprint,
1027
+ listenCrossTab,
1028
+ codecOpt,
1029
+ schema,
1030
+ api.crossTabSyncMode
1031
+ ]);
1032
+ useEffect(() => {
1033
+ if (hasMounted) return;
1034
+ setHasMounted(true);
1035
+ }, [hasMounted, setHasMounted]);
1036
+ useEffect(() => {
1037
+ if (decoded.rewriteRaw && decoded.rewriteRaw !== raw) {
1038
+ api.setRaw(key, decoded.rewriteRaw);
1039
+ }
1040
+ }, [api, decoded.rewriteRaw, key, raw]);
1041
+ useEffect(() => {
1042
+ onDecodedEffect?.(decoded);
1043
+ }, [decoded, onDecodedEffect]);
1044
+ const prevRef = useRef(value);
1045
+ const mounted = useRef(false);
1046
+ useEffect(() => {
1047
+ if (mounted.current) return;
1048
+ mounted.current = true;
1049
+ onMount?.(value);
1050
+ prevRef.current = value;
1051
+ }, []);
1052
+ useEffect(() => {
1053
+ const prev = prevRef.current;
1054
+ if (Object.is(prev, value)) return;
1055
+ prevRef.current = value;
1056
+ onChange?.(value, prev);
1057
+ }, [value, onChange]);
1058
+ useEffect(() => {
1059
+ if (!listenCrossTab) return;
1060
+ const globalWindow = globalThis.window;
1061
+ if (globalWindow === void 0) return;
1062
+ const storageKey = api.prefix + key;
1063
+ const handler = (e) => {
1064
+ if (e.key === null) {
1065
+ api.removeRaw(key);
1066
+ return;
1067
+ }
1068
+ if (e.key !== storageKey) return;
1069
+ if (e.newValue == null) {
1070
+ api.removeRaw(key);
1071
+ return;
1072
+ }
1073
+ api.setRaw(key, e.newValue);
1074
+ };
1075
+ globalWindow.addEventListener("storage", handler);
1076
+ return () => globalWindow.removeEventListener("storage", handler);
1077
+ }, [listenCrossTab, api, key]);
1078
+ const set = useMemo(() => {
1079
+ return (next) => {
1080
+ const nextVal = typeof next === "function" ? next(decodeForRead(api.getRawSnapshot(key)).value) : next;
1081
+ try {
1082
+ const encoded = encodeForWrite(nextVal);
1083
+ api.setRaw(key, encoded);
1084
+ } catch (err) {
1085
+ if (err instanceof SchemaError) {
1086
+ console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
1087
+ return;
1088
+ }
1089
+ if (err instanceof CodecError) {
1090
+ console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
1091
+ return;
1092
+ }
1093
+ console.error(`[Mnemonic] Failed to persist key "${key}":`, err);
1094
+ }
1095
+ };
1096
+ }, [api, key, decodeForRead, encodeForWrite]);
1097
+ const reset = useMemo(() => {
1098
+ return () => {
1099
+ const v = getFallback();
1100
+ try {
1101
+ const encoded = encodeForWrite(v);
1102
+ api.setRaw(key, encoded);
1103
+ } catch (err) {
1104
+ if (err instanceof SchemaError) {
1105
+ console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
1106
+ return;
1107
+ }
1108
+ if (err instanceof CodecError) {
1109
+ console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
1110
+ }
1111
+ return;
1112
+ }
1113
+ };
1114
+ }, [api, key, getFallback, encodeForWrite]);
1115
+ const remove = useMemo(() => {
1116
+ return () => api.removeRaw(key);
1117
+ }, [api, key]);
1118
+ return useMemo(
1119
+ () => ({
1120
+ value,
1121
+ set,
1122
+ reset,
1123
+ remove
1124
+ }),
1125
+ [value, set, reset, remove]
1126
+ );
1127
+ }
1128
+
1129
+ // src/Mnemonic/use-core.ts
1130
+ function throwCoreSchemaImportError(key) {
1131
+ throw new Error(
1132
+ `[Mnemonic] useMnemonicKey("${key}") requested schema features from react-mnemonic/core. Import useMnemonicKey from "react-mnemonic/schema" or "react-mnemonic" for schema validation, autoschema, and migration support.`
1133
+ );
1134
+ }
1135
+ function useCoreRuntime(keyOrDescriptor, options) {
1136
+ const shared = useMnemonicKeyShared(keyOrDescriptor, options);
1137
+ const { api, key, codec, schema, reconcile, parseEnvelope, decodeStringPayload, buildFallbackResult } = shared;
1138
+ if (schema?.version !== void 0 || api.schemaMode !== "default") {
1139
+ throwCoreSchemaImportError(key);
1140
+ }
1141
+ const applyReconcile = useApplyReconcile({
1142
+ key,
1143
+ reconcile,
1144
+ buildFallbackResult
1145
+ });
1146
+ const encodeForWrite = useCallback(
1147
+ (nextValue) => {
1148
+ return serializeEnvelope(0, codec.encode(nextValue));
1149
+ },
1150
+ [codec]
1151
+ );
1152
+ const decodeForRead = useCallback(
1153
+ (rawText) => {
1154
+ if (rawText == null) return buildFallbackResult();
1155
+ const parsed = parseEnvelope(rawText);
1156
+ if (!parsed.ok) return buildFallbackResult(parsed.error);
1157
+ const envelope = parsed.envelope;
1158
+ if (typeof envelope.payload !== "string") {
1159
+ return applyReconcile({
1160
+ value: envelope.payload,
1161
+ persistedVersion: envelope.version,
1162
+ serializeForPersist: encodeForWrite
1163
+ });
1164
+ }
1165
+ try {
1166
+ const decoded = decodeStringPayload(envelope.payload, codec);
1167
+ return applyReconcile({
1168
+ value: decoded,
1169
+ persistedVersion: envelope.version,
1170
+ serializeForPersist: encodeForWrite
1171
+ });
1172
+ } catch (err) {
1173
+ return buildFallbackResult(err);
1174
+ }
1175
+ },
1176
+ [applyReconcile, buildFallbackResult, codec, decodeStringPayload, encodeForWrite, parseEnvelope]
1177
+ );
1178
+ const additionalDevWarnings = useCallback(
1179
+ ({ warnOnce: warnOnce2 }) => {
1180
+ if (!api.schemaRegistry) return;
1181
+ warnOnce2(
1182
+ `core-schema-registry:${key}`,
1183
+ `[Mnemonic] useMnemonicKey("${key}") is running from react-mnemonic/core, so registered schemas are ignored for this key. Import useMnemonicKey from "react-mnemonic/schema" or "react-mnemonic" to enable schema validation and migrations.`
1184
+ );
1185
+ },
1186
+ [api.schemaRegistry, key]
1187
+ );
1188
+ return useMnemonicKeyState(shared, {
1189
+ decodeForRead,
1190
+ encodeForWrite,
1191
+ additionalDevWarnings
1192
+ });
1193
+ }
1194
+ function useMnemonicKey(keyOrDescriptor, options) {
1195
+ return useCoreRuntime(keyOrDescriptor, options);
1196
+ }
1197
+ function uniqueKeys(keys) {
1198
+ return [...new Set(keys)];
1199
+ }
1200
+ function isDevelopmentRuntime2() {
1201
+ return getRuntimeNodeEnv() === "development";
1202
+ }
1203
+ var recoveryDiagnosticWarnings = /* @__PURE__ */ new WeakMap();
1204
+ function warnRecoveryOnce(api, id, message) {
1205
+ let warnings = recoveryDiagnosticWarnings.get(api);
1206
+ if (!warnings) {
1207
+ warnings = /* @__PURE__ */ new Set();
1208
+ recoveryDiagnosticWarnings.set(api, warnings);
1209
+ }
1210
+ if (warnings.has(id)) return;
1211
+ warnings.add(id);
1212
+ console.warn(message);
1213
+ }
1214
+ function useMnemonicRecovery(options = {}) {
1215
+ const api = useMnemonic();
1216
+ const { onRecover } = options;
1217
+ const namespace = useMemo(() => api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix, [api.prefix]);
1218
+ const emitRecovery = useCallback(
1219
+ (action, clearedKeys) => {
1220
+ const event = {
1221
+ action,
1222
+ namespace,
1223
+ clearedKeys
1224
+ };
1225
+ onRecover?.(event);
1226
+ },
1227
+ [namespace, onRecover]
1228
+ );
1229
+ const listKeys = useCallback(() => api.keys(), [api]);
1230
+ const clearResolvedKeys = useCallback(
1231
+ (action, keys) => {
1232
+ const clearedKeys = uniqueKeys(keys);
1233
+ for (const key of clearedKeys) {
1234
+ api.removeRaw(key);
1235
+ }
1236
+ emitRecovery(action, clearedKeys);
1237
+ return clearedKeys;
1238
+ },
1239
+ [api, emitRecovery]
1240
+ );
1241
+ const clearKeys = useCallback(
1242
+ (keys) => clearResolvedKeys("clear-keys", keys),
1243
+ [clearResolvedKeys]
1244
+ );
1245
+ const clearAll = useCallback(() => {
1246
+ if (!api.canEnumerateKeys) {
1247
+ if (isDevelopmentRuntime2()) {
1248
+ warnRecoveryOnce(
1249
+ api,
1250
+ "recovery-clear-all-non-enumerable",
1251
+ `[Mnemonic] clearAll() requires an enumerable storage backend in namespace "${namespace}". Use clearKeys([...]) with an explicit durable-key list, or supply a storage backend that implements length and key(index).`
1252
+ );
1253
+ }
1254
+ throw new Error(
1255
+ "clearAll requires an enumerable storage backend. Use clearKeys([...]) with an explicit key list instead."
1256
+ );
1257
+ }
1258
+ return clearResolvedKeys("clear-all", api.keys());
1259
+ }, [api, clearResolvedKeys, namespace]);
1260
+ const clearMatching = useCallback(
1261
+ (predicate) => {
1262
+ if (!api.canEnumerateKeys) {
1263
+ if (isDevelopmentRuntime2()) {
1264
+ warnRecoveryOnce(
1265
+ api,
1266
+ "recovery-clear-matching-non-enumerable",
1267
+ `[Mnemonic] clearMatching() requires an enumerable storage backend in namespace "${namespace}". Use clearKeys([...]) with an explicit durable-key list, or supply a storage backend that implements length and key(index).`
1268
+ );
1269
+ }
1270
+ throw new Error(
1271
+ "clearMatching requires an enumerable storage backend. Use clearKeys([...]) with an explicit key list instead."
1272
+ );
1273
+ }
1274
+ return clearResolvedKeys(
1275
+ "clear-matching",
1276
+ api.keys().filter((key) => predicate(key))
1277
+ );
1278
+ },
1279
+ [api, clearResolvedKeys, namespace]
1280
+ );
1281
+ return useMemo(
1282
+ () => ({
1283
+ namespace,
1284
+ canEnumerateKeys: api.canEnumerateKeys,
1285
+ listKeys,
1286
+ clearAll,
1287
+ clearKeys,
1288
+ clearMatching
1289
+ }),
1290
+ [namespace, api.canEnumerateKeys, listKeys, clearAll, clearKeys, clearMatching]
1291
+ );
1292
+ }
1293
+
1294
+ // src/Mnemonic/key.ts
1295
+ function defineMnemonicKey(keyOrSchema, options) {
1296
+ if (typeof keyOrSchema !== "string") {
1297
+ return Object.freeze({
1298
+ key: keyOrSchema.key,
1299
+ options: {
1300
+ ...options,
1301
+ schema: { version: keyOrSchema.version }
1302
+ }
1303
+ });
1304
+ }
1305
+ return Object.freeze({
1306
+ key: keyOrSchema,
1307
+ options
1308
+ });
1309
+ }
1310
+
1311
+ export { CodecError, JSONCodec, MnemonicProvider2 as MnemonicProvider, SchemaError, createCodec, defineMnemonicKey, useMnemonicKey, useMnemonicRecovery };
1312
+ //# sourceMappingURL=core.js.map
1313
+ //# sourceMappingURL=core.js.map