@tldraw/store 4.1.0-canary.5b2a01989756 → 4.1.0-canary.62b1976714aa

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.
Files changed (72) hide show
  1. package/dist-cjs/index.d.ts +1884 -153
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/AtomMap.js +241 -1
  4. package/dist-cjs/lib/AtomMap.js.map +2 -2
  5. package/dist-cjs/lib/BaseRecord.js.map +2 -2
  6. package/dist-cjs/lib/ImmutableMap.js +141 -0
  7. package/dist-cjs/lib/ImmutableMap.js.map +2 -2
  8. package/dist-cjs/lib/IncrementalSetConstructor.js +45 -5
  9. package/dist-cjs/lib/IncrementalSetConstructor.js.map +2 -2
  10. package/dist-cjs/lib/RecordType.js +116 -21
  11. package/dist-cjs/lib/RecordType.js.map +2 -2
  12. package/dist-cjs/lib/RecordsDiff.js.map +2 -2
  13. package/dist-cjs/lib/Store.js +233 -39
  14. package/dist-cjs/lib/Store.js.map +2 -2
  15. package/dist-cjs/lib/StoreQueries.js +135 -22
  16. package/dist-cjs/lib/StoreQueries.js.map +2 -2
  17. package/dist-cjs/lib/StoreSchema.js +207 -2
  18. package/dist-cjs/lib/StoreSchema.js.map +2 -2
  19. package/dist-cjs/lib/StoreSideEffects.js +102 -10
  20. package/dist-cjs/lib/StoreSideEffects.js.map +2 -2
  21. package/dist-cjs/lib/executeQuery.js.map +2 -2
  22. package/dist-cjs/lib/migrate.js.map +2 -2
  23. package/dist-cjs/lib/setUtils.js.map +2 -2
  24. package/dist-esm/index.d.mts +1884 -153
  25. package/dist-esm/index.mjs +1 -1
  26. package/dist-esm/lib/AtomMap.mjs +241 -1
  27. package/dist-esm/lib/AtomMap.mjs.map +2 -2
  28. package/dist-esm/lib/BaseRecord.mjs.map +2 -2
  29. package/dist-esm/lib/ImmutableMap.mjs +141 -0
  30. package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
  31. package/dist-esm/lib/IncrementalSetConstructor.mjs +45 -5
  32. package/dist-esm/lib/IncrementalSetConstructor.mjs.map +2 -2
  33. package/dist-esm/lib/RecordType.mjs +116 -21
  34. package/dist-esm/lib/RecordType.mjs.map +2 -2
  35. package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
  36. package/dist-esm/lib/Store.mjs +233 -39
  37. package/dist-esm/lib/Store.mjs.map +2 -2
  38. package/dist-esm/lib/StoreQueries.mjs +135 -22
  39. package/dist-esm/lib/StoreQueries.mjs.map +2 -2
  40. package/dist-esm/lib/StoreSchema.mjs +207 -2
  41. package/dist-esm/lib/StoreSchema.mjs.map +2 -2
  42. package/dist-esm/lib/StoreSideEffects.mjs +102 -10
  43. package/dist-esm/lib/StoreSideEffects.mjs.map +2 -2
  44. package/dist-esm/lib/executeQuery.mjs.map +2 -2
  45. package/dist-esm/lib/migrate.mjs.map +2 -2
  46. package/dist-esm/lib/setUtils.mjs.map +2 -2
  47. package/package.json +3 -3
  48. package/src/lib/AtomMap.ts +241 -1
  49. package/src/lib/BaseRecord.test.ts +44 -0
  50. package/src/lib/BaseRecord.ts +118 -4
  51. package/src/lib/ImmutableMap.test.ts +103 -0
  52. package/src/lib/ImmutableMap.ts +212 -0
  53. package/src/lib/IncrementalSetConstructor.test.ts +111 -0
  54. package/src/lib/IncrementalSetConstructor.ts +63 -6
  55. package/src/lib/RecordType.ts +149 -25
  56. package/src/lib/RecordsDiff.test.ts +144 -0
  57. package/src/lib/RecordsDiff.ts +145 -10
  58. package/src/lib/Store.test.ts +827 -0
  59. package/src/lib/Store.ts +533 -67
  60. package/src/lib/StoreQueries.test.ts +627 -0
  61. package/src/lib/StoreQueries.ts +194 -27
  62. package/src/lib/StoreSchema.test.ts +226 -0
  63. package/src/lib/StoreSchema.ts +386 -8
  64. package/src/lib/StoreSideEffects.test.ts +239 -19
  65. package/src/lib/StoreSideEffects.ts +266 -19
  66. package/src/lib/devFreeze.test.ts +137 -0
  67. package/src/lib/executeQuery.test.ts +481 -0
  68. package/src/lib/executeQuery.ts +80 -2
  69. package/src/lib/migrate.test.ts +400 -0
  70. package/src/lib/migrate.ts +187 -14
  71. package/src/lib/setUtils.test.ts +105 -0
  72. package/src/lib/setUtils.ts +44 -4
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/RecordsDiff.ts"],
4
- "sourcesContent": ["import { objectMapEntries } from '@tldraw/utils'\nimport { IdOf, UnknownRecord } from './BaseRecord'\n\n/**\n * A diff describing the changes to a record.\n *\n * @public\n */\nexport interface RecordsDiff<R extends UnknownRecord> {\n\tadded: Record<IdOf<R>, R>\n\tupdated: Record<IdOf<R>, [from: R, to: R]>\n\tremoved: Record<IdOf<R>, R>\n}\n\n/** @internal */\nexport function createEmptyRecordsDiff<R extends UnknownRecord>(): RecordsDiff<R> {\n\treturn { added: {}, updated: {}, removed: {} } as RecordsDiff<R>\n}\n\n/** @public */\nexport function reverseRecordsDiff(diff: RecordsDiff<any>) {\n\tconst result: RecordsDiff<any> = { added: diff.removed, removed: diff.added, updated: {} }\n\tfor (const [from, to] of Object.values(diff.updated)) {\n\t\tresult.updated[from.id] = [to, from]\n\t}\n\treturn result\n}\n\n/**\n * Is a records diff empty?\n * @internal\n */\nexport function isRecordsDiffEmpty<T extends UnknownRecord>(diff: RecordsDiff<T>) {\n\treturn (\n\t\tObject.keys(diff.added).length === 0 &&\n\t\tObject.keys(diff.updated).length === 0 &&\n\t\tObject.keys(diff.removed).length === 0\n\t)\n}\n\n/**\n * Squash a collection of diffs into a single diff.\n *\n * @param diffs - An array of diffs to squash.\n * @param options - An optional object with a `mutateFirstDiff` property. If `mutateFirstDiff` is true, the first diff in the array will be mutated in-place.\n * @returns A single diff that represents the squashed diffs.\n * @public\n */\nexport function squashRecordDiffs<T extends UnknownRecord>(\n\tdiffs: RecordsDiff<T>[],\n\toptions?: {\n\t\tmutateFirstDiff?: boolean\n\t}\n): RecordsDiff<T> {\n\tconst result = options?.mutateFirstDiff\n\t\t? diffs[0]\n\t\t: ({ added: {}, removed: {}, updated: {} } as RecordsDiff<T>)\n\n\tsquashRecordDiffsMutable(result, options?.mutateFirstDiff ? diffs.slice(1) : diffs)\n\treturn result\n}\n\n/**\n * Apply the array `diffs` to the `target` diff, mutating it in-place.\n * @internal\n */\nexport function squashRecordDiffsMutable<T extends UnknownRecord>(\n\ttarget: RecordsDiff<T>,\n\tdiffs: RecordsDiff<T>[]\n): void {\n\tfor (const diff of diffs) {\n\t\tfor (const [id, value] of objectMapEntries(diff.added)) {\n\t\t\tif (target.removed[id]) {\n\t\t\t\tconst original = target.removed[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tif (original !== value) {\n\t\t\t\t\ttarget.updated[id] = [original, value]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget.added[id] = value\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, [_from, to]] of objectMapEntries(diff.updated)) {\n\t\t\tif (target.added[id]) {\n\t\t\t\ttarget.added[id] = to\n\t\t\t\tdelete target.updated[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (target.updated[id]) {\n\t\t\t\ttarget.updated[id] = [target.updated[id][0], to]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttarget.updated[id] = diff.updated[id]\n\t\t\tdelete target.removed[id]\n\t\t}\n\n\t\tfor (const [id, value] of objectMapEntries(diff.removed)) {\n\t\t\t// the same record was added in this diff sequence, just drop it\n\t\t\tif (target.added[id]) {\n\t\t\t\tdelete target.added[id]\n\t\t\t} else if (target.updated[id]) {\n\t\t\t\ttarget.removed[id] = target.updated[id][0]\n\t\t\t\tdelete target.updated[id]\n\t\t\t} else {\n\t\t\t\ttarget.removed[id] = value\n\t\t\t}\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiC;AAe1B,SAAS,yBAAkE;AACjF,SAAO,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAC9C;AAGO,SAAS,mBAAmB,MAAwB;AAC1D,QAAM,SAA2B,EAAE,OAAO,KAAK,SAAS,SAAS,KAAK,OAAO,SAAS,CAAC,EAAE;AACzF,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG;AACrD,WAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI;AAAA,EACpC;AACA,SAAO;AACR;AAMO,SAAS,mBAA4C,MAAsB;AACjF,SACC,OAAO,KAAK,KAAK,KAAK,EAAE,WAAW,KACnC,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW,KACrC,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW;AAEvC;AAUO,SAAS,kBACf,OACA,SAGiB;AACjB,QAAM,SAAS,SAAS,kBACrB,MAAM,CAAC,IACN,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAE1C,2BAAyB,QAAQ,SAAS,kBAAkB,MAAM,MAAM,CAAC,IAAI,KAAK;AAClF,SAAO;AACR;AAMO,SAAS,yBACf,QACA,OACO;AACP,aAAW,QAAQ,OAAO;AACzB,eAAW,CAAC,IAAI,KAAK,SAAK,+BAAiB,KAAK,KAAK,GAAG;AACvD,UAAI,OAAO,QAAQ,EAAE,GAAG;AACvB,cAAM,WAAW,OAAO,QAAQ,EAAE;AAClC,eAAO,OAAO,QAAQ,EAAE;AACxB,YAAI,aAAa,OAAO;AACvB,iBAAO,QAAQ,EAAE,IAAI,CAAC,UAAU,KAAK;AAAA,QACtC;AAAA,MACD,OAAO;AACN,eAAO,MAAM,EAAE,IAAI;AAAA,MACpB;AAAA,IACD;AAEA,eAAW,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAK,+BAAiB,KAAK,OAAO,GAAG;AAC/D,UAAI,OAAO,MAAM,EAAE,GAAG;AACrB,eAAO,MAAM,EAAE,IAAI;AACnB,eAAO,OAAO,QAAQ,EAAE;AACxB,eAAO,OAAO,QAAQ,EAAE;AACxB;AAAA,MACD;AACA,UAAI,OAAO,QAAQ,EAAE,GAAG;AACvB,eAAO,QAAQ,EAAE,IAAI,CAAC,OAAO,QAAQ,EAAE,EAAE,CAAC,GAAG,EAAE;AAC/C,eAAO,OAAO,QAAQ,EAAE;AACxB;AAAA,MACD;AAEA,aAAO,QAAQ,EAAE,IAAI,KAAK,QAAQ,EAAE;AACpC,aAAO,OAAO,QAAQ,EAAE;AAAA,IACzB;AAEA,eAAW,CAAC,IAAI,KAAK,SAAK,+BAAiB,KAAK,OAAO,GAAG;AAEzD,UAAI,OAAO,MAAM,EAAE,GAAG;AACrB,eAAO,OAAO,MAAM,EAAE;AAAA,MACvB,WAAW,OAAO,QAAQ,EAAE,GAAG;AAC9B,eAAO,QAAQ,EAAE,IAAI,OAAO,QAAQ,EAAE,EAAE,CAAC;AACzC,eAAO,OAAO,QAAQ,EAAE;AAAA,MACzB,OAAO;AACN,eAAO,QAAQ,EAAE,IAAI;AAAA,MACtB;AAAA,IACD;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import { objectMapEntries } from '@tldraw/utils'\nimport { IdOf, UnknownRecord } from './BaseRecord'\n\n/**\n * A diff describing the changes to records, containing collections of records that were added,\n * updated, or removed. This is the fundamental data structure used throughout the store system\n * to track and communicate changes.\n *\n * @example\n * ```ts\n * const diff: RecordsDiff<Book> = {\n * added: {\n * 'book:1': { id: 'book:1', typeName: 'book', title: 'New Book' }\n * },\n * updated: {\n * 'book:2': [\n * { id: 'book:2', typeName: 'book', title: 'Old Title' }, // from\n * { id: 'book:2', typeName: 'book', title: 'New Title' } // to\n * ]\n * },\n * removed: {\n * 'book:3': { id: 'book:3', typeName: 'book', title: 'Deleted Book' }\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface RecordsDiff<R extends UnknownRecord> {\n\t/** Records that were created, keyed by their ID */\n\tadded: Record<IdOf<R>, R>\n\t/** Records that were modified, keyed by their ID. Each entry contains [from, to] tuple */\n\tupdated: Record<IdOf<R>, [from: R, to: R]>\n\t/** Records that were deleted, keyed by their ID */\n\tremoved: Record<IdOf<R>, R>\n}\n\n/**\n * Creates an empty RecordsDiff with no added, updated, or removed records.\n * This is useful as a starting point when building diffs programmatically.\n *\n * @returns An empty RecordsDiff with all collections initialized to empty objects\n * @example\n * ```ts\n * const emptyDiff = createEmptyRecordsDiff<Book>()\n * // Result: { added: {}, updated: {}, removed: {} }\n * ```\n *\n * @internal\n */\nexport function createEmptyRecordsDiff<R extends UnknownRecord>(): RecordsDiff<R> {\n\treturn { added: {}, updated: {}, removed: {} } as RecordsDiff<R>\n}\n\n/**\n * Creates the inverse of a RecordsDiff, effectively reversing all changes.\n * Added records become removed, removed records become added, and updated records\n * have their from/to values swapped. This is useful for implementing undo operations.\n *\n * @param diff - The diff to reverse\n * @returns A new RecordsDiff that represents the inverse of the input diff\n * @example\n * ```ts\n * const originalDiff: RecordsDiff<Book> = {\n * added: { 'book:1': newBook },\n * updated: { 'book:2': [oldBook, updatedBook] },\n * removed: { 'book:3': deletedBook }\n * }\n *\n * const reversedDiff = reverseRecordsDiff(originalDiff)\n * // Result: {\n * // added: { 'book:3': deletedBook },\n * // updated: { 'book:2': [updatedBook, oldBook] },\n * // removed: { 'book:1': newBook }\n * // }\n * ```\n *\n * @public\n */\nexport function reverseRecordsDiff(diff: RecordsDiff<any>) {\n\tconst result: RecordsDiff<any> = { added: diff.removed, removed: diff.added, updated: {} }\n\tfor (const [from, to] of Object.values(diff.updated)) {\n\t\tresult.updated[from.id] = [to, from]\n\t}\n\treturn result\n}\n\n/**\n * Checks whether a RecordsDiff contains any changes. A diff is considered empty\n * if it has no added, updated, or removed records.\n *\n * @param diff - The diff to check\n * @returns True if the diff contains no changes, false otherwise\n * @example\n * ```ts\n * const emptyDiff = createEmptyRecordsDiff<Book>()\n * console.log(isRecordsDiffEmpty(emptyDiff)) // true\n *\n * const nonEmptyDiff: RecordsDiff<Book> = {\n * added: { 'book:1': someBook },\n * updated: {},\n * removed: {}\n * }\n * console.log(isRecordsDiffEmpty(nonEmptyDiff)) // false\n * ```\n *\n * @public\n */\nexport function isRecordsDiffEmpty<T extends UnknownRecord>(diff: RecordsDiff<T>) {\n\treturn (\n\t\tObject.keys(diff.added).length === 0 &&\n\t\tObject.keys(diff.updated).length === 0 &&\n\t\tObject.keys(diff.removed).length === 0\n\t)\n}\n\n/**\n * Combines multiple RecordsDiff objects into a single consolidated diff.\n * This function intelligently merges changes, handling cases where the same record\n * is modified multiple times across different diffs. For example, if a record is\n * added in one diff and then updated in another, the result will show it as added\n * with the final state.\n *\n * @param diffs - An array of diffs to combine into a single diff\n * @param options - Configuration options for the squashing operation\n * - mutateFirstDiff - If true, modifies the first diff in place instead of creating a new one\n * @returns A single diff that represents the cumulative effect of all input diffs\n * @example\n * ```ts\n * const diff1: RecordsDiff<Book> = {\n * added: { 'book:1': { id: 'book:1', title: 'New Book' } },\n * updated: {},\n * removed: {}\n * }\n *\n * const diff2: RecordsDiff<Book> = {\n * added: {},\n * updated: { 'book:1': [{ id: 'book:1', title: 'New Book' }, { id: 'book:1', title: 'Updated Title' }] },\n * removed: {}\n * }\n *\n * const squashed = squashRecordDiffs([diff1, diff2])\n * // Result: {\n * // added: { 'book:1': { id: 'book:1', title: 'Updated Title' } },\n * // updated: {},\n * // removed: {}\n * // }\n * ```\n *\n * @public\n */\nexport function squashRecordDiffs<T extends UnknownRecord>(\n\tdiffs: RecordsDiff<T>[],\n\toptions?: {\n\t\tmutateFirstDiff?: boolean\n\t}\n): RecordsDiff<T> {\n\tconst result = options?.mutateFirstDiff\n\t\t? diffs[0]\n\t\t: ({ added: {}, removed: {}, updated: {} } as RecordsDiff<T>)\n\n\tsquashRecordDiffsMutable(result, options?.mutateFirstDiff ? diffs.slice(1) : diffs)\n\treturn result\n}\n\n/**\n * Applies an array of diffs to a target diff by mutating the target in-place.\n * This is the core implementation used by squashRecordDiffs. It handles complex\n * scenarios where records move between added/updated/removed states across multiple diffs.\n *\n * The function processes each diff sequentially, applying the following logic:\n * - Added records: If the record was previously removed, convert to an update; otherwise add it\n * - Updated records: Chain updates together, preserving the original 'from' state\n * - Removed records: If the record was added in this sequence, cancel both operations\n *\n * @param target - The diff to modify in-place (will be mutated)\n * @param diffs - Array of diffs to apply to the target\n * @example\n * ```ts\n * const targetDiff: RecordsDiff<Book> = {\n * added: {},\n * updated: {},\n * removed: { 'book:1': oldBook }\n * }\n *\n * const newDiffs = [{\n * added: { 'book:1': newBook },\n * updated: {},\n * removed: {}\n * }]\n *\n * squashRecordDiffsMutable(targetDiff, newDiffs)\n * // targetDiff is now: {\n * // added: {},\n * // updated: { 'book:1': [oldBook, newBook] },\n * // removed: {}\n * // }\n * ```\n *\n * @internal\n */\nexport function squashRecordDiffsMutable<T extends UnknownRecord>(\n\ttarget: RecordsDiff<T>,\n\tdiffs: RecordsDiff<T>[]\n): void {\n\tfor (const diff of diffs) {\n\t\tfor (const [id, value] of objectMapEntries(diff.added)) {\n\t\t\tif (target.removed[id]) {\n\t\t\t\tconst original = target.removed[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tif (original !== value) {\n\t\t\t\t\ttarget.updated[id] = [original, value]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttarget.added[id] = value\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, [_from, to]] of objectMapEntries(diff.updated)) {\n\t\t\tif (target.added[id]) {\n\t\t\t\ttarget.added[id] = to\n\t\t\t\tdelete target.updated[id]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (target.updated[id]) {\n\t\t\t\ttarget.updated[id] = [target.updated[id][0], to]\n\t\t\t\tdelete target.removed[id]\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ttarget.updated[id] = diff.updated[id]\n\t\t\tdelete target.removed[id]\n\t\t}\n\n\t\tfor (const [id, value] of objectMapEntries(diff.removed)) {\n\t\t\t// the same record was added in this diff sequence, just drop it\n\t\t\tif (target.added[id]) {\n\t\t\t\tdelete target.added[id]\n\t\t\t} else if (target.updated[id]) {\n\t\t\t\ttarget.removed[id] = target.updated[id][0]\n\t\t\t\tdelete target.updated[id]\n\t\t\t} else {\n\t\t\t\ttarget.removed[id] = value\n\t\t\t}\n\t\t}\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAiC;AAkD1B,SAAS,yBAAkE;AACjF,SAAO,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAC9C;AA2BO,SAAS,mBAAmB,MAAwB;AAC1D,QAAM,SAA2B,EAAE,OAAO,KAAK,SAAS,SAAS,KAAK,OAAO,SAAS,CAAC,EAAE;AACzF,aAAW,CAAC,MAAM,EAAE,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG;AACrD,WAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI;AAAA,EACpC;AACA,SAAO;AACR;AAuBO,SAAS,mBAA4C,MAAsB;AACjF,SACC,OAAO,KAAK,KAAK,KAAK,EAAE,WAAW,KACnC,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW,KACrC,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW;AAEvC;AAqCO,SAAS,kBACf,OACA,SAGiB;AACjB,QAAM,SAAS,SAAS,kBACrB,MAAM,CAAC,IACN,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAE1C,2BAAyB,QAAQ,SAAS,kBAAkB,MAAM,MAAM,CAAC,IAAI,KAAK;AAClF,SAAO;AACR;AAsCO,SAAS,yBACf,QACA,OACO;AACP,aAAW,QAAQ,OAAO;AACzB,eAAW,CAAC,IAAI,KAAK,SAAK,+BAAiB,KAAK,KAAK,GAAG;AACvD,UAAI,OAAO,QAAQ,EAAE,GAAG;AACvB,cAAM,WAAW,OAAO,QAAQ,EAAE;AAClC,eAAO,OAAO,QAAQ,EAAE;AACxB,YAAI,aAAa,OAAO;AACvB,iBAAO,QAAQ,EAAE,IAAI,CAAC,UAAU,KAAK;AAAA,QACtC;AAAA,MACD,OAAO;AACN,eAAO,MAAM,EAAE,IAAI;AAAA,MACpB;AAAA,IACD;AAEA,eAAW,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAK,+BAAiB,KAAK,OAAO,GAAG;AAC/D,UAAI,OAAO,MAAM,EAAE,GAAG;AACrB,eAAO,MAAM,EAAE,IAAI;AACnB,eAAO,OAAO,QAAQ,EAAE;AACxB,eAAO,OAAO,QAAQ,EAAE;AACxB;AAAA,MACD;AACA,UAAI,OAAO,QAAQ,EAAE,GAAG;AACvB,eAAO,QAAQ,EAAE,IAAI,CAAC,OAAO,QAAQ,EAAE,EAAE,CAAC,GAAG,EAAE;AAC/C,eAAO,OAAO,QAAQ,EAAE;AACxB;AAAA,MACD;AAEA,aAAO,QAAQ,EAAE,IAAI,KAAK,QAAQ,EAAE;AACpC,aAAO,OAAO,QAAQ,EAAE;AAAA,IACzB;AAEA,eAAW,CAAC,IAAI,KAAK,SAAK,+BAAiB,KAAK,OAAO,GAAG;AAEzD,UAAI,OAAO,MAAM,EAAE,GAAG;AACrB,eAAO,OAAO,MAAM,EAAE;AAAA,MACvB,WAAW,OAAO,QAAQ,EAAE,GAAG;AAC9B,eAAO,QAAQ,EAAE,IAAI,OAAO,QAAQ,EAAE,EAAE,CAAC;AACzC,eAAO,OAAO,QAAQ,EAAE;AAAA,MACzB,OAAO;AACN,eAAO,QAAQ,EAAE,IAAI;AAAA,MACtB;AAAA,IACD;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -31,7 +31,9 @@ var import_StoreSideEffects = require("./StoreSideEffects");
31
31
  var import_devFreeze = require("./devFreeze");
32
32
  class Store {
33
33
  /**
34
- * The random id of the store.
34
+ * The unique identifier of the store instance.
35
+ *
36
+ * @public
35
37
  */
36
38
  id;
37
39
  /**
@@ -51,7 +53,19 @@ class Store {
51
53
  historyLength: 1e3
52
54
  });
53
55
  /**
54
- * A StoreQueries instance for this store.
56
+ * Reactive queries and indexes for efficiently accessing store data.
57
+ * Provides methods for filtering, indexing, and subscribing to subsets of records.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * // Create an index by a property
62
+ * const booksByAuthor = store.query.index('book', 'author')
63
+ *
64
+ * // Get records matching criteria
65
+ * const inStockBooks = store.query.records('book', () => ({
66
+ * inStock: { eq: true }
67
+ * }))
68
+ * ```
55
69
  *
56
70
  * @public
57
71
  * @readonly
@@ -83,10 +97,53 @@ class Store {
83
97
  */
84
98
  cancelHistoryReactor() {
85
99
  }
100
+ /**
101
+ * The schema that defines the structure and validation rules for records in this store.
102
+ *
103
+ * @public
104
+ */
86
105
  schema;
106
+ /**
107
+ * Custom properties associated with this store instance.
108
+ *
109
+ * @public
110
+ */
87
111
  props;
112
+ /**
113
+ * A mapping of record scopes to the set of record type names that belong to each scope.
114
+ * Used to filter records by their persistence and synchronization behavior.
115
+ *
116
+ * @public
117
+ */
88
118
  scopedTypes;
119
+ /**
120
+ * Side effects manager that handles lifecycle events for record operations.
121
+ * Allows registration of callbacks for create, update, delete, and validation events.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * store.sideEffects.registerAfterCreateHandler('book', (book) => {
126
+ * console.log('Book created:', book.title)
127
+ * })
128
+ * ```
129
+ *
130
+ * @public
131
+ */
89
132
  sideEffects = new import_StoreSideEffects.StoreSideEffects(this);
133
+ /**
134
+ * Creates a new Store instance.
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * const store = new Store({
139
+ * schema: StoreSchema.create({ book: Book }),
140
+ * props: { appName: 'MyLibrary' },
141
+ * initialData: savedData
142
+ * })
143
+ * ```
144
+ *
145
+ * @param config - Configuration object for the store
146
+ */
90
147
  constructor(config) {
91
148
  const { initialData, schema, id } = config;
92
149
  this.id = id ?? (0, import_utils.uniqueId)();
@@ -195,10 +252,21 @@ class Store {
195
252
  this.allRecords().forEach((record) => this.schema.validateRecord(this, record, phase, null));
196
253
  }
197
254
  /**
198
- * Add some records to the store. It's an error if they already exist.
255
+ * Add or update records in the store. If a record with the same ID already exists, it will be updated.
256
+ * Otherwise, a new record will be created.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * // Add new records
261
+ * const book = Book.create({ title: 'Lathe Of Heaven', author: 'Le Guin' })
262
+ * store.put([book])
199
263
  *
200
- * @param records - The records to add.
201
- * @param phaseOverride - The phase override.
264
+ * // Update existing record
265
+ * store.put([{ ...book, title: 'The Lathe of Heaven' }])
266
+ * ```
267
+ *
268
+ * @param records - The records to add or update
269
+ * @param phaseOverride - Override the validation phase (used internally)
202
270
  * @public
203
271
  */
204
272
  put(records, phaseOverride) {
@@ -249,9 +317,18 @@ class Store {
249
317
  });
250
318
  }
251
319
  /**
252
- * Remove some records from the store via their ids.
320
+ * Remove records from the store by their IDs.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * // Remove a single record
325
+ * store.remove([book.id])
326
+ *
327
+ * // Remove multiple records
328
+ * store.remove([book1.id, book2.id, book3.id])
329
+ * ```
253
330
  *
254
- * @param ids - The ids of the records to remove.
331
+ * @param ids - The IDs of the records to remove
255
332
  * @public
256
333
  */
257
334
  remove(ids) {
@@ -278,28 +355,56 @@ class Store {
278
355
  });
279
356
  }
280
357
  /**
281
- * Get the value of a store record by its id.
358
+ * Get a record by its ID. This creates a reactive subscription to the record.
282
359
  *
283
- * @param id - The id of the record to get.
360
+ * @example
361
+ * ```ts
362
+ * const book = store.get(bookId)
363
+ * if (book) {
364
+ * console.log(book.title)
365
+ * }
366
+ * ```
367
+ *
368
+ * @param id - The ID of the record to get
369
+ * @returns The record if it exists, undefined otherwise
284
370
  * @public
285
371
  */
286
372
  get(id) {
287
373
  return this.records.get(id);
288
374
  }
289
375
  /**
290
- * Get the value of a store record by its id without updating its epoch.
376
+ * Get a record by its ID without creating a reactive subscription.
377
+ * Use this when you need to access a record but don't want reactive updates.
291
378
  *
292
- * @param id - The id of the record to get.
379
+ * @example
380
+ * ```ts
381
+ * // Won't trigger reactive updates when this record changes
382
+ * const book = store.unsafeGetWithoutCapture(bookId)
383
+ * ```
384
+ *
385
+ * @param id - The ID of the record to get
386
+ * @returns The record if it exists, undefined otherwise
293
387
  * @public
294
388
  */
295
389
  unsafeGetWithoutCapture(id) {
296
390
  return this.records.__unsafe__getWithoutCapture(id);
297
391
  }
298
392
  /**
299
- * Creates a JSON payload from the record store.
393
+ * Serialize the store's records to a plain JavaScript object.
394
+ * Only includes records matching the specified scope.
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * // Serialize only document records (default)
399
+ * const documentData = store.serialize('document')
300
400
  *
301
- * @param scope - The scope of records to serialize. Defaults to 'document'.
302
- * @returns The record store snapshot as a JSON payload.
401
+ * // Serialize all records
402
+ * const allData = store.serialize('all')
403
+ * ```
404
+ *
405
+ * @param scope - The scope of records to serialize. Defaults to 'document'
406
+ * @returns The serialized store data
407
+ * @public
303
408
  */
304
409
  serialize(scope = "document") {
305
410
  const result = {};
@@ -312,14 +417,20 @@ class Store {
312
417
  }
313
418
  /**
314
419
  * Get a serialized snapshot of the store and its schema.
420
+ * This includes both the data and schema information needed for proper migration.
315
421
  *
422
+ * @example
316
423
  * ```ts
317
424
  * const snapshot = store.getStoreSnapshot()
318
- * store.loadStoreSnapshot(snapshot)
319
- * ```
425
+ * localStorage.setItem('myApp', JSON.stringify(snapshot))
320
426
  *
321
- * @param scope - The scope of records to serialize. Defaults to 'document'.
427
+ * // Later...
428
+ * const saved = JSON.parse(localStorage.getItem('myApp'))
429
+ * store.loadStoreSnapshot(saved)
430
+ * ```
322
431
  *
432
+ * @param scope - The scope of records to serialize. Defaults to 'document'
433
+ * @returns A snapshot containing both store data and schema information
323
434
  * @public
324
435
  */
325
436
  getStoreSnapshot(scope = "document") {
@@ -329,14 +440,18 @@ class Store {
329
440
  };
330
441
  }
331
442
  /**
332
- * Migrate a serialized snapshot of the store and its schema.
443
+ * Migrate a serialized snapshot to the current schema version.
444
+ * This applies any necessary migrations to bring old data up to date.
333
445
  *
446
+ * @example
334
447
  * ```ts
335
- * const snapshot = store.getStoreSnapshot()
336
- * store.migrateSnapshot(snapshot)
448
+ * const oldSnapshot = JSON.parse(localStorage.getItem('myApp'))
449
+ * const migratedSnapshot = store.migrateSnapshot(oldSnapshot)
337
450
  * ```
338
451
  *
339
- * @param snapshot - The snapshot to load.
452
+ * @param snapshot - The snapshot to migrate
453
+ * @returns The migrated snapshot with current schema version
454
+ * @throws Error if migration fails
340
455
  * @public
341
456
  */
342
457
  migrateSnapshot(snapshot) {
@@ -350,14 +465,17 @@ class Store {
350
465
  };
351
466
  }
352
467
  /**
353
- * Load a serialized snapshot.
468
+ * Load a serialized snapshot into the store, replacing all current data.
469
+ * The snapshot will be automatically migrated to the current schema version if needed.
354
470
  *
471
+ * @example
355
472
  * ```ts
356
- * const snapshot = store.getStoreSnapshot()
473
+ * const snapshot = JSON.parse(localStorage.getItem('myApp'))
357
474
  * store.loadStoreSnapshot(snapshot)
358
475
  * ```
359
476
  *
360
- * @param snapshot - The snapshot to load.
477
+ * @param snapshot - The snapshot to load
478
+ * @throws Error if migration fails or snapshot is invalid
361
479
  * @public
362
480
  */
363
481
  loadStoreSnapshot(snapshot) {
@@ -378,16 +496,28 @@ class Store {
378
496
  }
379
497
  }
380
498
  /**
381
- * Get an array of all values in the store.
499
+ * Get an array of all records in the store.
382
500
  *
383
- * @returns An array of all values in the store.
501
+ * @example
502
+ * ```ts
503
+ * const allRecords = store.allRecords()
504
+ * const books = allRecords.filter(r => r.typeName === 'book')
505
+ * ```
506
+ *
507
+ * @returns An array containing all records in the store
384
508
  * @public
385
509
  */
386
510
  allRecords() {
387
511
  return Array.from(this.records.values());
388
512
  }
389
513
  /**
390
- * Removes all records from the store.
514
+ * Remove all records from the store.
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * store.clear()
519
+ * console.log(store.allRecords().length) // 0
520
+ * ```
391
521
  *
392
522
  * @public
393
523
  */
@@ -395,11 +525,20 @@ class Store {
395
525
  this.remove(Array.from(this.records.keys()));
396
526
  }
397
527
  /**
398
- * Update a record. To update multiple records at once, use the `update` method of the
399
- * `TypedStore` class.
528
+ * Update a single record using an updater function. To update multiple records at once,
529
+ * use the `update` method of the `TypedStore` class.
400
530
  *
401
- * @param id - The id of the record to update.
402
- * @param updater - A function that updates the record.
531
+ * @example
532
+ * ```ts
533
+ * store.update(book.id, (book) => ({
534
+ * ...book,
535
+ * title: 'Updated Title'
536
+ * }))
537
+ * ```
538
+ *
539
+ * @param id - The ID of the record to update
540
+ * @param updater - A function that receives the current record and returns the updated record
541
+ * @public
403
542
  */
404
543
  update(id, updater) {
405
544
  const existing = this.unsafeGetWithoutCapture(id);
@@ -410,20 +549,47 @@ class Store {
410
549
  this.put([updater(existing)]);
411
550
  }
412
551
  /**
413
- * Get whether the record store has a id.
552
+ * Check whether a record with the given ID exists in the store.
414
553
  *
415
- * @param id - The id of the record to check.
554
+ * @example
555
+ * ```ts
556
+ * if (store.has(bookId)) {
557
+ * console.log('Book exists!')
558
+ * }
559
+ * ```
560
+ *
561
+ * @param id - The ID of the record to check
562
+ * @returns True if the record exists, false otherwise
416
563
  * @public
417
564
  */
418
565
  has(id) {
419
566
  return this.records.has(id);
420
567
  }
421
568
  /**
422
- * Add a new listener to the store.
569
+ * Add a listener that will be called when the store changes.
570
+ * Returns a function to remove the listener.
571
+ *
572
+ * @example
573
+ * ```ts
574
+ * const removeListener = store.listen((entry) => {
575
+ * console.log('Changes:', entry.changes)
576
+ * console.log('Source:', entry.source)
577
+ * })
578
+ *
579
+ * // Listen only to user changes to document records
580
+ * const removeDocumentListener = store.listen(
581
+ * (entry) => console.log('Document changed:', entry),
582
+ * { source: 'user', scope: 'document' }
583
+ * )
423
584
  *
424
- * @param onHistory - The listener to call when the store updates.
425
- * @param filters - Filters to apply to the listener.
426
- * @returns A function to remove the listener.
585
+ * // Later, remove the listener
586
+ * removeListener()
587
+ * ```
588
+ *
589
+ * @param onHistory - The listener function to call when changes occur
590
+ * @param filters - Optional filters to control when the listener is called
591
+ * @returns A function that removes the listener when called
592
+ * @public
427
593
  */
428
594
  listen(onHistory, filters) {
429
595
  this._flushHistory();
@@ -448,9 +614,19 @@ class Store {
448
614
  }
449
615
  isMergingRemoteChanges = false;
450
616
  /**
451
- * Merge changes from a remote source
617
+ * Merge changes from a remote source. Changes made within the provided function
618
+ * will be marked with source 'remote' instead of 'user'.
619
+ *
620
+ * @example
621
+ * ```ts
622
+ * // Changes from sync/collaboration
623
+ * store.mergeRemoteChanges(() => {
624
+ * store.put(remoteRecords)
625
+ * store.remove(deletedIds)
626
+ * })
627
+ * ```
452
628
  *
453
- * @param fn - A function that merges the external changes.
629
+ * @param fn - A function that applies the remote changes
454
630
  * @public
455
631
  */
456
632
  mergeRemoteChanges(fn) {
@@ -679,26 +855,44 @@ function squashHistoryEntries(entries) {
679
855
  class HistoryAccumulator {
680
856
  _history = [];
681
857
  _interceptors = /* @__PURE__ */ new Set();
858
+ /**
859
+ * Add an interceptor that will be called for each history entry.
860
+ * Returns a function to remove the interceptor.
861
+ */
682
862
  addInterceptor(fn) {
683
863
  this._interceptors.add(fn);
684
864
  return () => {
685
865
  this._interceptors.delete(fn);
686
866
  };
687
867
  }
868
+ /**
869
+ * Add a history entry to the accumulator.
870
+ * Calls all registered interceptors with the entry.
871
+ */
688
872
  add(entry) {
689
873
  this._history.push(entry);
690
874
  for (const interceptor of this._interceptors) {
691
875
  interceptor(entry);
692
876
  }
693
877
  }
878
+ /**
879
+ * Flush all accumulated history entries, squashing adjacent entries from the same source.
880
+ * Clears the internal history buffer.
881
+ */
694
882
  flush() {
695
883
  const history = squashHistoryEntries(this._history);
696
884
  this._history = [];
697
885
  return history;
698
886
  }
887
+ /**
888
+ * Clear all accumulated history entries without flushing.
889
+ */
699
890
  clear() {
700
891
  this._history = [];
701
892
  }
893
+ /**
894
+ * Check if there are any accumulated history entries.
895
+ */
702
896
  hasChanges() {
703
897
  return this._history.length > 0;
704
898
  }