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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,70 +1,28 @@
1
1
  # react-mnemonic
2
2
 
3
- Persistent, type-safe state management for React.
3
+ AI-friendly, persistent, type-safe state for React.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/react-mnemonic.svg)](https://www.npmjs.com/package/react-mnemonic)
6
- [![bundle size](https://img.shields.io/bundlephobia/minzip/react-mnemonic)](https://bundlephobia.com/package/react-mnemonic)
7
- [![license](https://img.shields.io/npm/l/react-mnemonic.svg)](./LICENSE.md)
8
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
6
+ [![docs](https://img.shields.io/badge/docs-online-0A7EA4.svg)](https://thirtytwobits.github.io/react-mnemonic/)
7
+ [![license](https://img.shields.io/npm/l/react-mnemonic.svg)](https://github.com/thirtytwobits/react-mnemonic/blob/main/LICENSE.md)
9
8
 
10
- **react-mnemonic** gives your React components persistent memory. Values survive
11
- page refreshes, synchronize across tabs, and stay type-safe end-to-end -- all
12
- through a single hook that works like `useState`.
13
-
14
- `1.0.0` is currently being shipped as a beta on the npm `beta` dist-tag while
15
- the release candidate hardening work finishes.
16
-
17
- ## Features
18
-
19
- - **`useState`-like API** -- `useMnemonicKey` returns `{ value, set, reset, remove }`
20
- - **JSON Schema validation** -- optional schema-based validation using a built-in JSON Schema subset
21
- - **Namespace isolation** -- `MnemonicProvider` prefixes every key to prevent collisions
22
- - **Cross-tab sync** -- opt-in `listenCrossTab` uses the browser `storage` event
23
- - **Pluggable storage** -- bring your own backend via the `StorageLike` interface (IndexedDB, sessionStorage, etc.)
24
- - **Schema versioning and migration** -- upgrade stored data with versioned schemas and migration rules
25
- - **Structural migration helpers** -- optional tree utilities for idempotent insert/rename/dedupe migration steps
26
- - **Read-time reconciliation** -- selectively enforce new defaults on persisted values without clearing the whole key
27
- - **Recovery helpers** -- build user-facing soft reset and hard reset flows with namespace-scoped clear helpers
28
- - **Write-time normalization** -- migrations where `fromVersion === toVersion` run on every write
29
- - **Lifecycle callbacks** -- `onMount` and `onChange` hooks
30
- - **DevTools** -- inspect and mutate state from the browser console
31
- - **SSR-safe** -- returns defaults when `window` is unavailable
32
- - **Tree-shakeable, zero dependencies** -- ships ESM + CJS with full TypeScript declarations
9
+ `react-mnemonic` gives your components persistent memory through a hook that feels like `useState`. Values survive reloads, can stay in sync across tabs, and remain SSR-safe by default. It is designed to be AI-friendly, prioritizing visible structure and unambiguous specifications. When you need more than raw storage, the package can validate, version, and migrate persisted data.
33
10
 
34
11
  ## Installation
35
12
 
36
13
  ```bash
37
- npm install react-mnemonic@beta
38
- ```
39
-
40
- ```bash
41
- yarn add react-mnemonic@beta
42
- ```
43
-
44
- ```bash
45
- pnpm add react-mnemonic@beta
14
+ npm install react-mnemonic
46
15
  ```
47
16
 
48
- ### Peer dependencies
49
-
50
- React 18 or later is required. CI verifies packaged-consumer installs against
51
- React 18 and React 19.
52
-
53
- ```json
54
- {
55
- "peerDependencies": {
56
- "react": ">=18",
57
- "react-dom": ">=18"
58
- }
59
- }
60
- ```
17
+ React 18 or later is required.
61
18
 
62
19
  ## Quick start
63
20
 
64
- Wrap your app in a `MnemonicProvider`, then call `useMnemonicKey` anywhere inside it.
21
+ Wrap your app in a `MnemonicProvider`, then call `useMnemonicKey` anywhere
22
+ inside it.
65
23
 
66
24
  ```tsx
67
- import { MnemonicProvider, useMnemonicKey } from "react-mnemonic";
25
+ import { MnemonicProvider, useMnemonicKey } from "react-mnemonic/core";
68
26
 
69
27
  function Counter() {
70
28
  const { value: count, set } = useMnemonicKey("count", {
@@ -88,496 +46,48 @@ export default function App() {
88
46
  }
89
47
  ```
90
48
 
91
- The counter value persists in `localStorage` under the key `my-app.count` and
92
- survives full page reloads.
93
-
94
- Persist only the durable slice of your app state. `useMnemonicKey` stores
95
- whatever you pass to `set`, so keep transient UI state like loading flags,
96
- hover state, and draft search text in plain React state unless you explicitly
97
- want them to rehydrate after reload. See the
98
- [Persisted vs Ephemeral State guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/persisted-vs-ephemeral-state)
99
- for patterns and an interactive example.
100
-
101
- For self-service recovery UX, pair your per-key hooks with
102
- `useMnemonicRecovery` so users can clear stale filters, reset broken settings,
103
- or fully wipe a namespace without opening DevTools. See the
104
- [Reset and Recovery guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/reset-and-recovery)
105
- for soft-reset and hard-reset recipes.
106
-
107
- If a field must stay cleared across reloads, model it as nullable and persist
108
- `null` explicitly. `remove()` deletes the key and falls back to `defaultValue`,
109
- while `reset()` writes the default again. See the
110
- [Clearable Persisted Values guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/clearable-persisted-values)
111
- for the canonical nullable pattern.
112
-
113
- ## API
49
+ This persists the counter in `localStorage` as `my-app.count`, so the value
50
+ survives a full page reload.
114
51
 
115
- ### `<MnemonicProvider>`
52
+ ## Why use it
116
53
 
117
- Context provider that scopes storage keys under a namespace.
54
+ - `useState`-like API: `useMnemonicKey` returns `{ value, set, reset, remove }`
55
+ - Namespaced persistence through `MnemonicProvider`
56
+ - Optional cross-tab synchronization
57
+ - SSR-safe defaults for server-rendered React apps
58
+ - Optional schema validation, versioning, migrations, and reconciliation
59
+ - Zero runtime dependencies with published TypeScript types
118
60
 
119
- ```tsx
120
- <MnemonicProvider
121
- namespace="my-app" // key prefix (required)
122
- storage={localStorage} // StorageLike backend (default: localStorage)
123
- schemaMode="default" // "default" | "strict" | "autoschema" (default: "default")
124
- schemaRegistry={registry} // optional SchemaRegistry for versioned schemas
125
- enableDevTools={false} // expose console helpers (default: false)
126
- >
127
- {children}
128
- </MnemonicProvider>
129
- ```
130
-
131
- Multiple providers with different namespaces can coexist in the same app.
132
-
133
- ### `useMnemonicKey<T>(key, options)`
134
-
135
- Hook for reading and writing a single persistent value.
136
-
137
- ```ts
138
- const { value, set, reset, remove } = useMnemonicKey<T>(key, options);
139
- ```
140
-
141
- | Return | Type | Description |
142
- | -------- | ------------------------------------ | --------------------------------------------- |
143
- | `value` | `T` | Current decoded value (or default) |
144
- | `set` | `(next: T \| (cur: T) => T) => void` | Update the value (direct or updater function) |
145
- | `reset` | `() => void` | Reset to `defaultValue` and persist it |
146
- | `remove` | `() => void` | Delete the key from storage entirely |
147
-
148
- For clearable fields, remember the semantic split:
149
-
150
- - `set(null)` persists a cleared value and stays cleared after reload
151
- - `remove()` deletes the key, so the next read falls back to `defaultValue`
152
- - `reset()` persists `defaultValue`
153
-
154
- #### Options
155
-
156
- | Option | Type | Default | Description |
157
- | ---------------- | ------------------------------------------------- | ----------- | ------------------------------------------------------------- |
158
- | `defaultValue` | `T \| ((error?: CodecError \| SchemaError) => T)` | _required_ | Fallback value or error-aware factory |
159
- | `codec` | `Codec<T>` | `JSONCodec` | Encode/decode strategy (bypasses schema validation) |
160
- | `reconcile` | `(value: T, context: ReconcileContext) => T` | -- | Adjust a persisted value after read and persist if it changes |
161
- | `onMount` | `(value: T) => void` | -- | Called once with the initial value |
162
- | `onChange` | `(value: T, prev: T) => void` | -- | Called on every value change |
163
- | `listenCrossTab` | `boolean` | `false` | Sync via the browser `storage` event |
164
- | `schema` | `{ version?: number }` | -- | Pin writes to a specific schema version |
165
-
166
- ### `useMnemonicRecovery(options)`
167
-
168
- Hook for namespace-scoped recovery actions such as "clear saved filters" or
169
- "reset all persisted app data".
170
-
171
- ```ts
172
- const { namespace, canEnumerateKeys, listKeys, clearAll, clearKeys, clearMatching } = useMnemonicRecovery({
173
- onRecover: (event) => console.log(event.action, event.clearedKeys),
174
- });
175
- ```
61
+ ## Pick the right entrypoint
176
62
 
177
- | Return | Type | Description |
178
- | ------------------ | --------------------------------------------------- | ----------------------------------------------------- |
179
- | `namespace` | `string` | Current provider namespace |
180
- | `canEnumerateKeys` | `boolean` | Whether the storage backend can list namespace keys |
181
- | `listKeys` | `() => string[]` | List visible unprefixed keys in the current namespace |
182
- | `clearAll` | `() => string[]` | Clear every key in the namespace |
183
- | `clearKeys` | `(keys: readonly string[]) => string[]` | Clear an explicit set of unprefixed keys |
184
- | `clearMatching` | `(predicate: (key: string) => boolean) => string[]` | Clear keys whose names match a predicate |
63
+ - `react-mnemonic/core` for the lean persisted-state path
64
+ - `react-mnemonic/schema` when you want schemas, validation, and migrations
65
+ - `react-mnemonic` if you need the backward-compatible root entrypoint
185
66
 
186
- `clearAll()` and `clearMatching()` require an enumerable storage backend such
187
- as `localStorage` or `sessionStorage`. If your custom storage does not support
188
- `length` and `key(index)`, use `clearKeys([...])` with the explicit durable-key
189
- list your app owns.
190
-
191
- ### Codecs
192
-
193
- The default codec is `JSONCodec`, which handles all JSON-serializable values.
194
- You can create custom codecs using `createCodec` for types that need special
195
- serialization (e.g., `Date`, `Set`, `Map`).
196
-
197
- Using a custom codec bypasses JSON Schema validation -- the codec is a low-level
198
- escape hatch for when you need full control over serialization.
199
-
200
- ```ts
201
- import { createCodec } from "react-mnemonic";
202
-
203
- const DateCodec = createCodec<Date>(
204
- (date) => date.toISOString(),
205
- (str) => new Date(str),
206
- );
207
- ```
208
-
209
- ### `StorageLike`
210
-
211
- The interface your custom storage backend must satisfy.
212
-
213
- ```ts
214
- interface StorageLike {
215
- getItem(key: string): string | null;
216
- setItem(key: string, value: string): void;
217
- removeItem(key: string): void;
218
- key?(index: number): string | null;
219
- readonly length?: number;
220
- onExternalChange?: (callback: (changedKeys?: string[]) => void) => () => void;
221
- }
222
- ```
223
-
224
- `onExternalChange` enables cross-tab sync for non-localStorage backends (e.g.
225
- IndexedDB over `BroadcastChannel`). The library handles all error cases
226
- internally -- see the `StorageLike` JSDoc for the full error-handling contract.
227
- Namespace-wide recovery helpers can only enumerate keys when the backend also
228
- implements `length` and `key(index)`.
229
-
230
- ### `validateJsonSchema(schema, value)`
231
-
232
- Validate an arbitrary value against a JSON Schema (the same subset used by the
233
- hook). Returns an array of validation errors, empty when the value is valid.
234
-
235
- ```ts
236
- import { validateJsonSchema } from "react-mnemonic";
237
-
238
- const errors = validateJsonSchema(
239
- { type: "object", properties: { name: { type: "string" } }, required: ["name"] },
240
- { name: 42 },
241
- );
242
- // [{ path: ".name", message: 'Expected type "string"' }]
243
- ```
244
-
245
- ### `compileSchema(schema)`
246
-
247
- Pre-compile a JSON Schema into a reusable validator function. The compiled
248
- validator is cached by schema reference (via `WeakMap`), so calling
249
- `compileSchema` twice with the same object returns the identical function.
250
-
251
- ```ts
252
- import { compileSchema } from "react-mnemonic";
253
- import type { CompiledValidator } from "react-mnemonic";
254
-
255
- const validate: CompiledValidator = compileSchema({
256
- type: "object",
257
- properties: {
258
- name: { type: "string", minLength: 1 },
259
- age: { type: "number", minimum: 0 },
260
- },
261
- required: ["name"],
262
- });
263
-
264
- validate({ name: "Alice", age: 30 }); // []
265
- validate({ age: -1 }); // [{ path: "", … }, { path: ".age", … }]
266
- ```
267
-
268
- This is useful when you validate the same schema frequently outside of the hook
269
- (e.g. in form validation or server responses).
270
-
271
- ### Error classes
272
-
273
- | Class | Thrown when |
274
- | ------------- | ------------------------------------ |
275
- | `CodecError` | Encoding or decoding fails |
276
- | `SchemaError` | Schema validation or migration fails |
277
-
278
- Both are passed to `defaultValue` factories so you can inspect or log the
279
- failure reason.
280
-
281
- ## Usage examples
282
-
283
- ### Cross-tab theme sync
284
-
285
- ```tsx
286
- const { value: theme, set } = useMnemonicKey<"light" | "dark">("theme", {
287
- defaultValue: "light",
288
- listenCrossTab: true,
289
- onChange: (t) => {
290
- document.documentElement.setAttribute("data-theme", t);
291
- },
292
- });
293
- ```
67
+ ## AI resources
294
68
 
295
- ### Error-aware defaults
296
-
297
- ```tsx
298
- import { useMnemonicKey, CodecError, SchemaError } from "react-mnemonic";
299
-
300
- const getDefault = (error?: CodecError | SchemaError) => {
301
- if (error instanceof CodecError) {
302
- console.warn("Corrupt stored data:", error.message);
303
- }
304
- if (error instanceof SchemaError) {
305
- console.warn("Schema validation failed:", error.message);
306
- }
307
- return { count: 0 };
308
- };
309
-
310
- const { value } = useMnemonicKey("counter", { defaultValue: getDefault });
311
- ```
312
-
313
- ## Schema modes and versioning
314
-
315
- Mnemonic supports optional schema versioning through `schemaMode` and an
316
- optional `schemaRegistry`.
317
-
318
- - `default`: Schemas are optional. Reads use a schema when one exists for the
319
- stored version, otherwise the hook codec. Writes use the highest registered
320
- schema for the key; if no schemas are registered, writes use an unversioned
321
- (v0) envelope.
322
- - `strict`: Every stored version must have a registered schema. Reads without a
323
- matching schema fall back to `defaultValue` with a `SchemaError`.
324
- Writes require a registered schema when any schemas exist, but fall back to
325
- a v0 envelope when the registry has none.
326
- - `autoschema`: Like `default`, but if no schema exists for a key, the first
327
- successful read infers and registers a v1 schema. Subsequent reads/writes use
328
- that schema.
329
-
330
- Version `0` is valid for schemas and migrations. Schemas at version `0` are
331
- treated like any other version.
332
-
333
- ### JSON Schema validation
334
-
335
- Schemas use a subset of JSON Schema for validation. The supported keywords are:
336
-
337
- - `type` (including array form for nullable types, e.g., `["string", "null"]`)
338
- - `enum`, `const`
339
- - `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`
340
- - `minLength`, `maxLength`
341
- - `properties`, `required`, `additionalProperties`
342
- - `items`, `minItems`, `maxItems`
343
-
344
- ```ts
345
- // Schema definition -- fully serializable JSON, no functions
346
- const schema: KeySchema = {
347
- key: "profile",
348
- version: 1,
349
- schema: {
350
- type: "object",
351
- properties: {
352
- name: { type: "string", minLength: 1 },
353
- email: { type: "string" },
354
- age: { type: "number", minimum: 0 },
355
- },
356
- required: ["name", "email"],
357
- },
358
- };
359
- ```
360
-
361
- ### Write-time migrations (normalizers)
362
-
363
- A migration where `fromVersion === toVersion` runs on every write, acting as a
364
- normalizer. This is useful for trimming whitespace, lowercasing strings, etc.
365
-
366
- ```ts
367
- const normalizer: MigrationRule = {
368
- key: "name",
369
- fromVersion: 1,
370
- toVersion: 1,
371
- migrate: (value) => String(value).trim().toLowerCase(),
372
- };
373
- ```
374
-
375
- ### Reconciliation
376
-
377
- Use `reconcile` when you want to keep persisted data but selectively enforce
378
- new application defaults after the value has been decoded and any read-time
379
- migrations have already run.
380
-
381
- ```ts
382
- const { value } = useMnemonicKey("preferences", {
383
- defaultValue: { theme: "dark", density: "comfortable", accents: true },
384
- reconcile: (persisted, { persistedVersion }) => ({
385
- ...persisted,
386
- accents: persistedVersion === 0 ? true : persisted.accents,
387
- }),
388
- });
389
- ```
390
-
391
- Use a schema migration when the stored shape must move from one explicit version
392
- to another. Use `reconcile` for conditional, field-level policy changes such as
393
- rolling out a new default while preserving the rest of a user's stored data.
394
-
395
- ### Structural migration helpers
396
-
397
- For layout-like data that already uses `id` and `children`, Mnemonic ships
398
- optional pure helpers for common idempotent migration steps:
399
-
400
- ```ts
401
- import { insertChildIfMissing, renameNode, dedupeChildrenBy } from "react-mnemonic";
402
-
403
- const migrated = dedupeChildrenBy(
404
- renameNode(insertChildIfMissing(layout, "sidebar", { id: "search", title: "Search" }), "prefs", "preferences"),
405
- (node) => node.id,
406
- );
407
- ```
408
-
409
- Use these inside your `MigrationRule.migrate` functions when you want repeatable
410
- tree edits without hand-writing the same traversal logic each time. See the
411
- [Schema Migration guide](https://thirtytwobits.github.io/react-mnemonic/docs/guides/schema-migration)
412
- for a cookbook example and custom adapter usage.
413
-
414
- ### Example schema registry
415
-
416
- A schema registry stores versioned schemas for each key, and resolves migration
417
- paths to upgrade stored data. For the common immutable case, use
418
- `createSchemaRegistry(...)` instead of hand-rolling the indexing boilerplate.
419
-
420
- ```tsx
421
- import {
422
- createSchemaRegistry,
423
- MnemonicProvider,
424
- useMnemonicKey,
425
- type KeySchema,
426
- type MigrationRule,
427
- } from "react-mnemonic";
428
-
429
- const schemas: KeySchema[] = [
430
- {
431
- key: "profile",
432
- version: 1,
433
- schema: {
434
- type: "object",
435
- properties: { name: { type: "string" }, email: { type: "string" } },
436
- required: ["name", "email"],
437
- },
438
- },
439
- {
440
- key: "profile",
441
- version: 2,
442
- schema: {
443
- type: "object",
444
- properties: {
445
- name: { type: "string" },
446
- email: { type: "string" },
447
- migratedAt: { type: "string" },
448
- },
449
- required: ["name", "email", "migratedAt"],
450
- },
451
- },
452
- ];
453
-
454
- const migrations: MigrationRule[] = [
455
- {
456
- key: "profile",
457
- fromVersion: 1,
458
- toVersion: 2,
459
- migrate: (value) => {
460
- const v1 = value as { name: string; email: string };
461
- return { ...v1, migratedAt: new Date().toISOString() };
462
- },
463
- },
464
- {
465
- key: "profile",
466
- fromVersion: 2,
467
- toVersion: 2,
468
- migrate: (value) => {
469
- const profile = value as { name: string; email: string; migratedAt: string };
470
- return { ...profile, email: profile.email.trim().toLowerCase() };
471
- },
472
- },
473
- ];
474
-
475
- const registry = createSchemaRegistry({
476
- schemas,
477
- migrations,
478
- });
479
-
480
- function ProfileEditor() {
481
- const { value, set } = useMnemonicKey<{ name: string; email: string; migratedAt: string }>("profile", {
482
- defaultValue: { name: "", email: "", migratedAt: "" },
483
- });
484
- return <input value={value.name} onChange={(e) => set({ ...value, name: e.target.value })} />;
485
- }
486
-
487
- <MnemonicProvider namespace="app" schemaMode="default" schemaRegistry={registry}>
488
- <ProfileEditor />
489
- </MnemonicProvider>;
490
- ```
491
-
492
- `createSchemaRegistry` validates duplicate schemas and ambiguous migration
493
- graphs up front. If you need runtime schema registration for
494
- `schemaMode="autoschema"`, keep a custom mutable `SchemaRegistry`
495
- implementation.
496
-
497
- ### Registry immutability
498
-
499
- In `default` and `strict` modes, the schema registry is treated as immutable for
500
- the lifetime of the provider. The hook caches registry lookups to keep read and
501
- write hot paths fast. To ship new schemas or migrations, publish a new app
502
- version and remount the provider.
503
-
504
- `autoschema` remains mutable because inferred schemas are registered at runtime.
505
-
506
- ### Custom storage backend
507
-
508
- ```tsx
509
- import { MnemonicProvider } from "react-mnemonic";
510
- import type { StorageLike } from "react-mnemonic";
511
-
512
- const idbStorage: StorageLike = {
513
- getItem: (key) => /* read from IndexedDB */,
514
- setItem: (key, value) => /* write to IndexedDB */,
515
- removeItem: (key) => /* delete from IndexedDB */,
516
- onExternalChange: (cb) => {
517
- const bc = new BroadcastChannel("my-app-sync");
518
- bc.onmessage = (e) => cb(e.data.keys);
519
- return () => bc.close();
520
- },
521
- };
522
-
523
- <MnemonicProvider namespace="my-app" storage={idbStorage}>
524
- <App />
525
- </MnemonicProvider>
526
- ```
527
-
528
- ### DevTools
529
-
530
- Enable the console inspector in development:
531
-
532
- ```tsx
533
- <MnemonicProvider namespace="app" enableDevTools={process.env.NODE_ENV === "development"}>
534
- ```
535
-
536
- Then in the browser console:
537
-
538
- ```js
539
- const app = window.__REACT_MNEMONIC_DEVTOOLS__?.resolve("app");
540
-
541
- app?.dump(); // table of all keys
542
- app?.get("theme"); // read a decoded value
543
- app?.set("theme", "dark"); // write
544
- app?.remove("theme"); // delete
545
- app?.keys(); // list all keys
546
- app?.clear(); // remove all keys
547
- ```
548
-
549
- ## TypeScript
550
-
551
- The library is written in strict TypeScript and ships its own declarations.
552
- All public types are re-exported from the package root:
553
-
554
- ```ts
555
- import type {
556
- Codec,
557
- StorageLike,
558
- MnemonicProviderOptions,
559
- MnemonicProviderProps,
560
- UseMnemonicKeyOptions,
561
- KeySchema,
562
- MigrationRule,
563
- MigrationPath,
564
- SchemaRegistry,
565
- SchemaMode,
566
- JsonSchema,
567
- JsonSchemaType,
568
- JsonSchemaValidationError,
569
- CompiledValidator,
570
- } from "react-mnemonic";
571
- ```
69
+ | Resource | Purpose |
70
+ | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
71
+ | [AI Docs](https://thirtytwobits.github.io/react-mnemonic/docs/ai) | Canonical invariants, decision matrix, recipes, anti-patterns, and setup guidance |
72
+ | [`llms.txt`](https://thirtytwobits.github.io/react-mnemonic/llms.txt) | Compact retrieval index for tight context windows |
73
+ | [`llms-full.txt`](https://thirtytwobits.github.io/react-mnemonic/llms-full.txt) | Long-form export for indexing and larger prompt contexts |
74
+ | [`ai-contract.json`](https://thirtytwobits.github.io/react-mnemonic/ai-contract.json) | Machine-readable persistence contract for tooling and agent integrations |
75
+ | [DeepWiki priorities](https://github.com/thirtytwobits/react-mnemonic/blob/main/.devin/wiki.json) | Steering file that points DeepWiki toward the highest-signal sources |
76
+ | [AI Assistant Setup](https://thirtytwobits.github.io/react-mnemonic/docs/ai/assistant-setup) | Generated instruction packs plus the documented MCP-friendly retrieval path |
572
77
 
573
- ## Disclaimer
78
+ ## Learn more
574
79
 
575
- THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
576
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
577
- FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. The authors make no guarantees
578
- regarding the reliability, availability, or suitability of this library for any
579
- particular use case. See the [MIT License](./LICENSE.md) for full terms.
80
+ - [Documentation home](https://thirtytwobits.github.io/react-mnemonic/)
81
+ - [Quick Start](https://thirtytwobits.github.io/react-mnemonic/docs/getting-started/quick-start)
82
+ - [Server Rendering](https://thirtytwobits.github.io/react-mnemonic/docs/guides/server-rendering)
83
+ - [Canonical Key Definitions](https://thirtytwobits.github.io/react-mnemonic/docs/guides/canonical-key-definitions)
84
+ - [Single Source of Truth Schemas](https://thirtytwobits.github.io/react-mnemonic/docs/guides/single-source-of-truth-schemas)
85
+ - [Schema Migration](https://thirtytwobits.github.io/react-mnemonic/docs/guides/schema-migration)
86
+ - [Auth-Aware Persistence](https://thirtytwobits.github.io/react-mnemonic/docs/guides/auth-aware-persistence)
87
+ - [Context7 Rankings](https://thirtytwobits.github.io/react-mnemonic/docs/guides/context7-rankings)
88
+ - [API Reference](https://thirtytwobits.github.io/react-mnemonic/docs/api)
89
+ - [AI Overview](https://thirtytwobits.github.io/react-mnemonic/docs/ai)
580
90
 
581
91
  ## License
582
92
 
583
- [MIT](./LICENSE.md) -- Copyright Scott Dixon
93
+ [MIT](https://github.com/thirtytwobits/react-mnemonic/blob/main/LICENSE.md)