react-mnemonic 1.3.0 → 1.5.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 +11 -4
- package/dist/bootstrap.cjs +864 -0
- package/dist/bootstrap.cjs.map +1 -0
- package/dist/bootstrap.d.cts +100 -0
- package/dist/bootstrap.d.ts +100 -0
- package/dist/bootstrap.js +857 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/core.cjs +932 -880
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +3 -3
- package/dist/core.d.ts +3 -3
- package/dist/core.js +933 -881
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +918 -866
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +919 -867
- package/dist/index.js.map +1 -1
- package/dist/{key-Bad1hAKN.d.cts → key-B0_N_rl6.d.cts} +1 -1
- package/dist/{key-QIDPiubI.d.ts → key-yGSxLOVj.d.ts} +1 -1
- package/dist/optional.cjs +12 -1
- package/dist/optional.cjs.map +1 -1
- package/dist/optional.d.cts +2 -2
- package/dist/optional.d.ts +2 -2
- package/dist/optional.js +12 -1
- package/dist/optional.js.map +1 -1
- package/dist/schema.cjs +918 -866
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.d.cts +4 -4
- package/dist/schema.d.ts +4 -4
- package/dist/schema.js +919 -867
- package/dist/schema.js.map +1 -1
- package/dist/{types-DcdXbmVl.d.cts → types-RML7bepB.d.cts} +72 -1
- package/dist/{types-DcdXbmVl.d.ts → types-RML7bepB.d.ts} +72 -1
- package/package.json +10 -1
package/dist/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useMemo, useCallback,
|
|
1
|
+
import { createContext, useMemo, useCallback, useRef, useEffect, useContext, createElement, useState, useSyncExternalStore } from 'react';
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/Mnemonic/provider.tsx
|
|
@@ -412,789 +412,368 @@ var SchemaError = class extends Error {
|
|
|
412
412
|
}
|
|
413
413
|
};
|
|
414
414
|
|
|
415
|
-
// src/Mnemonic/
|
|
416
|
-
function
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const runtimeProcess = getGlobalProcess();
|
|
421
|
-
if (runtimeProcess?.env?.NODE_ENV !== void 0) {
|
|
422
|
-
return runtimeProcess.env.NODE_ENV;
|
|
415
|
+
// src/Mnemonic/persistence-shared.ts
|
|
416
|
+
function objectHasOwn2(value, property) {
|
|
417
|
+
const hasOwn = Object.hasOwn;
|
|
418
|
+
if (typeof hasOwn === "function") {
|
|
419
|
+
return hasOwn(value, property);
|
|
423
420
|
}
|
|
424
|
-
return void 0;
|
|
425
|
-
}
|
|
426
|
-
function getNativeBrowserStorages() {
|
|
427
|
-
const globalWindow = globalThis.window;
|
|
428
|
-
if (!globalWindow) return [];
|
|
429
|
-
const storages = [];
|
|
430
|
-
const addStorage = (getter) => {
|
|
431
|
-
try {
|
|
432
|
-
storages.push(getter());
|
|
433
|
-
} catch {
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
addStorage(() => globalWindow.localStorage);
|
|
437
|
-
addStorage(() => globalWindow.sessionStorage);
|
|
438
|
-
return storages;
|
|
421
|
+
return Object.getOwnPropertyDescriptor(value, property) !== void 0;
|
|
439
422
|
}
|
|
440
|
-
|
|
441
|
-
// src/Mnemonic/use-shared.ts
|
|
442
|
-
var SSR_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol("mnemonic:ssr-snapshot");
|
|
443
|
-
var diagnosticContractRegistry = /* @__PURE__ */ new WeakMap();
|
|
444
|
-
var diagnosticWarningRegistry = /* @__PURE__ */ new WeakMap();
|
|
445
|
-
var diagnosticObjectIds = /* @__PURE__ */ new WeakMap();
|
|
446
|
-
var nextDiagnosticObjectId = 1;
|
|
447
423
|
function serializeEnvelope(version, payload) {
|
|
448
424
|
return JSON.stringify({
|
|
449
425
|
version,
|
|
450
426
|
payload
|
|
451
427
|
});
|
|
452
428
|
}
|
|
453
|
-
function
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
429
|
+
function parseEnvelope(key, rawText) {
|
|
430
|
+
try {
|
|
431
|
+
const parsed = JSON.parse(rawText);
|
|
432
|
+
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn2(parsed, "payload")) {
|
|
433
|
+
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`);
|
|
434
|
+
}
|
|
435
|
+
return parsed;
|
|
436
|
+
} catch (error) {
|
|
437
|
+
if (error instanceof SchemaError) {
|
|
438
|
+
throw error;
|
|
439
|
+
}
|
|
440
|
+
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, error);
|
|
457
441
|
}
|
|
458
|
-
if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
|
|
459
|
-
return result;
|
|
460
442
|
}
|
|
461
|
-
function
|
|
462
|
-
|
|
443
|
+
function decodeStringPayload(key, payload, codec) {
|
|
444
|
+
try {
|
|
445
|
+
return codec.decode(payload);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
throw error instanceof CodecError ? error : new CodecError(`Codec decode failed for key "${key}"`, error);
|
|
448
|
+
}
|
|
463
449
|
}
|
|
464
|
-
function
|
|
465
|
-
|
|
466
|
-
if (
|
|
467
|
-
|
|
468
|
-
diagnosticWarningRegistry.set(api, warnings);
|
|
450
|
+
function validateAgainstSchema(key, value, jsonSchema) {
|
|
451
|
+
const errors = validateJsonSchema(value, jsonSchema);
|
|
452
|
+
if (errors.length === 0) {
|
|
453
|
+
return;
|
|
469
454
|
}
|
|
470
|
-
|
|
455
|
+
const message = errors.map((entry) => `${entry.path || "/"}: ${entry.message}`).join("; ");
|
|
456
|
+
throw new SchemaError("TYPE_MISMATCH", `Schema validation failed for key "${key}": ${message}`);
|
|
471
457
|
}
|
|
472
|
-
function
|
|
473
|
-
|
|
474
|
-
if (warnings.has(id)) return;
|
|
475
|
-
warnings.add(id);
|
|
476
|
-
console.warn(message);
|
|
458
|
+
function getLatestSchema(schemaRegistry, key) {
|
|
459
|
+
return schemaRegistry?.getLatestSchema(key);
|
|
477
460
|
}
|
|
478
|
-
function
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
461
|
+
function getSchemaForVersion(schemaRegistry, key, version) {
|
|
462
|
+
return schemaRegistry?.getSchema(key, version);
|
|
463
|
+
}
|
|
464
|
+
function getMigrationPath(schemaRegistry, key, fromVersion, toVersion) {
|
|
465
|
+
return schemaRegistry?.getMigrationPath(key, fromVersion, toVersion) ?? null;
|
|
466
|
+
}
|
|
467
|
+
function resolveTargetWriteSchema({
|
|
468
|
+
key,
|
|
469
|
+
explicitVersion,
|
|
470
|
+
schemaMode,
|
|
471
|
+
schemaRegistry
|
|
472
|
+
}) {
|
|
473
|
+
const latestSchema = getLatestSchema(schemaRegistry, key);
|
|
474
|
+
if (explicitVersion === void 0) {
|
|
475
|
+
return latestSchema;
|
|
483
476
|
}
|
|
484
|
-
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
477
|
+
const explicitSchema = getSchemaForVersion(schemaRegistry, key, explicitVersion);
|
|
478
|
+
if (explicitSchema) {
|
|
479
|
+
return explicitSchema;
|
|
480
|
+
}
|
|
481
|
+
return schemaMode === "strict" ? void 0 : latestSchema;
|
|
482
|
+
}
|
|
483
|
+
function encodePersistedValueForWrite({
|
|
484
|
+
key,
|
|
485
|
+
nextValue,
|
|
486
|
+
codec,
|
|
487
|
+
explicitVersion,
|
|
488
|
+
schemaMode,
|
|
489
|
+
schemaRegistry
|
|
490
|
+
}) {
|
|
491
|
+
const targetSchema = resolveTargetWriteSchema({
|
|
492
|
+
key,
|
|
493
|
+
explicitVersion,
|
|
494
|
+
schemaMode,
|
|
495
|
+
schemaRegistry
|
|
496
|
+
});
|
|
497
|
+
if (!targetSchema) {
|
|
498
|
+
if (explicitVersion !== void 0 && schemaMode === "strict") {
|
|
499
|
+
throw new SchemaError("WRITE_SCHEMA_REQUIRED", `Write requires schema for key "${key}" in strict mode`);
|
|
500
|
+
}
|
|
501
|
+
return serializeEnvelope(0, codec.encode(nextValue));
|
|
502
|
+
}
|
|
503
|
+
let valueToStore = nextValue;
|
|
504
|
+
const writeMigration = schemaRegistry?.getWriteMigration?.(key, targetSchema.version);
|
|
505
|
+
if (writeMigration) {
|
|
506
|
+
try {
|
|
507
|
+
valueToStore = writeMigration.migrate(valueToStore);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
throw error instanceof SchemaError ? error : new SchemaError("MIGRATION_FAILED", `Write-time migration failed for key "${key}"`, error);
|
|
493
510
|
}
|
|
494
|
-
return tag;
|
|
495
511
|
}
|
|
512
|
+
validateAgainstSchema(key, valueToStore, targetSchema.schema);
|
|
513
|
+
return serializeEnvelope(targetSchema.version, valueToStore);
|
|
496
514
|
}
|
|
497
|
-
|
|
498
|
-
|
|
515
|
+
|
|
516
|
+
// src/Mnemonic/optional-bridge-adapter.ts
|
|
517
|
+
function resolveOptionalDefaultValue(defaultValue) {
|
|
518
|
+
return typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
499
519
|
}
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
if (typeof hasOwn === "function") {
|
|
503
|
-
return hasOwn(value, property);
|
|
504
|
-
}
|
|
505
|
-
return Object.getOwnPropertyDescriptor(value, property) !== void 0;
|
|
520
|
+
function getSchemaCapabilities(schemaRegistry) {
|
|
521
|
+
return schemaRegistry !== void 0;
|
|
506
522
|
}
|
|
507
|
-
function
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
diagnosticObjectIds.set(value, id);
|
|
512
|
-
return id;
|
|
523
|
+
function buildFallbackResult(options) {
|
|
524
|
+
return {
|
|
525
|
+
value: resolveOptionalDefaultValue(options.defaultValue)
|
|
526
|
+
};
|
|
513
527
|
}
|
|
514
|
-
function
|
|
515
|
-
|
|
516
|
-
key,
|
|
517
|
-
defaultValue,
|
|
518
|
-
codecOpt,
|
|
519
|
-
schemaVersion,
|
|
520
|
-
reconcile,
|
|
521
|
-
listenCrossTab,
|
|
522
|
-
ssrOptions
|
|
523
|
-
}) {
|
|
524
|
-
const codecSignature = codecOpt == null || !isObjectLike(codecOpt) ? "default-json-codec" : `codec:${stableDiagnosticValue(codecOpt.encode)}:${stableDiagnosticValue(codecOpt.decode)}`;
|
|
525
|
-
const reconcileSignature = reconcile == null || !isObjectLike(reconcile) ? "no-reconcile" : `reconcile:${stableDiagnosticValue(reconcile)}`;
|
|
526
|
-
return JSON.stringify({
|
|
528
|
+
function encodeValueForWrite(key, nextValue, options, schemaMode, schemaRegistry) {
|
|
529
|
+
return encodePersistedValueForWrite({
|
|
527
530
|
key,
|
|
528
|
-
|
|
529
|
-
codec:
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
ssrHydration: ssrOptions?.hydration ?? null,
|
|
534
|
-
hasServerValue: ssrOptions?.serverValue !== void 0,
|
|
535
|
-
providerHydration: api.ssrHydration ?? null
|
|
531
|
+
nextValue,
|
|
532
|
+
codec: options.codec ?? JSONCodec,
|
|
533
|
+
explicitVersion: options.schema?.version,
|
|
534
|
+
schemaMode,
|
|
535
|
+
schemaRegistry
|
|
536
536
|
});
|
|
537
537
|
}
|
|
538
|
-
function
|
|
539
|
-
if (typeof
|
|
540
|
-
return
|
|
538
|
+
function decodeCodecManagedEnvelope(key, envelope, options) {
|
|
539
|
+
if (typeof envelope.payload !== "string") {
|
|
540
|
+
return {
|
|
541
|
+
value: envelope.payload
|
|
542
|
+
};
|
|
541
543
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
+
return {
|
|
545
|
+
value: decodeStringPayload(key, envelope.payload, options.codec ?? JSONCodec)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry) {
|
|
549
|
+
if (!schemaRegistry?.registerSchema) {
|
|
550
|
+
throw new SchemaError(
|
|
551
|
+
"MODE_CONFIGURATION_INVALID",
|
|
552
|
+
`Autoschema mode requires schema registry registration for key "${key}"`
|
|
553
|
+
);
|
|
544
554
|
}
|
|
555
|
+
const decoded = typeof envelope.payload === "string" ? decodeStringPayload(key, envelope.payload, options.codec ?? JSONCodec) : envelope.payload;
|
|
556
|
+
const pendingSchema = {
|
|
557
|
+
key,
|
|
558
|
+
version: 1,
|
|
559
|
+
schema: inferJsonSchema(decoded)
|
|
560
|
+
};
|
|
545
561
|
return {
|
|
546
|
-
|
|
547
|
-
|
|
562
|
+
value: decoded,
|
|
563
|
+
rewriteRaw: serializeEnvelope(pendingSchema.version, decoded),
|
|
564
|
+
pendingSchema
|
|
548
565
|
};
|
|
549
566
|
}
|
|
550
|
-
function
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
() => developmentRuntime ? buildContractFingerprint({
|
|
570
|
-
api,
|
|
571
|
-
key,
|
|
572
|
-
defaultValue,
|
|
573
|
-
codecOpt,
|
|
574
|
-
...{} ,
|
|
575
|
-
reconcile,
|
|
576
|
-
listenCrossTab,
|
|
577
|
-
ssrOptions
|
|
578
|
-
}) : null,
|
|
579
|
-
[
|
|
580
|
-
developmentRuntime,
|
|
581
|
-
api,
|
|
582
|
-
key,
|
|
583
|
-
defaultValue,
|
|
584
|
-
codecOpt,
|
|
585
|
-
schemaVersion,
|
|
586
|
-
reconcile,
|
|
587
|
-
listenCrossTab,
|
|
588
|
-
ssrOptions?.hydration,
|
|
589
|
-
ssrOptions?.serverValue
|
|
590
|
-
]
|
|
591
|
-
);
|
|
592
|
-
const getFallback = useCallback(
|
|
593
|
-
(error) => typeof defaultValue === "function" ? defaultValue(error) : defaultValue,
|
|
594
|
-
[defaultValue]
|
|
595
|
-
);
|
|
596
|
-
const getServerValue = useCallback(() => {
|
|
597
|
-
const serverValue = ssrOptions?.serverValue;
|
|
598
|
-
if (serverValue === void 0) {
|
|
599
|
-
return getFallback();
|
|
600
|
-
}
|
|
601
|
-
return typeof serverValue === "function" ? serverValue() : serverValue;
|
|
602
|
-
}, [getFallback, ssrOptions?.serverValue]);
|
|
603
|
-
const parseEnvelope2 = useCallback(
|
|
604
|
-
(rawText) => {
|
|
605
|
-
try {
|
|
606
|
-
const parsed = JSON.parse(rawText);
|
|
607
|
-
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn2(parsed, "payload")) {
|
|
608
|
-
return {
|
|
609
|
-
ok: false,
|
|
610
|
-
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`)
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
return { ok: true, envelope: parsed };
|
|
614
|
-
} catch (err) {
|
|
615
|
-
return {
|
|
616
|
-
ok: false,
|
|
617
|
-
error: new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, err)
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
},
|
|
621
|
-
[key]
|
|
622
|
-
);
|
|
623
|
-
const decodeStringPayload2 = useCallback(
|
|
624
|
-
(payload, activeCodec) => {
|
|
625
|
-
try {
|
|
626
|
-
return activeCodec.decode(payload);
|
|
627
|
-
} catch (err) {
|
|
628
|
-
throw err instanceof CodecError ? err : new CodecError(`Codec decode failed for key "${key}"`, err);
|
|
629
|
-
}
|
|
630
|
-
},
|
|
631
|
-
[key]
|
|
632
|
-
);
|
|
633
|
-
const buildFallbackResult2 = useCallback(
|
|
634
|
-
(error, extra) => {
|
|
635
|
-
return withReadMetadata(getFallback(error), void 0, extra);
|
|
636
|
-
},
|
|
637
|
-
[getFallback]
|
|
638
|
-
);
|
|
567
|
+
function decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry) {
|
|
568
|
+
let current = envelope.payload;
|
|
569
|
+
validateAgainstSchema(key, current, schemaForVersion.schema);
|
|
570
|
+
if (!latestSchema || envelope.version >= latestSchema.version) {
|
|
571
|
+
return {
|
|
572
|
+
value: current
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
const path = getMigrationPath(schemaRegistry, key, envelope.version, latestSchema.version);
|
|
576
|
+
if (!path) {
|
|
577
|
+
throw new SchemaError(
|
|
578
|
+
"MIGRATION_PATH_NOT_FOUND",
|
|
579
|
+
`No migration path for key "${key}" from v${envelope.version} to v${latestSchema.version}`
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
for (const step of path) {
|
|
583
|
+
current = step.migrate(current);
|
|
584
|
+
}
|
|
585
|
+
validateAgainstSchema(key, current, latestSchema.schema);
|
|
639
586
|
return {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
codec,
|
|
643
|
-
codecOpt,
|
|
644
|
-
schema,
|
|
645
|
-
reconcile,
|
|
646
|
-
onMount,
|
|
647
|
-
onChange,
|
|
648
|
-
listenCrossTab,
|
|
649
|
-
getFallback,
|
|
650
|
-
getServerValue,
|
|
651
|
-
parseEnvelope: parseEnvelope2,
|
|
652
|
-
decodeStringPayload: decodeStringPayload2,
|
|
653
|
-
buildFallbackResult: buildFallbackResult2,
|
|
654
|
-
developmentRuntime,
|
|
655
|
-
contractFingerprint,
|
|
656
|
-
hasMounted,
|
|
657
|
-
setHasMounted,
|
|
658
|
-
hydrationMode,
|
|
659
|
-
ssrOptions
|
|
587
|
+
value: current,
|
|
588
|
+
rewriteRaw: serializeEnvelope(latestSchema.version, current)
|
|
660
589
|
};
|
|
661
590
|
}
|
|
662
|
-
function
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
591
|
+
function decodePersistedValue(key, raw, options, api, schemaRegistry) {
|
|
592
|
+
if (raw == null) {
|
|
593
|
+
return buildFallbackResult(options);
|
|
594
|
+
}
|
|
595
|
+
const envelope = parseEnvelope(key, raw);
|
|
596
|
+
const latestSchema = getLatestSchema(schemaRegistry, key);
|
|
597
|
+
const schemaForVersion = getSchemaForVersion(schemaRegistry, key, envelope.version);
|
|
598
|
+
if (api.schemaMode === "strict" && !schemaForVersion) {
|
|
599
|
+
throw new SchemaError("SCHEMA_NOT_FOUND", `No schema for key "${key}" v${envelope.version}`);
|
|
600
|
+
}
|
|
601
|
+
if (api.schemaMode === "autoschema" && !schemaForVersion) {
|
|
602
|
+
return decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry);
|
|
603
|
+
}
|
|
604
|
+
if (!schemaForVersion) {
|
|
605
|
+
return decodeCodecManagedEnvelope(key, envelope, options);
|
|
606
|
+
}
|
|
607
|
+
return decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry);
|
|
608
|
+
}
|
|
609
|
+
function createMnemonicOptionalBridge({
|
|
610
|
+
api,
|
|
611
|
+
schemaRegistry
|
|
666
612
|
}) {
|
|
667
|
-
return
|
|
668
|
-
(
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
const context = {
|
|
681
|
-
key,
|
|
682
|
-
persistedVersion
|
|
683
|
-
};
|
|
684
|
-
if (latestVersion !== void 0) {
|
|
685
|
-
context.latestVersion = latestVersion;
|
|
613
|
+
return {
|
|
614
|
+
namespace: api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix,
|
|
615
|
+
capabilities: {
|
|
616
|
+
persistence: true,
|
|
617
|
+
schema: getSchemaCapabilities(schemaRegistry)
|
|
618
|
+
},
|
|
619
|
+
subscribeRaw: (key, listener) => api.subscribeRaw(key, listener),
|
|
620
|
+
getRawSnapshot: (key) => api.getRawSnapshot(key),
|
|
621
|
+
decodeSnapshot: (key, raw, options) => {
|
|
622
|
+
try {
|
|
623
|
+
return decodePersistedValue(key, raw, options, api, schemaRegistry);
|
|
624
|
+
} catch {
|
|
625
|
+
return buildFallbackResult(options);
|
|
686
626
|
}
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return serializeForPersist(value);
|
|
690
|
-
} catch {
|
|
691
|
-
return rewriteRaw;
|
|
692
|
-
}
|
|
693
|
-
})();
|
|
627
|
+
},
|
|
628
|
+
setValue: (key, nextValue, options) => {
|
|
694
629
|
try {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
630
|
+
api.setRaw(key, encodeValueForWrite(key, nextValue, options, api.schemaMode, schemaRegistry));
|
|
631
|
+
} catch (error) {
|
|
632
|
+
if (error instanceof SchemaError) {
|
|
633
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${error.code}):`, error.message);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (error instanceof CodecError) {
|
|
637
|
+
console.error(`[Mnemonic] Codec error for key "${key}":`, error.message);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
throw error;
|
|
703
641
|
}
|
|
704
642
|
},
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
listenCrossTab,
|
|
717
|
-
getFallback,
|
|
718
|
-
getServerValue,
|
|
719
|
-
developmentRuntime,
|
|
720
|
-
contractFingerprint,
|
|
721
|
-
hasMounted,
|
|
722
|
-
setHasMounted,
|
|
723
|
-
hydrationMode,
|
|
724
|
-
ssrOptions
|
|
725
|
-
} = shared;
|
|
726
|
-
const { decodeForRead, encodeForWrite, active = true, additionalDevWarnings, onDecodedEffect } = config;
|
|
727
|
-
const getServerRawSnapshot = useCallback(
|
|
728
|
-
() => ssrOptions?.serverValue === void 0 ? null : SSR_SNAPSHOT_TOKEN,
|
|
729
|
-
[ssrOptions?.serverValue]
|
|
730
|
-
);
|
|
731
|
-
const deferStorageRead = hydrationMode === "client-only" && !hasMounted;
|
|
732
|
-
const subscribe = useCallback(
|
|
733
|
-
(listener) => {
|
|
734
|
-
if (!active) {
|
|
735
|
-
return () => void 0;
|
|
643
|
+
removeValue: (key) => {
|
|
644
|
+
api.removeRaw(key);
|
|
645
|
+
},
|
|
646
|
+
commitSnapshot: (key, raw, snapshot) => {
|
|
647
|
+
if (snapshot.pendingSchema && schemaRegistry?.registerSchema) {
|
|
648
|
+
if (!schemaRegistry.getSchema(snapshot.pendingSchema.key, snapshot.pendingSchema.version)) {
|
|
649
|
+
try {
|
|
650
|
+
schemaRegistry.registerSchema(snapshot.pendingSchema);
|
|
651
|
+
} catch {
|
|
652
|
+
}
|
|
653
|
+
}
|
|
736
654
|
}
|
|
737
|
-
if (
|
|
738
|
-
|
|
655
|
+
if (snapshot.rewriteRaw !== void 0 && snapshot.rewriteRaw !== raw) {
|
|
656
|
+
api.setRaw(key, snapshot.rewriteRaw);
|
|
739
657
|
}
|
|
740
|
-
return api.subscribeRaw(key, listener);
|
|
741
|
-
},
|
|
742
|
-
[active, api, deferStorageRead, key]
|
|
743
|
-
);
|
|
744
|
-
const raw = useSyncExternalStore(
|
|
745
|
-
subscribe,
|
|
746
|
-
() => active && !deferStorageRead ? api.getRawSnapshot(key) : getServerRawSnapshot(),
|
|
747
|
-
getServerRawSnapshot
|
|
748
|
-
);
|
|
749
|
-
const decoded = useMemo(() => {
|
|
750
|
-
if (raw === SSR_SNAPSHOT_TOKEN) {
|
|
751
|
-
return withReadMetadata(getServerValue());
|
|
752
658
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
var OPTIONAL_BRIDGE_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("react-mnemonic.optional-bridge-context");
|
|
662
|
+
function getMnemonicOptionalBridgeContext() {
|
|
663
|
+
const globalStore = globalThis;
|
|
664
|
+
const existing = globalStore[OPTIONAL_BRIDGE_CONTEXT_KEY];
|
|
665
|
+
if (existing) {
|
|
666
|
+
return existing;
|
|
667
|
+
}
|
|
668
|
+
const context = createContext(null);
|
|
669
|
+
globalStore[OPTIONAL_BRIDGE_CONTEXT_KEY] = context;
|
|
670
|
+
return context;
|
|
671
|
+
}
|
|
672
|
+
var MnemonicOptionalBridgeContext = getMnemonicOptionalBridgeContext();
|
|
673
|
+
|
|
674
|
+
// src/Mnemonic/optional-bridge-provider.tsx
|
|
675
|
+
function MnemonicOptionalBridgeProvider({
|
|
676
|
+
bridge,
|
|
677
|
+
children
|
|
678
|
+
}) {
|
|
679
|
+
return createElement(MnemonicOptionalBridgeContext.Provider, { value: bridge }, children);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/Mnemonic/runtime.ts
|
|
683
|
+
function getGlobalProcess() {
|
|
684
|
+
return globalThis.process;
|
|
685
|
+
}
|
|
686
|
+
function getRuntimeNodeEnv() {
|
|
687
|
+
const runtimeProcess = getGlobalProcess();
|
|
688
|
+
if (runtimeProcess?.env?.NODE_ENV !== void 0) {
|
|
689
|
+
return runtimeProcess.env.NODE_ENV;
|
|
690
|
+
}
|
|
691
|
+
return void 0;
|
|
692
|
+
}
|
|
693
|
+
function getDefaultBrowserStorage() {
|
|
694
|
+
const globalWindow = globalThis.window;
|
|
695
|
+
if (globalWindow === void 0) return void 0;
|
|
696
|
+
try {
|
|
697
|
+
return globalWindow.localStorage;
|
|
698
|
+
} catch {
|
|
699
|
+
return void 0;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
function getNativeBrowserStorages() {
|
|
703
|
+
const globalWindow = globalThis.window;
|
|
704
|
+
if (!globalWindow) return [];
|
|
705
|
+
const storages = [];
|
|
706
|
+
const addStorage = (getter) => {
|
|
707
|
+
try {
|
|
708
|
+
storages.push(getter());
|
|
709
|
+
} catch {
|
|
766
710
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
codecOpt,
|
|
772
|
-
schema,
|
|
773
|
-
warnOnce: (id, message) => warnOnce(api, id, message)
|
|
774
|
-
});
|
|
775
|
-
let keyContracts = diagnosticContractRegistry.get(api);
|
|
776
|
-
if (!keyContracts) {
|
|
777
|
-
keyContracts = /* @__PURE__ */ new Map();
|
|
778
|
-
diagnosticContractRegistry.set(api, keyContracts);
|
|
779
|
-
}
|
|
780
|
-
if (contractFingerprint === null) {
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
const previousContract = keyContracts.get(key);
|
|
784
|
-
if (previousContract === void 0) {
|
|
785
|
-
keyContracts.set(key, contractFingerprint);
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
if (previousContract === contractFingerprint) {
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
warnOnce(
|
|
792
|
-
api,
|
|
793
|
-
`contract-conflict:${key}`,
|
|
794
|
-
`[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.`
|
|
795
|
-
);
|
|
796
|
-
}, [
|
|
797
|
-
active,
|
|
798
|
-
additionalDevWarnings,
|
|
799
|
-
api,
|
|
800
|
-
key,
|
|
801
|
-
developmentRuntime,
|
|
802
|
-
contractFingerprint,
|
|
803
|
-
listenCrossTab,
|
|
804
|
-
codecOpt,
|
|
805
|
-
schema,
|
|
806
|
-
api.crossTabSyncMode
|
|
807
|
-
]);
|
|
808
|
-
useEffect(() => {
|
|
809
|
-
if (hasMounted) return;
|
|
810
|
-
setHasMounted(true);
|
|
811
|
-
}, [hasMounted, setHasMounted]);
|
|
812
|
-
useEffect(() => {
|
|
813
|
-
if (!active) return;
|
|
814
|
-
if (decoded.rewriteRaw && decoded.rewriteRaw !== raw) {
|
|
815
|
-
api.setRaw(key, decoded.rewriteRaw);
|
|
816
|
-
}
|
|
817
|
-
}, [active, api, decoded.rewriteRaw, key, raw]);
|
|
818
|
-
useEffect(() => {
|
|
819
|
-
if (!active) return;
|
|
820
|
-
onDecodedEffect?.(decoded);
|
|
821
|
-
}, [active, decoded, onDecodedEffect]);
|
|
822
|
-
const prevRef = useRef(value);
|
|
823
|
-
const mounted = useRef(false);
|
|
824
|
-
useEffect(() => {
|
|
825
|
-
if (!active) return;
|
|
826
|
-
if (mounted.current) return;
|
|
827
|
-
mounted.current = true;
|
|
828
|
-
onMount?.(value);
|
|
829
|
-
prevRef.current = value;
|
|
830
|
-
}, [active]);
|
|
831
|
-
useEffect(() => {
|
|
832
|
-
if (!active) return;
|
|
833
|
-
const prev = prevRef.current;
|
|
834
|
-
if (Object.is(prev, value)) return;
|
|
835
|
-
prevRef.current = value;
|
|
836
|
-
onChange?.(value, prev);
|
|
837
|
-
}, [active, value, onChange]);
|
|
838
|
-
useEffect(() => {
|
|
839
|
-
if (!active) return;
|
|
840
|
-
if (!listenCrossTab) return;
|
|
841
|
-
const globalWindow = globalThis.window;
|
|
842
|
-
if (globalWindow === void 0) return;
|
|
843
|
-
const storageKey = api.prefix + key;
|
|
844
|
-
const handler = (e) => {
|
|
845
|
-
if (e.key === null) {
|
|
846
|
-
api.removeRaw(key);
|
|
847
|
-
return;
|
|
848
|
-
}
|
|
849
|
-
if (e.key !== storageKey) return;
|
|
850
|
-
if (e.newValue == null) {
|
|
851
|
-
api.removeRaw(key);
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
api.setRaw(key, e.newValue);
|
|
855
|
-
};
|
|
856
|
-
globalWindow.addEventListener("storage", handler);
|
|
857
|
-
return () => globalWindow.removeEventListener("storage", handler);
|
|
858
|
-
}, [active, listenCrossTab, api, key]);
|
|
859
|
-
const set = useMemo(() => {
|
|
860
|
-
if (!active) {
|
|
861
|
-
return () => void 0;
|
|
862
|
-
}
|
|
863
|
-
return (next) => {
|
|
864
|
-
const nextVal = typeof next === "function" ? next(decodeForRead(api.getRawSnapshot(key)).value) : next;
|
|
865
|
-
try {
|
|
866
|
-
const encoded = encodeForWrite(nextVal);
|
|
867
|
-
api.setRaw(key, encoded);
|
|
868
|
-
} catch (err) {
|
|
869
|
-
if (err instanceof SchemaError) {
|
|
870
|
-
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
if (err instanceof CodecError) {
|
|
874
|
-
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
console.error(`[Mnemonic] Failed to persist key "${key}":`, err);
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
}, [active, api, key, decodeForRead, encodeForWrite]);
|
|
881
|
-
const reset = useMemo(() => {
|
|
882
|
-
if (!active) {
|
|
883
|
-
return () => void 0;
|
|
884
|
-
}
|
|
885
|
-
return () => {
|
|
886
|
-
const v = getFallback();
|
|
887
|
-
try {
|
|
888
|
-
const encoded = encodeForWrite(v);
|
|
889
|
-
api.setRaw(key, encoded);
|
|
890
|
-
} catch (err) {
|
|
891
|
-
if (err instanceof SchemaError) {
|
|
892
|
-
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
893
|
-
return;
|
|
894
|
-
}
|
|
895
|
-
if (err instanceof CodecError) {
|
|
896
|
-
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
897
|
-
}
|
|
898
|
-
return;
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
|
-
}, [active, api, key, getFallback, encodeForWrite]);
|
|
902
|
-
const remove = useMemo(() => {
|
|
903
|
-
if (!active) {
|
|
904
|
-
return () => void 0;
|
|
905
|
-
}
|
|
906
|
-
return () => api.removeRaw(key);
|
|
907
|
-
}, [active, api, key]);
|
|
908
|
-
return useMemo(
|
|
909
|
-
() => ({
|
|
910
|
-
value,
|
|
911
|
-
set,
|
|
912
|
-
reset,
|
|
913
|
-
remove
|
|
914
|
-
}),
|
|
915
|
-
[value, set, reset, remove]
|
|
916
|
-
);
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// src/Mnemonic/optional-bridge-adapter.ts
|
|
920
|
-
function resolveOptionalDefaultValue(defaultValue) {
|
|
921
|
-
return typeof defaultValue === "function" ? defaultValue() : defaultValue;
|
|
711
|
+
};
|
|
712
|
+
addStorage(() => globalWindow.localStorage);
|
|
713
|
+
addStorage(() => globalWindow.sessionStorage);
|
|
714
|
+
return storages;
|
|
922
715
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
716
|
+
var MnemonicContext = createContext(null);
|
|
717
|
+
var warnedNestedProviderStores = /* @__PURE__ */ new WeakSet();
|
|
718
|
+
function useMnemonic() {
|
|
719
|
+
const context = useMnemonicOptional();
|
|
720
|
+
if (!context) {
|
|
721
|
+
throw new Error("useMnemonic must be used within a MnemonicProvider");
|
|
927
722
|
}
|
|
928
|
-
return
|
|
723
|
+
return context;
|
|
929
724
|
}
|
|
930
|
-
function
|
|
931
|
-
|
|
932
|
-
const parsed = JSON.parse(rawText);
|
|
933
|
-
if (typeof parsed !== "object" || parsed == null || !Number.isInteger(parsed.version) || parsed.version < 0 || !objectHasOwn3(parsed, "payload")) {
|
|
934
|
-
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`);
|
|
935
|
-
}
|
|
936
|
-
return parsed;
|
|
937
|
-
} catch (error) {
|
|
938
|
-
if (error instanceof SchemaError) {
|
|
939
|
-
throw error;
|
|
940
|
-
}
|
|
941
|
-
throw new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, error);
|
|
942
|
-
}
|
|
725
|
+
function useMnemonicOptional() {
|
|
726
|
+
return useContext(MnemonicContext);
|
|
943
727
|
}
|
|
944
|
-
function
|
|
945
|
-
|
|
728
|
+
function detectEnumerableStorage(storage) {
|
|
729
|
+
if (!storage) return false;
|
|
946
730
|
try {
|
|
947
|
-
return
|
|
948
|
-
} catch
|
|
949
|
-
|
|
731
|
+
return typeof storage.length === "number" && typeof storage.key === "function";
|
|
732
|
+
} catch {
|
|
733
|
+
return false;
|
|
950
734
|
}
|
|
951
735
|
}
|
|
952
|
-
function
|
|
953
|
-
const
|
|
954
|
-
if (
|
|
955
|
-
return;
|
|
736
|
+
function isProductionRuntime() {
|
|
737
|
+
const env = getRuntimeNodeEnv();
|
|
738
|
+
if (env === void 0) {
|
|
739
|
+
return true;
|
|
956
740
|
}
|
|
957
|
-
|
|
958
|
-
throw new SchemaError("TYPE_MISMATCH", `Schema validation failed for key "${key}": ${message}`);
|
|
741
|
+
return env === "production";
|
|
959
742
|
}
|
|
960
|
-
function
|
|
961
|
-
|
|
743
|
+
function weakRefConstructor() {
|
|
744
|
+
const ctor = globalThis.WeakRef;
|
|
745
|
+
return typeof ctor === "function" ? ctor : null;
|
|
962
746
|
}
|
|
963
|
-
function
|
|
964
|
-
return
|
|
965
|
-
value: resolveOptionalDefaultValue(options.defaultValue)
|
|
966
|
-
};
|
|
747
|
+
function hasFinalizationRegistry() {
|
|
748
|
+
return typeof globalThis.FinalizationRegistry === "function";
|
|
967
749
|
}
|
|
968
|
-
function
|
|
969
|
-
|
|
750
|
+
function isPromiseLike(value) {
|
|
751
|
+
if (value == null) return false;
|
|
752
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
753
|
+
return typeof value.then === "function";
|
|
970
754
|
}
|
|
971
|
-
function
|
|
972
|
-
|
|
755
|
+
function getCrossTabSyncMode(requestedStorage, activeStorage) {
|
|
756
|
+
const isExplicitNativeBrowserStorage = activeStorage !== void 0 && requestedStorage !== void 0 && getNativeBrowserStorages().includes(activeStorage);
|
|
757
|
+
if (requestedStorage === void 0 && activeStorage !== void 0 || isExplicitNativeBrowserStorage) {
|
|
758
|
+
return "browser-storage-event";
|
|
759
|
+
}
|
|
760
|
+
if (typeof activeStorage?.onExternalChange === "function") {
|
|
761
|
+
return "custom-external-change";
|
|
762
|
+
}
|
|
763
|
+
return "none";
|
|
973
764
|
}
|
|
974
|
-
function
|
|
975
|
-
return
|
|
765
|
+
function getDevToolsWindow() {
|
|
766
|
+
return globalThis.window;
|
|
976
767
|
}
|
|
977
|
-
function
|
|
978
|
-
const
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
return serializeEnvelope(0, codec.encode(nextValue));
|
|
984
|
-
}
|
|
985
|
-
let valueToStore = nextValue;
|
|
986
|
-
const writeMigration = schemaRegistry?.getWriteMigration?.(key, targetSchema.version);
|
|
987
|
-
if (writeMigration) {
|
|
768
|
+
function sanitizeDevToolsRoot(root) {
|
|
769
|
+
const reserved = /* @__PURE__ */ new Set(["providers", "resolve", "list", "capabilities", "__meta"]);
|
|
770
|
+
for (const key of Object.keys(root)) {
|
|
771
|
+
if (reserved.has(key)) continue;
|
|
772
|
+
const descriptor = Object.getOwnPropertyDescriptor(root, key);
|
|
773
|
+
if (descriptor && !descriptor.configurable) continue;
|
|
988
774
|
try {
|
|
989
|
-
|
|
990
|
-
} catch
|
|
991
|
-
throw error instanceof SchemaError ? error : new SchemaError("MIGRATION_FAILED", `Write-time migration failed for key "${key}"`, error);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
validateAgainstSchema(key, valueToStore, targetSchema.schema);
|
|
995
|
-
return serializeEnvelope(targetSchema.version, valueToStore);
|
|
996
|
-
}
|
|
997
|
-
function decodeCodecManagedEnvelope(key, envelope, options) {
|
|
998
|
-
if (typeof envelope.payload !== "string") {
|
|
999
|
-
return {
|
|
1000
|
-
value: envelope.payload
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
return {
|
|
1004
|
-
value: decodeStringPayload(key, envelope.payload, options)
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
function decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry) {
|
|
1008
|
-
if (!schemaRegistry?.registerSchema) {
|
|
1009
|
-
throw new SchemaError(
|
|
1010
|
-
"MODE_CONFIGURATION_INVALID",
|
|
1011
|
-
`Autoschema mode requires schema registry registration for key "${key}"`
|
|
1012
|
-
);
|
|
1013
|
-
}
|
|
1014
|
-
const decoded = typeof envelope.payload === "string" ? decodeStringPayload(key, envelope.payload, options) : envelope.payload;
|
|
1015
|
-
const pendingSchema = {
|
|
1016
|
-
key,
|
|
1017
|
-
version: 1,
|
|
1018
|
-
schema: inferJsonSchema(decoded)
|
|
1019
|
-
};
|
|
1020
|
-
return {
|
|
1021
|
-
value: decoded,
|
|
1022
|
-
rewriteRaw: serializeEnvelope(pendingSchema.version, decoded),
|
|
1023
|
-
pendingSchema
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
function decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry) {
|
|
1027
|
-
let current = envelope.payload;
|
|
1028
|
-
validateAgainstSchema(key, current, schemaForVersion.schema);
|
|
1029
|
-
if (!latestSchema || envelope.version >= latestSchema.version) {
|
|
1030
|
-
return {
|
|
1031
|
-
value: current
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
const path = getMigrationPath(schemaRegistry, key, envelope.version, latestSchema.version);
|
|
1035
|
-
if (!path) {
|
|
1036
|
-
throw new SchemaError(
|
|
1037
|
-
"MIGRATION_PATH_NOT_FOUND",
|
|
1038
|
-
`No migration path for key "${key}" from v${envelope.version} to v${latestSchema.version}`
|
|
1039
|
-
);
|
|
1040
|
-
}
|
|
1041
|
-
for (const step of path) {
|
|
1042
|
-
current = step.migrate(current);
|
|
1043
|
-
}
|
|
1044
|
-
validateAgainstSchema(key, current, latestSchema.schema);
|
|
1045
|
-
return {
|
|
1046
|
-
value: current,
|
|
1047
|
-
rewriteRaw: serializeEnvelope(latestSchema.version, current)
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
function decodePersistedValue(key, raw, options, api, schemaRegistry) {
|
|
1051
|
-
if (raw == null) {
|
|
1052
|
-
return buildFallbackResult(options);
|
|
1053
|
-
}
|
|
1054
|
-
const envelope = parseEnvelope(key, raw);
|
|
1055
|
-
const latestSchema = getLatestSchema(schemaRegistry, key);
|
|
1056
|
-
const schemaForVersion = getSchemaForVersion(schemaRegistry, key, envelope.version);
|
|
1057
|
-
if (api.schemaMode === "strict" && !schemaForVersion) {
|
|
1058
|
-
throw new SchemaError("SCHEMA_NOT_FOUND", `No schema for key "${key}" v${envelope.version}`);
|
|
1059
|
-
}
|
|
1060
|
-
if (api.schemaMode === "autoschema" && !schemaForVersion) {
|
|
1061
|
-
return decodeAutoschemaEnvelope(key, envelope, options, schemaRegistry);
|
|
1062
|
-
}
|
|
1063
|
-
if (!schemaForVersion) {
|
|
1064
|
-
return decodeCodecManagedEnvelope(key, envelope, options);
|
|
1065
|
-
}
|
|
1066
|
-
return decodeSchemaManagedEnvelope(key, envelope, schemaForVersion, latestSchema, schemaRegistry);
|
|
1067
|
-
}
|
|
1068
|
-
function createMnemonicOptionalBridge({
|
|
1069
|
-
api,
|
|
1070
|
-
schemaRegistry
|
|
1071
|
-
}) {
|
|
1072
|
-
return {
|
|
1073
|
-
namespace: api.prefix.endsWith(".") ? api.prefix.slice(0, -1) : api.prefix,
|
|
1074
|
-
capabilities: {
|
|
1075
|
-
persistence: true,
|
|
1076
|
-
schema: getSchemaCapabilities(schemaRegistry)
|
|
1077
|
-
},
|
|
1078
|
-
subscribeRaw: (key, listener) => api.subscribeRaw(key, listener),
|
|
1079
|
-
getRawSnapshot: (key) => api.getRawSnapshot(key),
|
|
1080
|
-
decodeSnapshot: (key, raw, options) => {
|
|
1081
|
-
try {
|
|
1082
|
-
return decodePersistedValue(key, raw, options, api, schemaRegistry);
|
|
1083
|
-
} catch {
|
|
1084
|
-
return buildFallbackResult(options);
|
|
1085
|
-
}
|
|
1086
|
-
},
|
|
1087
|
-
setValue: (key, nextValue, options) => {
|
|
1088
|
-
try {
|
|
1089
|
-
api.setRaw(key, encodeValueForWrite(key, nextValue, options, schemaRegistry));
|
|
1090
|
-
} catch (error) {
|
|
1091
|
-
if (error instanceof SchemaError) {
|
|
1092
|
-
console.error(`[Mnemonic] Schema error for key "${key}" (${error.code}):`, error.message);
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
if (error instanceof CodecError) {
|
|
1096
|
-
console.error(`[Mnemonic] Codec error for key "${key}":`, error.message);
|
|
1097
|
-
return;
|
|
1098
|
-
}
|
|
1099
|
-
throw error;
|
|
1100
|
-
}
|
|
1101
|
-
},
|
|
1102
|
-
removeValue: (key) => {
|
|
1103
|
-
api.removeRaw(key);
|
|
1104
|
-
},
|
|
1105
|
-
commitSnapshot: (key, raw, snapshot) => {
|
|
1106
|
-
if (snapshot.pendingSchema && schemaRegistry?.registerSchema) {
|
|
1107
|
-
if (!schemaRegistry.getSchema(snapshot.pendingSchema.key, snapshot.pendingSchema.version)) {
|
|
1108
|
-
try {
|
|
1109
|
-
schemaRegistry.registerSchema(snapshot.pendingSchema);
|
|
1110
|
-
} catch {
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
if (snapshot.rewriteRaw !== void 0 && snapshot.rewriteRaw !== raw) {
|
|
1115
|
-
api.setRaw(key, snapshot.rewriteRaw);
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
};
|
|
1119
|
-
}
|
|
1120
|
-
var MnemonicOptionalBridgeContext = createContext(null);
|
|
1121
|
-
|
|
1122
|
-
// src/Mnemonic/optional-bridge-provider.tsx
|
|
1123
|
-
function MnemonicOptionalBridgeProvider({
|
|
1124
|
-
bridge,
|
|
1125
|
-
children
|
|
1126
|
-
}) {
|
|
1127
|
-
return createElement(MnemonicOptionalBridgeContext.Provider, { value: bridge }, children);
|
|
1128
|
-
}
|
|
1129
|
-
var MnemonicContext = createContext(null);
|
|
1130
|
-
function useMnemonic() {
|
|
1131
|
-
const context = useMnemonicOptional();
|
|
1132
|
-
if (!context) {
|
|
1133
|
-
throw new Error("useMnemonic must be used within a MnemonicProvider");
|
|
1134
|
-
}
|
|
1135
|
-
return context;
|
|
1136
|
-
}
|
|
1137
|
-
function useMnemonicOptional() {
|
|
1138
|
-
return useContext(MnemonicContext);
|
|
1139
|
-
}
|
|
1140
|
-
function defaultBrowserStorage() {
|
|
1141
|
-
const globalWindow = globalThis.window;
|
|
1142
|
-
if (globalWindow === void 0) return void 0;
|
|
1143
|
-
try {
|
|
1144
|
-
return globalWindow.localStorage;
|
|
1145
|
-
} catch {
|
|
1146
|
-
return void 0;
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
function detectEnumerableStorage(storage) {
|
|
1150
|
-
if (!storage) return false;
|
|
1151
|
-
try {
|
|
1152
|
-
return typeof storage.length === "number" && typeof storage.key === "function";
|
|
1153
|
-
} catch {
|
|
1154
|
-
return false;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
function isProductionRuntime() {
|
|
1158
|
-
const env = getRuntimeNodeEnv();
|
|
1159
|
-
if (env === void 0) {
|
|
1160
|
-
return true;
|
|
1161
|
-
}
|
|
1162
|
-
return env === "production";
|
|
1163
|
-
}
|
|
1164
|
-
function weakRefConstructor() {
|
|
1165
|
-
const ctor = globalThis.WeakRef;
|
|
1166
|
-
return typeof ctor === "function" ? ctor : null;
|
|
1167
|
-
}
|
|
1168
|
-
function hasFinalizationRegistry() {
|
|
1169
|
-
return typeof globalThis.FinalizationRegistry === "function";
|
|
1170
|
-
}
|
|
1171
|
-
function isPromiseLike(value) {
|
|
1172
|
-
if (value == null) return false;
|
|
1173
|
-
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
1174
|
-
return typeof value.then === "function";
|
|
1175
|
-
}
|
|
1176
|
-
function getCrossTabSyncMode(requestedStorage, activeStorage) {
|
|
1177
|
-
const isExplicitNativeBrowserStorage = activeStorage !== void 0 && requestedStorage !== void 0 && getNativeBrowserStorages().includes(activeStorage);
|
|
1178
|
-
if (requestedStorage === void 0 && activeStorage !== void 0 || isExplicitNativeBrowserStorage) {
|
|
1179
|
-
return "browser-storage-event";
|
|
1180
|
-
}
|
|
1181
|
-
if (typeof activeStorage?.onExternalChange === "function") {
|
|
1182
|
-
return "custom-external-change";
|
|
1183
|
-
}
|
|
1184
|
-
return "none";
|
|
1185
|
-
}
|
|
1186
|
-
function getDevToolsWindow() {
|
|
1187
|
-
return globalThis.window;
|
|
1188
|
-
}
|
|
1189
|
-
function sanitizeDevToolsRoot(root) {
|
|
1190
|
-
const reserved = /* @__PURE__ */ new Set(["providers", "resolve", "list", "capabilities", "__meta"]);
|
|
1191
|
-
for (const key of Object.keys(root)) {
|
|
1192
|
-
if (reserved.has(key)) continue;
|
|
1193
|
-
const descriptor = Object.getOwnPropertyDescriptor(root, key);
|
|
1194
|
-
if (descriptor && !descriptor.configurable) continue;
|
|
1195
|
-
try {
|
|
1196
|
-
delete root[key];
|
|
1197
|
-
} catch {
|
|
775
|
+
delete root[key];
|
|
776
|
+
} catch {
|
|
1198
777
|
}
|
|
1199
778
|
}
|
|
1200
779
|
}
|
|
@@ -1530,7 +1109,8 @@ function MnemonicProvider({
|
|
|
1530
1109
|
enableDevTools = false,
|
|
1531
1110
|
schemaMode = "default",
|
|
1532
1111
|
schemaRegistry,
|
|
1533
|
-
ssr
|
|
1112
|
+
ssr,
|
|
1113
|
+
bootstrap
|
|
1534
1114
|
}) {
|
|
1535
1115
|
if (schemaMode === "strict" && !schemaRegistry) {
|
|
1536
1116
|
throw new Error("MnemonicProvider strict mode requires schemaRegistry");
|
|
@@ -1538,14 +1118,32 @@ function MnemonicProvider({
|
|
|
1538
1118
|
if (schemaMode === "autoschema" && typeof schemaRegistry?.registerSchema !== "function") {
|
|
1539
1119
|
throw new Error("MnemonicProvider autoschema mode requires schemaRegistry.registerSchema");
|
|
1540
1120
|
}
|
|
1121
|
+
const prefix = `${namespace}.`;
|
|
1122
|
+
const parentStore = useMnemonicOptional();
|
|
1123
|
+
const bootstrapRawSeed = useRef(bootstrap?.raw).current;
|
|
1124
|
+
useEffect(() => {
|
|
1125
|
+
if (isProductionRuntime()) return;
|
|
1126
|
+
if (parentStore?.prefix !== prefix) return;
|
|
1127
|
+
if (warnedNestedProviderStores.has(parentStore)) return;
|
|
1128
|
+
warnedNestedProviderStores.add(parentStore);
|
|
1129
|
+
console.warn(
|
|
1130
|
+
`[Mnemonic] Nested MnemonicProvider detected for namespace "${namespace}". The nearest provider wins, so the inner provider creates a separate store and cache even though the namespace matches. Prefer a single provider per namespace, or use distinct namespaces for intentionally separate scopes.`
|
|
1131
|
+
);
|
|
1132
|
+
}, [namespace, parentStore, prefix]);
|
|
1541
1133
|
const store = useMemo(() => {
|
|
1542
|
-
const
|
|
1543
|
-
const st = storage ?? defaultBrowserStorage();
|
|
1134
|
+
const st = storage ?? getDefaultBrowserStorage();
|
|
1544
1135
|
const ssrHydration = ssr?.hydration ?? "immediate";
|
|
1545
1136
|
const devToolsRoot = ensureDevToolsRoot(enableDevTools);
|
|
1546
1137
|
const canEnumerateKeys = detectEnumerableStorage(st);
|
|
1547
1138
|
const crossTabSyncMode = getCrossTabSyncMode(storage, st);
|
|
1548
1139
|
const cache = /* @__PURE__ */ new Map();
|
|
1140
|
+
if (bootstrapRawSeed) {
|
|
1141
|
+
for (const [key, raw] of Object.entries(bootstrapRawSeed)) {
|
|
1142
|
+
if (raw != null) {
|
|
1143
|
+
cache.set(key, raw);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1549
1147
|
const listeners = /* @__PURE__ */ new Map();
|
|
1550
1148
|
let quotaErrorLogged = false;
|
|
1551
1149
|
let accessErrorLogged = false;
|
|
@@ -1570,168 +1168,622 @@ function MnemonicProvider({
|
|
|
1570
1168
|
);
|
|
1571
1169
|
accessErrorLogged = true;
|
|
1572
1170
|
}
|
|
1573
|
-
};
|
|
1574
|
-
const handleAsyncStorageContractViolation = (method, thenable) => {
|
|
1575
|
-
asyncContractViolationDetected = true;
|
|
1576
|
-
void Promise.resolve(thenable).catch(() => void 0);
|
|
1577
|
-
if (accessErrorLogged) return;
|
|
1578
|
-
console.error(
|
|
1579
|
-
`[Mnemonic] StorageLike.${method} returned a Promise. StorageLike must remain synchronous for react-mnemonic v1. Wrap async persistence behind a synchronous cache facade instead.`
|
|
1580
|
-
);
|
|
1581
|
-
accessErrorLogged = true;
|
|
1582
|
-
};
|
|
1583
|
-
const readThrough = (key) => {
|
|
1584
|
-
if (cache.has(key)) return cache.get(key) ?? null;
|
|
1585
|
-
if (!st || asyncContractViolationDetected) {
|
|
1586
|
-
cache.set(key, null);
|
|
1587
|
-
return null;
|
|
1171
|
+
};
|
|
1172
|
+
const handleAsyncStorageContractViolation = (method, thenable) => {
|
|
1173
|
+
asyncContractViolationDetected = true;
|
|
1174
|
+
void Promise.resolve(thenable).catch(() => void 0);
|
|
1175
|
+
if (accessErrorLogged) return;
|
|
1176
|
+
console.error(
|
|
1177
|
+
`[Mnemonic] StorageLike.${method} returned a Promise. StorageLike must remain synchronous for react-mnemonic v1. Wrap async persistence behind a synchronous cache facade instead.`
|
|
1178
|
+
);
|
|
1179
|
+
accessErrorLogged = true;
|
|
1180
|
+
};
|
|
1181
|
+
const readThrough = (key) => {
|
|
1182
|
+
if (cache.has(key)) return cache.get(key) ?? null;
|
|
1183
|
+
if (!st || asyncContractViolationDetected) {
|
|
1184
|
+
cache.set(key, null);
|
|
1185
|
+
return null;
|
|
1186
|
+
}
|
|
1187
|
+
const raw = readStorageRaw(st, fullKey(key), storageAccessCallbacks);
|
|
1188
|
+
cache.set(key, raw);
|
|
1189
|
+
return raw;
|
|
1190
|
+
};
|
|
1191
|
+
const writeRaw = (key, raw) => {
|
|
1192
|
+
cache.set(key, raw);
|
|
1193
|
+
if (st && !asyncContractViolationDetected) {
|
|
1194
|
+
try {
|
|
1195
|
+
const result = st.setItem(fullKey(key), raw);
|
|
1196
|
+
if (isPromiseLike(result)) {
|
|
1197
|
+
handleAsyncStorageContractViolation("setItem", result);
|
|
1198
|
+
} else {
|
|
1199
|
+
quotaErrorLogged = false;
|
|
1200
|
+
accessErrorLogged = false;
|
|
1201
|
+
}
|
|
1202
|
+
} catch (err) {
|
|
1203
|
+
if (!quotaErrorLogged && err instanceof DOMException && err.name === "QuotaExceededError") {
|
|
1204
|
+
console.error(
|
|
1205
|
+
`[Mnemonic] Storage quota exceeded writing key "${key}". Data is cached in memory but will not persist.`
|
|
1206
|
+
);
|
|
1207
|
+
quotaErrorLogged = true;
|
|
1208
|
+
}
|
|
1209
|
+
logAccessError(err);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
emit(key);
|
|
1213
|
+
bumpDevToolsVersion(devToolsRoot, namespace, `set:${key}`);
|
|
1214
|
+
};
|
|
1215
|
+
const removeRaw = (key) => {
|
|
1216
|
+
cache.set(key, null);
|
|
1217
|
+
if (st && !asyncContractViolationDetected) {
|
|
1218
|
+
try {
|
|
1219
|
+
const result = st.removeItem(fullKey(key));
|
|
1220
|
+
if (isPromiseLike(result)) {
|
|
1221
|
+
handleAsyncStorageContractViolation("removeItem", result);
|
|
1222
|
+
} else {
|
|
1223
|
+
accessErrorLogged = false;
|
|
1224
|
+
}
|
|
1225
|
+
} catch (err) {
|
|
1226
|
+
logAccessError(err);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
emit(key);
|
|
1230
|
+
bumpDevToolsVersion(devToolsRoot, namespace, `remove:${key}`);
|
|
1231
|
+
};
|
|
1232
|
+
const subscribeRaw = (key, listener) => {
|
|
1233
|
+
let set = listeners.get(key);
|
|
1234
|
+
if (!set) {
|
|
1235
|
+
set = /* @__PURE__ */ new Set();
|
|
1236
|
+
listeners.set(key, set);
|
|
1237
|
+
}
|
|
1238
|
+
set.add(listener);
|
|
1239
|
+
readThrough(key);
|
|
1240
|
+
return () => {
|
|
1241
|
+
const s = listeners.get(key);
|
|
1242
|
+
if (!s) return;
|
|
1243
|
+
s.delete(listener);
|
|
1244
|
+
if (s.size === 0) listeners.delete(key);
|
|
1245
|
+
};
|
|
1246
|
+
};
|
|
1247
|
+
const getRawSnapshot = (key) => readThrough(key);
|
|
1248
|
+
const keys = () => {
|
|
1249
|
+
if (asyncContractViolationDetected) {
|
|
1250
|
+
return Array.from(cache.entries()).filter(([, value]) => value != null).map(([key]) => key);
|
|
1251
|
+
}
|
|
1252
|
+
if (!canEnumerateKeys) return [];
|
|
1253
|
+
return enumerateNamespaceKeys(st, prefix, storageAccessCallbacks);
|
|
1254
|
+
};
|
|
1255
|
+
const dump = () => {
|
|
1256
|
+
const out = {};
|
|
1257
|
+
for (const k of keys()) {
|
|
1258
|
+
const raw = readThrough(k);
|
|
1259
|
+
if (raw != null) out[k] = raw;
|
|
1260
|
+
}
|
|
1261
|
+
return out;
|
|
1262
|
+
};
|
|
1263
|
+
const reloadFromStorage = createReloadFromStorage({
|
|
1264
|
+
storage: st,
|
|
1265
|
+
hasAsyncContractViolation: () => asyncContractViolationDetected,
|
|
1266
|
+
prefix,
|
|
1267
|
+
listeners,
|
|
1268
|
+
cache,
|
|
1269
|
+
emit,
|
|
1270
|
+
callbacks: storageAccessCallbacks,
|
|
1271
|
+
devToolsRoot,
|
|
1272
|
+
namespace
|
|
1273
|
+
});
|
|
1274
|
+
const store2 = {
|
|
1275
|
+
prefix,
|
|
1276
|
+
canEnumerateKeys,
|
|
1277
|
+
subscribeRaw,
|
|
1278
|
+
getRawSnapshot,
|
|
1279
|
+
setRaw: writeRaw,
|
|
1280
|
+
removeRaw,
|
|
1281
|
+
keys,
|
|
1282
|
+
dump,
|
|
1283
|
+
reloadFromStorage,
|
|
1284
|
+
schemaMode,
|
|
1285
|
+
ssrHydration,
|
|
1286
|
+
crossTabSyncMode,
|
|
1287
|
+
...schemaRegistry ? { schemaRegistry } : {}
|
|
1288
|
+
};
|
|
1289
|
+
if (devToolsRoot) {
|
|
1290
|
+
registerDevToolsProvider({
|
|
1291
|
+
devToolsRoot,
|
|
1292
|
+
namespace,
|
|
1293
|
+
store: store2,
|
|
1294
|
+
dump,
|
|
1295
|
+
keys,
|
|
1296
|
+
readThrough,
|
|
1297
|
+
writeRaw,
|
|
1298
|
+
removeRaw
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
return store2;
|
|
1302
|
+
}, [namespace, storage, enableDevTools, schemaMode, schemaRegistry, ssr?.hydration, bootstrapRawSeed]);
|
|
1303
|
+
const optionalBridge = useMemo(
|
|
1304
|
+
() => createMnemonicOptionalBridge({
|
|
1305
|
+
api: store,
|
|
1306
|
+
...schemaRegistry ? { schemaRegistry } : {}
|
|
1307
|
+
}),
|
|
1308
|
+
[schemaRegistry, store]
|
|
1309
|
+
);
|
|
1310
|
+
useEffect(() => {
|
|
1311
|
+
if (!storage?.onExternalChange) return;
|
|
1312
|
+
return storage.onExternalChange((changedKeys) => store.reloadFromStorage(changedKeys));
|
|
1313
|
+
}, [storage, store]);
|
|
1314
|
+
return /* @__PURE__ */ jsx(MnemonicContext.Provider, { value: store, children: /* @__PURE__ */ jsx(MnemonicOptionalBridgeProvider, { bridge: optionalBridge, children }) });
|
|
1315
|
+
}
|
|
1316
|
+
function throwCoreProviderSchemaImportError(propName) {
|
|
1317
|
+
throw new Error(
|
|
1318
|
+
`[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.`
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
function assertNoSchemaProps(props) {
|
|
1322
|
+
if (props.schemaMode !== void 0) {
|
|
1323
|
+
throwCoreProviderSchemaImportError("schemaMode");
|
|
1324
|
+
}
|
|
1325
|
+
if (props.schemaRegistry !== void 0) {
|
|
1326
|
+
throwCoreProviderSchemaImportError("schemaRegistry");
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
function MnemonicProvider2(props) {
|
|
1330
|
+
assertNoSchemaProps(props);
|
|
1331
|
+
return /* @__PURE__ */ jsx(MnemonicProvider, { ...props });
|
|
1332
|
+
}
|
|
1333
|
+
var SSR_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol("mnemonic:ssr-snapshot");
|
|
1334
|
+
var diagnosticContractRegistry = /* @__PURE__ */ new WeakMap();
|
|
1335
|
+
var diagnosticWarningRegistry = /* @__PURE__ */ new WeakMap();
|
|
1336
|
+
var diagnosticObjectIds = /* @__PURE__ */ new WeakMap();
|
|
1337
|
+
var nextDiagnosticObjectId = 1;
|
|
1338
|
+
function withReadMetadata(value, rewriteRaw, extra) {
|
|
1339
|
+
const result = { value };
|
|
1340
|
+
if (extra !== void 0) {
|
|
1341
|
+
Object.assign(result, extra);
|
|
1342
|
+
}
|
|
1343
|
+
if (rewriteRaw !== void 0) result.rewriteRaw = rewriteRaw;
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1346
|
+
function isDevelopmentRuntime() {
|
|
1347
|
+
return getRuntimeNodeEnv() === "development";
|
|
1348
|
+
}
|
|
1349
|
+
function getDiagnosticWarnings(api) {
|
|
1350
|
+
let warnings = diagnosticWarningRegistry.get(api);
|
|
1351
|
+
if (!warnings) {
|
|
1352
|
+
warnings = /* @__PURE__ */ new Set();
|
|
1353
|
+
diagnosticWarningRegistry.set(api, warnings);
|
|
1354
|
+
}
|
|
1355
|
+
return warnings;
|
|
1356
|
+
}
|
|
1357
|
+
function warnOnce(api, id, message) {
|
|
1358
|
+
const warnings = getDiagnosticWarnings(api);
|
|
1359
|
+
if (warnings.has(id)) return;
|
|
1360
|
+
warnings.add(id);
|
|
1361
|
+
console.warn(message);
|
|
1362
|
+
}
|
|
1363
|
+
function stableDiagnosticValue(value) {
|
|
1364
|
+
if (typeof value === "function") {
|
|
1365
|
+
const source = Function.prototype.toString.call(value).split(/\s+/).join(" ").trim();
|
|
1366
|
+
const name = value.name || "anonymous";
|
|
1367
|
+
return `[factory:${name}/${value.length}:${source}]`;
|
|
1368
|
+
}
|
|
1369
|
+
if (typeof value === "bigint") return `${value.toString()}n`;
|
|
1370
|
+
if (typeof value === "symbol") return value.toString();
|
|
1371
|
+
if (value === void 0) return "undefined";
|
|
1372
|
+
try {
|
|
1373
|
+
return JSON.stringify(value);
|
|
1374
|
+
} catch {
|
|
1375
|
+
const tag = Object.prototype.toString.call(value);
|
|
1376
|
+
if (value !== null && (typeof value === "object" || typeof value === "function")) {
|
|
1377
|
+
return `${tag}#${getDiagnosticObjectId(value)}`;
|
|
1378
|
+
}
|
|
1379
|
+
return tag;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
function isObjectLike(value) {
|
|
1383
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
1384
|
+
}
|
|
1385
|
+
function getDiagnosticObjectId(value) {
|
|
1386
|
+
const existing = diagnosticObjectIds.get(value);
|
|
1387
|
+
if (existing !== void 0) return existing;
|
|
1388
|
+
const id = nextDiagnosticObjectId++;
|
|
1389
|
+
diagnosticObjectIds.set(value, id);
|
|
1390
|
+
return id;
|
|
1391
|
+
}
|
|
1392
|
+
function buildContractFingerprint({
|
|
1393
|
+
api,
|
|
1394
|
+
key,
|
|
1395
|
+
defaultValue,
|
|
1396
|
+
codecOpt,
|
|
1397
|
+
schemaVersion,
|
|
1398
|
+
reconcile,
|
|
1399
|
+
listenCrossTab,
|
|
1400
|
+
ssrOptions
|
|
1401
|
+
}) {
|
|
1402
|
+
const codecSignature = codecOpt == null || !isObjectLike(codecOpt) ? "default-json-codec" : `codec:${stableDiagnosticValue(codecOpt.encode)}:${stableDiagnosticValue(codecOpt.decode)}`;
|
|
1403
|
+
const reconcileSignature = reconcile == null || !isObjectLike(reconcile) ? "no-reconcile" : `reconcile:${stableDiagnosticValue(reconcile)}`;
|
|
1404
|
+
return JSON.stringify({
|
|
1405
|
+
key,
|
|
1406
|
+
defaultValue: stableDiagnosticValue(defaultValue),
|
|
1407
|
+
codec: codecSignature,
|
|
1408
|
+
schemaVersion: schemaVersion ?? null,
|
|
1409
|
+
listenCrossTab: Boolean(listenCrossTab),
|
|
1410
|
+
reconcile: reconcileSignature,
|
|
1411
|
+
ssrHydration: ssrOptions?.hydration ?? null,
|
|
1412
|
+
hasServerValue: ssrOptions?.serverValue !== void 0,
|
|
1413
|
+
providerHydration: api.ssrHydration ?? null
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
function resolveMnemonicKeyArgs(keyOrDescriptor, options) {
|
|
1417
|
+
if (typeof keyOrDescriptor !== "string") {
|
|
1418
|
+
return keyOrDescriptor;
|
|
1419
|
+
}
|
|
1420
|
+
if (!options) {
|
|
1421
|
+
throw new Error("useMnemonicKey requires options when called with a string key");
|
|
1422
|
+
}
|
|
1423
|
+
return {
|
|
1424
|
+
key: keyOrDescriptor,
|
|
1425
|
+
options
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
function useMnemonicKeySharedFromApi(api, keyOrDescriptor, options, schemaVersion) {
|
|
1429
|
+
const descriptor = resolveMnemonicKeyArgs(keyOrDescriptor, options);
|
|
1430
|
+
const key = descriptor.key;
|
|
1431
|
+
const resolvedOptions = descriptor.options;
|
|
1432
|
+
const {
|
|
1433
|
+
defaultValue,
|
|
1434
|
+
onMount,
|
|
1435
|
+
onChange,
|
|
1436
|
+
listenCrossTab,
|
|
1437
|
+
codec: codecOpt,
|
|
1438
|
+
schema,
|
|
1439
|
+
reconcile,
|
|
1440
|
+
ssr: ssrOptions
|
|
1441
|
+
} = resolvedOptions;
|
|
1442
|
+
const codec = codecOpt ?? JSONCodec;
|
|
1443
|
+
const hydrationMode = ssrOptions?.hydration ?? api.ssrHydration;
|
|
1444
|
+
const [hasMounted, setHasMounted] = useState(hydrationMode !== "client-only");
|
|
1445
|
+
const developmentRuntime = isDevelopmentRuntime();
|
|
1446
|
+
const contractFingerprint = useMemo(
|
|
1447
|
+
() => developmentRuntime ? buildContractFingerprint({
|
|
1448
|
+
api,
|
|
1449
|
+
key,
|
|
1450
|
+
defaultValue,
|
|
1451
|
+
codecOpt,
|
|
1452
|
+
...{} ,
|
|
1453
|
+
reconcile,
|
|
1454
|
+
listenCrossTab,
|
|
1455
|
+
ssrOptions
|
|
1456
|
+
}) : null,
|
|
1457
|
+
[
|
|
1458
|
+
developmentRuntime,
|
|
1459
|
+
api,
|
|
1460
|
+
key,
|
|
1461
|
+
defaultValue,
|
|
1462
|
+
codecOpt,
|
|
1463
|
+
schemaVersion,
|
|
1464
|
+
reconcile,
|
|
1465
|
+
listenCrossTab,
|
|
1466
|
+
ssrOptions?.hydration,
|
|
1467
|
+
ssrOptions?.serverValue
|
|
1468
|
+
]
|
|
1469
|
+
);
|
|
1470
|
+
const getFallback = useCallback(
|
|
1471
|
+
(error) => typeof defaultValue === "function" ? defaultValue(error) : defaultValue,
|
|
1472
|
+
[defaultValue]
|
|
1473
|
+
);
|
|
1474
|
+
const getServerValue = useCallback(() => {
|
|
1475
|
+
const serverValue = ssrOptions?.serverValue;
|
|
1476
|
+
if (serverValue === void 0) {
|
|
1477
|
+
return getFallback();
|
|
1478
|
+
}
|
|
1479
|
+
return typeof serverValue === "function" ? serverValue() : serverValue;
|
|
1480
|
+
}, [getFallback, ssrOptions?.serverValue]);
|
|
1481
|
+
const parseEnvelope2 = useCallback(
|
|
1482
|
+
(rawText) => {
|
|
1483
|
+
try {
|
|
1484
|
+
return { ok: true, envelope: parseEnvelope(key, rawText) };
|
|
1485
|
+
} catch (error) {
|
|
1486
|
+
return {
|
|
1487
|
+
ok: false,
|
|
1488
|
+
error: error instanceof SchemaError ? error : new SchemaError("INVALID_ENVELOPE", `Invalid envelope for key "${key}"`, error)
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
},
|
|
1492
|
+
[key]
|
|
1493
|
+
);
|
|
1494
|
+
const decodeStringPayload2 = useCallback(
|
|
1495
|
+
(payload, activeCodec) => {
|
|
1496
|
+
return decodeStringPayload(key, payload, activeCodec);
|
|
1497
|
+
},
|
|
1498
|
+
[key]
|
|
1499
|
+
);
|
|
1500
|
+
const buildFallbackResult2 = useCallback(
|
|
1501
|
+
(error, extra) => {
|
|
1502
|
+
return withReadMetadata(getFallback(error), void 0, extra);
|
|
1503
|
+
},
|
|
1504
|
+
[getFallback]
|
|
1505
|
+
);
|
|
1506
|
+
return {
|
|
1507
|
+
api,
|
|
1508
|
+
key,
|
|
1509
|
+
codec,
|
|
1510
|
+
codecOpt,
|
|
1511
|
+
schema,
|
|
1512
|
+
reconcile,
|
|
1513
|
+
onMount,
|
|
1514
|
+
onChange,
|
|
1515
|
+
listenCrossTab,
|
|
1516
|
+
getFallback,
|
|
1517
|
+
getServerValue,
|
|
1518
|
+
parseEnvelope: parseEnvelope2,
|
|
1519
|
+
decodeStringPayload: decodeStringPayload2,
|
|
1520
|
+
buildFallbackResult: buildFallbackResult2,
|
|
1521
|
+
developmentRuntime,
|
|
1522
|
+
contractFingerprint,
|
|
1523
|
+
hasMounted,
|
|
1524
|
+
setHasMounted,
|
|
1525
|
+
hydrationMode,
|
|
1526
|
+
ssrOptions
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
function useApplyReconcile({
|
|
1530
|
+
key,
|
|
1531
|
+
reconcile,
|
|
1532
|
+
buildFallbackResult: buildFallbackResult2
|
|
1533
|
+
}) {
|
|
1534
|
+
return useCallback(
|
|
1535
|
+
({
|
|
1536
|
+
value,
|
|
1537
|
+
rewriteRaw,
|
|
1538
|
+
extra,
|
|
1539
|
+
persistedVersion,
|
|
1540
|
+
latestVersion,
|
|
1541
|
+
serializeForPersist,
|
|
1542
|
+
deriveExtra
|
|
1543
|
+
}) => {
|
|
1544
|
+
if (!reconcile) {
|
|
1545
|
+
return withReadMetadata(value, rewriteRaw, extra);
|
|
1546
|
+
}
|
|
1547
|
+
const context = {
|
|
1548
|
+
key,
|
|
1549
|
+
persistedVersion
|
|
1550
|
+
};
|
|
1551
|
+
if (latestVersion !== void 0) {
|
|
1552
|
+
context.latestVersion = latestVersion;
|
|
1553
|
+
}
|
|
1554
|
+
const baselineSerialized = (() => {
|
|
1555
|
+
try {
|
|
1556
|
+
return serializeForPersist(value);
|
|
1557
|
+
} catch {
|
|
1558
|
+
return rewriteRaw;
|
|
1559
|
+
}
|
|
1560
|
+
})();
|
|
1561
|
+
try {
|
|
1562
|
+
const reconciled = reconcile(value, context);
|
|
1563
|
+
const nextExtra = deriveExtra ? deriveExtra(reconciled, extra) : extra;
|
|
1564
|
+
const nextSerialized = serializeForPersist(reconciled);
|
|
1565
|
+
const nextRewriteRaw = baselineSerialized === void 0 || nextSerialized !== baselineSerialized ? nextSerialized : rewriteRaw;
|
|
1566
|
+
return withReadMetadata(reconciled, nextRewriteRaw, nextExtra);
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
const typedErr = err instanceof SchemaError ? err : new SchemaError("RECONCILE_FAILED", `Reconciliation failed for key "${key}"`, err);
|
|
1569
|
+
return buildFallbackResult2(typedErr, extra);
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
[buildFallbackResult2, key, reconcile]
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
function useMnemonicKeyState(shared, config) {
|
|
1576
|
+
const {
|
|
1577
|
+
api,
|
|
1578
|
+
key,
|
|
1579
|
+
codecOpt,
|
|
1580
|
+
schema,
|
|
1581
|
+
onMount,
|
|
1582
|
+
onChange,
|
|
1583
|
+
listenCrossTab,
|
|
1584
|
+
getFallback,
|
|
1585
|
+
getServerValue,
|
|
1586
|
+
developmentRuntime,
|
|
1587
|
+
contractFingerprint,
|
|
1588
|
+
hasMounted,
|
|
1589
|
+
setHasMounted,
|
|
1590
|
+
hydrationMode,
|
|
1591
|
+
ssrOptions
|
|
1592
|
+
} = shared;
|
|
1593
|
+
const { decodeForRead, encodeForWrite, active = true, additionalDevWarnings, onDecodedEffect } = config;
|
|
1594
|
+
const getServerRawSnapshot = useCallback(
|
|
1595
|
+
() => ssrOptions?.serverValue === void 0 ? null : SSR_SNAPSHOT_TOKEN,
|
|
1596
|
+
[ssrOptions?.serverValue]
|
|
1597
|
+
);
|
|
1598
|
+
const deferStorageRead = hydrationMode === "client-only" && !hasMounted;
|
|
1599
|
+
const subscribe = useCallback(
|
|
1600
|
+
(listener) => {
|
|
1601
|
+
if (!active) {
|
|
1602
|
+
return () => void 0;
|
|
1603
|
+
}
|
|
1604
|
+
if (deferStorageRead) {
|
|
1605
|
+
return () => void 0;
|
|
1606
|
+
}
|
|
1607
|
+
return api.subscribeRaw(key, listener);
|
|
1608
|
+
},
|
|
1609
|
+
[active, api, deferStorageRead, key]
|
|
1610
|
+
);
|
|
1611
|
+
const raw = useSyncExternalStore(
|
|
1612
|
+
subscribe,
|
|
1613
|
+
() => active && !deferStorageRead ? api.getRawSnapshot(key) : getServerRawSnapshot(),
|
|
1614
|
+
getServerRawSnapshot
|
|
1615
|
+
);
|
|
1616
|
+
const decoded = useMemo(() => {
|
|
1617
|
+
if (raw === SSR_SNAPSHOT_TOKEN) {
|
|
1618
|
+
return withReadMetadata(getServerValue());
|
|
1619
|
+
}
|
|
1620
|
+
return decodeForRead(raw);
|
|
1621
|
+
}, [decodeForRead, getServerValue, raw]);
|
|
1622
|
+
const value = decoded.value;
|
|
1623
|
+
useEffect(() => {
|
|
1624
|
+
if (!active) return;
|
|
1625
|
+
if (!developmentRuntime) return;
|
|
1626
|
+
const globalWindow = globalThis.window;
|
|
1627
|
+
if (listenCrossTab && (api.crossTabSyncMode ?? "none") === "none" && globalWindow !== void 0) {
|
|
1628
|
+
warnOnce(
|
|
1629
|
+
api,
|
|
1630
|
+
`listenCrossTab:${key}`,
|
|
1631
|
+
`[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.`
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
additionalDevWarnings?.({
|
|
1635
|
+
api,
|
|
1636
|
+
key,
|
|
1637
|
+
listenCrossTab,
|
|
1638
|
+
codecOpt,
|
|
1639
|
+
schema,
|
|
1640
|
+
warnOnce: (id, message) => warnOnce(api, id, message)
|
|
1641
|
+
});
|
|
1642
|
+
let keyContracts = diagnosticContractRegistry.get(api);
|
|
1643
|
+
if (!keyContracts) {
|
|
1644
|
+
keyContracts = /* @__PURE__ */ new Map();
|
|
1645
|
+
diagnosticContractRegistry.set(api, keyContracts);
|
|
1646
|
+
}
|
|
1647
|
+
if (contractFingerprint === null) {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const previousContract = keyContracts.get(key);
|
|
1651
|
+
if (previousContract === void 0) {
|
|
1652
|
+
keyContracts.set(key, contractFingerprint);
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
if (previousContract === contractFingerprint) {
|
|
1656
|
+
return;
|
|
1657
|
+
}
|
|
1658
|
+
warnOnce(
|
|
1659
|
+
api,
|
|
1660
|
+
`contract-conflict:${key}`,
|
|
1661
|
+
`[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.`
|
|
1662
|
+
);
|
|
1663
|
+
}, [
|
|
1664
|
+
active,
|
|
1665
|
+
additionalDevWarnings,
|
|
1666
|
+
api,
|
|
1667
|
+
key,
|
|
1668
|
+
developmentRuntime,
|
|
1669
|
+
contractFingerprint,
|
|
1670
|
+
listenCrossTab,
|
|
1671
|
+
codecOpt,
|
|
1672
|
+
schema,
|
|
1673
|
+
api.crossTabSyncMode
|
|
1674
|
+
]);
|
|
1675
|
+
useEffect(() => {
|
|
1676
|
+
if (hasMounted) return;
|
|
1677
|
+
setHasMounted(true);
|
|
1678
|
+
}, [hasMounted, setHasMounted]);
|
|
1679
|
+
useEffect(() => {
|
|
1680
|
+
if (!active) return;
|
|
1681
|
+
if (decoded.rewriteRaw && decoded.rewriteRaw !== raw) {
|
|
1682
|
+
api.setRaw(key, decoded.rewriteRaw);
|
|
1683
|
+
}
|
|
1684
|
+
}, [active, api, decoded.rewriteRaw, key, raw]);
|
|
1685
|
+
useEffect(() => {
|
|
1686
|
+
if (!active) return;
|
|
1687
|
+
onDecodedEffect?.(decoded);
|
|
1688
|
+
}, [active, decoded, onDecodedEffect]);
|
|
1689
|
+
const prevRef = useRef(value);
|
|
1690
|
+
const mounted = useRef(false);
|
|
1691
|
+
useEffect(() => {
|
|
1692
|
+
if (!active) return;
|
|
1693
|
+
if (mounted.current) return;
|
|
1694
|
+
mounted.current = true;
|
|
1695
|
+
onMount?.(value);
|
|
1696
|
+
prevRef.current = value;
|
|
1697
|
+
}, [active]);
|
|
1698
|
+
useEffect(() => {
|
|
1699
|
+
if (!active) return;
|
|
1700
|
+
const prev = prevRef.current;
|
|
1701
|
+
if (Object.is(prev, value)) return;
|
|
1702
|
+
prevRef.current = value;
|
|
1703
|
+
onChange?.(value, prev);
|
|
1704
|
+
}, [active, value, onChange]);
|
|
1705
|
+
useEffect(() => {
|
|
1706
|
+
if (!active) return;
|
|
1707
|
+
if (!listenCrossTab) return;
|
|
1708
|
+
const globalWindow = globalThis.window;
|
|
1709
|
+
if (globalWindow === void 0) return;
|
|
1710
|
+
const storageKey = api.prefix + key;
|
|
1711
|
+
const handler = (e) => {
|
|
1712
|
+
if (e.key === null) {
|
|
1713
|
+
api.removeRaw(key);
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
if (e.key !== storageKey) return;
|
|
1717
|
+
if (e.newValue == null) {
|
|
1718
|
+
api.removeRaw(key);
|
|
1719
|
+
return;
|
|
1588
1720
|
}
|
|
1589
|
-
|
|
1590
|
-
cache.set(key, raw);
|
|
1591
|
-
return raw;
|
|
1721
|
+
api.setRaw(key, e.newValue);
|
|
1592
1722
|
};
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
quotaErrorLogged = true;
|
|
1610
|
-
}
|
|
1611
|
-
logAccessError(err);
|
|
1723
|
+
globalWindow.addEventListener("storage", handler);
|
|
1724
|
+
return () => globalWindow.removeEventListener("storage", handler);
|
|
1725
|
+
}, [active, listenCrossTab, api, key]);
|
|
1726
|
+
const set = useMemo(() => {
|
|
1727
|
+
if (!active) {
|
|
1728
|
+
return () => void 0;
|
|
1729
|
+
}
|
|
1730
|
+
return (next) => {
|
|
1731
|
+
const nextVal = typeof next === "function" ? next(decodeForRead(api.getRawSnapshot(key)).value) : next;
|
|
1732
|
+
try {
|
|
1733
|
+
const encoded = encodeForWrite(nextVal);
|
|
1734
|
+
api.setRaw(key, encoded);
|
|
1735
|
+
} catch (err) {
|
|
1736
|
+
if (err instanceof SchemaError) {
|
|
1737
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
1738
|
+
return;
|
|
1612
1739
|
}
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
};
|
|
1617
|
-
const removeRaw = (key) => {
|
|
1618
|
-
cache.set(key, null);
|
|
1619
|
-
if (st && !asyncContractViolationDetected) {
|
|
1620
|
-
try {
|
|
1621
|
-
const result = st.removeItem(fullKey(key));
|
|
1622
|
-
if (isPromiseLike(result)) {
|
|
1623
|
-
handleAsyncStorageContractViolation("removeItem", result);
|
|
1624
|
-
} else {
|
|
1625
|
-
accessErrorLogged = false;
|
|
1626
|
-
}
|
|
1627
|
-
} catch (err) {
|
|
1628
|
-
logAccessError(err);
|
|
1740
|
+
if (err instanceof CodecError) {
|
|
1741
|
+
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
1742
|
+
return;
|
|
1629
1743
|
}
|
|
1744
|
+
console.error(`[Mnemonic] Failed to persist key "${key}":`, err);
|
|
1630
1745
|
}
|
|
1631
|
-
emit(key);
|
|
1632
|
-
bumpDevToolsVersion(devToolsRoot, namespace, `remove:${key}`);
|
|
1633
|
-
};
|
|
1634
|
-
const subscribeRaw = (key, listener) => {
|
|
1635
|
-
let set = listeners.get(key);
|
|
1636
|
-
if (!set) {
|
|
1637
|
-
set = /* @__PURE__ */ new Set();
|
|
1638
|
-
listeners.set(key, set);
|
|
1639
|
-
}
|
|
1640
|
-
set.add(listener);
|
|
1641
|
-
readThrough(key);
|
|
1642
|
-
return () => {
|
|
1643
|
-
const s = listeners.get(key);
|
|
1644
|
-
if (!s) return;
|
|
1645
|
-
s.delete(listener);
|
|
1646
|
-
if (s.size === 0) listeners.delete(key);
|
|
1647
|
-
};
|
|
1648
|
-
};
|
|
1649
|
-
const getRawSnapshot = (key) => readThrough(key);
|
|
1650
|
-
const keys = () => {
|
|
1651
|
-
if (asyncContractViolationDetected) {
|
|
1652
|
-
return Array.from(cache.entries()).filter(([, value]) => value != null).map(([key]) => key);
|
|
1653
|
-
}
|
|
1654
|
-
if (!canEnumerateKeys) return [];
|
|
1655
|
-
return enumerateNamespaceKeys(st, prefix, storageAccessCallbacks);
|
|
1656
1746
|
};
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1747
|
+
}, [active, api, key, decodeForRead, encodeForWrite]);
|
|
1748
|
+
const reset = useMemo(() => {
|
|
1749
|
+
if (!active) {
|
|
1750
|
+
return () => void 0;
|
|
1751
|
+
}
|
|
1752
|
+
return () => {
|
|
1753
|
+
const v = getFallback();
|
|
1754
|
+
try {
|
|
1755
|
+
const encoded = encodeForWrite(v);
|
|
1756
|
+
api.setRaw(key, encoded);
|
|
1757
|
+
} catch (err) {
|
|
1758
|
+
if (err instanceof SchemaError) {
|
|
1759
|
+
console.error(`[Mnemonic] Schema error for key "${key}" (${err.code}):`, err.message);
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1762
|
+
if (err instanceof CodecError) {
|
|
1763
|
+
console.error(`[Mnemonic] Codec encode error for key "${key}":`, err.message);
|
|
1764
|
+
}
|
|
1765
|
+
return;
|
|
1662
1766
|
}
|
|
1663
|
-
return out;
|
|
1664
|
-
};
|
|
1665
|
-
const reloadFromStorage = createReloadFromStorage({
|
|
1666
|
-
storage: st,
|
|
1667
|
-
hasAsyncContractViolation: () => asyncContractViolationDetected,
|
|
1668
|
-
prefix,
|
|
1669
|
-
listeners,
|
|
1670
|
-
cache,
|
|
1671
|
-
emit,
|
|
1672
|
-
callbacks: storageAccessCallbacks,
|
|
1673
|
-
devToolsRoot,
|
|
1674
|
-
namespace
|
|
1675
|
-
});
|
|
1676
|
-
const store2 = {
|
|
1677
|
-
prefix,
|
|
1678
|
-
canEnumerateKeys,
|
|
1679
|
-
subscribeRaw,
|
|
1680
|
-
getRawSnapshot,
|
|
1681
|
-
setRaw: writeRaw,
|
|
1682
|
-
removeRaw,
|
|
1683
|
-
keys,
|
|
1684
|
-
dump,
|
|
1685
|
-
reloadFromStorage,
|
|
1686
|
-
schemaMode,
|
|
1687
|
-
ssrHydration,
|
|
1688
|
-
crossTabSyncMode,
|
|
1689
|
-
...schemaRegistry ? { schemaRegistry } : {}
|
|
1690
1767
|
};
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
store: store2,
|
|
1696
|
-
dump,
|
|
1697
|
-
keys,
|
|
1698
|
-
readThrough,
|
|
1699
|
-
writeRaw,
|
|
1700
|
-
removeRaw
|
|
1701
|
-
});
|
|
1768
|
+
}, [active, api, key, getFallback, encodeForWrite]);
|
|
1769
|
+
const remove = useMemo(() => {
|
|
1770
|
+
if (!active) {
|
|
1771
|
+
return () => void 0;
|
|
1702
1772
|
}
|
|
1703
|
-
return
|
|
1704
|
-
}, [
|
|
1705
|
-
|
|
1706
|
-
() =>
|
|
1707
|
-
|
|
1708
|
-
|
|
1773
|
+
return () => api.removeRaw(key);
|
|
1774
|
+
}, [active, api, key]);
|
|
1775
|
+
return useMemo(
|
|
1776
|
+
() => ({
|
|
1777
|
+
value,
|
|
1778
|
+
set,
|
|
1779
|
+
reset,
|
|
1780
|
+
remove
|
|
1709
1781
|
}),
|
|
1710
|
-
[
|
|
1711
|
-
);
|
|
1712
|
-
useEffect(() => {
|
|
1713
|
-
if (!storage?.onExternalChange) return;
|
|
1714
|
-
return storage.onExternalChange((changedKeys) => store.reloadFromStorage(changedKeys));
|
|
1715
|
-
}, [storage, store]);
|
|
1716
|
-
return /* @__PURE__ */ jsx(MnemonicContext.Provider, { value: store, children: /* @__PURE__ */ jsx(MnemonicOptionalBridgeProvider, { bridge: optionalBridge, children }) });
|
|
1717
|
-
}
|
|
1718
|
-
function throwCoreProviderSchemaImportError(propName) {
|
|
1719
|
-
throw new Error(
|
|
1720
|
-
`[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.`
|
|
1782
|
+
[value, set, reset, remove]
|
|
1721
1783
|
);
|
|
1722
1784
|
}
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
throwCoreProviderSchemaImportError("schemaMode");
|
|
1726
|
-
}
|
|
1727
|
-
if (props.schemaRegistry !== void 0) {
|
|
1728
|
-
throwCoreProviderSchemaImportError("schemaRegistry");
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
function MnemonicProvider2(props) {
|
|
1732
|
-
assertNoSchemaProps(props);
|
|
1733
|
-
return /* @__PURE__ */ jsx(MnemonicProvider, { ...props });
|
|
1734
|
-
}
|
|
1785
|
+
|
|
1786
|
+
// src/Mnemonic/use-core.ts
|
|
1735
1787
|
function throwCoreSchemaImportError(key) {
|
|
1736
1788
|
throw new Error(
|
|
1737
1789
|
`[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.`
|