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