react-mnemonic 1.0.0-beta.0 → 1.2.0-beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1723 @@
1
+ /**
2
+ * @fileoverview Codec implementations for encoding and decoding values to/from storage.
3
+ *
4
+ * This module provides the built-in JSON codec and a factory for creating custom
5
+ * codecs. Codecs handle the bidirectional transformation between typed JavaScript
6
+ * values and their string representations for storage.
7
+ *
8
+ * Codecs are a low-level mechanism for keys that opt out of the JSON Schema
9
+ * validation system. When a schema is registered for a key, the schema's
10
+ * JSON Schema is used for validation and the payload is stored as a JSON value
11
+ * directly (no codec encoding needed).
12
+ */
13
+
14
+ /**
15
+ * Custom error class for codec encoding and decoding failures.
16
+ *
17
+ * Thrown when a codec cannot successfully encode a value to a string or
18
+ * decode a string back to its typed representation. This allows callers
19
+ * to distinguish codec errors from other types of errors.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * try {
24
+ * const value = JSONCodec.decode('not-valid-json');
25
+ * } catch (error) {
26
+ * if (error instanceof CodecError) {
27
+ * console.error('Failed to decode:', error.message);
28
+ * }
29
+ * }
30
+ * ```
31
+ */
32
+ declare class CodecError extends Error {
33
+ /**
34
+ * The underlying error that caused the codec failure, if any.
35
+ *
36
+ * Useful for debugging when wrapping errors from JSON.parse or
37
+ * other parsing operations.
38
+ */
39
+ readonly cause?: unknown;
40
+ /**
41
+ * Creates a new CodecError.
42
+ *
43
+ * @param message - Human-readable error description
44
+ * @param cause - Optional underlying error that caused this failure
45
+ */
46
+ constructor(message: string, cause?: unknown);
47
+ }
48
+ /**
49
+ * JSON codec for encoding and decoding JSON-serializable values.
50
+ *
51
+ * This is the default codec used by `useMnemonicKey` when no codec is specified.
52
+ * It uses `JSON.stringify` for encoding and `JSON.parse` for decoding, making it
53
+ * suitable for objects, arrays, and primitive values.
54
+ *
55
+ * @remarks
56
+ * - Supports any JSON-serializable type: objects, arrays, strings, numbers, booleans, null
57
+ * - Does not preserve JavaScript-specific types like Date, Map, Set, or undefined
58
+ * - Throws standard JSON parsing errors for malformed JSON strings
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * // Used automatically as the default
63
+ * const { value, set } = useMnemonicKey('userProfile', {
64
+ * defaultValue: { name: 'Guest', preferences: { theme: 'dark' } }
65
+ * // codec: JSONCodec is implicit
66
+ * });
67
+ *
68
+ * // Can be specified explicitly
69
+ * const { value, set } = useMnemonicKey('settings', {
70
+ * defaultValue: { notifications: true },
71
+ * codec: JSONCodec
72
+ * });
73
+ * ```
74
+ *
75
+ * @see {@link createCodec} - For custom encoding schemes
76
+ */
77
+ declare const JSONCodec: Codec<any>;
78
+ /**
79
+ * Factory function for creating custom codecs.
80
+ *
81
+ * Creates a `Codec<T>` from separate encode and decode functions. This is
82
+ * useful for implementing custom serialization strategies for types that
83
+ * aren't supported by JSONCodec. Using a custom codec on a key opts out
84
+ * of JSON Schema validation for that key.
85
+ *
86
+ * @template T - The TypeScript type of values to encode/decode
87
+ *
88
+ * @param encode - Function that converts a typed value to a string
89
+ * @param decode - Function that converts a string back to a typed value
90
+ * @returns A `Codec<T>` object compatible with useMnemonicKey
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // Codec for Date objects
95
+ * const DateCodec = createCodec<Date>(
96
+ * (date) => date.toISOString(),
97
+ * (str) => new Date(str)
98
+ * );
99
+ *
100
+ * const { value, set } = useMnemonicKey('lastLogin', {
101
+ * defaultValue: new Date(),
102
+ * codec: DateCodec
103
+ * });
104
+ * ```
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * // Codec for Set<string>
109
+ * const StringSetCodec = createCodec<Set<string>>(
110
+ * (set) => JSON.stringify(Array.from(set)),
111
+ * (str) => new Set(JSON.parse(str))
112
+ * );
113
+ *
114
+ * const { value, set } = useMnemonicKey('tags', {
115
+ * defaultValue: new Set<string>(),
116
+ * codec: StringSetCodec
117
+ * });
118
+ * ```
119
+ *
120
+ * @see {@link Codec} - The codec interface
121
+ * @see {@link CodecError} - Error to throw when encoding/decoding fails
122
+ * @see {@link JSONCodec} - Built-in codec for JSON values
123
+ */
124
+ declare function createCodec<T>(encode: (value: T) => string, decode: (encoded: string) => T): Codec<T>;
125
+
126
+ /**
127
+ * @fileoverview Schema versioning primitives for Mnemonic.
128
+ *
129
+ * This module defines the envelope format used to wrap every persisted value
130
+ * and the error class thrown when schema-related operations fail.
131
+ */
132
+ /**
133
+ * Error thrown for schema registry, versioning, and migration failures.
134
+ *
135
+ * Each instance carries a machine-readable {@link code} that categorises
136
+ * the failure. When a `defaultValue` factory is provided to
137
+ * `useMnemonicKey`, the `SchemaError` is passed as the `error` argument
138
+ * so the factory can inspect the failure reason.
139
+ *
140
+ * Error codes:
141
+ *
142
+ * | Code | Meaning |
143
+ * | ------------------------------- | --------------------------------------------------------------- |
144
+ * | `INVALID_ENVELOPE` | The raw stored value is not a valid `MnemonicEnvelope`. |
145
+ * | `SCHEMA_NOT_FOUND` | No schema registered for the stored key + version. |
146
+ * | `WRITE_SCHEMA_REQUIRED` | Strict mode requires a schema to write, but none was found. |
147
+ * | `MIGRATION_PATH_NOT_FOUND` | No contiguous migration path between the stored and latest version. |
148
+ * | `MIGRATION_FAILED` | A migration step threw during execution. |
149
+ * | `MIGRATION_GRAPH_INVALID` | The schema registry helper received an ambiguous or cyclic migration graph. |
150
+ * | `RECONCILE_FAILED` | A read-time reconciliation hook threw or returned an unpersistable value. |
151
+ * | `SCHEMA_REGISTRATION_CONFLICT` | `registerSchema` was called with a conflicting definition. |
152
+ * | `TYPE_MISMATCH` | The decoded value failed JSON Schema validation. |
153
+ * | `MODE_CONFIGURATION_INVALID` | The schema mode requires a capability the registry doesn't provide. |
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * defaultValue: (error) => {
158
+ * if (error instanceof SchemaError) {
159
+ * console.warn(`Schema issue [${error.code}]:`, error.message);
160
+ * }
161
+ * return { name: "Guest" };
162
+ * }
163
+ * ```
164
+ *
165
+ * @see {@link SchemaMode} - How the provider uses schemas
166
+ * @see {@link SchemaRegistry} - Where schemas and migrations are registered
167
+ */
168
+ declare class SchemaError extends Error {
169
+ /**
170
+ * Machine-readable code identifying the category of schema failure.
171
+ */
172
+ readonly code: "INVALID_ENVELOPE" | "SCHEMA_NOT_FOUND" | "WRITE_SCHEMA_REQUIRED" | "MIGRATION_PATH_NOT_FOUND" | "MIGRATION_FAILED" | "MIGRATION_GRAPH_INVALID" | "RECONCILE_FAILED" | "SCHEMA_REGISTRATION_CONFLICT" | "TYPE_MISMATCH" | "MODE_CONFIGURATION_INVALID";
173
+ /**
174
+ * The underlying error that caused this failure, if any.
175
+ */
176
+ readonly cause?: unknown;
177
+ /**
178
+ * Creates a new SchemaError.
179
+ *
180
+ * @param code - Machine-readable failure category
181
+ * @param message - Human-readable error description
182
+ * @param cause - Optional underlying error
183
+ */
184
+ constructor(code: SchemaError["code"], message: string, cause?: unknown);
185
+ }
186
+
187
+ /**
188
+ * @fileoverview JSON Schema subset validator for Mnemonic.
189
+ *
190
+ * This module implements a minimal JSON Schema validator sufficient for
191
+ * validating localStorage state. Only a subset of JSON Schema keywords
192
+ * are supported; see {@link JsonSchema} for the full list.
193
+ *
194
+ * JSON Schema documents are plain JSON objects (inherently serializable),
195
+ * making them suitable for storage alongside the data they describe.
196
+ */
197
+ /**
198
+ * Supported JSON Schema type keywords.
199
+ *
200
+ * `"integer"` is a JSON Schema keyword meaning "a number that is a whole number."
201
+ */
202
+ type JsonSchemaType = "string" | "number" | "integer" | "boolean" | "null" | "object" | "array";
203
+ /**
204
+ * A subset of JSON Schema sufficient for localStorage state management.
205
+ *
206
+ * Supported keywords:
207
+ * type, enum, const,
208
+ * minimum, maximum, exclusiveMinimum, exclusiveMaximum,
209
+ * minLength, maxLength,
210
+ * properties, required, additionalProperties,
211
+ * items, minItems, maxItems
212
+ *
213
+ * Deliberately omitted: $ref, $id, $schema, $defs, allOf, anyOf,
214
+ * oneOf, not, pattern, format, patternProperties, if/then/else,
215
+ * dependencies, uniqueItems, multipleOf, propertyNames.
216
+ *
217
+ * An empty schema `{}` accepts any value.
218
+ */
219
+ interface JsonSchema {
220
+ /** The expected JSON type(s). An array form like `["string", "null"]` accepts either type. */
221
+ type?: JsonSchemaType | JsonSchemaType[];
222
+ /** The value must be deeply equal to one of these entries. */
223
+ enum?: readonly unknown[];
224
+ /** The value must be deeply equal to this exact value. */
225
+ const?: unknown;
226
+ /** Inclusive lower bound for numbers. */
227
+ minimum?: number;
228
+ /** Inclusive upper bound for numbers. */
229
+ maximum?: number;
230
+ /** Exclusive lower bound for numbers. */
231
+ exclusiveMinimum?: number;
232
+ /** Exclusive upper bound for numbers. */
233
+ exclusiveMaximum?: number;
234
+ /** Minimum string length (inclusive). */
235
+ minLength?: number;
236
+ /** Maximum string length (inclusive). */
237
+ maxLength?: number;
238
+ /** Property name to sub-schema mapping for objects. */
239
+ properties?: Record<string, JsonSchema>;
240
+ /** Properties that must be present on the object. */
241
+ required?: readonly string[];
242
+ /**
243
+ * Controls extra properties not listed in `properties`.
244
+ * `false` disallows them. A schema validates their values.
245
+ * `true` (or omitted) allows anything.
246
+ */
247
+ additionalProperties?: boolean | JsonSchema;
248
+ /** Schema applied to every element of an array. */
249
+ items?: JsonSchema;
250
+ /** Minimum array length (inclusive). */
251
+ minItems?: number;
252
+ /** Maximum array length (inclusive). */
253
+ maxItems?: number;
254
+ }
255
+ /**
256
+ * A single validation error produced by {@link validateJsonSchema}.
257
+ */
258
+ type JsonSchemaValidationError = {
259
+ /** JSON Pointer path to the failing value (e.g., "/foo/bar/0"). Empty string for root. */
260
+ path: string;
261
+ /** Human-readable error description. */
262
+ message: string;
263
+ /** The JSON Schema keyword that failed. */
264
+ keyword: string;
265
+ };
266
+ /**
267
+ * A pre-compiled validation function generated by {@link compileSchema}.
268
+ *
269
+ * Accepts a value and an optional JSON Pointer path for error reporting.
270
+ * Returns an array of validation errors (empty = valid).
271
+ */
272
+ type CompiledValidator = (value: unknown, path?: string) => JsonSchemaValidationError[];
273
+ /**
274
+ * Pre-compiles a {@link JsonSchema} into a reusable validation function.
275
+ *
276
+ * Inspects the schema once and builds a specialized closure that
277
+ * eliminates runtime branching for unused keywords, pre-converts
278
+ * `required` arrays to `Set`s, recursively pre-compiles nested property
279
+ * and item schemas, and pre-builds primitive `Set`s for O(1) enum
280
+ * lookups when possible.
281
+ *
282
+ * Results are cached by schema object identity in a `WeakMap`, so
283
+ * calling `compileSchema` with the same schema reference is free
284
+ * after the first call.
285
+ *
286
+ * @param schema - The JSON Schema to compile
287
+ * @returns A compiled validation function
288
+ */
289
+ declare function compileSchema(schema: JsonSchema): CompiledValidator;
290
+ /**
291
+ * Validates a value against a {@link JsonSchema}.
292
+ *
293
+ * Returns an empty array when the value is valid.
294
+ * Returns one or more {@link JsonSchemaValidationError} entries on failure.
295
+ * Short-circuits on type mismatch (does not report downstream keyword errors).
296
+ *
297
+ * @param value - The value to validate
298
+ * @param schema - The JSON Schema to validate against
299
+ * @param path - Internal: JSON Pointer path for error reporting (default: `""`)
300
+ * @returns Array of validation errors (empty = valid)
301
+ */
302
+ declare function validateJsonSchema(value: unknown, schema: JsonSchema, path?: string): JsonSchemaValidationError[];
303
+
304
+ declare const typedSchemaBrand: unique symbol;
305
+ declare const optionalSchemaBrand: unique symbol;
306
+ type JsonPrimitive = string | number | boolean | null;
307
+ type JsonConstValue = JsonPrimitive | readonly JsonConstValue[] | {
308
+ readonly [key: string]: JsonConstValue;
309
+ };
310
+ type TypedJsonSchema<T> = JsonSchema & {
311
+ readonly [typedSchemaBrand]?: T;
312
+ };
313
+ type OptionalTypedJsonSchema<T> = TypedJsonSchema<T> & {
314
+ readonly [optionalSchemaBrand]: true;
315
+ };
316
+ type InferJsonSchemaValue<TSchema> = TSchema extends TypedJsonSchema<infer TValue> ? TValue : unknown;
317
+ type ObjectValueFromSchemas<TShape extends Record<string, TypedJsonSchema<unknown> | OptionalTypedJsonSchema<unknown>>> = {
318
+ [K in keyof TShape as TShape[K] extends OptionalTypedJsonSchema<unknown> ? never : K]: InferJsonSchemaValue<TShape[K]>;
319
+ } & {
320
+ [K in keyof TShape as TShape[K] extends OptionalTypedJsonSchema<unknown> ? K : never]?: InferJsonSchemaValue<TShape[K]>;
321
+ };
322
+ type StringSchemaOptions = Pick<JsonSchema, "minLength" | "maxLength">;
323
+ type NumberSchemaOptions = Pick<JsonSchema, "minimum" | "maximum" | "exclusiveMinimum" | "exclusiveMaximum">;
324
+ type ArraySchemaOptions = Pick<JsonSchema, "minItems" | "maxItems">;
325
+ type ObjectSchemaOptions = Pick<JsonSchema, "additionalProperties">;
326
+ /**
327
+ * Builder helpers for strongly typed schemas backed by Mnemonic's built-in
328
+ * JSON Schema subset.
329
+ *
330
+ * The returned schemas are plain `JsonSchema` objects at runtime, so they can
331
+ * be registered directly in `createSchemaRegistry(...)` while also carrying a
332
+ * phantom TypeScript type for inference.
333
+ */
334
+ declare const mnemonicSchema: {
335
+ string(options?: StringSchemaOptions): TypedJsonSchema<string>;
336
+ number(options?: NumberSchemaOptions): TypedJsonSchema<number>;
337
+ integer(options?: NumberSchemaOptions): TypedJsonSchema<number>;
338
+ boolean(): TypedJsonSchema<boolean>;
339
+ nullValue(): TypedJsonSchema<null>;
340
+ literal<const TValue extends JsonConstValue>(value: TValue): TypedJsonSchema<TValue>;
341
+ enum<const TValues extends readonly [JsonPrimitive, ...JsonPrimitive[]]>(values: TValues): TypedJsonSchema<TValues[number]>;
342
+ optional<T>(schema: TypedJsonSchema<T>): OptionalTypedJsonSchema<T>;
343
+ nullable<T>(schema: TypedJsonSchema<T>): TypedJsonSchema<T | null>;
344
+ array<TItemSchema extends TypedJsonSchema<unknown>>(itemSchema: TItemSchema, options?: ArraySchemaOptions): TypedJsonSchema<InferJsonSchemaValue<TItemSchema>[]>;
345
+ object<TShape extends Record<string, TypedJsonSchema<unknown> | OptionalTypedJsonSchema<unknown>>>(shape: TShape, options?: ObjectSchemaOptions): TypedJsonSchema<ObjectValueFromSchemas<TShape>>;
346
+ record<TValueSchema extends TypedJsonSchema<unknown>>(valueSchema: TValueSchema): TypedJsonSchema<Record<string, InferJsonSchemaValue<TValueSchema>>>;
347
+ };
348
+
349
+ /**
350
+ * @fileoverview Type definitions for the Mnemonic library.
351
+ *
352
+ * This module defines the core types and interfaces used throughout the Mnemonic
353
+ * library for type-safe, persistent state management in React applications.
354
+ */
355
+
356
+ declare const keySchemaValueBrand: unique symbol;
357
+ /**
358
+ * Codec for encoding and decoding values to and from storage.
359
+ *
360
+ * Codecs provide bidirectional transformations between typed values and their
361
+ * string representations suitable for storage in localStorage or similar backends.
362
+ *
363
+ * Using a codec on a key opts out of JSON Schema validation. Schema-managed
364
+ * keys store JSON values directly and are validated against their JSON Schema.
365
+ *
366
+ * @template T - The TypeScript type of the value to encode/decode
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * const DateCodec: Codec<Date> = {
371
+ * encode: (date) => date.toISOString(),
372
+ * decode: (str) => new Date(str)
373
+ * };
374
+ * ```
375
+ *
376
+ * @see {@link JSONCodec} - Default codec for JSON-serializable values
377
+ * @see {@link createCodec} - Helper function to create custom codecs
378
+ */
379
+ interface Codec<T> {
380
+ /**
381
+ * Transforms a typed value into a string suitable for storage.
382
+ *
383
+ * @param value - The typed value to encode
384
+ * @returns A string representation of the value
385
+ * @throws {CodecError} If the value cannot be encoded
386
+ */
387
+ encode: (value: T) => string;
388
+ /**
389
+ * Transforms a stored string back into a typed value.
390
+ *
391
+ * @param encoded - The string representation from storage
392
+ * @returns The decoded typed value
393
+ * @throws {CodecError} If the string cannot be decoded
394
+ */
395
+ decode: (encoded: string) => T;
396
+ }
397
+ /**
398
+ * Configuration options for MnemonicProvider.
399
+ *
400
+ * These options configure the behavior of the storage provider, including
401
+ * namespace isolation, storage backend selection, cross-tab synchronization,
402
+ * and developer tools integration.
403
+ *
404
+ * @example
405
+ * ```tsx
406
+ * <MnemonicProvider
407
+ * namespace="myApp"
408
+ * storage={localStorage}
409
+ * enableDevTools={process.env.NODE_ENV === 'development'}
410
+ * >
411
+ * <App />
412
+ * </MnemonicProvider>
413
+ * ```
414
+ */
415
+ interface MnemonicProviderOptions {
416
+ /**
417
+ * Namespace prefix for all storage keys.
418
+ *
419
+ * All keys stored by this provider will be prefixed with `${namespace}.`
420
+ * to avoid collisions between different parts of your application or
421
+ * different applications sharing the same storage backend.
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * // With namespace="myApp", a key "user" becomes "myApp.user" in storage
426
+ * namespace: "myApp"
427
+ * ```
428
+ */
429
+ namespace: string;
430
+ /**
431
+ * Storage backend to use for persistence.
432
+ *
433
+ * Defaults to `window.localStorage` in browser environments. You can provide
434
+ * a synchronous custom implementation (e.g., sessionStorage, an in-memory
435
+ * cache facade over IndexedDB, or a mock for testing).
436
+ *
437
+ * @default window.localStorage
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * // Use sessionStorage instead of localStorage
442
+ * storage: window.sessionStorage
443
+ *
444
+ * // Use a custom storage implementation
445
+ * storage: {
446
+ * getItem: (key) => myCustomStore.get(key),
447
+ * setItem: (key, value) => myCustomStore.set(key, value),
448
+ * removeItem: (key) => myCustomStore.delete(key)
449
+ * }
450
+ * ```
451
+ */
452
+ storage?: StorageLike;
453
+ /**
454
+ * Enable DevTools debugging interface.
455
+ *
456
+ * When enabled, registers this provider in the global
457
+ * `window.__REACT_MNEMONIC_DEVTOOLS__` registry.
458
+ *
459
+ * The registry stores providers as weak references and exposes:
460
+ * - `resolve(namespace)` to strengthen a provider reference and access
461
+ * inspection methods.
462
+ * - `list()` to enumerate provider availability.
463
+ *
464
+ * @default false
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * // Enable in development only
469
+ * enableDevTools: process.env.NODE_ENV === 'development'
470
+ *
471
+ * // Then in browser console:
472
+ * const provider = window.__REACT_MNEMONIC_DEVTOOLS__?.resolve('myApp')
473
+ * provider?.dump()
474
+ * provider?.get('user')
475
+ * provider?.set('user', { name: 'Test' })
476
+ * ```
477
+ */
478
+ enableDevTools?: boolean;
479
+ /**
480
+ * Versioning and schema enforcement mode.
481
+ *
482
+ * Controls whether stored values require a registered schema, and how
483
+ * missing schemas are handled. See {@link SchemaMode} for the behaviour
484
+ * of each mode.
485
+ *
486
+ * @default "default"
487
+ *
488
+ * @see {@link SchemaMode} - Detailed description of each mode
489
+ * @see {@link SchemaRegistry} - Registry supplied via `schemaRegistry`
490
+ */
491
+ schemaMode?: SchemaMode;
492
+ /**
493
+ * Schema registry used for version lookup and migration resolution.
494
+ *
495
+ * When provided, the library uses the registry to find the correct
496
+ * JSON Schema for each stored version, and to resolve migration paths
497
+ * when upgrading old data to the latest schema.
498
+ *
499
+ * Required when `schemaMode` is `"strict"` or `"autoschema"`.
500
+ * Optional (but recommended) in `"default"` mode.
501
+ *
502
+ * @remarks
503
+ * In `"default"` and `"strict"` modes, the registry is treated as
504
+ * immutable after the provider initializes. Updates should be shipped
505
+ * as part of a new app version and applied by remounting the provider.
506
+ * `"autoschema"` remains mutable so inferred schemas can be registered
507
+ * at runtime.
508
+ *
509
+ * @see {@link SchemaRegistry} - Interface the registry must implement
510
+ * @see {@link KeySchema} - Schema definition stored in the registry
511
+ */
512
+ schemaRegistry?: SchemaRegistry;
513
+ /**
514
+ * Server-rendering and hydration defaults for descendant hooks.
515
+ *
516
+ * Provider-level SSR settings establish the default hydration strategy for
517
+ * all `useMnemonicKey(...)` calls in this namespace. Individual hooks may
518
+ * still override the strategy when a specific key needs different behavior.
519
+ *
520
+ * @example
521
+ * ```tsx
522
+ * <MnemonicProvider
523
+ * namespace="app"
524
+ * ssr={{ hydration: "client-only" }}
525
+ * >
526
+ * <App />
527
+ * </MnemonicProvider>
528
+ * ```
529
+ */
530
+ ssr?: MnemonicProviderSSRConfig;
531
+ }
532
+ /**
533
+ * Controls how the provider enforces versioned schemas on stored values.
534
+ *
535
+ * - `"default"` — Schemas are optional. When a schema exists for the stored
536
+ * version it is used for validation; otherwise the hook's `codec` option is
537
+ * used directly with no validation. This is the recommended starting mode.
538
+ *
539
+ * - `"strict"` — Every read and write **must** have a registered schema for
540
+ * the stored version. If no matching schema is found the value falls back
541
+ * to `defaultValue` with a `SchemaError` (`SCHEMA_NOT_FOUND` on reads,
542
+ * `WRITE_SCHEMA_REQUIRED` on writes).
543
+ * When no schemas are registered and no explicit schema is provided, writes
544
+ * fall back to a codec-encoded (v0) envelope.
545
+ *
546
+ * - `"autoschema"` — Like `"default"`, but when a key has **no** schema
547
+ * registered at all, the library infers a JSON Schema at version 1 from the
548
+ * first successfully decoded value and registers it via
549
+ * `SchemaRegistry.registerSchema`. Subsequent reads/writes for that key
550
+ * then behave as if the schema had been registered manually.
551
+ *
552
+ * @remarks
553
+ * In `"default"` and `"strict"` modes, registry lookups are cached under the
554
+ * assumption that the schema registry is immutable for the lifetime of the
555
+ * provider. If you need to update schemas, publish a new app version and
556
+ * remount the provider. `"autoschema"` does not assume immutability.
557
+ *
558
+ * @default "default"
559
+ *
560
+ * @see {@link SchemaRegistry} - Registry that stores schemas and migrations
561
+ * @see {@link KeySchema} - Individual schema definition
562
+ */
563
+ type SchemaMode = "strict" | "default" | "autoschema";
564
+ /**
565
+ * Controls when a hook should read persisted storage during client rendering.
566
+ *
567
+ * - `"immediate"` — Default. The server snapshot is used during SSR/hydration,
568
+ * and the hook reads persisted storage as soon as React switches to the
569
+ * client snapshot.
570
+ *
571
+ * - `"client-only"` — Defers all storage reads until after the component has
572
+ * mounted on the client. This is useful when you want a deterministic server
573
+ * placeholder and prefer the persisted value to appear only after hydration
574
+ * completes.
575
+ */
576
+ type MnemonicHydrationMode = "immediate" | "client-only";
577
+ /**
578
+ * Provider-level SSR defaults shared by descendant hooks.
579
+ */
580
+ interface MnemonicProviderSSRConfig {
581
+ /**
582
+ * Default hydration strategy for descendant `useMnemonicKey(...)` hooks.
583
+ *
584
+ * @default "immediate"
585
+ */
586
+ hydration?: MnemonicHydrationMode;
587
+ }
588
+ /**
589
+ * Hook-level SSR controls for `useMnemonicKey(...)`.
590
+ *
591
+ * Lets a key render a deterministic server snapshot and optionally delay
592
+ * reading persisted storage until after client mount.
593
+ *
594
+ * @template T - The decoded value type for the key
595
+ */
596
+ interface MnemonicKeySSRConfig<T> {
597
+ /**
598
+ * Value to expose during SSR and hydration instead of `defaultValue`.
599
+ *
600
+ * This value is not persisted automatically. Once hydration completes,
601
+ * the hook transitions to the stored value (if any) or back to
602
+ * `defaultValue`.
603
+ *
604
+ * Factory functions should be deterministic across server render and
605
+ * client hydration to avoid markup mismatches.
606
+ */
607
+ serverValue?: T | (() => T);
608
+ /**
609
+ * Hydration strategy for this key.
610
+ *
611
+ * When omitted, inherits the provider default.
612
+ */
613
+ hydration?: MnemonicHydrationMode;
614
+ }
615
+ /**
616
+ * Weak-reference shape used by the devtools registry.
617
+ *
618
+ * Matches the standard `WeakRef` API while keeping the public type surface
619
+ * compatible with ES2020 TypeScript lib targets.
620
+ */
621
+ interface MnemonicDevToolsWeakRef<T extends object> {
622
+ /**
623
+ * Attempts to strengthen the weak reference.
624
+ *
625
+ * @returns The live object, or undefined if it was garbage-collected.
626
+ */
627
+ deref: () => T | undefined;
628
+ }
629
+ /**
630
+ * Provider inspection API exposed through devtools registry resolution.
631
+ *
632
+ * Resolve a provider from the registry, then invoke these methods for manual
633
+ * inspection/mutation from the browser console.
634
+ */
635
+ interface MnemonicDevToolsProviderApi {
636
+ /** Access the underlying store instance. */
637
+ getStore: () => Mnemonic;
638
+ /** Dump all raw key-value pairs for the provider namespace. */
639
+ dump: () => Record<string, string>;
640
+ /** Read decoded value for an unprefixed key. */
641
+ get: (key: string) => unknown;
642
+ /** Write value for an unprefixed key (JSON-encoded). */
643
+ set: (key: string, value: unknown) => void;
644
+ /** Remove a single unprefixed key. */
645
+ remove: (key: string) => void;
646
+ /** Remove all keys in this provider namespace. */
647
+ clear: () => void;
648
+ /** List all unprefixed keys in this provider namespace. */
649
+ keys: () => string[];
650
+ }
651
+ /**
652
+ * Registry entry for a single provider namespace.
653
+ */
654
+ interface MnemonicDevToolsProviderEntry {
655
+ /** Namespace key for this provider entry. */
656
+ namespace: string;
657
+ /** Weak reference to the provider inspection API. */
658
+ weakRef: MnemonicDevToolsWeakRef<MnemonicDevToolsProviderApi>;
659
+ /** Timestamp when this namespace was registered. */
660
+ registeredAt: number;
661
+ /** Timestamp when provider was last confirmed live. */
662
+ lastSeenAt: number;
663
+ /** Timestamp when provider was first observed unavailable, or null when live. */
664
+ staleSince: number | null;
665
+ }
666
+ /**
667
+ * Lightweight provider status returned by `list()`.
668
+ */
669
+ interface MnemonicDevToolsProviderDescriptor {
670
+ /** Namespace registered by the provider. */
671
+ namespace: string;
672
+ /** Whether the provider can currently be resolved to a live API instance. */
673
+ available: boolean;
674
+ /** Timestamp when the provider namespace was first registered. */
675
+ registeredAt: number;
676
+ /** Timestamp when the provider was last observed as live. */
677
+ lastSeenAt: number;
678
+ /** Timestamp when the provider first became unavailable, or `null` when live. */
679
+ staleSince: number | null;
680
+ }
681
+ /**
682
+ * Environment capabilities reported by devtools registry.
683
+ */
684
+ interface MnemonicDevToolsCapabilities {
685
+ /** Whether the runtime supports `WeakRef`. */
686
+ weakRef: boolean;
687
+ /** Whether the runtime supports `FinalizationRegistry`. */
688
+ finalizationRegistry: boolean;
689
+ }
690
+ /**
691
+ * Polling metadata for extension synchronization.
692
+ */
693
+ interface MnemonicDevToolsMeta {
694
+ /** Monotonic registry version incremented on register and mutation events. */
695
+ version: number;
696
+ /** Timestamp of the most recent registry update. */
697
+ lastUpdated: number;
698
+ /** Short label describing the most recent registry change. */
699
+ lastChange: string;
700
+ }
701
+ /**
702
+ * Global devtools registry contract available on window.
703
+ *
704
+ * This is an advanced public API used by the browser console integration and
705
+ * extension tooling. Direct namespace access
706
+ * (`window.__REACT_MNEMONIC_DEVTOOLS__.myNamespace`) is not part of the
707
+ * public API.
708
+ */
709
+ interface MnemonicDevToolsRegistry {
710
+ /** Provider entries keyed by namespace. */
711
+ providers: Record<string, MnemonicDevToolsProviderEntry>;
712
+ /** Resolve a namespace to a live provider API when one is available. */
713
+ resolve: (namespace: string) => MnemonicDevToolsProviderApi | null;
714
+ /** List provider availability without strengthening weak references manually. */
715
+ list: () => MnemonicDevToolsProviderDescriptor[];
716
+ /** Runtime capabilities relevant to the registry implementation. */
717
+ capabilities: MnemonicDevToolsCapabilities;
718
+ /** Versioning metadata used by polling devtools integrations. */
719
+ __meta: MnemonicDevToolsMeta;
720
+ }
721
+ /**
722
+ * Schema definition for a single key at a specific version.
723
+ *
724
+ * Each registered schema binds a storage key + version number to a
725
+ * JSON Schema that validates the payload. Schemas are fully serializable
726
+ * (no functions).
727
+ *
728
+ * When the provider reads a value whose envelope version matches a
729
+ * registered schema, the payload is validated against the schema's
730
+ * JSON Schema definition.
731
+ *
732
+ * @example
733
+ * ```typescript
734
+ * const userSchemaV1: KeySchema = {
735
+ * key: "user",
736
+ * version: 1,
737
+ * schema: {
738
+ * type: "object",
739
+ * properties: {
740
+ * name: { type: "string" },
741
+ * },
742
+ * required: ["name"],
743
+ * },
744
+ * };
745
+ * ```
746
+ *
747
+ * @see {@link SchemaRegistry} - Where schemas are registered and looked up
748
+ * @see {@link MigrationRule} - How values migrate between schema versions
749
+ * @see {@link JsonSchema} - The JSON Schema subset used for validation
750
+ */
751
+ type KeySchema<TValue = unknown, K extends string = string, TSchema extends JsonSchema = JsonSchema> = {
752
+ /**
753
+ * The unprefixed storage key this schema applies to.
754
+ */
755
+ key: K;
756
+ /**
757
+ * The version number for this schema.
758
+ *
759
+ * Must be a non-negative integer. Any version (including `0`) is valid.
760
+ */
761
+ version: number;
762
+ /**
763
+ * JSON Schema that validates the payload at this version.
764
+ *
765
+ * Only the subset of JSON Schema keywords defined in {@link JsonSchema}
766
+ * are supported. An empty schema `{}` accepts any value.
767
+ */
768
+ schema: TSchema;
769
+ /**
770
+ * Phantom type linking this runtime schema to its decoded TypeScript value.
771
+ *
772
+ * This field is never set at runtime. It exists only so helpers such as
773
+ * `defineKeySchema(...)`, `defineMnemonicKey(...)`, and `defineMigration(...)`
774
+ * can preserve a single source of truth between schema shape and value type.
775
+ */
776
+ readonly [keySchemaValueBrand]?: TValue;
777
+ };
778
+ /**
779
+ * A single migration step that transforms data from one schema version to
780
+ * another, or normalizes data at the same version.
781
+ *
782
+ * Migration rules are composed into a {@link MigrationPath} by the
783
+ * {@link SchemaRegistry} to upgrade stored data across multiple versions in
784
+ * sequence (e.g. v1 -> v2 -> v3).
785
+ *
786
+ * When `fromVersion === toVersion`, the rule is a **write-time normalizer**
787
+ * that runs on every write to that version. This is useful for data
788
+ * normalization (trimming strings, clamping values, injecting defaults).
789
+ *
790
+ * @example
791
+ * ```typescript
792
+ * // Version upgrade migration
793
+ * const userV1ToV2: MigrationRule = {
794
+ * key: "user",
795
+ * fromVersion: 1,
796
+ * toVersion: 2,
797
+ * migrate: (v1) => {
798
+ * const old = v1 as { name: string };
799
+ * return { firstName: old.name, lastName: "" };
800
+ * },
801
+ * };
802
+ *
803
+ * // Write-time normalizer (same version)
804
+ * const trimUserV2: MigrationRule = {
805
+ * key: "user",
806
+ * fromVersion: 2,
807
+ * toVersion: 2,
808
+ * migrate: (v) => {
809
+ * const user = v as { firstName: string; lastName: string };
810
+ * return { firstName: user.firstName.trim(), lastName: user.lastName.trim() };
811
+ * },
812
+ * };
813
+ * ```
814
+ *
815
+ * @see {@link MigrationPath} - Ordered list of rules applied in sequence
816
+ * @see {@link SchemaRegistry.getMigrationPath} - How the path is resolved
817
+ * @see {@link SchemaRegistry.getWriteMigration} - How write-time normalizers are resolved
818
+ */
819
+ type MigrationRule<TFrom = unknown, TTo = unknown, K extends string = string> = {
820
+ /**
821
+ * The unprefixed storage key this rule applies to.
822
+ */
823
+ key: K;
824
+ /**
825
+ * The version the stored data is migrating **from**.
826
+ *
827
+ * Version `0` is allowed, enabling migrations from unversioned data.
828
+ */
829
+ fromVersion: number;
830
+ /**
831
+ * The version the stored data is migrating **to**.
832
+ *
833
+ * When equal to `fromVersion`, this rule is a write-time normalizer
834
+ * that runs on every write to that version.
835
+ */
836
+ toVersion: number;
837
+ /**
838
+ * Transformation function that converts data from `fromVersion`
839
+ * to `toVersion`.
840
+ *
841
+ * Receives the decoded value at `fromVersion` and must return
842
+ * the value in the shape expected by `toVersion`.
843
+ *
844
+ * @param value - The decoded value at `fromVersion`
845
+ * @returns The transformed value for `toVersion`
846
+ */
847
+ migrate(value: TFrom): TTo;
848
+ };
849
+ /**
850
+ * An ordered sequence of {@link MigrationRule} steps that upgrades stored
851
+ * data from an older schema version to a newer one.
852
+ *
853
+ * The rules are applied in array order. Each step's output becomes the
854
+ * next step's input. After the final step the result is validated against
855
+ * the target schema and persisted back to storage so the migration only
856
+ * runs once per key.
857
+ *
858
+ * @see {@link MigrationRule} - Individual migration step
859
+ * @see {@link SchemaRegistry.getMigrationPath} - Resolves a path between versions
860
+ */
861
+ type MigrationPath<K extends string = string> = MigrationRule<unknown, unknown, K>[];
862
+ /**
863
+ * Input options for {@link createSchemaRegistry}.
864
+ *
865
+ * Use this helper when your registry contents are known up front and do not
866
+ * need runtime mutation. The returned registry is immutable and optimized for
867
+ * the common `"default"` / `"strict"` setup.
868
+ *
869
+ * For most apps, this should be your default entry point for schema-managed
870
+ * persistence. Implement {@link SchemaRegistry} manually only when you need
871
+ * custom lookup behavior or runtime schema registration beyond autoschema mode.
872
+ */
873
+ interface CreateSchemaRegistryOptions {
874
+ /**
875
+ * Versioned schemas to index by key and version.
876
+ *
877
+ * Duplicate `key + version` pairs are rejected up front with
878
+ * `SchemaError("SCHEMA_REGISTRATION_CONFLICT")`.
879
+ */
880
+ schemas?: readonly KeySchema[];
881
+ /**
882
+ * Migration rules to index by key and version edge.
883
+ *
884
+ * Write-time normalizers (`fromVersion === toVersion`) are indexed
885
+ * separately from read-time migration edges. Ambiguous outgoing edges,
886
+ * backward migrations, and duplicate write normalizers are rejected up
887
+ * front with `SchemaError("MIGRATION_GRAPH_INVALID")`.
888
+ */
889
+ migrations?: readonly MigrationRule[];
890
+ }
891
+ /**
892
+ * Lookup and registration API for key schemas and migration paths.
893
+ *
894
+ * Implementations of this interface are passed to `MnemonicProvider` via the
895
+ * `schemaRegistry` option. The provider calls these methods at read and write
896
+ * time to resolve the correct JSON Schema and migration chain for each
897
+ * stored value.
898
+ *
899
+ * In `"default"` and `"strict"` modes, callers should treat registry contents
900
+ * as immutable after provider initialization. The hook caches lookups to keep
901
+ * read/write hot paths fast. `"autoschema"` remains mutable to support
902
+ * inferred schema registration.
903
+ *
904
+ * Most applications should prefer {@link createSchemaRegistry} instead of
905
+ * implementing this interface manually. Manual implementations are mainly for
906
+ * advanced cases such as custom backing stores, dynamic schema discovery, or
907
+ * adapter layers around an existing registry system.
908
+ *
909
+ * @example
910
+ * ```typescript
911
+ * const registry = createSchemaRegistry({
912
+ * schemas: [
913
+ * { key: "settings", version: 1, schema: { type: "object", required: ["theme"] } },
914
+ * ],
915
+ * migrations: [],
916
+ * });
917
+ *
918
+ * <MnemonicProvider namespace="app" schemaRegistry={registry} schemaMode="strict">
919
+ * <App />
920
+ * </MnemonicProvider>
921
+ * ```
922
+ *
923
+ * @see {@link KeySchema} - Schema definition
924
+ * @see {@link MigrationPath} - Migration chain returned by `getMigrationPath`
925
+ * @see {@link SchemaMode} - How the provider uses the registry
926
+ */
927
+ interface SchemaRegistry {
928
+ /**
929
+ * Look up the schema registered for a specific key and version.
930
+ *
931
+ * @param key - The unprefixed storage key
932
+ * @param version - The version number to look up
933
+ * @returns The matching schema, or `undefined` if none is registered
934
+ */
935
+ getSchema(key: string, version: number): KeySchema | undefined;
936
+ /**
937
+ * Look up the highest-version schema registered for a key.
938
+ *
939
+ * Used by the write path to determine which version to stamp on new
940
+ * values, and by the read path to detect when a migration is needed.
941
+ *
942
+ * @param key - The unprefixed storage key
943
+ * @returns The latest schema, or `undefined` if none is registered
944
+ */
945
+ getLatestSchema(key: string): KeySchema | undefined;
946
+ /**
947
+ * Resolve an ordered migration path between two versions of a key.
948
+ *
949
+ * Returns `null` when no contiguous path exists. The returned rules
950
+ * are applied in order to transform data from `fromVersion` to
951
+ * `toVersion`.
952
+ *
953
+ * @param key - The unprefixed storage key
954
+ * @param fromVersion - The stored data's current version
955
+ * @param toVersion - The target version to migrate to
956
+ * @returns An ordered array of migration rules, or `null`
957
+ */
958
+ getMigrationPath(key: string, fromVersion: number, toVersion: number): MigrationPath | null;
959
+ /**
960
+ * Look up a write-time normalizer for a specific key and version.
961
+ *
962
+ * A write-time normalizer is a {@link MigrationRule} where
963
+ * `fromVersion === toVersion`. It runs on every write to that version,
964
+ * transforming the value before storage. The normalized value is
965
+ * re-validated against the schema after transformation.
966
+ *
967
+ * Optional. When not implemented or returns `undefined`, no write-time
968
+ * normalization is applied.
969
+ *
970
+ * @param key - The unprefixed storage key
971
+ * @param version - The target schema version
972
+ * @returns The normalizer rule, or `undefined` if none is registered
973
+ */
974
+ getWriteMigration?(key: string, version: number): MigrationRule | undefined;
975
+ /**
976
+ * Register a new schema.
977
+ *
978
+ * Optional. Required when `schemaMode` is `"autoschema"` so the
979
+ * library can persist inferred schemas. Implementations should throw
980
+ * if a schema already exists for the same key + version with a
981
+ * conflicting definition.
982
+ *
983
+ * @param schema - The schema to register
984
+ */
985
+ registerSchema?(schema: KeySchema): void;
986
+ }
987
+ /**
988
+ * Storage interface compatible with localStorage and synchronous custom storage implementations.
989
+ *
990
+ * Defines the minimum contract required for a storage backend. Compatible with
991
+ * browser Storage API (localStorage, sessionStorage) and custom implementations
992
+ * for testing or alternative storage solutions.
993
+ *
994
+ * All methods in this contract are intentionally synchronous. Promise-returning
995
+ * adapters such as React Native `AsyncStorage` are not directly supported by
996
+ * `StorageLike`; instead, keep a synchronous in-memory cache and flush to async
997
+ * persistence outside the hook contract.
998
+ *
999
+ * @remarks
1000
+ * **Error handling contract**
1001
+ *
1002
+ * The library wraps every storage call in a try/catch. Errors are handled as
1003
+ * follows:
1004
+ *
1005
+ * - **`DOMException` with `name === "QuotaExceededError"`** — Logged once via
1006
+ * `console.error` with the prefix `[Mnemonic] Storage quota exceeded`.
1007
+ * Squelched until a write succeeds, then the flag resets.
1008
+ *
1009
+ * - **Other `DOMException` errors (including `SecurityError`)** — Logged once
1010
+ * via `console.error` with the prefix `[Mnemonic] Storage access error`.
1011
+ * Squelched until any storage operation succeeds, then the flag resets.
1012
+ *
1013
+ * - **All other error types** — Silently suppressed.
1014
+ *
1015
+ * Custom `StorageLike` implementations are encouraged to throw `DOMException`
1016
+ * for storage access failures so the library can surface diagnostics. Throwing
1017
+ * non-`DOMException` errors is safe but results in silent suppression.
1018
+ *
1019
+ * In all error cases the library falls back to its in-memory cache, so
1020
+ * components continue to function when the storage backend is unavailable.
1021
+ *
1022
+ * Promise-returning `getItem`, `setItem`, or `removeItem` implementations are
1023
+ * treated as an invalid contract at runtime. Mnemonic logs the misuse once and
1024
+ * falls back to its in-memory cache for safety.
1025
+ *
1026
+ * @example
1027
+ * ```typescript
1028
+ * // In-memory storage for testing
1029
+ * const mockStorage: StorageLike = {
1030
+ * items: new Map<string, string>(),
1031
+ * getItem(key) { return this.items.get(key) ?? null; },
1032
+ * setItem(key, value) { this.items.set(key, value); },
1033
+ * removeItem(key) { this.items.delete(key); },
1034
+ * get length() { return this.items.size; },
1035
+ * key(index) {
1036
+ * return Array.from(this.items.keys())[index] ?? null;
1037
+ * }
1038
+ * };
1039
+ * ```
1040
+ */
1041
+ type StorageLike = {
1042
+ /**
1043
+ * Retrieves the value associated with a key.
1044
+ *
1045
+ * @param key - The storage key to retrieve
1046
+ * @returns The stored value as a string, or null if not found
1047
+ *
1048
+ * @remarks Must return synchronously. Returning a Promise is unsupported.
1049
+ */
1050
+ getItem(key: string): string | null;
1051
+ /**
1052
+ * Stores a key-value pair.
1053
+ *
1054
+ * @param key - The storage key
1055
+ * @param value - The string value to store
1056
+ *
1057
+ * @remarks Must complete synchronously. Returning a Promise is unsupported.
1058
+ */
1059
+ setItem(key: string, value: string): void;
1060
+ /**
1061
+ * Removes a key-value pair from storage.
1062
+ *
1063
+ * @param key - The storage key to remove
1064
+ *
1065
+ * @remarks Must complete synchronously. Returning a Promise is unsupported.
1066
+ */
1067
+ removeItem(key: string): void;
1068
+ /**
1069
+ * Returns the key at the specified index in storage.
1070
+ *
1071
+ * Optional method for enumeration support.
1072
+ *
1073
+ * @param index - The numeric index
1074
+ * @returns The key at the given index, or null if out of bounds
1075
+ */
1076
+ key?(index: number): string | null;
1077
+ /**
1078
+ * The number of items currently stored.
1079
+ *
1080
+ * Optional property for enumeration support.
1081
+ */
1082
+ readonly length?: number;
1083
+ /**
1084
+ * Subscribe to notifications when data changes externally.
1085
+ *
1086
+ * localStorage has built-in cross-tab notification via the browser's
1087
+ * native `storage` event (used by the `listenCrossTab` hook option).
1088
+ * Non-localStorage backends (IndexedDB, custom stores, etc.) lack this
1089
+ * built-in mechanism. Implementing `onExternalChange` allows those
1090
+ * adapters to provide equivalent cross-tab synchronization through
1091
+ * their own transport (e.g., BroadcastChannel).
1092
+ *
1093
+ * The callback accepts an optional `changedKeys` parameter:
1094
+ * - `callback()` or `callback(undefined)` triggers a blanket reload
1095
+ * of all actively subscribed keys.
1096
+ * - `callback(["ns.key1", "ns.key2"])` reloads only the specified
1097
+ * fully-qualified keys, which is more efficient when the adapter
1098
+ * knows exactly which keys changed.
1099
+ * - `callback([])` is a no-op.
1100
+ *
1101
+ * On a blanket reload the provider re-reads all actively subscribed
1102
+ * keys from the storage backend and emits change notifications for
1103
+ * any whose values differ from the cache.
1104
+ *
1105
+ * @param callback - Invoked when external data changes
1106
+ * @returns An unsubscribe function that removes the callback
1107
+ */
1108
+ onExternalChange?: (callback: (changedKeys?: string[]) => void) => () => void;
1109
+ };
1110
+ /**
1111
+ * Function type for unsubscribing from event listeners.
1112
+ *
1113
+ * Call this function to remove a subscription and stop receiving updates.
1114
+ *
1115
+ * @example
1116
+ * ```typescript
1117
+ * const unsubscribe = store.subscribeRaw('user', () => console.log('Updated!'));
1118
+ * // Later...
1119
+ * unsubscribe(); // Stop listening
1120
+ * ```
1121
+ */
1122
+ type Unsubscribe = () => void;
1123
+ /**
1124
+ * Callback function invoked when a subscribed value changes.
1125
+ *
1126
+ * Used by the external store contract to notify React when state updates.
1127
+ */
1128
+ type Listener = () => void;
1129
+ /**
1130
+ * Low-level Mnemonic store API provided via React Context.
1131
+ *
1132
+ * This interface powers `MnemonicProvider` internally and is also exposed to
1133
+ * advanced consumers through `MnemonicDevToolsProviderApi.getStore()`. Typical
1134
+ * application code should still prefer `useMnemonicKey`.
1135
+ *
1136
+ * All keys passed to these methods should be **unprefixed**. The store
1137
+ * automatically applies the namespace prefix internally.
1138
+ *
1139
+ * @remarks
1140
+ * This implements the React `useSyncExternalStore` contract for efficient,
1141
+ * tearing-free state synchronization. Most application code should still
1142
+ * prefer `useMnemonicKey`; this type mainly appears in the DevTools API via
1143
+ * `MnemonicDevToolsProviderApi.getStore()`.
1144
+ */
1145
+ type Mnemonic = {
1146
+ /**
1147
+ * The namespace prefix applied to all keys in storage.
1148
+ *
1149
+ * Keys are stored as `${prefix}${key}` in the underlying storage backend.
1150
+ */
1151
+ prefix: string;
1152
+ /**
1153
+ * Whether the active storage backend can enumerate keys in this namespace.
1154
+ *
1155
+ * This is `true` for `localStorage`-like backends that implement both
1156
+ * `length` and `key(index)`. Namespace-wide recovery helpers rely on this
1157
+ * capability unless the caller supplies an explicit key list.
1158
+ */
1159
+ canEnumerateKeys: boolean;
1160
+ /**
1161
+ * Subscribe to changes for a specific key.
1162
+ *
1163
+ * Follows the React external store subscription contract. The listener
1164
+ * will be called whenever the value for this key changes.
1165
+ *
1166
+ * @param key - The unprefixed storage key to subscribe to
1167
+ * @param listener - Callback invoked when the value changes
1168
+ * @returns Unsubscribe function to stop listening
1169
+ *
1170
+ * @example
1171
+ * ```typescript
1172
+ * const unsubscribe = store.subscribeRaw('user', () => {
1173
+ * console.log('User changed:', store.getRawSnapshot('user'));
1174
+ * });
1175
+ * ```
1176
+ */
1177
+ subscribeRaw: (key: string, listener: Listener) => Unsubscribe;
1178
+ /**
1179
+ * Get the current raw string value for a key.
1180
+ *
1181
+ * This is part of the external store snapshot contract. Values are
1182
+ * cached in memory for stable snapshots.
1183
+ *
1184
+ * @param key - The unprefixed storage key
1185
+ * @returns The raw string value, or null if not present
1186
+ */
1187
+ getRawSnapshot: (key: string) => string | null;
1188
+ /**
1189
+ * Write a raw string value to storage.
1190
+ *
1191
+ * Updates both the in-memory cache and the underlying storage backend,
1192
+ * then notifies all subscribers for this key.
1193
+ *
1194
+ * @param key - The unprefixed storage key
1195
+ * @param raw - The raw string value to store
1196
+ */
1197
+ setRaw: (key: string, raw: string) => void;
1198
+ /**
1199
+ * Remove a key from storage.
1200
+ *
1201
+ * Clears the value from both the cache and the underlying storage,
1202
+ * then notifies all subscribers.
1203
+ *
1204
+ * @param key - The unprefixed storage key to remove
1205
+ */
1206
+ removeRaw: (key: string) => void;
1207
+ /**
1208
+ * Enumerate all keys in this namespace.
1209
+ *
1210
+ * Returns unprefixed keys that belong to this store's namespace.
1211
+ *
1212
+ * @returns Array of unprefixed key names
1213
+ */
1214
+ keys: () => string[];
1215
+ /**
1216
+ * Dump all key-value pairs in this namespace.
1217
+ *
1218
+ * Useful for debugging and DevTools integration.
1219
+ *
1220
+ * @returns Object mapping unprefixed keys to raw string values
1221
+ */
1222
+ dump: () => Record<string, string>;
1223
+ /**
1224
+ * The active schema enforcement mode for this provider.
1225
+ *
1226
+ * Propagated from the `schemaMode` provider option. Hooks read this
1227
+ * to determine how to handle versioned envelopes.
1228
+ *
1229
+ * @see {@link SchemaMode}
1230
+ */
1231
+ schemaMode: SchemaMode;
1232
+ /**
1233
+ * Default hydration strategy inherited by descendant hooks.
1234
+ */
1235
+ ssrHydration: MnemonicHydrationMode;
1236
+ /**
1237
+ * How this provider can observe external changes from other tabs/processes.
1238
+ *
1239
+ * Hooks use this for development diagnostics when callers opt into
1240
+ * cross-tab synchronization on a backend that cannot actually deliver it.
1241
+ *
1242
+ * When omitted, consumers should treat this as equivalent to `"none"`.
1243
+ */
1244
+ crossTabSyncMode?: "browser-storage-event" | "custom-external-change" | "none";
1245
+ /**
1246
+ * The schema registry for this provider, if one was supplied.
1247
+ *
1248
+ * Hooks use this to look up schemas, resolve migration paths, and
1249
+ * (in autoschema mode) register inferred schemas.
1250
+ *
1251
+ * @see {@link SchemaRegistry}
1252
+ */
1253
+ schemaRegistry?: SchemaRegistry;
1254
+ };
1255
+ /**
1256
+ * Recovery action names emitted by {@link useMnemonicRecovery}.
1257
+ */
1258
+ type MnemonicRecoveryAction = "clear-all" | "clear-keys" | "clear-matching";
1259
+ /**
1260
+ * Recovery event payload emitted after a namespace recovery action completes.
1261
+ */
1262
+ interface MnemonicRecoveryEvent {
1263
+ /**
1264
+ * Recovery action that just ran.
1265
+ */
1266
+ action: MnemonicRecoveryAction;
1267
+ /**
1268
+ * Namespace where the recovery action ran.
1269
+ */
1270
+ namespace: string;
1271
+ /**
1272
+ * Unprefixed keys cleared by the action.
1273
+ */
1274
+ clearedKeys: string[];
1275
+ }
1276
+ /**
1277
+ * Options for {@link useMnemonicRecovery}.
1278
+ */
1279
+ interface UseMnemonicRecoveryOptions {
1280
+ /**
1281
+ * Optional callback invoked after a recovery action completes.
1282
+ *
1283
+ * Useful for analytics, audit trails, support diagnostics, or user-facing
1284
+ * confirmation toasts.
1285
+ */
1286
+ onRecover?: (event: MnemonicRecoveryEvent) => void;
1287
+ }
1288
+ /**
1289
+ * Namespace-scoped recovery helpers returned by {@link useMnemonicRecovery}.
1290
+ *
1291
+ * These helpers operate on the current provider namespace and are intended for
1292
+ * user-facing recovery UX such as "reset app data" or "clear stale filters".
1293
+ */
1294
+ interface MnemonicRecoveryHook {
1295
+ /**
1296
+ * Current provider namespace without the trailing storage prefix dot.
1297
+ */
1298
+ namespace: string;
1299
+ /**
1300
+ * Whether namespace keys can be enumerated automatically.
1301
+ *
1302
+ * `clearAll()` and `clearMatching()` require this to be `true`. If it is
1303
+ * `false`, prefer `clearKeys([...])` with an explicit durable-key list.
1304
+ */
1305
+ canEnumerateKeys: boolean;
1306
+ /**
1307
+ * Lists all unprefixed keys currently visible in this namespace.
1308
+ *
1309
+ * Returns an empty array when no keys exist or when the storage backend
1310
+ * cannot enumerate keys.
1311
+ */
1312
+ listKeys: () => string[];
1313
+ /**
1314
+ * Clears every key in the current namespace.
1315
+ *
1316
+ * @throws {Error} When the storage backend cannot enumerate namespace keys
1317
+ */
1318
+ clearAll: () => string[];
1319
+ /**
1320
+ * Clears a specific set of unprefixed keys in the current namespace.
1321
+ *
1322
+ * Duplicate keys are ignored.
1323
+ */
1324
+ clearKeys: (keys: readonly string[]) => string[];
1325
+ /**
1326
+ * Clears namespace keys whose names match the supplied predicate.
1327
+ *
1328
+ * @throws {Error} When the storage backend cannot enumerate namespace keys
1329
+ */
1330
+ clearMatching: (predicate: (key: string) => boolean) => string[];
1331
+ }
1332
+ /**
1333
+ * Return shape from {@link useMnemonicKey}.
1334
+ *
1335
+ * This mirrors the familiar `useState` mental model while making the storage
1336
+ * semantics explicit:
1337
+ *
1338
+ * - `set(...)` writes a new persisted value
1339
+ * - `reset()` writes `defaultValue` back into storage
1340
+ * - `remove()` deletes the key entirely so reads fall back to `defaultValue`
1341
+ *
1342
+ * See the
1343
+ * [Clearable Persisted Values guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/clearable-persisted-values)
1344
+ * for the semantic differences between clearing, resetting, and removing a key.
1345
+ *
1346
+ * @template T - The decoded value type for the key
1347
+ *
1348
+ * @see {@link UseMnemonicKeyOptions} - Hook configuration and lifecycle details
1349
+ */
1350
+ interface MnemonicKeyState<T> {
1351
+ /**
1352
+ * Current decoded value, or the default when the key is absent or invalid.
1353
+ */
1354
+ value: T;
1355
+ /**
1356
+ * Persist a new value.
1357
+ *
1358
+ * Accepts either a direct replacement value or an updater function that
1359
+ * receives the current decoded value.
1360
+ */
1361
+ set: (next: T | ((current: T) => T)) => void;
1362
+ /**
1363
+ * Reset the key back to `defaultValue` and persist that default.
1364
+ */
1365
+ reset: () => void;
1366
+ /**
1367
+ * Delete the key from storage entirely.
1368
+ *
1369
+ * Future reads will fall back to `defaultValue` until the key is written
1370
+ * again.
1371
+ */
1372
+ remove: () => void;
1373
+ }
1374
+ /**
1375
+ * Reusable, importable contract for a single persisted key.
1376
+ *
1377
+ * Descriptors package the key name and its `useMnemonicKey(...)` options into
1378
+ * a stable object that can be defined once at module scope and reused across
1379
+ * components. This helps keep persistence behavior explicit and consistent,
1380
+ * especially when the same key appears in multiple parts of an application.
1381
+ *
1382
+ * @template T - The decoded value type for the key
1383
+ * @template K - The literal key name
1384
+ *
1385
+ * @example
1386
+ * ```typescript
1387
+ * const themeKey = defineMnemonicKey("theme", {
1388
+ * defaultValue: "light" as "light" | "dark",
1389
+ * listenCrossTab: true,
1390
+ * });
1391
+ *
1392
+ * const { value, set } = useMnemonicKey(themeKey);
1393
+ * ```
1394
+ *
1395
+ * @see {@link defineMnemonicKey} - Helper for creating descriptors
1396
+ * @see {@link useMnemonicKey} - Hook that consumes descriptors
1397
+ */
1398
+ interface MnemonicKeyDescriptor<T, K extends string = string> {
1399
+ /**
1400
+ * Unprefixed storage key name.
1401
+ */
1402
+ readonly key: K;
1403
+ /**
1404
+ * Canonical options for this key.
1405
+ */
1406
+ readonly options: UseMnemonicKeyOptions<T>;
1407
+ }
1408
+ /**
1409
+ * Key descriptor options inferred from a typed key schema.
1410
+ *
1411
+ * This mirrors `UseMnemonicKeyOptions<T>` but intentionally omits the `schema`
1412
+ * override so the descriptor stays pinned to the supplied key schema version.
1413
+ */
1414
+ type SchemaBoundKeyOptions<T> = Omit<UseMnemonicKeyOptions<T>, "schema">;
1415
+ /**
1416
+ * Typed key schema shape inferred from a schema helper or branded JSON Schema.
1417
+ *
1418
+ * Useful when you want a versioned schema object to carry its decoded
1419
+ * TypeScript value through registries, descriptors, and migration helpers.
1420
+ */
1421
+ type TypedKeySchema<TSchema extends JsonSchema, K extends string = string> = KeySchema<InferJsonSchemaValue<TSchema>, K, TSchema>;
1422
+ /**
1423
+ * Configuration options for the useMnemonicKey hook.
1424
+ *
1425
+ * These options control how a value is persisted, decoded, and
1426
+ * synchronized across the application.
1427
+ *
1428
+ * @template T - The TypeScript type of the stored value
1429
+ *
1430
+ * @example
1431
+ * ```typescript
1432
+ * const { value, set } = useMnemonicKey<User>('currentUser', {
1433
+ * defaultValue: { name: 'Guest', id: null },
1434
+ * onMount: (user) => console.log('Loaded user:', user),
1435
+ * onChange: (current, previous) => {
1436
+ * console.log('User changed from', previous, 'to', current);
1437
+ * },
1438
+ * listenCrossTab: true
1439
+ * });
1440
+ * ```
1441
+ */
1442
+ type UseMnemonicKeyOptions<T> = {
1443
+ /**
1444
+ * Default value to use when no stored value exists, or when decoding/validation fails.
1445
+ *
1446
+ * Can be a literal value or a factory function that returns the default.
1447
+ * Factory functions receive an optional error argument describing why the
1448
+ * fallback is being used:
1449
+ *
1450
+ * - `undefined` — Nominal path: no value exists in storage for this key.
1451
+ * - `CodecError` — The stored value could not be decoded by the codec.
1452
+ * - `SchemaError` — A schema, migration, or validation issue occurred
1453
+ * (e.g. missing schema, failed migration, JSON Schema validation failure).
1454
+ *
1455
+ * Static (non-function) default values ignore the error entirely.
1456
+ *
1457
+ * @remarks
1458
+ * If a factory function is defined inline, it creates a new reference on
1459
+ * every render, which forces internal memoization to recompute. For best
1460
+ * performance, define the factory at module level or wrap it in `useCallback`:
1461
+ *
1462
+ * ```typescript
1463
+ * // Module-level (stable reference, preferred)
1464
+ * const getDefault = (error?: CodecError | SchemaError) => {
1465
+ * if (error) console.warn('Fallback:', error.message);
1466
+ * return { count: 0 };
1467
+ * };
1468
+ *
1469
+ * // Or with useCallback inside a component
1470
+ * const getDefault = useCallback(
1471
+ * (error?: CodecError | SchemaError) => ({ count: 0 }),
1472
+ * [],
1473
+ * );
1474
+ * ```
1475
+ *
1476
+ * @example
1477
+ * ```typescript
1478
+ * // Static default
1479
+ * defaultValue: { count: 0 }
1480
+ *
1481
+ * // Factory with no error handling
1482
+ * defaultValue: () => ({ timestamp: Date.now() })
1483
+ *
1484
+ * // Error-aware factory
1485
+ * defaultValue: (error) => {
1486
+ * if (error instanceof CodecError) {
1487
+ * console.error('Corrupt data:', error.message);
1488
+ * }
1489
+ * if (error instanceof SchemaError) {
1490
+ * console.warn('Schema issue:', error.code, error.message);
1491
+ * }
1492
+ * return { count: 0 };
1493
+ * }
1494
+ * ```
1495
+ */
1496
+ defaultValue: T | ((error?: CodecError | SchemaError) => T);
1497
+ /**
1498
+ * Codec for encoding and decoding values to/from storage.
1499
+ *
1500
+ * Determines how the typed value is serialized to a string and
1501
+ * deserialized back. Defaults to JSONCodec if not specified.
1502
+ *
1503
+ * Using a codec is a low-level option that bypasses JSON Schema
1504
+ * validation. Schema-managed keys store JSON values directly and
1505
+ * are validated against their registered JSON Schema.
1506
+ *
1507
+ * @default JSONCodec
1508
+ *
1509
+ * @example
1510
+ * ```typescript
1511
+ * // Custom codec for dates
1512
+ * codec: createCodec(
1513
+ * (date) => date.toISOString(),
1514
+ * (str) => new Date(str)
1515
+ * )
1516
+ * ```
1517
+ */
1518
+ codec?: Codec<T>;
1519
+ /**
1520
+ * Optional read-time reconciliation hook for persisted values.
1521
+ *
1522
+ * Runs after a stored value has been decoded and any read-time migrations
1523
+ * have completed, but before the hook exposes the value to React. This is
1524
+ * useful for selectively enforcing newly shipped defaults or normalizing
1525
+ * legacy persisted values without discarding the whole key.
1526
+ *
1527
+ * If the reconciled value would persist differently from the pre-reconcile
1528
+ * value, the hook rewrites storage once using the normal write path.
1529
+ *
1530
+ * @remarks
1531
+ * Prefer schema migrations for structural changes that must always happen
1532
+ * between explicit versions. Use `reconcile` for conditional, field-level
1533
+ * adjustments that depend on application policy rather than a strict schema
1534
+ * upgrade step.
1535
+ *
1536
+ * See the Schema Migration guide for migration-vs-reconciliation guidance:
1537
+ * https://thirtytwobits.github.io/react-mnemonic/docs/guides/schema-migration
1538
+ *
1539
+ * If `reconcile` throws a `SchemaError`, that error is preserved and passed
1540
+ * to `defaultValue`. Any other thrown error is wrapped as
1541
+ * `SchemaError("RECONCILE_FAILED")`.
1542
+ *
1543
+ * @param value - The decoded persisted value
1544
+ * @param context - Metadata about the stored and latest schema versions
1545
+ *
1546
+ * @example
1547
+ * ```typescript
1548
+ * reconcile: (value, { persistedVersion }) => ({
1549
+ * ...value,
1550
+ * theme: persistedVersion < 2 ? "dark" : value.theme,
1551
+ * })
1552
+ * ```
1553
+ */
1554
+ reconcile?: (value: T, context: ReconcileContext) => T;
1555
+ /**
1556
+ * Callback invoked once when the hook is first mounted.
1557
+ *
1558
+ * Receives the initial value (either from storage or the default).
1559
+ * Useful for triggering side effects based on the loaded state.
1560
+ *
1561
+ * @param value - The initial value loaded on mount
1562
+ *
1563
+ * @example
1564
+ * ```typescript
1565
+ * onMount: (theme) => {
1566
+ * document.body.className = theme;
1567
+ * console.log('Theme loaded:', theme);
1568
+ * }
1569
+ * ```
1570
+ */
1571
+ onMount?: (value: T) => void;
1572
+ /**
1573
+ * Callback invoked whenever the value changes.
1574
+ *
1575
+ * Receives both the new value and the previous value. This is called
1576
+ * for all changes, including those triggered by other components or tabs.
1577
+ *
1578
+ * @param value - The new current value
1579
+ * @param prev - The previous value
1580
+ *
1581
+ * @example
1582
+ * ```typescript
1583
+ * onChange: (newTheme, oldTheme) => {
1584
+ * document.body.classList.remove(oldTheme);
1585
+ * document.body.classList.add(newTheme);
1586
+ * console.log(`Theme changed: ${oldTheme} -> ${newTheme}`);
1587
+ * }
1588
+ * ```
1589
+ */
1590
+ onChange?: (value: T, prev: T) => void;
1591
+ /**
1592
+ * Enable listening for changes from other browser tabs.
1593
+ *
1594
+ * When true, uses the browser's `storage` event to detect changes
1595
+ * made to localStorage in other tabs and synchronizes them to this component.
1596
+ *
1597
+ * Only effective when using localStorage as the storage backend.
1598
+ *
1599
+ * @default false
1600
+ *
1601
+ * @example
1602
+ * ```typescript
1603
+ * // Enable cross-tab sync for shared state
1604
+ * listenCrossTab: true
1605
+ * ```
1606
+ *
1607
+ * @remarks
1608
+ * The `storage` event only fires for changes made in *other* tabs,
1609
+ * not the current tab. Changes within the same tab are synchronized
1610
+ * automatically via React's state management.
1611
+ */
1612
+ listenCrossTab?: boolean;
1613
+ /**
1614
+ * Server-rendering controls for this key.
1615
+ *
1616
+ * Use this when the server should render a value other than
1617
+ * `defaultValue`, or when persisted storage should only be read after the
1618
+ * component has mounted on the client.
1619
+ *
1620
+ * @example
1621
+ * ```typescript
1622
+ * ssr: {
1623
+ * serverValue: { theme: "system" },
1624
+ * hydration: "client-only",
1625
+ * }
1626
+ * ```
1627
+ */
1628
+ ssr?: MnemonicKeySSRConfig<T>;
1629
+ /**
1630
+ * Optional schema controls for this key.
1631
+ *
1632
+ * Allows overriding the version written by the `set` function. When
1633
+ * omitted, the library writes using the highest registered schema for
1634
+ * this key, or version `0` when no schemas are registered.
1635
+ *
1636
+ * @example
1637
+ * ```typescript
1638
+ * // Pin writes to schema version 2 even if version 3 exists
1639
+ * const { value, set } = useMnemonicKey("user", {
1640
+ * defaultValue: { name: "" },
1641
+ * schema: { version: 2 },
1642
+ * });
1643
+ * ```
1644
+ */
1645
+ schema?: {
1646
+ /**
1647
+ * Explicit schema version to use when writing values.
1648
+ *
1649
+ * When set, the `set` and `reset` functions encode using the
1650
+ * schema registered at this version instead of the latest. Useful
1651
+ * during gradual rollouts where not all consumers have been
1652
+ * updated yet.
1653
+ *
1654
+ * Must reference a version that exists in the `SchemaRegistry`.
1655
+ * If not found the write falls back to the latest schema (default
1656
+ * mode) or fails with a `SchemaError` (strict mode).
1657
+ */
1658
+ version?: number;
1659
+ };
1660
+ };
1661
+ /**
1662
+ * Metadata passed to `UseMnemonicKeyOptions.reconcile`.
1663
+ */
1664
+ type ReconcileContext = {
1665
+ /**
1666
+ * The unprefixed storage key being reconciled.
1667
+ */
1668
+ key: string;
1669
+ /**
1670
+ * The version found in the persisted envelope that was read.
1671
+ */
1672
+ persistedVersion: number;
1673
+ /**
1674
+ * The latest registered schema version for the key, when available.
1675
+ */
1676
+ latestVersion?: number;
1677
+ };
1678
+
1679
+ /**
1680
+ * Hook for namespace-scoped recovery actions such as hard reset and selective clear.
1681
+ *
1682
+ * Applications can use this to offer self-service recovery UX for corrupt or
1683
+ * legacy persisted state. The hook operates on the current provider namespace.
1684
+ *
1685
+ * See the
1686
+ * [Reset and Recovery guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/reset-and-recovery)
1687
+ * for soft-reset and hard-reset patterns.
1688
+ *
1689
+ * @param options - Optional recovery callback for telemetry/auditing
1690
+ * @returns Namespace recovery helpers
1691
+ *
1692
+ * @throws {Error} If used outside of a MnemonicProvider
1693
+ */
1694
+ declare function useMnemonicRecovery(options?: UseMnemonicRecoveryOptions): MnemonicRecoveryHook;
1695
+
1696
+ /**
1697
+ * Define a reusable, importable contract for a persisted key.
1698
+ *
1699
+ * This packages the storage key and the canonical `useMnemonicKey(...)`
1700
+ * options into a single object that can be shared across components, docs,
1701
+ * and generated code.
1702
+ *
1703
+ * @template K - The literal storage key name
1704
+ * @template T - The decoded value type for the key
1705
+ *
1706
+ * @param key - The unprefixed storage key
1707
+ * @param options - Canonical hook options for the key
1708
+ * @returns A descriptor that can be passed directly to `useMnemonicKey(...)`
1709
+ *
1710
+ * @example
1711
+ * ```typescript
1712
+ * const themeKey = defineMnemonicKey("theme", {
1713
+ * defaultValue: "light" as "light" | "dark",
1714
+ * listenCrossTab: true,
1715
+ * });
1716
+ *
1717
+ * const { value, set } = useMnemonicKey(themeKey);
1718
+ * ```
1719
+ */
1720
+ declare function defineMnemonicKey<const K extends string, T>(key: K, options: UseMnemonicKeyOptions<T>): MnemonicKeyDescriptor<T, K>;
1721
+ declare function defineMnemonicKey<const K extends string, TSchema extends KeySchema<unknown, K, JsonSchema>>(keySchema: TSchema, options: SchemaBoundKeyOptions<TSchema extends KeySchema<infer TValue, string, JsonSchema> ? TValue : never>): MnemonicKeyDescriptor<TSchema extends KeySchema<infer TValue, string, JsonSchema> ? TValue : never, TSchema["key"]>;
1722
+
1723
+ export { type JsonSchema as A, type MigrationRule as B, type Codec as C, type CompiledValidator as D, type JsonSchemaType as E, type JsonSchemaValidationError as F, type MigrationPath as G, type SchemaBoundKeyOptions as H, type InferJsonSchemaValue as I, JSONCodec as J, type KeySchema as K, type Listener as L, type MnemonicProviderOptions as M, type TypedKeySchema as N, compileSchema as O, mnemonicSchema as P, validateJsonSchema as Q, type ReconcileContext as R, SchemaError as S, type TypedJsonSchema as T, type UseMnemonicKeyOptions as U, type MnemonicKeyDescriptor as a, type MnemonicKeyState as b, CodecError as c, type Mnemonic as d, type MnemonicDevToolsCapabilities as e, type MnemonicDevToolsMeta as f, type MnemonicDevToolsProviderApi as g, type MnemonicDevToolsProviderDescriptor as h, type MnemonicDevToolsProviderEntry as i, type MnemonicDevToolsRegistry as j, type MnemonicDevToolsWeakRef as k, type MnemonicHydrationMode as l, type MnemonicKeySSRConfig as m, type MnemonicProviderSSRConfig as n, type MnemonicRecoveryAction as o, type MnemonicRecoveryEvent as p, type MnemonicRecoveryHook as q, type SchemaMode as r, type StorageLike as s, type Unsubscribe as t, type UseMnemonicRecoveryOptions as u, createCodec as v, defineMnemonicKey as w, useMnemonicRecovery as x, type CreateSchemaRegistryOptions as y, type SchemaRegistry as z };