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