@tldraw/store 4.6.0-next.5a871ec02ff3 → 4.6.0-next.d15997ff5a4b
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/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/AtomMap.js +1 -1
- package/dist-cjs/lib/AtomMap.js.map +1 -1
- package/dist-cjs/lib/AtomSet.js +1 -1
- package/dist-cjs/lib/AtomSet.js.map +1 -1
- package/dist-cjs/lib/RecordType.js.map +1 -1
- package/dist-cjs/lib/Store.js +1 -1
- package/dist-cjs/lib/Store.js.map +2 -2
- package/dist-cjs/lib/migrate.js.map +1 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/AtomMap.mjs +1 -1
- package/dist-esm/lib/AtomMap.mjs.map +1 -1
- package/dist-esm/lib/AtomSet.mjs +1 -1
- package/dist-esm/lib/AtomSet.mjs.map +1 -1
- package/dist-esm/lib/RecordType.mjs.map +1 -1
- package/dist-esm/lib/Store.mjs +1 -1
- package/dist-esm/lib/Store.mjs.map +2 -2
- package/dist-esm/lib/migrate.mjs.map +1 -1
- package/package.json +4 -4
- package/src/lib/AtomMap.ts +1 -1
- package/src/lib/AtomSet.ts +1 -1
- package/src/lib/RecordType.ts +1 -1
- package/src/lib/Store.ts +2 -2
- package/src/lib/StoreSchema.test.ts +1 -1
- package/src/lib/migrate.test.ts +1 -1
- package/src/lib/migrate.ts +8 -8
- package/src/lib/test/dependsOn.test.ts +1 -1
- package/src/lib/test/getMigrationsSince.test.ts +1 -1
- package/src/lib/test/migratePersistedRecord.test.ts +1 -1
- package/src/lib/test/testSchema.v1.ts +1 -1
package/dist-cjs/index.js
CHANGED
|
@@ -56,7 +56,7 @@ var import_StoreSchema = require("./lib/StoreSchema");
|
|
|
56
56
|
var import_StoreSideEffects = require("./lib/StoreSideEffects");
|
|
57
57
|
(0, import_utils.registerTldrawLibraryVersion)(
|
|
58
58
|
"@tldraw/store",
|
|
59
|
-
"4.6.0-next.
|
|
59
|
+
"4.6.0-next.d15997ff5a4b",
|
|
60
60
|
"cjs"
|
|
61
61
|
);
|
|
62
62
|
//# sourceMappingURL=index.js.map
|
package/dist-cjs/lib/AtomMap.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/AtomMap.ts"],
|
|
4
|
-
"sourcesContent": ["import { atom, Atom, transact, UNINITIALIZED } from '@tldraw/state'\nimport { assert } from '@tldraw/utils'\nimport { emptyMap, ImmutableMap } from './ImmutableMap'\n\n/**\n * A drop-in replacement for Map that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomMap<K, V> implements Map<K, V> {\n\tprivate atoms: Atom<ImmutableMap<K, Atom<V | UNINITIALIZED>>>\n\n\t/**\n\t * Creates a new AtomMap instance.\n\t *\n\t * name - A unique name for this map, used for atom identification\n\t * entries - Optional initial entries to populate the map with\n\t * @example\n\t * ```ts\n\t * // Create an empty map\n\t * const map = new AtomMap('userMap')\n\t *\n\t * // Create a map with initial data\n\t * const initialData: [string, number][] = [['a', 1], ['b', 2]]\n\t * const mapWithData = new AtomMap('numbersMap', initialData)\n\t * ```\n\t */\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tentries?: Iterable<readonly [K, V]>\n\t) {\n\t\tlet atoms = emptyMap<K, Atom<V>>()\n\t\tif (entries) {\n\t\t\tatoms = atoms.withMutations((atoms) => {\n\t\t\t\tfor (const [k, v] of entries) {\n\t\t\t\t\tatoms.set(k, atom(`${name}:${String(k)}`, v))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tthis.atoms = atom(`${name}:atoms`, atoms)\n\t}\n\n\t/**\n\t * Retrieves the underlying atom for a given key.\n\t *\n\t * @param key - The key to retrieve the atom for\n\t * @returns The atom containing the value, or undefined if the key doesn't exist\n\t * @internal\n\t */\n\tgetAtom(key: K): Atom<V | UNINITIALIZED> | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\t// if the value is missing, we want to track whether it's in the present keys set\n\t\t\tthis.atoms.get()\n\t\t\treturn undefined\n\t\t}\n\t\treturn valueAtom\n\t}\n\n\t/**\n\t * Gets the value associated with a key. Returns undefined if the key doesn't exist.\n\t * This method is reactive and will cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice')\n\t * console.log(map.get('name')) // 'Alice'\n\t * console.log(map.get('missing')) // undefined\n\t * ```\n\t */\n\tget(key: K): V | undefined {\n\t\tconst value = this.getAtom(key)?.get()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Gets the value associated with a key without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 42)\n\t * const value = map.__unsafe__getWithoutCapture('count') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__getWithoutCapture(key: K): V | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return undefined\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.has('name')) // false\n\t * map.set('name', 'Alice')\n\t * console.log(map.has('name')) // true\n\t * ```\n\t */\n\thas(key: K): boolean {\n\t\tconst valueAtom = this.getAtom(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\t\treturn valueAtom.get() !== UNINITIALIZED\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('active', true)\n\t * const exists = map.__unsafe__hasWithoutCapture('active') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__hasWithoutCapture(key: K): boolean {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return false\n\t\tassert(valueAtom.__unsafe__getWithoutCapture() !== UNINITIALIZED)\n\t\treturn true\n\t}\n\n\t/**\n\t * Sets a value for the given key. If the key already exists, its value is updated.\n\t * If the key doesn't exist, a new entry is created.\n\t *\n\t * @param key - The key to set the value for\n\t * @param value - The value to associate with the key\n\t * @returns This AtomMap instance for method chaining\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * ```\n\t */\n\tset(key: K, value: V) {\n\t\tconst existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (existingAtom) {\n\t\t\texistingAtom.set(value)\n\t\t} else {\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.set(key, atom(`${this.name}:${String(key)}`, value))\n\t\t\t})\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Updates an existing value using an updater function.\n\t *\n\t * @param key - The key of the value to update\n\t * @param updater - A function that receives the current value and returns the new value\n\t * @throws Error if the key doesn't exist in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 5)\n\t * map.update('count', count => count + 1) // count is now 6\n\t * ```\n\t */\n\tupdate(key: K, updater: (value: V) => V) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\tthrow new Error(`AtomMap: key ${key} not found`)\n\t\t}\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\tvalueAtom.set(updater(value))\n\t}\n\n\t/**\n\t * Removes a key-value pair from the map.\n\t *\n\t * @param key - The key to remove\n\t * @returns True if the key existed and was removed, false if it didn't exist\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('temp', 'value')\n\t * console.log(map.delete('temp')) // true\n\t * console.log(map.delete('missing')) // false\n\t * ```\n\t */\n\tdelete(key: K) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\n\t\ttransact(() => {\n\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.delete(key)\n\t\t\t})\n\t\t})\n\t\treturn true\n\t}\n\n\t/**\n\t * Removes multiple key-value pairs from the map in a single transaction.\n\t *\n\t * @param keys - An iterable of keys to remove\n\t * @returns An array of [key, value] pairs that were actually deleted\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2).set('c', 3)\n\t * const deleted = map.deleteMany(['a', 'c', 'missing'])\n\t * console.log(deleted) // [['a', 1], ['c', 3]]\n\t * ```\n\t */\n\tdeleteMany(keys: Iterable<K>): [K, V][] {\n\t\treturn transact(() => {\n\t\t\tconst deleted: [K, V][] = []\n\t\t\tconst newAtoms = this.atoms.get().withMutations((atoms) => {\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst valueAtom = atoms.get(key)\n\t\t\t\t\tif (!valueAtom) continue\n\t\t\t\t\tconst oldValue = valueAtom.get()\n\t\t\t\t\tassert(oldValue !== UNINITIALIZED)\n\n\t\t\t\t\tdeleted.push([key, oldValue])\n\n\t\t\t\t\tatoms.delete(key)\n\t\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tif (deleted.length) {\n\t\t\t\tthis.atoms.set(newAtoms)\n\t\t\t}\n\n\t\t\treturn deleted\n\t\t})\n\t}\n\n\t/**\n\t * Removes all key-value pairs from the map.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.clear()\n\t * console.log(map.size) // 0\n\t * ```\n\t */\n\tclear() {\n\t\treturn transact(() => {\n\t\t\tfor (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {\n\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t}\n\t\t\tthis.atoms.set(emptyMap())\n\t\t})\n\t}\n\n\t/**\n\t * Returns an iterator that yields [key, value] pairs for each entry in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @returns A generator that yields [key, value] tuples\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t*entries(): Generator<[K, V], undefined, unknown> {\n\t\tfor (const [key, valueAtom] of this.atoms.get()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield [key, value]\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all keys in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys change.\n\t *\n\t * @returns A generator that yields keys\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const key of map.keys()) {\n\t * console.log(key) // 'name', 'age'\n\t * }\n\t * ```\n\t */\n\t*keys(): Generator<K, undefined, unknown> {\n\t\tfor (const key of this.atoms.get().keys()) {\n\t\t\tyield key\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all values in the map.\n\t * This method is reactive and will cause reactive contexts to update when values change.\n\t *\n\t * @returns A generator that yields values\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const value of map.values()) {\n\t * console.log(value) // 'Alice', 30\n\t * }\n\t * ```\n\t */\n\t*values(): Generator<V, undefined, unknown> {\n\t\tfor (const valueAtom of this.atoms.get().values()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield value\n\t\t}\n\t}\n\n\t/**\n\t * The number of key-value pairs in the map.\n\t * This property is reactive and will cause reactive contexts to update when the size changes.\n\t *\n\t * @returns The number of entries in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.size) // 0\n\t * map.set('a', 1)\n\t * console.log(map.size) // 1\n\t * ```\n\t */\n\t// eslint-disable-next-line no-restricted-syntax\n\tget size() {\n\t\treturn this.atoms.get().size\n\t}\n\n\t/**\n\t * Executes a provided function once for each key-value pair in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @param callbackfn - Function to execute for each entry\n\t * - value - The value of the current entry\n\t * - key - The key of the current entry\n\t * - map - The AtomMap being traversed\n\t * @param thisArg - Value to use as `this` when executing the callback\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.forEach((value, key) => {\n\t * console.log(`${key} = ${value}`)\n\t * })\n\t * ```\n\t */\n\tforEach(callbackfn: (value: V, key: K, map: AtomMap<K, V>) => void, thisArg?: any): void {\n\t\tfor (const [key, value] of this.entries()) {\n\t\t\tcallbackfn.call(thisArg, value, key, this)\n\t\t}\n\t}\n\n\t/**\n\t * Returns the default iterator for the map, which is the same as entries().\n\t * This allows the map to be used in for...of loops and other iterable contexts.\n\t *\n\t * @returns The same iterator as entries()\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t *\n\t * // These are equivalent:\n\t * for (const [key, value] of map) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t *\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t[Symbol.iterator]() {\n\t\treturn this.entries()\n\t}\n\n\t/**\n\t * The string tag used by Object.prototype.toString for this class.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(Object.prototype.toString.call(map)) // '[object AtomMap]'\n\t * ```\n\t */\n\t[Symbol.toStringTag] = 'AtomMap'\n}\n"],
|
|
4
|
+
"sourcesContent": ["import { atom, Atom, transact, UNINITIALIZED } from '@tldraw/state'\nimport { assert } from '@tldraw/utils'\nimport { emptyMap, ImmutableMap } from './ImmutableMap'\n\n/**\n * A drop-in replacement for Map that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomMap<K, V> implements Map<K, V> {\n\tprivate atoms: Atom<ImmutableMap<K, Atom<V | UNINITIALIZED>>>\n\n\t/**\n\t * Creates a new AtomMap instance.\n\t *\n\t * name - A unique name for this map, used for atom identification\n\t * entries - Optional initial entries to populate the map with\n\t * @example\n\t * ```ts\n\t * // Create an empty map\n\t * const map = new AtomMap('userMap')\n\t *\n\t * // Create a map with initial data\n\t * const initialData: [string, number][] = [['a', 1], ['b', 2]]\n\t * const mapWithData = new AtomMap('numbersMap', initialData)\n\t * ```\n\t */\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tentries?: Iterable<readonly [K, V]>\n\t) {\n\t\tlet atoms = emptyMap<K, Atom<V>>()\n\t\tif (entries) {\n\t\t\tatoms = atoms.withMutations((atoms) => {\n\t\t\t\tfor (const [k, v] of entries) {\n\t\t\t\t\tatoms.set(k, atom(`${name}:${String(k)}`, v))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t\tthis.atoms = atom(`${name}:atoms`, atoms)\n\t}\n\n\t/**\n\t * Retrieves the underlying atom for a given key.\n\t *\n\t * @param key - The key to retrieve the atom for\n\t * @returns The atom containing the value, or undefined if the key doesn't exist\n\t * @internal\n\t */\n\tgetAtom(key: K): Atom<V | UNINITIALIZED> | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\t// if the value is missing, we want to track whether it's in the present keys set\n\t\t\tthis.atoms.get()\n\t\t\treturn undefined\n\t\t}\n\t\treturn valueAtom\n\t}\n\n\t/**\n\t * Gets the value associated with a key. Returns undefined if the key doesn't exist.\n\t * This method is reactive and will cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice')\n\t * console.log(map.get('name')) // 'Alice'\n\t * console.log(map.get('missing')) // undefined\n\t * ```\n\t */\n\tget(key: K): V | undefined {\n\t\tconst value = this.getAtom(key)?.get()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Gets the value associated with a key without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when the value changes.\n\t *\n\t * @param key - The key to retrieve the value for\n\t * @returns The value associated with the key, or undefined if not found\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 42)\n\t * const value = map.__unsafe__getWithoutCapture('count') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__getWithoutCapture(key: K): V | undefined {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return undefined\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\treturn value\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.has('name')) // false\n\t * map.set('name', 'Alice')\n\t * console.log(map.has('name')) // true\n\t * ```\n\t */\n\thas(key: K): boolean {\n\t\tconst valueAtom = this.getAtom(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\t\treturn valueAtom.get() !== UNINITIALIZED\n\t}\n\n\t/**\n\t * Checks whether a key exists in the map without creating reactive dependencies.\n\t * This method will not cause reactive contexts to update when keys are added or removed.\n\t *\n\t * @param key - The key to check for\n\t * @returns True if the key exists in the map, false otherwise\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('active', true)\n\t * const exists = map.__unsafe__hasWithoutCapture('active') // No reactive subscription\n\t * ```\n\t */\n\t__unsafe__hasWithoutCapture(key: K): boolean {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) return false\n\t\tassert(valueAtom.__unsafe__getWithoutCapture() !== UNINITIALIZED)\n\t\treturn true\n\t}\n\n\t/**\n\t * Sets a value for the given key. If the key already exists, its value is updated.\n\t * If the key doesn't exist, a new entry is created.\n\t *\n\t * @param key - The key to set the value for\n\t * @param value - The value to associate with the key\n\t * @returns This AtomMap instance for method chaining\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * ```\n\t */\n\tset(key: K, value: V) {\n\t\tconst existingAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (existingAtom) {\n\t\t\texistingAtom.set(value)\n\t\t} else {\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.set(key, atom(`${this.name}:${String(key)}`, value))\n\t\t\t})\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Updates an existing value using an updater function.\n\t *\n\t * @param key - The key of the value to update\n\t * @param updater - A function that receives the current value and returns the new value\n\t * @throws Error if the key doesn't exist in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('count', 5)\n\t * map.update('count', count => count + 1) // count is now 6\n\t * ```\n\t */\n\tupdate(key: K, updater: (value: V) => V) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\tthrow new Error(`AtomMap: key ${key} not found`)\n\t\t}\n\t\tconst value = valueAtom.__unsafe__getWithoutCapture()\n\t\tassert(value !== UNINITIALIZED)\n\t\tvalueAtom.set(updater(value))\n\t}\n\n\t/**\n\t * Removes a key-value pair from the map.\n\t *\n\t * @param key - The key to remove\n\t * @returns True if the key existed and was removed, false if it didn't exist\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('temp', 'value')\n\t * console.log(map.delete('temp')) // true\n\t * console.log(map.delete('missing')) // false\n\t * ```\n\t */\n\tdelete(key: K) {\n\t\tconst valueAtom = this.atoms.__unsafe__getWithoutCapture().get(key)\n\t\tif (!valueAtom) {\n\t\t\treturn false\n\t\t}\n\n\t\ttransact(() => {\n\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\tthis.atoms.update((atoms) => {\n\t\t\t\treturn atoms.delete(key)\n\t\t\t})\n\t\t})\n\t\treturn true\n\t}\n\n\t/**\n\t * Removes multiple key-value pairs from the map in a single transaction.\n\t *\n\t * @param keys - An iterable of keys to remove\n\t * @returns An array of [key, value] pairs that were actually deleted\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2).set('c', 3)\n\t * const deleted = map.deleteMany(['a', 'c', 'missing'])\n\t * console.log(deleted) // [['a', 1], ['c', 3]]\n\t * ```\n\t */\n\tdeleteMany(keys: Iterable<K>): [K, V][] {\n\t\treturn transact(() => {\n\t\t\tconst deleted: [K, V][] = []\n\t\t\tconst newAtoms = this.atoms.get().withMutations((atoms) => {\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tconst valueAtom = atoms.get(key)\n\t\t\t\t\tif (!valueAtom) continue\n\t\t\t\t\tconst oldValue = valueAtom.get()\n\t\t\t\t\tassert(oldValue !== UNINITIALIZED)\n\n\t\t\t\t\tdeleted.push([key, oldValue])\n\n\t\t\t\t\tatoms.delete(key)\n\t\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t\t}\n\t\t\t})\n\n\t\t\tif (deleted.length) {\n\t\t\t\tthis.atoms.set(newAtoms)\n\t\t\t}\n\n\t\t\treturn deleted\n\t\t})\n\t}\n\n\t/**\n\t * Removes all key-value pairs from the map.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.clear()\n\t * console.log(map.size) // 0\n\t * ```\n\t */\n\tclear() {\n\t\treturn transact(() => {\n\t\t\tfor (const valueAtom of this.atoms.__unsafe__getWithoutCapture().values()) {\n\t\t\t\tvalueAtom.set(UNINITIALIZED)\n\t\t\t}\n\t\t\tthis.atoms.set(emptyMap())\n\t\t})\n\t}\n\n\t/**\n\t * Returns an iterator that yields [key, value] pairs for each entry in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @returns A generator that yields [key, value] tuples\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t*entries(): Generator<[K, V], undefined, unknown> {\n\t\tfor (const [key, valueAtom] of this.atoms.get()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield [key, value]\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all keys in the map.\n\t * This method is reactive and will cause reactive contexts to update when keys change.\n\t *\n\t * @returns A generator that yields keys\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const key of map.keys()) {\n\t * console.log(key) // 'name', 'age'\n\t * }\n\t * ```\n\t */\n\t*keys(): Generator<K, undefined, unknown> {\n\t\tfor (const key of this.atoms.get().keys()) {\n\t\t\tyield key\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that yields all values in the map.\n\t * This method is reactive and will cause reactive contexts to update when values change.\n\t *\n\t * @returns A generator that yields values\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('name', 'Alice').set('age', 30)\n\t * for (const value of map.values()) {\n\t * console.log(value) // 'Alice', 30\n\t * }\n\t * ```\n\t */\n\t*values(): Generator<V, undefined, unknown> {\n\t\tfor (const valueAtom of this.atoms.get().values()) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tassert(value !== UNINITIALIZED)\n\t\t\tyield value\n\t\t}\n\t}\n\n\t/**\n\t * The number of key-value pairs in the map.\n\t * This property is reactive and will cause reactive contexts to update when the size changes.\n\t *\n\t * @returns The number of entries in the map\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.size) // 0\n\t * map.set('a', 1)\n\t * console.log(map.size) // 1\n\t * ```\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget size() {\n\t\treturn this.atoms.get().size\n\t}\n\n\t/**\n\t * Executes a provided function once for each key-value pair in the map.\n\t * This method is reactive and will cause reactive contexts to update when entries change.\n\t *\n\t * @param callbackfn - Function to execute for each entry\n\t * - value - The value of the current entry\n\t * - key - The key of the current entry\n\t * - map - The AtomMap being traversed\n\t * @param thisArg - Value to use as `this` when executing the callback\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t * map.forEach((value, key) => {\n\t * console.log(`${key} = ${value}`)\n\t * })\n\t * ```\n\t */\n\tforEach(callbackfn: (value: V, key: K, map: AtomMap<K, V>) => void, thisArg?: any): void {\n\t\tfor (const [key, value] of this.entries()) {\n\t\t\tcallbackfn.call(thisArg, value, key, this)\n\t\t}\n\t}\n\n\t/**\n\t * Returns the default iterator for the map, which is the same as entries().\n\t * This allows the map to be used in for...of loops and other iterable contexts.\n\t *\n\t * @returns The same iterator as entries()\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * map.set('a', 1).set('b', 2)\n\t *\n\t * // These are equivalent:\n\t * for (const [key, value] of map) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t *\n\t * for (const [key, value] of map.entries()) {\n\t * console.log(`${key}: ${value}`)\n\t * }\n\t * ```\n\t */\n\t[Symbol.iterator]() {\n\t\treturn this.entries()\n\t}\n\n\t/**\n\t * The string tag used by Object.prototype.toString for this class.\n\t *\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(Object.prototype.toString.call(map)) // '[object AtomMap]'\n\t * ```\n\t */\n\t[Symbol.toStringTag] = 'AtomMap'\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["atoms"]
|
|
7
7
|
}
|
package/dist-cjs/lib/AtomSet.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/AtomSet.ts"],
|
|
4
|
-
"sourcesContent": ["import { AtomMap } from './AtomMap'\n\n/**\n * A drop-in replacement for Set that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomSet<T> {\n\tprivate readonly map: AtomMap<T, T>\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tkeys?: Iterable<T>\n\t) {\n\t\tconst entries = keys ? Array.from(keys, (k) => [k, k] as const) : undefined\n\t\tthis.map = new AtomMap(name, entries)\n\t}\n\n\tadd(value: T): this {\n\t\tthis.map.set(value, value)\n\t\treturn this\n\t}\n\tclear(): void {\n\t\tthis.map.clear()\n\t}\n\tdelete(value: T): boolean {\n\t\treturn this.map.delete(value)\n\t}\n\tforEach(callbackfn: (value: T, value2: T, set: AtomSet<T>) => void, thisArg?: any): void {\n\t\tfor (const value of this) {\n\t\t\tcallbackfn.call(thisArg, value, value, this)\n\t\t}\n\t}\n\thas(value: T): boolean {\n\t\treturn this.map.has(value)\n\t}\n\t// eslint-disable-next-line no-
|
|
4
|
+
"sourcesContent": ["import { AtomMap } from './AtomMap'\n\n/**\n * A drop-in replacement for Set that stores values in atoms and can be used in reactive contexts.\n * @public\n */\nexport class AtomSet<T> {\n\tprivate readonly map: AtomMap<T, T>\n\tconstructor(\n\t\tprivate readonly name: string,\n\t\tkeys?: Iterable<T>\n\t) {\n\t\tconst entries = keys ? Array.from(keys, (k) => [k, k] as const) : undefined\n\t\tthis.map = new AtomMap(name, entries)\n\t}\n\n\tadd(value: T): this {\n\t\tthis.map.set(value, value)\n\t\treturn this\n\t}\n\tclear(): void {\n\t\tthis.map.clear()\n\t}\n\tdelete(value: T): boolean {\n\t\treturn this.map.delete(value)\n\t}\n\tforEach(callbackfn: (value: T, value2: T, set: AtomSet<T>) => void, thisArg?: any): void {\n\t\tfor (const value of this) {\n\t\t\tcallbackfn.call(thisArg, value, value, this)\n\t\t}\n\t}\n\thas(value: T): boolean {\n\t\treturn this.map.has(value)\n\t}\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget size(): number {\n\t\treturn this.map.size\n\t}\n\tentries(): Generator<[T, T], undefined, unknown> {\n\t\treturn this.map.entries()\n\t}\n\tkeys(): Generator<T, undefined, unknown> {\n\t\treturn this.map.keys()\n\t}\n\tvalues(): Generator<T, undefined, unknown> {\n\t\treturn this.map.keys()\n\t}\n\t[Symbol.iterator](): Generator<T, undefined, unknown> {\n\t\treturn this.map.keys()\n\t}\n\t[Symbol.toStringTag]: string = 'AtomSet'\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAwB;AAMjB,MAAM,QAAW;AAAA,EAEvB,YACkB,MACjB,MACC;AAFgB;AAGjB,UAAM,UAAU,OAAO,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAU,IAAI;AAClE,SAAK,MAAM,IAAI,uBAAQ,MAAM,OAAO;AAAA,EACrC;AAAA,EAPiB;AAAA,EASjB,IAAI,OAAgB;AACnB,SAAK,IAAI,IAAI,OAAO,KAAK;AACzB,WAAO;AAAA,EACR;AAAA,EACA,QAAc;AACb,SAAK,IAAI,MAAM;AAAA,EAChB;AAAA,EACA,OAAO,OAAmB;AACzB,WAAO,KAAK,IAAI,OAAO,KAAK;AAAA,EAC7B;AAAA,EACA,QAAQ,YAA4D,SAAqB;AACxF,eAAW,SAAS,MAAM;AACzB,iBAAW,KAAK,SAAS,OAAO,OAAO,IAAI;AAAA,IAC5C;AAAA,EACD;AAAA,EACA,IAAI,OAAmB;AACtB,WAAO,KAAK,IAAI,IAAI,KAAK;AAAA,EAC1B;AAAA;AAAA,EAEA,IAAI,OAAe;AAClB,WAAO,KAAK,IAAI;AAAA,EACjB;AAAA,EACA,UAAiD;AAChD,WAAO,KAAK,IAAI,QAAQ;AAAA,EACzB;AAAA,EACA,OAAyC;AACxC,WAAO,KAAK,IAAI,KAAK;AAAA,EACtB;AAAA,EACA,SAA2C;AAC1C,WAAO,KAAK,IAAI,KAAK;AAAA,EACtB;AAAA,EACA,CAAC,OAAO,QAAQ,IAAsC;AACrD,WAAO,KAAK,IAAI,KAAK;AAAA,EACtB;AAAA,EACA,CAAC,OAAO,WAAW,IAAY;AAChC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/RecordType.ts"],
|
|
4
|
-
"sourcesContent": ["import { Expand, objectMapEntries, structuredClone, uniqueId } from '@tldraw/utils'\nimport { IdOf, UnknownRecord } from './BaseRecord'\nimport { StoreValidator } from './Store'\n\n/**\n * Utility type that extracts the record type from a RecordType instance.\n *\n * @example\n * ```ts\n * const Book = createRecordType<BookRecord>('book', { scope: 'document' })\n * type BookFromType = RecordTypeRecord<typeof Book> // BookRecord\n * ```\n *\n * @public\n */\nexport type RecordTypeRecord<R extends RecordType<any, any>> = ReturnType<R['create']>\n\n/**\n * Defines the scope of the record\n *\n * session: The record belongs to a single instance of the store. It should not be synced, and any persistence logic should 'de-instance-ize' the record before persisting it, and apply the reverse when rehydrating.\n * document: The record is persisted and synced. It is available to all store instances.\n * presence: The record belongs to a single instance of the store. It may be synced to other instances, but other instances should not make changes to it. It should not be persisted.\n *\n * @public\n * */\nexport type RecordScope = 'session' | 'document' | 'presence'\n\n/**\n * A record type is a type that can be stored in a record store. It is created with\n * `createRecordType`.\n *\n * @public\n */\nexport class RecordType<\n\tR extends UnknownRecord,\n\tRequiredProperties extends keyof Omit<R, 'id' | 'typeName'>,\n> {\n\t/**\n\t * Factory function that creates default properties for new records.\n\t * @public\n\t */\n\treadonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>\n\n\t/**\n\t * Validator function used to validate records of this type.\n\t * @public\n\t */\n\treadonly validator: StoreValidator<R>\n\n\t/**\n\t * Optional configuration specifying which record properties are ephemeral.\n\t * Ephemeral properties are not included in snapshots or synchronization.\n\t * @public\n\t */\n\treadonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\n\t/**\n\t * Set of property names that are marked as ephemeral for efficient lookup.\n\t * @public\n\t */\n\treadonly ephemeralKeySet: ReadonlySet<string>\n\n\t/**\n\t * The scope that determines how records of this type are persisted and synchronized.\n\t * @public\n\t */\n\treadonly scope: RecordScope\n\n\t/**\n\t * Creates a new RecordType instance.\n\t *\n\t * typeName - The unique type name for records created by this RecordType\n\t * config - Configuration object for the RecordType\n\t * - createDefaultProperties - Function that returns default properties for new records\n\t * - validator - Optional validator function for record validation\n\t * - scope - Optional scope determining persistence behavior (defaults to 'document')\n\t * - ephemeralKeys - Optional mapping of property names to ephemeral status\n\t * @public\n\t */\n\tconstructor(\n\t\t/**\n\t\t * The unique type associated with this record.\n\t\t *\n\t\t * @public\n\t\t * @readonly\n\t\t */\n\t\tpublic readonly typeName: R['typeName'],\n\t\tconfig: {\n\t\t\t// eslint-disable-next-line @typescript-eslint/method-signature-style\n\t\t\treadonly createDefaultProperties: () => Exclude<\n\t\t\t\tOmit<R, 'id' | 'typeName'>,\n\t\t\t\tRequiredProperties\n\t\t\t>\n\t\t\treadonly validator?: StoreValidator<R>\n\t\t\treadonly scope?: RecordScope\n\t\t\treadonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\t\t}\n\t) {\n\t\tthis.createDefaultProperties = config.createDefaultProperties\n\t\tthis.validator = config.validator ?? { validate: (r: unknown) => r as R }\n\t\tthis.scope = config.scope ?? 'document'\n\t\tthis.ephemeralKeys = config.ephemeralKeys\n\n\t\tconst ephemeralKeySet = new Set<string>()\n\t\tif (config.ephemeralKeys) {\n\t\t\tfor (const [key, isEphemeral] of objectMapEntries(config.ephemeralKeys)) {\n\t\t\t\tif (isEphemeral) ephemeralKeySet.add(key as string)\n\t\t\t}\n\t\t}\n\t\tthis.ephemeralKeySet = ephemeralKeySet\n\t}\n\n\t/**\n\t * Creates a new record of this type with the given properties.\n\t *\n\t * Properties are merged with default properties from the RecordType configuration.\n\t * If no id is provided, a unique id will be generated automatically.\n\t *\n\t * @example\n\t * ```ts\n\t * const book = Book.create({\n\t * title: 'The Great Gatsby',\n\t * author: 'F. Scott Fitzgerald'\n\t * })\n\t * // Result: { id: 'book:abc123', typeName: 'book', title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', inStock: true }\n\t * ```\n\t *\n\t * @param properties - The properties for the new record, including both required and optional fields\n\t * @returns The newly created record with generated id and typeName\n\t * @public\n\t */\n\tcreate(\n\t\tproperties: Expand<Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>>\n\t): R {\n\t\tconst result = {\n\t\t\t...this.createDefaultProperties(),\n\t\t\tid: 'id' in properties ? properties.id : this.createId(),\n\t\t} as any\n\n\t\tfor (const [k, v] of Object.entries(properties)) {\n\t\t\tif (v !== undefined) {\n\t\t\t\tresult[k] = v\n\t\t\t}\n\t\t}\n\n\t\tresult.typeName = this.typeName\n\n\t\treturn result as R\n\t}\n\n\t/**\n\t * Creates a deep copy of an existing record with a new unique id.\n\t *\n\t * This method performs a deep clone of all properties while generating a fresh id,\n\t * making it useful for duplicating records without id conflicts.\n\t *\n\t * @example\n\t * ```ts\n\t * const originalBook = Book.create({ title: '1984', author: 'George Orwell' })\n\t * const duplicatedBook = Book.clone(originalBook)\n\t * // duplicatedBook has same properties but different id\n\t * ```\n\t *\n\t * @param record - The record to clone\n\t * @returns A new record with the same properties but a different id\n\t * @public\n\t */\n\tclone(record: R): R {\n\t\treturn { ...structuredClone(record), id: this.createId() }\n\t}\n\n\t/**\n\t * Create a new ID for this record type.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const id = recordType.createId()\n\t * ```\n\t *\n\t * @returns The new ID.\n\t * @public\n\t */\n\tcreateId(customUniquePart?: string): IdOf<R> {\n\t\treturn (this.typeName + ':' + (customUniquePart ?? uniqueId())) as IdOf<R>\n\t}\n\n\t/**\n\t * Extracts the unique identifier part from a full record id.\n\t *\n\t * Record ids have the format `typeName:uniquePart`. This method returns just the unique part.\n\t *\n\t * @example\n\t * ```ts\n\t * const bookId = Book.createId() // 'book:abc123'\n\t * const uniquePart = Book.parseId(bookId) // 'abc123'\n\t * ```\n\t *\n\t * @param id - The full record id to parse\n\t * @returns The unique identifier portion after the colon\n\t * @throws Error if the id is not valid for this record type\n\t * @public\n\t */\n\tparseId(id: IdOf<R>): string {\n\t\tif (!this.isId(id)) {\n\t\t\tthrow new Error(`ID \"${id}\" is not a valid ID for type \"${this.typeName}\"`)\n\t\t}\n\n\t\treturn id.slice(this.typeName.length + 1)\n\t}\n\n\t/**\n\t * Type guard that checks whether a record belongs to this RecordType.\n\t *\n\t * This method performs a runtime check by comparing the record's typeName\n\t * against this RecordType's typeName.\n\t *\n\t * @example\n\t * ```ts\n\t * if (Book.isInstance(someRecord)) {\n\t * // someRecord is now typed as a book record\n\t * console.log(someRecord.title)\n\t * }\n\t * ```\n\t *\n\t * @param record - The record to check, may be undefined\n\t * @returns True if the record is an instance of this record type\n\t * @public\n\t */\n\tisInstance(record?: UnknownRecord): record is R {\n\t\treturn record?.typeName === this.typeName\n\t}\n\n\t/**\n\t * Type guard that checks whether an id string belongs to this RecordType.\n\t *\n\t * Validates that the id starts with this RecordType's typeName followed by a colon.\n\t * This is more efficient than parsing the full id when you only need to verify the type.\n\t *\n\t * @example\n\t * ```ts\n\t * if (Book.isId(someId)) {\n\t * // someId is now typed as IdOf<BookRecord>\n\t * const book = store.get(someId)\n\t * }\n\t * ```\n\t *\n\t * @param id - The id string to check, may be undefined\n\t * @returns True if the id belongs to this record type\n\t * @public\n\t */\n\tisId(id?: string): id is IdOf<R> {\n\t\tif (!id) return false\n\t\tfor (let i = 0; i < this.typeName.length; i++) {\n\t\t\tif (id[i] !== this.typeName[i]) return false\n\t\t}\n\n\t\treturn id[this.typeName.length] === ':'\n\t}\n\n\t/**\n\t * Create a new RecordType that has the same type name as this RecordType and includes the given\n\t * default properties.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const authorType = createRecordType('author', () => ({ living: true }))\n\t * const deadAuthorType = authorType.withDefaultProperties({ living: false })\n\t * ```\n\t *\n\t * @param createDefaultProperties - A function that returns the default properties of the new RecordType.\n\t * @returns The new RecordType.\n\t */\n\twithDefaultProperties<DefaultProps extends Omit<Partial<R>, 'typeName' | 'id'>>(\n\t\tcreateDefaultProperties: () => DefaultProps\n\t): RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>> {\n\t\treturn new RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>>(this.typeName, {\n\t\t\tcreateDefaultProperties: createDefaultProperties as any,\n\t\t\tvalidator: this.validator,\n\t\t\tscope: this.scope,\n\t\t\tephemeralKeys: this.ephemeralKeys,\n\t\t})\n\t}\n\n\t/**\n\t * Validates a record against this RecordType's validator and returns it with proper typing.\n\t *\n\t * This method runs the configured validator function and throws an error if validation fails.\n\t * If a previous version of the record is provided, it may use optimized validation.\n\t *\n\t * @example\n\t * ```ts\n\t * try {\n\t * const validBook = Book.validate(untrustedData)\n\t * // validBook is now properly typed and validated\n\t * } catch (error) {\n\t * console.log('Validation failed:', error.message)\n\t * }\n\t * ```\n\t *\n\t * @param record - The unknown record data to validate\n\t * @param recordBefore - Optional previous version for optimized validation\n\t * @returns The validated and properly typed record\n\t * @throws Error if validation fails\n\t * @public\n\t */\n\tvalidate(record: unknown, recordBefore?: R): R {\n\t\tif (recordBefore && this.validator.validateUsingKnownGoodVersion) {\n\t\t\treturn this.validator.validateUsingKnownGoodVersion(recordBefore, record)\n\t\t}\n\t\treturn this.validator.validate(record)\n\t}\n}\n\n/**\n * Creates a new RecordType with the specified configuration.\n *\n * This factory function creates a RecordType that can be used to create, validate, and manage\n * records of a specific type within a store. The resulting RecordType can be extended with\n * default properties using the withDefaultProperties method.\n *\n * @example\n * ```ts\n * interface BookRecord extends BaseRecord<'book', RecordId<BookRecord>> {\n * title: string\n * author: string\n * inStock: boolean\n * }\n *\n * const Book = createRecordType<BookRecord>('book', {\n * scope: 'document',\n * validator: bookValidator\n * })\n * ```\n *\n * @param typeName - The unique type name for this record type\n * @param config - Configuration object containing validator, scope, and ephemeral keys\n * @returns A new RecordType instance for creating and managing records\n * @public\n */\nexport function createRecordType<R extends UnknownRecord>(\n\ttypeName: R['typeName'],\n\tconfig: {\n\t\tvalidator?: StoreValidator<R>\n\t\tscope: RecordScope\n\t\tephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\t}\n): RecordType<R, keyof Omit<R, 'id' | 'typeName'>> {\n\treturn new RecordType<R, keyof Omit<R, 'id' | 'typeName'>>(typeName, {\n\t\tcreateDefaultProperties: () => ({}) as any,\n\t\tvalidator: config.validator,\n\t\tscope: config.scope,\n\t\tephemeralKeys: config.ephemeralKeys,\n\t})\n}\n\n/**\n * Assert whether an id correspond to a record type.\n *\n * @example\n *\n * ```ts\n * assertIdType(myId, \"shape\")\n * ```\n *\n * @param id - The id to check.\n * @param type - The type of the record.\n * @public\n */\nexport function assertIdType<R extends UnknownRecord>(\n\tid: string | undefined,\n\ttype: RecordType<R, any>\n): asserts id is IdOf<R> {\n\tif (!id || !type.isId(id)) {\n\t\tthrow new Error(`string ${JSON.stringify(id)} is not a valid ${type.typeName} id`)\n\t}\n}\n"],
|
|
4
|
+
"sourcesContent": ["import { Expand, objectMapEntries, structuredClone, uniqueId } from '@tldraw/utils'\nimport { IdOf, UnknownRecord } from './BaseRecord'\nimport { StoreValidator } from './Store'\n\n/**\n * Utility type that extracts the record type from a RecordType instance.\n *\n * @example\n * ```ts\n * const Book = createRecordType<BookRecord>('book', { scope: 'document' })\n * type BookFromType = RecordTypeRecord<typeof Book> // BookRecord\n * ```\n *\n * @public\n */\nexport type RecordTypeRecord<R extends RecordType<any, any>> = ReturnType<R['create']>\n\n/**\n * Defines the scope of the record\n *\n * session: The record belongs to a single instance of the store. It should not be synced, and any persistence logic should 'de-instance-ize' the record before persisting it, and apply the reverse when rehydrating.\n * document: The record is persisted and synced. It is available to all store instances.\n * presence: The record belongs to a single instance of the store. It may be synced to other instances, but other instances should not make changes to it. It should not be persisted.\n *\n * @public\n * */\nexport type RecordScope = 'session' | 'document' | 'presence'\n\n/**\n * A record type is a type that can be stored in a record store. It is created with\n * `createRecordType`.\n *\n * @public\n */\nexport class RecordType<\n\tR extends UnknownRecord,\n\tRequiredProperties extends keyof Omit<R, 'id' | 'typeName'>,\n> {\n\t/**\n\t * Factory function that creates default properties for new records.\n\t * @public\n\t */\n\treadonly createDefaultProperties: () => Exclude<Omit<R, 'id' | 'typeName'>, RequiredProperties>\n\n\t/**\n\t * Validator function used to validate records of this type.\n\t * @public\n\t */\n\treadonly validator: StoreValidator<R>\n\n\t/**\n\t * Optional configuration specifying which record properties are ephemeral.\n\t * Ephemeral properties are not included in snapshots or synchronization.\n\t * @public\n\t */\n\treadonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\n\t/**\n\t * Set of property names that are marked as ephemeral for efficient lookup.\n\t * @public\n\t */\n\treadonly ephemeralKeySet: ReadonlySet<string>\n\n\t/**\n\t * The scope that determines how records of this type are persisted and synchronized.\n\t * @public\n\t */\n\treadonly scope: RecordScope\n\n\t/**\n\t * Creates a new RecordType instance.\n\t *\n\t * typeName - The unique type name for records created by this RecordType\n\t * config - Configuration object for the RecordType\n\t * - createDefaultProperties - Function that returns default properties for new records\n\t * - validator - Optional validator function for record validation\n\t * - scope - Optional scope determining persistence behavior (defaults to 'document')\n\t * - ephemeralKeys - Optional mapping of property names to ephemeral status\n\t * @public\n\t */\n\tconstructor(\n\t\t/**\n\t\t * The unique type associated with this record.\n\t\t *\n\t\t * @public\n\t\t * @readonly\n\t\t */\n\t\tpublic readonly typeName: R['typeName'],\n\t\tconfig: {\n\t\t\t// eslint-disable-next-line tldraw/method-signature-style\n\t\t\treadonly createDefaultProperties: () => Exclude<\n\t\t\t\tOmit<R, 'id' | 'typeName'>,\n\t\t\t\tRequiredProperties\n\t\t\t>\n\t\t\treadonly validator?: StoreValidator<R>\n\t\t\treadonly scope?: RecordScope\n\t\t\treadonly ephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\t\t}\n\t) {\n\t\tthis.createDefaultProperties = config.createDefaultProperties\n\t\tthis.validator = config.validator ?? { validate: (r: unknown) => r as R }\n\t\tthis.scope = config.scope ?? 'document'\n\t\tthis.ephemeralKeys = config.ephemeralKeys\n\n\t\tconst ephemeralKeySet = new Set<string>()\n\t\tif (config.ephemeralKeys) {\n\t\t\tfor (const [key, isEphemeral] of objectMapEntries(config.ephemeralKeys)) {\n\t\t\t\tif (isEphemeral) ephemeralKeySet.add(key as string)\n\t\t\t}\n\t\t}\n\t\tthis.ephemeralKeySet = ephemeralKeySet\n\t}\n\n\t/**\n\t * Creates a new record of this type with the given properties.\n\t *\n\t * Properties are merged with default properties from the RecordType configuration.\n\t * If no id is provided, a unique id will be generated automatically.\n\t *\n\t * @example\n\t * ```ts\n\t * const book = Book.create({\n\t * title: 'The Great Gatsby',\n\t * author: 'F. Scott Fitzgerald'\n\t * })\n\t * // Result: { id: 'book:abc123', typeName: 'book', title: 'The Great Gatsby', author: 'F. Scott Fitzgerald', inStock: true }\n\t * ```\n\t *\n\t * @param properties - The properties for the new record, including both required and optional fields\n\t * @returns The newly created record with generated id and typeName\n\t * @public\n\t */\n\tcreate(\n\t\tproperties: Expand<Pick<R, RequiredProperties> & Omit<Partial<R>, RequiredProperties>>\n\t): R {\n\t\tconst result = {\n\t\t\t...this.createDefaultProperties(),\n\t\t\tid: 'id' in properties ? properties.id : this.createId(),\n\t\t} as any\n\n\t\tfor (const [k, v] of Object.entries(properties)) {\n\t\t\tif (v !== undefined) {\n\t\t\t\tresult[k] = v\n\t\t\t}\n\t\t}\n\n\t\tresult.typeName = this.typeName\n\n\t\treturn result as R\n\t}\n\n\t/**\n\t * Creates a deep copy of an existing record with a new unique id.\n\t *\n\t * This method performs a deep clone of all properties while generating a fresh id,\n\t * making it useful for duplicating records without id conflicts.\n\t *\n\t * @example\n\t * ```ts\n\t * const originalBook = Book.create({ title: '1984', author: 'George Orwell' })\n\t * const duplicatedBook = Book.clone(originalBook)\n\t * // duplicatedBook has same properties but different id\n\t * ```\n\t *\n\t * @param record - The record to clone\n\t * @returns A new record with the same properties but a different id\n\t * @public\n\t */\n\tclone(record: R): R {\n\t\treturn { ...structuredClone(record), id: this.createId() }\n\t}\n\n\t/**\n\t * Create a new ID for this record type.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const id = recordType.createId()\n\t * ```\n\t *\n\t * @returns The new ID.\n\t * @public\n\t */\n\tcreateId(customUniquePart?: string): IdOf<R> {\n\t\treturn (this.typeName + ':' + (customUniquePart ?? uniqueId())) as IdOf<R>\n\t}\n\n\t/**\n\t * Extracts the unique identifier part from a full record id.\n\t *\n\t * Record ids have the format `typeName:uniquePart`. This method returns just the unique part.\n\t *\n\t * @example\n\t * ```ts\n\t * const bookId = Book.createId() // 'book:abc123'\n\t * const uniquePart = Book.parseId(bookId) // 'abc123'\n\t * ```\n\t *\n\t * @param id - The full record id to parse\n\t * @returns The unique identifier portion after the colon\n\t * @throws Error if the id is not valid for this record type\n\t * @public\n\t */\n\tparseId(id: IdOf<R>): string {\n\t\tif (!this.isId(id)) {\n\t\t\tthrow new Error(`ID \"${id}\" is not a valid ID for type \"${this.typeName}\"`)\n\t\t}\n\n\t\treturn id.slice(this.typeName.length + 1)\n\t}\n\n\t/**\n\t * Type guard that checks whether a record belongs to this RecordType.\n\t *\n\t * This method performs a runtime check by comparing the record's typeName\n\t * against this RecordType's typeName.\n\t *\n\t * @example\n\t * ```ts\n\t * if (Book.isInstance(someRecord)) {\n\t * // someRecord is now typed as a book record\n\t * console.log(someRecord.title)\n\t * }\n\t * ```\n\t *\n\t * @param record - The record to check, may be undefined\n\t * @returns True if the record is an instance of this record type\n\t * @public\n\t */\n\tisInstance(record?: UnknownRecord): record is R {\n\t\treturn record?.typeName === this.typeName\n\t}\n\n\t/**\n\t * Type guard that checks whether an id string belongs to this RecordType.\n\t *\n\t * Validates that the id starts with this RecordType's typeName followed by a colon.\n\t * This is more efficient than parsing the full id when you only need to verify the type.\n\t *\n\t * @example\n\t * ```ts\n\t * if (Book.isId(someId)) {\n\t * // someId is now typed as IdOf<BookRecord>\n\t * const book = store.get(someId)\n\t * }\n\t * ```\n\t *\n\t * @param id - The id string to check, may be undefined\n\t * @returns True if the id belongs to this record type\n\t * @public\n\t */\n\tisId(id?: string): id is IdOf<R> {\n\t\tif (!id) return false\n\t\tfor (let i = 0; i < this.typeName.length; i++) {\n\t\t\tif (id[i] !== this.typeName[i]) return false\n\t\t}\n\n\t\treturn id[this.typeName.length] === ':'\n\t}\n\n\t/**\n\t * Create a new RecordType that has the same type name as this RecordType and includes the given\n\t * default properties.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const authorType = createRecordType('author', () => ({ living: true }))\n\t * const deadAuthorType = authorType.withDefaultProperties({ living: false })\n\t * ```\n\t *\n\t * @param createDefaultProperties - A function that returns the default properties of the new RecordType.\n\t * @returns The new RecordType.\n\t */\n\twithDefaultProperties<DefaultProps extends Omit<Partial<R>, 'typeName' | 'id'>>(\n\t\tcreateDefaultProperties: () => DefaultProps\n\t): RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>> {\n\t\treturn new RecordType<R, Exclude<RequiredProperties, keyof DefaultProps>>(this.typeName, {\n\t\t\tcreateDefaultProperties: createDefaultProperties as any,\n\t\t\tvalidator: this.validator,\n\t\t\tscope: this.scope,\n\t\t\tephemeralKeys: this.ephemeralKeys,\n\t\t})\n\t}\n\n\t/**\n\t * Validates a record against this RecordType's validator and returns it with proper typing.\n\t *\n\t * This method runs the configured validator function and throws an error if validation fails.\n\t * If a previous version of the record is provided, it may use optimized validation.\n\t *\n\t * @example\n\t * ```ts\n\t * try {\n\t * const validBook = Book.validate(untrustedData)\n\t * // validBook is now properly typed and validated\n\t * } catch (error) {\n\t * console.log('Validation failed:', error.message)\n\t * }\n\t * ```\n\t *\n\t * @param record - The unknown record data to validate\n\t * @param recordBefore - Optional previous version for optimized validation\n\t * @returns The validated and properly typed record\n\t * @throws Error if validation fails\n\t * @public\n\t */\n\tvalidate(record: unknown, recordBefore?: R): R {\n\t\tif (recordBefore && this.validator.validateUsingKnownGoodVersion) {\n\t\t\treturn this.validator.validateUsingKnownGoodVersion(recordBefore, record)\n\t\t}\n\t\treturn this.validator.validate(record)\n\t}\n}\n\n/**\n * Creates a new RecordType with the specified configuration.\n *\n * This factory function creates a RecordType that can be used to create, validate, and manage\n * records of a specific type within a store. The resulting RecordType can be extended with\n * default properties using the withDefaultProperties method.\n *\n * @example\n * ```ts\n * interface BookRecord extends BaseRecord<'book', RecordId<BookRecord>> {\n * title: string\n * author: string\n * inStock: boolean\n * }\n *\n * const Book = createRecordType<BookRecord>('book', {\n * scope: 'document',\n * validator: bookValidator\n * })\n * ```\n *\n * @param typeName - The unique type name for this record type\n * @param config - Configuration object containing validator, scope, and ephemeral keys\n * @returns A new RecordType instance for creating and managing records\n * @public\n */\nexport function createRecordType<R extends UnknownRecord>(\n\ttypeName: R['typeName'],\n\tconfig: {\n\t\tvalidator?: StoreValidator<R>\n\t\tscope: RecordScope\n\t\tephemeralKeys?: { readonly [K in Exclude<keyof R, 'id' | 'typeName'>]: boolean }\n\t}\n): RecordType<R, keyof Omit<R, 'id' | 'typeName'>> {\n\treturn new RecordType<R, keyof Omit<R, 'id' | 'typeName'>>(typeName, {\n\t\tcreateDefaultProperties: () => ({}) as any,\n\t\tvalidator: config.validator,\n\t\tscope: config.scope,\n\t\tephemeralKeys: config.ephemeralKeys,\n\t})\n}\n\n/**\n * Assert whether an id correspond to a record type.\n *\n * @example\n *\n * ```ts\n * assertIdType(myId, \"shape\")\n * ```\n *\n * @param id - The id to check.\n * @param type - The type of the record.\n * @public\n */\nexport function assertIdType<R extends UnknownRecord>(\n\tid: string | undefined,\n\ttype: RecordType<R, any>\n): asserts id is IdOf<R> {\n\tif (!id || !type.isId(id)) {\n\t\tthrow new Error(`string ${JSON.stringify(id)} is not a valid ${type.typeName} id`)\n\t}\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/Store.js
CHANGED
|
@@ -25,10 +25,10 @@ module.exports = __toCommonJS(Store_exports);
|
|
|
25
25
|
var import_state = require("@tldraw/state");
|
|
26
26
|
var import_utils = require("@tldraw/utils");
|
|
27
27
|
var import_AtomMap = require("./AtomMap");
|
|
28
|
+
var import_devFreeze = require("./devFreeze");
|
|
28
29
|
var import_RecordsDiff = require("./RecordsDiff");
|
|
29
30
|
var import_StoreQueries = require("./StoreQueries");
|
|
30
31
|
var import_StoreSideEffects = require("./StoreSideEffects");
|
|
31
|
-
var import_devFreeze = require("./devFreeze");
|
|
32
32
|
class Store {
|
|
33
33
|
/**
|
|
34
34
|
* The unique identifier of the store instance.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/Store.ts"],
|
|
4
|
-
"sourcesContent": ["import { Atom, Reactor, Signal, atom, computed, reactor, transact } from '@tldraw/state'\nimport {\n\tWeakCache,\n\tassert,\n\tfilterEntries,\n\tgetOwnProperty,\n\tisEqual,\n\tobjectMapEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tthrottleToNextFrame,\n\tuniqueId,\n} from '@tldraw/utils'\nimport { AtomMap } from './AtomMap'\nimport { IdOf, RecordId, UnknownRecord } from './BaseRecord'\nimport { RecordScope } from './RecordType'\nimport { RecordsDiff, squashRecordDiffs } from './RecordsDiff'\nimport { StoreQueries } from './StoreQueries'\nimport { SerializedSchema, StoreSchema } from './StoreSchema'\nimport { StoreSideEffects } from './StoreSideEffects'\nimport { devFreeze } from './devFreeze'\n\n/**\n * Extracts the record type from a record ID type.\n *\n * @example\n * ```ts\n * type BookId = RecordId<Book>\n * type BookType = RecordFromId<BookId> // Book\n * ```\n *\n * @public\n */\nexport type RecordFromId<K extends RecordId<UnknownRecord>> =\n\tK extends RecordId<infer R> ? R : never\n\n/**\n * A diff describing the changes to a collection.\n *\n * @example\n * ```ts\n * const diff: CollectionDiff<string> = {\n * added: new Set(['newItem']),\n * removed: new Set(['oldItem'])\n * }\n * ```\n *\n * @public\n */\nexport interface CollectionDiff<T> {\n\t/** Items that were added to the collection */\n\tadded?: Set<T>\n\t/** Items that were removed from the collection */\n\tremoved?: Set<T>\n}\n\n/**\n * The source of a change to the store.\n * - `'user'` - Changes originating from local user actions\n * - `'remote'` - Changes originating from remote synchronization\n *\n * @public\n */\nexport type ChangeSource = 'user' | 'remote'\n\n/**\n * Filters for store listeners to control which changes trigger the listener.\n *\n * @example\n * ```ts\n * const filters: StoreListenerFilters = {\n * source: 'user', // Only listen to user changes\n * scope: 'document' // Only listen to document-scoped records\n * }\n * ```\n *\n * @public\n */\nexport interface StoreListenerFilters {\n\t/** Filter by the source of changes */\n\tsource: ChangeSource | 'all'\n\t/** Filter by the scope of records */\n\tscope: RecordScope | 'all'\n}\n\n/**\n * An entry containing changes that originated either by user actions or remote changes.\n * History entries are used to track and replay changes to the store.\n *\n * @example\n * ```ts\n * const entry: HistoryEntry<Book> = {\n * changes: {\n * added: { 'book:123': bookRecord },\n * updated: {},\n * removed: {}\n * },\n * source: 'user'\n * }\n * ```\n *\n * @public\n */\nexport interface HistoryEntry<R extends UnknownRecord = UnknownRecord> {\n\t/** The changes that occurred in this history entry */\n\tchanges: RecordsDiff<R>\n\t/** The source of these changes */\n\tsource: ChangeSource\n}\n\n/**\n * A function that will be called when the history changes.\n *\n * @example\n * ```ts\n * const listener: StoreListener<Book> = (entry) => {\n * console.log('Changes:', entry.changes)\n * console.log('Source:', entry.source)\n * }\n *\n * store.listen(listener)\n * ```\n *\n * @param entry - The history entry containing the changes\n *\n * @public\n */\nexport type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void\n\n/**\n * A computed cache that stores derived data for records.\n * The cache automatically updates when underlying records change and cleans up when records are deleted.\n *\n * @example\n * ```ts\n * const expensiveCache = store.createComputedCache(\n * 'expensive',\n * (book: Book) => performExpensiveCalculation(book)\n * )\n *\n * const result = expensiveCache.get(bookId)\n * ```\n *\n * @public\n */\nexport interface ComputedCache<Data, R extends UnknownRecord> {\n\t/**\n\t * Get the cached data for a record by its ID.\n\t *\n\t * @param id - The ID of the record\n\t * @returns The cached data or undefined if the record doesn't exist\n\t */\n\tget(id: IdOf<R>): Data | undefined\n}\n\n/**\n * Options for creating a computed cache.\n *\n * @example\n * ```ts\n * const options: CreateComputedCacheOpts<string[], Book> = {\n * areRecordsEqual: (a, b) => a.title === b.title,\n * areResultsEqual: (a, b) => JSON.stringify(a) === JSON.stringify(b)\n * }\n * ```\n *\n * @public\n */\nexport interface CreateComputedCacheOpts<Data, R extends UnknownRecord> {\n\t/** Custom equality function for comparing records */\n\tareRecordsEqual?(a: R, b: R): boolean\n\t/** Custom equality function for comparing results */\n\tareResultsEqual?(a: Data, b: Data): boolean\n}\n\n/**\n * A serialized snapshot of the record store's values.\n * This is a plain JavaScript object that can be saved to storage or transmitted over the network.\n *\n * @example\n * ```ts\n * const serialized: SerializedStore<Book> = {\n * 'book:123': { id: 'book:123', typeName: 'book', title: 'The Lathe of Heaven' },\n * 'book:456': { id: 'book:456', typeName: 'book', title: 'The Left Hand of Darkness' }\n * }\n * ```\n *\n * @public\n */\nexport type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>\n\n/**\n * A snapshot of the store including both data and schema information.\n * This enables proper migration when loading data from different schema versions.\n *\n * @example\n * ```ts\n * const snapshot = store.getStoreSnapshot()\n * // Later...\n * store.loadStoreSnapshot(snapshot)\n * ```\n *\n * @public\n */\nexport interface StoreSnapshot<R extends UnknownRecord> {\n\t/** The serialized store data */\n\tstore: SerializedStore<R>\n\t/** The serialized schema information */\n\tschema: SerializedSchema\n}\n\n/**\n * A validator for store records that ensures data integrity.\n * Validators are called when records are created or updated.\n *\n * @example\n * ```ts\n * const bookValidator: StoreValidator<Book> = {\n * validate(record: unknown): Book {\n * // Validate and return the record\n * if (typeof record !== 'object' || !record.title) {\n * throw new Error('Invalid book')\n * }\n * return record as Book\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface StoreValidator<R extends UnknownRecord> {\n\t/**\n\t * Validate a record.\n\t *\n\t * @param record - The record to validate\n\t * @returns The validated record\n\t * @throws When validation fails\n\t */\n\tvalidate(record: unknown): R\n\t/**\n\t * Validate a record using a known good version for reference.\n\t *\n\t * @param knownGoodVersion - A known valid version of the record\n\t * @param record - The record to validate\n\t * @returns The validated record\n\t */\n\tvalidateUsingKnownGoodVersion?(knownGoodVersion: R, record: unknown): R\n}\n\n/**\n * A map of validators for each record type in the store.\n *\n * @example\n * ```ts\n * const validators: StoreValidators<Book | Author> = {\n * book: bookValidator,\n * author: authorValidator\n * }\n * ```\n *\n * @public\n */\nexport type StoreValidators<R extends UnknownRecord> = {\n\t[K in R['typeName']]: StoreValidator<Extract<R, { typeName: K }>>\n}\n\n/**\n * Information about an error that occurred in the store.\n *\n * @example\n * ```ts\n * const error: StoreError = {\n * error: new Error('Validation failed'),\n * phase: 'updateRecord',\n * recordBefore: oldRecord,\n * recordAfter: newRecord,\n * isExistingValidationIssue: false\n * }\n * ```\n *\n * @public\n */\nexport interface StoreError {\n\t/** The error that occurred */\n\terror: Error\n\t/** The phase during which the error occurred */\n\tphase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests'\n\t/** The record state before the operation (if applicable) */\n\trecordBefore?: unknown\n\t/** The record state after the operation */\n\trecordAfter: unknown\n\t/** Whether this is an existing validation issue */\n\tisExistingValidationIssue: boolean\n}\n\n/**\n * Extract the record type from a Store type.\n * Used internally for type inference.\n *\n * @internal\n */\nexport type StoreRecord<S extends Store<any>> = S extends Store<infer R> ? R : never\n\n/**\n * A reactive store that manages collections of typed records.\n *\n * The Store is the central container for your application's data, providing:\n * - Reactive state management with automatic updates\n * - Type-safe record operations\n * - History tracking and change notifications\n * - Schema validation and migrations\n * - Side effects and business logic hooks\n * - Efficient querying and indexing\n *\n * @example\n * ```ts\n * // Create a store with schema\n * const schema = StoreSchema.create({\n * book: Book,\n * author: Author\n * })\n *\n * const store = new Store({\n * schema,\n * props: {}\n * })\n *\n * // Add records\n * const book = Book.create({ title: 'The Lathe of Heaven', author: 'Le Guin' })\n * store.put([book])\n *\n * // Listen to changes\n * store.listen((entry) => {\n * console.log('Changes:', entry.changes)\n * })\n * ```\n *\n * @public\n */\nexport class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {\n\t/**\n\t * The unique identifier of the store instance.\n\t *\n\t * @public\n\t */\n\tpublic readonly id: string\n\t/**\n\t * An AtomMap containing the stores records.\n\t *\n\t * @internal\n\t * @readonly\n\t */\n\tprivate readonly records: AtomMap<IdOf<R>, R>\n\n\t/**\n\t * An atom containing the store's history.\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly history: Atom<number, RecordsDiff<R>> = atom('history', 0, {\n\t\thistoryLength: 1000,\n\t})\n\n\t/**\n\t * Reactive queries and indexes for efficiently accessing store data.\n\t * Provides methods for filtering, indexing, and subscribing to subsets of records.\n\t *\n\t * @example\n\t * ```ts\n\t * // Create an index by a property\n\t * const booksByAuthor = store.query.index('book', 'author')\n\t *\n\t * // Get records matching criteria\n\t * const inStockBooks = store.query.records('book', () => ({\n\t * inStock: { eq: true }\n\t * }))\n\t * ```\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly query: StoreQueries<R>\n\n\t/**\n\t * A set containing listeners that have been added to this store.\n\t *\n\t * @internal\n\t */\n\tprivate listeners = new Set<{ onHistory: StoreListener<R>; filters: StoreListenerFilters }>()\n\n\t/**\n\t * An array of history entries that have not yet been flushed.\n\t *\n\t * @internal\n\t */\n\tprivate historyAccumulator = new HistoryAccumulator<R>()\n\n\t/**\n\t * A reactor that responds to changes to the history by squashing the accumulated history and\n\t * notifying listeners of the changes.\n\t *\n\t * @internal\n\t */\n\tprivate historyReactor: Reactor\n\n\t/**\n\t * Function to dispose of any in-flight timeouts.\n\t *\n\t * @internal\n\t */\n\tprivate cancelHistoryReactor(): void {\n\t\t/* noop */\n\t}\n\n\t/**\n\t * The schema that defines the structure and validation rules for records in this store.\n\t *\n\t * @public\n\t */\n\treadonly schema: StoreSchema<R, Props>\n\n\t/**\n\t * Custom properties associated with this store instance.\n\t *\n\t * @public\n\t */\n\treadonly props: Props\n\n\t/**\n\t * A mapping of record scopes to the set of record type names that belong to each scope.\n\t * Used to filter records by their persistence and synchronization behavior.\n\t *\n\t * @public\n\t */\n\tpublic readonly scopedTypes: { readonly [K in RecordScope]: ReadonlySet<R['typeName']> }\n\n\t/**\n\t * Side effects manager that handles lifecycle events for record operations.\n\t * Allows registration of callbacks for create, update, delete, and validation events.\n\t *\n\t * @example\n\t * ```ts\n\t * store.sideEffects.registerAfterCreateHandler('book', (book) => {\n\t * console.log('Book created:', book.title)\n\t * })\n\t * ```\n\t *\n\t * @public\n\t */\n\tpublic readonly sideEffects = new StoreSideEffects<R>(this)\n\n\t/**\n\t * Creates a new Store instance.\n\t *\n\t * @example\n\t * ```ts\n\t * const store = new Store({\n\t * schema: StoreSchema.create({ book: Book }),\n\t * props: { appName: 'MyLibrary' },\n\t * initialData: savedData\n\t * })\n\t * ```\n\t *\n\t * @param config - Configuration object for the store\n\t */\n\tconstructor(config: {\n\t\t/** Optional unique identifier for the store */\n\t\tid?: string\n\t\t/** The store's initial data to populate on creation */\n\t\tinitialData?: SerializedStore<R>\n\t\t/** The schema defining record types, validation, and migrations */\n\t\tschema: StoreSchema<R, Props>\n\t\t/** Custom properties for the store instance */\n\t\tprops: Props\n\t}) {\n\t\tconst { initialData, schema, id } = config\n\n\t\tthis.id = id ?? uniqueId()\n\t\tthis.schema = schema\n\t\tthis.props = config.props\n\n\t\tif (initialData) {\n\t\t\tthis.records = new AtomMap(\n\t\t\t\t'store',\n\t\t\t\tobjectMapEntries(initialData).map(([id, record]) => [\n\t\t\t\t\tid,\n\t\t\t\t\tdevFreeze(this.schema.validateRecord(this, record, 'initialize', null)),\n\t\t\t\t])\n\t\t\t)\n\t\t} else {\n\t\t\tthis.records = new AtomMap('store')\n\t\t}\n\n\t\tthis.query = new StoreQueries<R>(this.records, this.history)\n\n\t\tthis.historyReactor = reactor(\n\t\t\t'Store.historyReactor',\n\t\t\t() => {\n\t\t\t\t// deref to make sure we're subscribed regardless of whether we need to propagate\n\t\t\t\tthis.history.get()\n\t\t\t\t// If we have accumulated history, flush it and update listeners\n\t\t\t\tthis._flushHistory()\n\t\t\t},\n\t\t\t{ scheduleEffect: (cb) => (this.cancelHistoryReactor = throttleToNextFrame(cb)) }\n\t\t)\n\t\tthis.scopedTypes = {\n\t\t\tdocument: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'document')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tsession: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'session')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tpresence: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'presence')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t}\n\t}\n\n\tpublic _flushHistory() {\n\t\t// If we have accumulated history, flush it and update listeners\n\t\tif (this.historyAccumulator.hasChanges()) {\n\t\t\tconst entries = this.historyAccumulator.flush()\n\t\t\tfor (const { changes, source } of entries) {\n\t\t\t\tlet instanceChanges = null as null | RecordsDiff<R>\n\t\t\t\tlet documentChanges = null as null | RecordsDiff<R>\n\t\t\t\tlet presenceChanges = null as null | RecordsDiff<R>\n\t\t\t\tfor (const { onHistory, filters } of this.listeners) {\n\t\t\t\t\tif (filters.source !== 'all' && filters.source !== source) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (filters.scope !== 'all') {\n\t\t\t\t\t\tif (filters.scope === 'document') {\n\t\t\t\t\t\t\tdocumentChanges ??= this.filterChangesByScope(changes, 'document')\n\t\t\t\t\t\t\tif (!documentChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: documentChanges, source })\n\t\t\t\t\t\t} else if (filters.scope === 'session') {\n\t\t\t\t\t\t\tinstanceChanges ??= this.filterChangesByScope(changes, 'session')\n\t\t\t\t\t\t\tif (!instanceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: instanceChanges, source })\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpresenceChanges ??= this.filterChangesByScope(changes, 'presence')\n\t\t\t\t\t\t\tif (!presenceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: presenceChanges, source })\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tonHistory({ changes, source })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.cancelHistoryReactor()\n\t}\n\n\t/**\n\t * Filters out non-document changes from a diff. Returns null if there are no changes left.\n\t * @param change - the records diff\n\t * @param scope - the records scope\n\t * @returns\n\t */\n\tfilterChangesByScope(change: RecordsDiff<R>, scope: RecordScope) {\n\t\tconst result = {\n\t\t\tadded: filterEntries(change.added, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t\tupdated: filterEntries(change.updated, (_, r) => this.scopedTypes[scope].has(r[1].typeName)),\n\t\t\tremoved: filterEntries(change.removed, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t}\n\t\tif (\n\t\t\tObject.keys(result.added).length === 0 &&\n\t\t\tObject.keys(result.updated).length === 0 &&\n\t\t\tObject.keys(result.removed).length === 0\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Update the history with a diff of changes.\n\t *\n\t * @param changes - The changes to add to the history.\n\t */\n\tprivate updateHistory(changes: RecordsDiff<R>): void {\n\t\tthis.historyAccumulator.add({\n\t\t\tchanges,\n\t\t\tsource: this.isMergingRemoteChanges ? 'remote' : 'user',\n\t\t})\n\t\tif (this.listeners.size === 0) {\n\t\t\tthis.historyAccumulator.clear()\n\t\t}\n\t\tthis.history.set(this.history.get() + 1, changes)\n\t}\n\n\tvalidate(phase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests') {\n\t\tthis.allRecords().forEach((record) => this.schema.validateRecord(this, record, phase, null))\n\t}\n\n\t/**\n\t * Add or update records in the store. If a record with the same ID already exists, it will be updated.\n\t * Otherwise, a new record will be created.\n\t *\n\t * @example\n\t * ```ts\n\t * // Add new records\n\t * const book = Book.create({ title: 'Lathe Of Heaven', author: 'Le Guin' })\n\t * store.put([book])\n\t *\n\t * // Update existing record\n\t * store.put([{ ...book, title: 'The Lathe of Heaven' }])\n\t * ```\n\t *\n\t * @param records - The records to add or update\n\t * @param phaseOverride - Override the validation phase (used internally)\n\t * @public\n\t */\n\tput(records: R[], phaseOverride?: 'initialize'): void {\n\t\tthis.atomic(() => {\n\t\t\tconst updates: Record<IdOf<UnknownRecord>, [from: R, to: R]> = {}\n\t\t\tconst additions: Record<IdOf<UnknownRecord>, R> = {}\n\n\t\t\t// Iterate through all records, creating, updating or removing as needed\n\t\t\tlet record: R\n\n\t\t\t// There's a chance that, despite having records, all of the values are\n\t\t\t// identical to what they were before; and so we'd end up with an \"empty\"\n\t\t\t// history entry. Let's keep track of whether we've actually made any\n\t\t\t// changes (e.g. additions, deletions, or updates that produce a new value).\n\t\t\tlet didChange = false\n\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tfor (let i = 0, n = records.length; i < n; i++) {\n\t\t\t\trecord = records[i]\n\n\t\t\t\tconst initialValue = this.records.__unsafe__getWithoutCapture(record.id)\n\t\t\t\t// If we already have an atom for this record, update its value.\n\t\t\t\tif (initialValue) {\n\t\t\t\t\t// If we have a beforeUpdate callback, run it against the initial and next records\n\t\t\t\t\trecord = this.sideEffects.handleBeforeChange(initialValue, record, source)\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\tconst validated = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord,\n\t\t\t\t\t\tphaseOverride ?? 'updateRecord',\n\t\t\t\t\t\tinitialValue\n\t\t\t\t\t)\n\n\t\t\t\t\tif (validated === initialValue) continue\n\n\t\t\t\t\trecord = devFreeze(record)\n\t\t\t\t\tthis.records.set(record.id, record)\n\n\t\t\t\t\tdidChange = true\n\t\t\t\t\tupdates[record.id] = [initialValue, record]\n\t\t\t\t\tthis.addDiffForAfterEvent(initialValue, record)\n\t\t\t\t} else {\n\t\t\t\t\trecord = this.sideEffects.handleBeforeCreate(record, source)\n\n\t\t\t\t\tdidChange = true\n\n\t\t\t\t\t// If we don't have an atom, create one.\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\trecord = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord as R,\n\t\t\t\t\t\tphaseOverride ?? 'createRecord',\n\t\t\t\t\t\tnull\n\t\t\t\t\t)\n\n\t\t\t\t\t// freeze it\n\t\t\t\t\trecord = devFreeze(record)\n\n\t\t\t\t\t// Mark the change as a new addition.\n\t\t\t\t\tadditions[record.id] = record\n\t\t\t\t\tthis.addDiffForAfterEvent(null, record)\n\n\t\t\t\t\tthis.records.set(record.id, record)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we did change, update the history\n\t\t\tif (!didChange) return\n\t\t\tthis.updateHistory({\n\t\t\t\tadded: additions,\n\t\t\t\tupdated: updates,\n\t\t\t\tremoved: {} as Record<IdOf<R>, R>,\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Remove records from the store by their IDs.\n\t *\n\t * @example\n\t * ```ts\n\t * // Remove a single record\n\t * store.remove([book.id])\n\t *\n\t * // Remove multiple records\n\t * store.remove([book1.id, book2.id, book3.id])\n\t * ```\n\t *\n\t * @param ids - The IDs of the records to remove\n\t * @public\n\t */\n\tremove(ids: IdOf<R>[]): void {\n\t\tthis.atomic(() => {\n\t\t\tconst toDelete = new Set<IdOf<R>>(ids)\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tif (this.sideEffects.isEnabled()) {\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst record = this.records.__unsafe__getWithoutCapture(id)\n\t\t\t\t\tif (!record) continue\n\n\t\t\t\t\tif (this.sideEffects.handleBeforeDelete(record, source) === false) {\n\t\t\t\t\t\ttoDelete.delete(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst actuallyDeleted = this.records.deleteMany(toDelete)\n\t\t\tif (actuallyDeleted.length === 0) return\n\n\t\t\tconst removed = {} as RecordsDiff<R>['removed']\n\t\t\tfor (const [id, record] of actuallyDeleted) {\n\t\t\t\tremoved[id] = record\n\t\t\t\tthis.addDiffForAfterEvent(record, null)\n\t\t\t}\n\n\t\t\t// Update the history with the removed records.\n\t\t\tthis.updateHistory({ added: {}, updated: {}, removed } as RecordsDiff<R>)\n\t\t})\n\t}\n\n\t/**\n\t * Get a record by its ID. This creates a reactive subscription to the record.\n\t *\n\t * @example\n\t * ```ts\n\t * const book = store.get(bookId)\n\t * if (book) {\n\t * console.log(book.title)\n\t * }\n\t * ```\n\t *\n\t * @param id - The ID of the record to get\n\t * @returns The record if it exists, undefined otherwise\n\t * @public\n\t */\n\tget<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined {\n\t\treturn this.records.get(id) as RecordFromId<K> | undefined\n\t}\n\n\t/**\n\t * Get a record by its ID without creating a reactive subscription.\n\t * Use this when you need to access a record but don't want reactive updates.\n\t *\n\t * @example\n\t * ```ts\n\t * // Won't trigger reactive updates when this record changes\n\t * const book = store.unsafeGetWithoutCapture(bookId)\n\t * ```\n\t *\n\t * @param id - The ID of the record to get\n\t * @returns The record if it exists, undefined otherwise\n\t * @public\n\t */\n\tunsafeGetWithoutCapture<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined {\n\t\treturn this.records.__unsafe__getWithoutCapture(id) as RecordFromId<K> | undefined\n\t}\n\n\t/**\n\t * Serialize the store's records to a plain JavaScript object.\n\t * Only includes records matching the specified scope.\n\t *\n\t * @example\n\t * ```ts\n\t * // Serialize only document records (default)\n\t * const documentData = store.serialize('document')\n\t *\n\t * // Serialize all records\n\t * const allData = store.serialize('all')\n\t * ```\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'\n\t * @returns The serialized store data\n\t * @public\n\t */\n\tserialize(scope: RecordScope | 'all' = 'document'): SerializedStore<R> {\n\t\tconst result = {} as SerializedStore<R>\n\t\tfor (const [id, record] of this.records) {\n\t\t\tif (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) {\n\t\t\t\tresult[id as IdOf<R>] = record\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Get a serialized snapshot of the store and its schema.\n\t * This includes both the data and schema information needed for proper migration.\n\t *\n\t * @example\n\t * ```ts\n\t * const snapshot = store.getStoreSnapshot()\n\t * localStorage.setItem('myApp', JSON.stringify(snapshot))\n\t *\n\t * // Later...\n\t * const saved = JSON.parse(localStorage.getItem('myApp'))\n\t * store.loadStoreSnapshot(saved)\n\t * ```\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'\n\t * @returns A snapshot containing both store data and schema information\n\t * @public\n\t */\n\tgetStoreSnapshot(scope: RecordScope | 'all' = 'document'): StoreSnapshot<R> {\n\t\treturn {\n\t\t\tstore: this.serialize(scope),\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * Migrate a serialized snapshot to the current schema version.\n\t * This applies any necessary migrations to bring old data up to date.\n\t *\n\t * @example\n\t * ```ts\n\t * const oldSnapshot = JSON.parse(localStorage.getItem('myApp'))\n\t * const migratedSnapshot = store.migrateSnapshot(oldSnapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to migrate\n\t * @returns The migrated snapshot with current schema version\n\t * @throws Error if migration fails\n\t * @public\n\t */\n\tmigrateSnapshot(snapshot: StoreSnapshot<R>): StoreSnapshot<R> {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\treturn {\n\t\t\tstore: migrationResult.value,\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * Load a serialized snapshot into the store, replacing all current data.\n\t * The snapshot will be automatically migrated to the current schema version if needed.\n\t *\n\t * @example\n\t * ```ts\n\t * const snapshot = JSON.parse(localStorage.getItem('myApp'))\n\t * store.loadStoreSnapshot(snapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to load\n\t * @throws Error if migration fails or snapshot is invalid\n\t * @public\n\t */\n\tloadStoreSnapshot(snapshot: StoreSnapshot<R>): void {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\ttry {\n\t\t\tthis.sideEffects.setIsEnabled(false)\n\t\t\tthis.atomic(() => {\n\t\t\t\tthis.clear()\n\t\t\t\tthis.put(Object.values(migrationResult.value))\n\t\t\t\tthis.ensureStoreIsUsable()\n\t\t\t})\n\t\t} finally {\n\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t}\n\t}\n\n\t/**\n\t * Get an array of all records in the store.\n\t *\n\t * @example\n\t * ```ts\n\t * const allRecords = store.allRecords()\n\t * const books = allRecords.filter(r => r.typeName === 'book')\n\t * ```\n\t *\n\t * @returns An array containing all records in the store\n\t * @public\n\t */\n\tallRecords(): R[] {\n\t\treturn Array.from(this.records.values())\n\t}\n\n\t/**\n\t * Remove all records from the store.\n\t *\n\t * @example\n\t * ```ts\n\t * store.clear()\n\t * console.log(store.allRecords().length) // 0\n\t * ```\n\t *\n\t * @public\n\t */\n\tclear(): void {\n\t\tthis.remove(Array.from(this.records.keys()))\n\t}\n\n\t/**\n\t * Update a single record using an updater function. To update multiple records at once,\n\t * use the `update` method of the `TypedStore` class.\n\t *\n\t * @example\n\t * ```ts\n\t * store.update(book.id, (book) => ({\n\t * ...book,\n\t * title: 'Updated Title'\n\t * }))\n\t * ```\n\t *\n\t * @param id - The ID of the record to update\n\t * @param updater - A function that receives the current record and returns the updated record\n\t * @public\n\t */\n\tupdate<K extends IdOf<R>>(id: K, updater: (record: RecordFromId<K>) => RecordFromId<K>) {\n\t\tconst existing = this.unsafeGetWithoutCapture(id)\n\t\tif (!existing) {\n\t\t\tconsole.error(`Record ${id} not found. This is probably an error`)\n\t\t\treturn\n\t\t}\n\n\t\tthis.put([updater(existing) as any])\n\t}\n\n\t/**\n\t * Check whether a record with the given ID exists in the store.\n\t *\n\t * @example\n\t * ```ts\n\t * if (store.has(bookId)) {\n\t * console.log('Book exists!')\n\t * }\n\t * ```\n\t *\n\t * @param id - The ID of the record to check\n\t * @returns True if the record exists, false otherwise\n\t * @public\n\t */\n\thas<K extends IdOf<R>>(id: K): boolean {\n\t\treturn this.records.has(id)\n\t}\n\n\t/**\n\t * Add a listener that will be called when the store changes.\n\t * Returns a function to remove the listener.\n\t *\n\t * @example\n\t * ```ts\n\t * const removeListener = store.listen((entry) => {\n\t * console.log('Changes:', entry.changes)\n\t * console.log('Source:', entry.source)\n\t * })\n\t *\n\t * // Listen only to user changes to document records\n\t * const removeDocumentListener = store.listen(\n\t * (entry) => console.log('Document changed:', entry),\n\t * { source: 'user', scope: 'document' }\n\t * )\n\t *\n\t * // Later, remove the listener\n\t * removeListener()\n\t * ```\n\t *\n\t * @param onHistory - The listener function to call when changes occur\n\t * @param filters - Optional filters to control when the listener is called\n\t * @returns A function that removes the listener when called\n\t * @public\n\t */\n\tlisten(onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>) {\n\t\t// flush history so that this listener's history starts from exactly now\n\t\tthis._flushHistory()\n\n\t\tconst listener = {\n\t\t\tonHistory,\n\t\t\tfilters: {\n\t\t\t\tsource: filters?.source ?? 'all',\n\t\t\t\tscope: filters?.scope ?? 'all',\n\t\t\t},\n\t\t}\n\n\t\tif (!this.historyReactor.scheduler.isActivelyListening) {\n\t\t\tthis.historyReactor.start()\n\t\t\tthis.historyReactor.scheduler.execute()\n\t\t}\n\n\t\tthis.listeners.add(listener)\n\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener)\n\n\t\t\tif (this.listeners.size === 0) {\n\t\t\t\tthis.historyReactor.stop()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isMergingRemoteChanges = false\n\n\t/**\n\t * Merge changes from a remote source. Changes made within the provided function\n\t * will be marked with source 'remote' instead of 'user'.\n\t *\n\t * @example\n\t * ```ts\n\t * // Changes from sync/collaboration\n\t * store.mergeRemoteChanges(() => {\n\t * store.put(remoteRecords)\n\t * store.remove(deletedIds)\n\t * })\n\t * ```\n\t *\n\t * @param fn - A function that applies the remote changes\n\t * @public\n\t */\n\tmergeRemoteChanges(fn: () => void) {\n\t\tif (this.isMergingRemoteChanges) {\n\t\t\treturn fn()\n\t\t}\n\n\t\tif (this._isInAtomicOp) {\n\t\t\tthrow new Error('Cannot merge remote changes while in atomic operation')\n\t\t}\n\n\t\ttry {\n\t\t\tthis.atomic(fn, true, true)\n\t\t} finally {\n\t\t\tthis.ensureStoreIsUsable()\n\t\t}\n\t}\n\n\t/**\n\t * Run `fn` and return a {@link RecordsDiff} of the changes that occurred as a result.\n\t */\n\textractingChanges(fn: () => void): RecordsDiff<R> {\n\t\tconst changes: Array<RecordsDiff<R>> = []\n\t\tconst dispose = this.historyAccumulator.addInterceptor((entry) => changes.push(entry.changes))\n\t\ttry {\n\t\t\ttransact(fn)\n\t\t\treturn squashRecordDiffs(changes)\n\t\t} finally {\n\t\t\tdispose()\n\t\t}\n\t}\n\n\tapplyDiff(\n\t\tdiff: RecordsDiff<R>,\n\t\t{\n\t\t\trunCallbacks = true,\n\t\t\tignoreEphemeralKeys = false,\n\t\t}: { runCallbacks?: boolean; ignoreEphemeralKeys?: boolean } = {}\n\t) {\n\t\tthis.atomic(() => {\n\t\t\tconst toPut = objectMapValues(diff.added)\n\n\t\t\tfor (const [_from, to] of objectMapValues(diff.updated)) {\n\t\t\t\tconst type = this.schema.getType(to.typeName)\n\t\t\t\tif (ignoreEphemeralKeys && type.ephemeralKeySet.size) {\n\t\t\t\t\tconst existing = this.get(to.id)\n\t\t\t\t\tif (!existing) {\n\t\t\t\t\t\ttoPut.push(to)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tlet changed: R | null = null\n\t\t\t\t\tfor (const [key, value] of Object.entries(to)) {\n\t\t\t\t\t\tif (type.ephemeralKeySet.has(key) || Object.is(value, getOwnProperty(existing, key))) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!changed) changed = { ...existing } as R\n\t\t\t\t\t\t;(changed as any)[key] = value\n\t\t\t\t\t}\n\t\t\t\t\tif (changed) toPut.push(changed)\n\t\t\t\t} else {\n\t\t\t\t\ttoPut.push(to)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst toRemove = objectMapKeys(diff.removed)\n\t\t\tif (toPut.length) {\n\t\t\t\tthis.put(toPut)\n\t\t\t}\n\t\t\tif (toRemove.length) {\n\t\t\t\tthis.remove(toRemove)\n\t\t\t}\n\t\t}, runCallbacks)\n\t}\n\n\t/**\n\t * Create a cache based on values in the store. Pass in a function that takes and ID and a\n\t * signal for the underlying record. Return a signal (usually a computed) for the cached value.\n\t * For simple derivations, use {@link Store.createComputedCache}. This function is useful if you\n\t * need more precise control over intermediate values.\n\t */\n\tcreateCache<Result, Record extends R = R>(\n\t\tcreate: (id: IdOf<Record>, recordSignal: Signal<R>) => Signal<Result>\n\t) {\n\t\tconst cache = new WeakCache<Atom<any>, Signal<Result>>()\n\t\treturn {\n\t\t\tget: (id: IdOf<Record>) => {\n\t\t\t\tconst atom = this.records.getAtom(id)\n\t\t\t\tif (!atom) return undefined\n\t\t\t\treturn cache.get(atom, () => create(id, atom as Signal<R>)).get()\n\t\t\t},\n\t\t}\n\t}\n\n\t/**\n\t * Create a computed cache.\n\t *\n\t * @param name - The name of the derivation cache.\n\t * @param derive - A function used to derive the value of the cache.\n\t * @param opts - Options for the computed cache.\n\t * @public\n\t */\n\tcreateComputedCache<Result, Record extends R = R>(\n\t\tname: string,\n\t\tderive: (record: Record) => Result | undefined,\n\t\topts?: CreateComputedCacheOpts<Result, Record>\n\t): ComputedCache<Result, Record> {\n\t\treturn this.createCache((id, record) => {\n\t\t\tconst recordSignal = opts?.areRecordsEqual\n\t\t\t\t? computed(`${name}:${id}:isEqual`, () => record.get(), { isEqual: opts.areRecordsEqual })\n\t\t\t\t: record\n\n\t\t\treturn computed<Result | undefined>(\n\t\t\t\tname + ':' + id,\n\t\t\t\t() => {\n\t\t\t\t\treturn derive(recordSignal.get() as Record)\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tisEqual: opts?.areResultsEqual,\n\t\t\t\t}\n\t\t\t)\n\t\t})\n\t}\n\n\tprivate _integrityChecker?: () => void | undefined\n\n\t/** @internal */\n\tensureStoreIsUsable() {\n\t\tthis.atomic(() => {\n\t\t\tthis._integrityChecker ??= this.schema.createIntegrityChecker(this)\n\t\t\tthis._integrityChecker?.()\n\t\t})\n\t}\n\n\tprivate _isPossiblyCorrupted = false\n\t/** @internal */\n\tmarkAsPossiblyCorrupted() {\n\t\tthis._isPossiblyCorrupted = true\n\t}\n\t/** @internal */\n\tisPossiblyCorrupted() {\n\t\treturn this._isPossiblyCorrupted\n\t}\n\n\tprivate pendingAfterEvents: Map<IdOf<R>, { before: R | null; after: R | null }> | null = null\n\tprivate addDiffForAfterEvent(before: R | null, after: R | null) {\n\t\tassert(this.pendingAfterEvents, 'must be in event operation')\n\t\tif (before === after) return\n\t\tif (before && after) assert(before.id === after.id)\n\t\tif (!before && !after) return\n\t\tconst id = (before || after)!.id\n\t\tconst existing = this.pendingAfterEvents.get(id)\n\t\tif (existing) {\n\t\t\texisting.after = after\n\t\t} else {\n\t\t\tthis.pendingAfterEvents.set(id, { before, after })\n\t\t}\n\t}\n\tprivate flushAtomicCallbacks(isMergingRemoteChanges: boolean) {\n\t\tlet updateDepth = 0\n\t\tlet source: ChangeSource = isMergingRemoteChanges ? 'remote' : 'user'\n\t\twhile (this.pendingAfterEvents) {\n\t\t\tconst events = this.pendingAfterEvents\n\t\t\tthis.pendingAfterEvents = null\n\n\t\t\tif (!this.sideEffects.isEnabled()) continue\n\n\t\t\tupdateDepth++\n\t\t\tif (updateDepth > 100) {\n\t\t\t\tthrow new Error('Maximum store update depth exceeded, bailing out')\n\t\t\t}\n\n\t\t\tfor (const { before, after } of events.values()) {\n\t\t\t\tif (before && after && before !== after && !isEqual(before, after)) {\n\t\t\t\t\tthis.sideEffects.handleAfterChange(before, after, source)\n\t\t\t\t} else if (before && !after) {\n\t\t\t\t\tthis.sideEffects.handleAfterDelete(before, source)\n\t\t\t\t} else if (!before && after) {\n\t\t\t\t\tthis.sideEffects.handleAfterCreate(after, source)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.pendingAfterEvents) {\n\t\t\t\tthis.sideEffects.handleOperationComplete(source)\n\t\t\t} else {\n\t\t\t\t// if the side effects triggered by a remote operation resulted in more effects,\n\t\t\t\t// those extra effects should not be marked as originating remotely.\n\t\t\t\tsource = 'user'\n\t\t\t}\n\t\t}\n\t}\n\tprivate _isInAtomicOp = false\n\t/** @internal */\n\tatomic<T>(fn: () => T, runCallbacks = true, isMergingRemoteChanges = false): T {\n\t\treturn transact(() => {\n\t\t\tif (this._isInAtomicOp) {\n\t\t\t\tif (!this.pendingAfterEvents) this.pendingAfterEvents = new Map()\n\t\t\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\t\t\tassert(!isMergingRemoteChanges, 'cannot call mergeRemoteChanges while in atomic operation')\n\t\t\t\ttry {\n\t\t\t\t\t// if we are in an atomic context with side effects ON allow switching before* callbacks OFF.\n\t\t\t\t\t// but don't allow switching them ON if they had been marked OFF before.\n\t\t\t\t\tif (prevSideEffectsEnabled && !runCallbacks) {\n\t\t\t\t\t\tthis.sideEffects.setIsEnabled(false)\n\t\t\t\t\t}\n\t\t\t\t\treturn fn()\n\t\t\t\t} finally {\n\t\t\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.pendingAfterEvents = new Map()\n\t\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\t\tthis.sideEffects.setIsEnabled(runCallbacks ?? prevSideEffectsEnabled)\n\t\t\tthis._isInAtomicOp = true\n\n\t\t\tif (isMergingRemoteChanges) {\n\t\t\t\tthis.isMergingRemoteChanges = true\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = fn()\n\t\t\t\tthis.isMergingRemoteChanges = false\n\n\t\t\t\tthis.flushAtomicCallbacks(isMergingRemoteChanges)\n\n\t\t\t\treturn result\n\t\t\t} finally {\n\t\t\t\tthis.pendingAfterEvents = null\n\t\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t\t\tthis._isInAtomicOp = false\n\t\t\t\tthis.isMergingRemoteChanges = false\n\t\t\t}\n\t\t})\n\t}\n\n\t/** @internal */\n\taddHistoryInterceptor(fn: (entry: HistoryEntry<R>, source: ChangeSource) => void) {\n\t\treturn this.historyAccumulator.addInterceptor((entry) =>\n\t\t\tfn(entry, this.isMergingRemoteChanges ? 'remote' : 'user')\n\t\t)\n\t}\n}\n\n/**\n * Collect and squash history entries by their adjacent sources.\n * Adjacent entries from the same source are combined into a single entry.\n *\n * For example: [user, user, remote, remote, user] becomes [user, remote, user]\n *\n * @example\n * ```ts\n * const entries = [\n * { source: 'user', changes: userChanges1 },\n * { source: 'user', changes: userChanges2 },\n * { source: 'remote', changes: remoteChanges }\n * ]\n *\n * const squashed = squashHistoryEntries(entries)\n * // Results in 2 entries: combined user changes + remote changes\n * ```\n *\n * @param entries - The array of history entries to squash\n * @returns An array of squashed history entries\n * @public\n */\nfunction squashHistoryEntries<T extends UnknownRecord>(\n\tentries: HistoryEntry<T>[]\n): HistoryEntry<T>[] {\n\tif (entries.length === 0) return []\n\n\tconst chunked: HistoryEntry<T>[][] = []\n\tlet chunk: HistoryEntry<T>[] = [entries[0]]\n\tlet entry: HistoryEntry<T>\n\n\tfor (let i = 1, n = entries.length; i < n; i++) {\n\t\tentry = entries[i]\n\t\tif (chunk[0].source !== entry.source) {\n\t\t\tchunked.push(chunk)\n\t\t\tchunk = []\n\t\t}\n\t\tchunk.push(entry)\n\t}\n\t// Push the last chunk\n\tchunked.push(chunk)\n\n\treturn devFreeze(\n\t\tchunked.map((chunk) => ({\n\t\t\tsource: chunk[0].source,\n\t\t\tchanges: squashRecordDiffs(chunk.map((e) => e.changes)),\n\t\t}))\n\t)\n}\n\n/**\n * Internal class that accumulates history entries before they are flushed to listeners.\n * Handles batching and squashing of adjacent entries from the same source.\n *\n * @internal\n */\nclass HistoryAccumulator<T extends UnknownRecord> {\n\tprivate _history: HistoryEntry<T>[] = []\n\n\tprivate _interceptors: Set<(entry: HistoryEntry<T>) => void> = new Set()\n\n\t/**\n\t * Add an interceptor that will be called for each history entry.\n\t * Returns a function to remove the interceptor.\n\t */\n\taddInterceptor(fn: (entry: HistoryEntry<T>) => void) {\n\t\tthis._interceptors.add(fn)\n\t\treturn () => {\n\t\t\tthis._interceptors.delete(fn)\n\t\t}\n\t}\n\n\t/**\n\t * Add a history entry to the accumulator.\n\t * Calls all registered interceptors with the entry.\n\t */\n\tadd(entry: HistoryEntry<T>) {\n\t\tthis._history.push(entry)\n\t\tfor (const interceptor of this._interceptors) {\n\t\t\tinterceptor(entry)\n\t\t}\n\t}\n\n\t/**\n\t * Flush all accumulated history entries, squashing adjacent entries from the same source.\n\t * Clears the internal history buffer.\n\t */\n\tflush() {\n\t\tconst history = squashHistoryEntries(this._history)\n\t\tthis._history = []\n\t\treturn history\n\t}\n\n\t/**\n\t * Clear all accumulated history entries without flushing.\n\t */\n\tclear() {\n\t\tthis._history = []\n\t}\n\n\t/**\n\t * Check if there are any accumulated history entries.\n\t */\n\thasChanges() {\n\t\treturn this._history.length > 0\n\t}\n}\n\n/**\n * A store or an object containing a store.\n * This type is used for APIs that can accept either a store directly or an object with a store property.\n *\n * @example\n * ```ts\n * function useStore(storeOrObject: StoreObject<MyRecord>) {\n * const store = storeOrObject instanceof Store ? storeOrObject : storeOrObject.store\n * return store\n * }\n * ```\n *\n * @public\n */\nexport type StoreObject<R extends UnknownRecord> = Store<R> | { store: Store<R> }\n/**\n * Extract the record type from a StoreObject.\n *\n * @example\n * ```ts\n * type MyStoreObject = { store: Store<Book | Author> }\n * type Records = StoreObjectRecordType<MyStoreObject> // Book | Author\n * ```\n *\n * @public\n */\nexport type StoreObjectRecordType<Context extends StoreObject<any>> =\n\tContext extends Store<infer R> ? R : Context extends { store: Store<infer R> } ? R : never\n\n/**\n * Create a computed cache that works with any StoreObject (store or object containing a store).\n * This is a standalone version of Store.createComputedCache that can work with multiple store instances.\n *\n * @example\n * ```ts\n * const expensiveCache = createComputedCache(\n * 'expensiveData',\n * (context: { store: Store<Book> }, book: Book) => {\n * return performExpensiveCalculation(book)\n * }\n * )\n *\n * // Use with different store instances\n * const result1 = expensiveCache.get(storeObject1, bookId)\n * const result2 = expensiveCache.get(storeObject2, bookId)\n * ```\n *\n * @param name - A unique name for the cache (used for debugging)\n * @param derive - Function that derives a value from the context and record\n * @param opts - Optional configuration for equality checks\n * @returns A cache that can be used with multiple store instances\n * @public\n */\nexport function createComputedCache<\n\tContext extends StoreObject<any>,\n\tResult,\n\tRecord extends StoreObjectRecordType<Context> = StoreObjectRecordType<Context>,\n>(\n\tname: string,\n\tderive: (context: Context, record: Record) => Result | undefined,\n\topts?: CreateComputedCacheOpts<Result, Record>\n) {\n\tconst cache = new WeakCache<Context, ComputedCache<Result, Record>>()\n\treturn {\n\t\tget(context: Context, id: IdOf<Record>) {\n\t\t\tconst computedCache = cache.get(context, () => {\n\t\t\t\tconst store = (context instanceof Store ? context : context.store) as Store<Record>\n\t\t\t\treturn store.createComputedCache(name, (record) => derive(context, record), opts)\n\t\t\t})\n\t\t\treturn computedCache.get(id)\n\t\t},\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { Atom, Reactor, Signal, atom, computed, reactor, transact } from '@tldraw/state'\nimport {\n\tWeakCache,\n\tassert,\n\tfilterEntries,\n\tgetOwnProperty,\n\tisEqual,\n\tobjectMapEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tthrottleToNextFrame,\n\tuniqueId,\n} from '@tldraw/utils'\nimport { AtomMap } from './AtomMap'\nimport { IdOf, RecordId, UnknownRecord } from './BaseRecord'\nimport { devFreeze } from './devFreeze'\nimport { RecordsDiff, squashRecordDiffs } from './RecordsDiff'\nimport { RecordScope } from './RecordType'\nimport { StoreQueries } from './StoreQueries'\nimport { SerializedSchema, StoreSchema } from './StoreSchema'\nimport { StoreSideEffects } from './StoreSideEffects'\n\n/**\n * Extracts the record type from a record ID type.\n *\n * @example\n * ```ts\n * type BookId = RecordId<Book>\n * type BookType = RecordFromId<BookId> // Book\n * ```\n *\n * @public\n */\nexport type RecordFromId<K extends RecordId<UnknownRecord>> =\n\tK extends RecordId<infer R> ? R : never\n\n/**\n * A diff describing the changes to a collection.\n *\n * @example\n * ```ts\n * const diff: CollectionDiff<string> = {\n * added: new Set(['newItem']),\n * removed: new Set(['oldItem'])\n * }\n * ```\n *\n * @public\n */\nexport interface CollectionDiff<T> {\n\t/** Items that were added to the collection */\n\tadded?: Set<T>\n\t/** Items that were removed from the collection */\n\tremoved?: Set<T>\n}\n\n/**\n * The source of a change to the store.\n * - `'user'` - Changes originating from local user actions\n * - `'remote'` - Changes originating from remote synchronization\n *\n * @public\n */\nexport type ChangeSource = 'user' | 'remote'\n\n/**\n * Filters for store listeners to control which changes trigger the listener.\n *\n * @example\n * ```ts\n * const filters: StoreListenerFilters = {\n * source: 'user', // Only listen to user changes\n * scope: 'document' // Only listen to document-scoped records\n * }\n * ```\n *\n * @public\n */\nexport interface StoreListenerFilters {\n\t/** Filter by the source of changes */\n\tsource: ChangeSource | 'all'\n\t/** Filter by the scope of records */\n\tscope: RecordScope | 'all'\n}\n\n/**\n * An entry containing changes that originated either by user actions or remote changes.\n * History entries are used to track and replay changes to the store.\n *\n * @example\n * ```ts\n * const entry: HistoryEntry<Book> = {\n * changes: {\n * added: { 'book:123': bookRecord },\n * updated: {},\n * removed: {}\n * },\n * source: 'user'\n * }\n * ```\n *\n * @public\n */\nexport interface HistoryEntry<R extends UnknownRecord = UnknownRecord> {\n\t/** The changes that occurred in this history entry */\n\tchanges: RecordsDiff<R>\n\t/** The source of these changes */\n\tsource: ChangeSource\n}\n\n/**\n * A function that will be called when the history changes.\n *\n * @example\n * ```ts\n * const listener: StoreListener<Book> = (entry) => {\n * console.log('Changes:', entry.changes)\n * console.log('Source:', entry.source)\n * }\n *\n * store.listen(listener)\n * ```\n *\n * @param entry - The history entry containing the changes\n *\n * @public\n */\nexport type StoreListener<R extends UnknownRecord> = (entry: HistoryEntry<R>) => void\n\n/**\n * A computed cache that stores derived data for records.\n * The cache automatically updates when underlying records change and cleans up when records are deleted.\n *\n * @example\n * ```ts\n * const expensiveCache = store.createComputedCache(\n * 'expensive',\n * (book: Book) => performExpensiveCalculation(book)\n * )\n *\n * const result = expensiveCache.get(bookId)\n * ```\n *\n * @public\n */\nexport interface ComputedCache<Data, R extends UnknownRecord> {\n\t/**\n\t * Get the cached data for a record by its ID.\n\t *\n\t * @param id - The ID of the record\n\t * @returns The cached data or undefined if the record doesn't exist\n\t */\n\tget(id: IdOf<R>): Data | undefined\n}\n\n/**\n * Options for creating a computed cache.\n *\n * @example\n * ```ts\n * const options: CreateComputedCacheOpts<string[], Book> = {\n * areRecordsEqual: (a, b) => a.title === b.title,\n * areResultsEqual: (a, b) => JSON.stringify(a) === JSON.stringify(b)\n * }\n * ```\n *\n * @public\n */\nexport interface CreateComputedCacheOpts<Data, R extends UnknownRecord> {\n\t/** Custom equality function for comparing records */\n\tareRecordsEqual?(a: R, b: R): boolean\n\t/** Custom equality function for comparing results */\n\tareResultsEqual?(a: Data, b: Data): boolean\n}\n\n/**\n * A serialized snapshot of the record store's values.\n * This is a plain JavaScript object that can be saved to storage or transmitted over the network.\n *\n * @example\n * ```ts\n * const serialized: SerializedStore<Book> = {\n * 'book:123': { id: 'book:123', typeName: 'book', title: 'The Lathe of Heaven' },\n * 'book:456': { id: 'book:456', typeName: 'book', title: 'The Left Hand of Darkness' }\n * }\n * ```\n *\n * @public\n */\nexport type SerializedStore<R extends UnknownRecord> = Record<IdOf<R>, R>\n\n/**\n * A snapshot of the store including both data and schema information.\n * This enables proper migration when loading data from different schema versions.\n *\n * @example\n * ```ts\n * const snapshot = store.getStoreSnapshot()\n * // Later...\n * store.loadStoreSnapshot(snapshot)\n * ```\n *\n * @public\n */\nexport interface StoreSnapshot<R extends UnknownRecord> {\n\t/** The serialized store data */\n\tstore: SerializedStore<R>\n\t/** The serialized schema information */\n\tschema: SerializedSchema\n}\n\n/**\n * A validator for store records that ensures data integrity.\n * Validators are called when records are created or updated.\n *\n * @example\n * ```ts\n * const bookValidator: StoreValidator<Book> = {\n * validate(record: unknown): Book {\n * // Validate and return the record\n * if (typeof record !== 'object' || !record.title) {\n * throw new Error('Invalid book')\n * }\n * return record as Book\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface StoreValidator<R extends UnknownRecord> {\n\t/**\n\t * Validate a record.\n\t *\n\t * @param record - The record to validate\n\t * @returns The validated record\n\t * @throws When validation fails\n\t */\n\tvalidate(record: unknown): R\n\t/**\n\t * Validate a record using a known good version for reference.\n\t *\n\t * @param knownGoodVersion - A known valid version of the record\n\t * @param record - The record to validate\n\t * @returns The validated record\n\t */\n\tvalidateUsingKnownGoodVersion?(knownGoodVersion: R, record: unknown): R\n}\n\n/**\n * A map of validators for each record type in the store.\n *\n * @example\n * ```ts\n * const validators: StoreValidators<Book | Author> = {\n * book: bookValidator,\n * author: authorValidator\n * }\n * ```\n *\n * @public\n */\nexport type StoreValidators<R extends UnknownRecord> = {\n\t[K in R['typeName']]: StoreValidator<Extract<R, { typeName: K }>>\n}\n\n/**\n * Information about an error that occurred in the store.\n *\n * @example\n * ```ts\n * const error: StoreError = {\n * error: new Error('Validation failed'),\n * phase: 'updateRecord',\n * recordBefore: oldRecord,\n * recordAfter: newRecord,\n * isExistingValidationIssue: false\n * }\n * ```\n *\n * @public\n */\nexport interface StoreError {\n\t/** The error that occurred */\n\terror: Error\n\t/** The phase during which the error occurred */\n\tphase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests'\n\t/** The record state before the operation (if applicable) */\n\trecordBefore?: unknown\n\t/** The record state after the operation */\n\trecordAfter: unknown\n\t/** Whether this is an existing validation issue */\n\tisExistingValidationIssue: boolean\n}\n\n/**\n * Extract the record type from a Store type.\n * Used internally for type inference.\n *\n * @internal\n */\nexport type StoreRecord<S extends Store<any>> = S extends Store<infer R> ? R : never\n\n/**\n * A reactive store that manages collections of typed records.\n *\n * The Store is the central container for your application's data, providing:\n * - Reactive state management with automatic updates\n * - Type-safe record operations\n * - History tracking and change notifications\n * - Schema validation and migrations\n * - Side effects and business logic hooks\n * - Efficient querying and indexing\n *\n * @example\n * ```ts\n * // Create a store with schema\n * const schema = StoreSchema.create({\n * book: Book,\n * author: Author\n * })\n *\n * const store = new Store({\n * schema,\n * props: {}\n * })\n *\n * // Add records\n * const book = Book.create({ title: 'The Lathe of Heaven', author: 'Le Guin' })\n * store.put([book])\n *\n * // Listen to changes\n * store.listen((entry) => {\n * console.log('Changes:', entry.changes)\n * })\n * ```\n *\n * @public\n */\nexport class Store<R extends UnknownRecord = UnknownRecord, Props = unknown> {\n\t/**\n\t * The unique identifier of the store instance.\n\t *\n\t * @public\n\t */\n\tpublic readonly id: string\n\t/**\n\t * An AtomMap containing the stores records.\n\t *\n\t * @internal\n\t * @readonly\n\t */\n\tprivate readonly records: AtomMap<IdOf<R>, R>\n\n\t/**\n\t * An atom containing the store's history.\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly history: Atom<number, RecordsDiff<R>> = atom('history', 0, {\n\t\thistoryLength: 1000,\n\t})\n\n\t/**\n\t * Reactive queries and indexes for efficiently accessing store data.\n\t * Provides methods for filtering, indexing, and subscribing to subsets of records.\n\t *\n\t * @example\n\t * ```ts\n\t * // Create an index by a property\n\t * const booksByAuthor = store.query.index('book', 'author')\n\t *\n\t * // Get records matching criteria\n\t * const inStockBooks = store.query.records('book', () => ({\n\t * inStock: { eq: true }\n\t * }))\n\t * ```\n\t *\n\t * @public\n\t * @readonly\n\t */\n\treadonly query: StoreQueries<R>\n\n\t/**\n\t * A set containing listeners that have been added to this store.\n\t *\n\t * @internal\n\t */\n\tprivate listeners = new Set<{ onHistory: StoreListener<R>; filters: StoreListenerFilters }>()\n\n\t/**\n\t * An array of history entries that have not yet been flushed.\n\t *\n\t * @internal\n\t */\n\tprivate historyAccumulator = new HistoryAccumulator<R>()\n\n\t/**\n\t * A reactor that responds to changes to the history by squashing the accumulated history and\n\t * notifying listeners of the changes.\n\t *\n\t * @internal\n\t */\n\tprivate historyReactor: Reactor\n\n\t/**\n\t * Function to dispose of any in-flight timeouts.\n\t *\n\t * @internal\n\t */\n\tprivate cancelHistoryReactor(): void {\n\t\t/* noop */\n\t}\n\n\t/**\n\t * The schema that defines the structure and validation rules for records in this store.\n\t *\n\t * @public\n\t */\n\treadonly schema: StoreSchema<R, Props>\n\n\t/**\n\t * Custom properties associated with this store instance.\n\t *\n\t * @public\n\t */\n\treadonly props: Props\n\n\t/**\n\t * A mapping of record scopes to the set of record type names that belong to each scope.\n\t * Used to filter records by their persistence and synchronization behavior.\n\t *\n\t * @public\n\t */\n\tpublic readonly scopedTypes: { readonly [K in RecordScope]: ReadonlySet<R['typeName']> }\n\n\t/**\n\t * Side effects manager that handles lifecycle events for record operations.\n\t * Allows registration of callbacks for create, update, delete, and validation events.\n\t *\n\t * @example\n\t * ```ts\n\t * store.sideEffects.registerAfterCreateHandler('book', (book) => {\n\t * console.log('Book created:', book.title)\n\t * })\n\t * ```\n\t *\n\t * @public\n\t */\n\tpublic readonly sideEffects = new StoreSideEffects<R>(this)\n\n\t/**\n\t * Creates a new Store instance.\n\t *\n\t * @example\n\t * ```ts\n\t * const store = new Store({\n\t * schema: StoreSchema.create({ book: Book }),\n\t * props: { appName: 'MyLibrary' },\n\t * initialData: savedData\n\t * })\n\t * ```\n\t *\n\t * @param config - Configuration object for the store\n\t */\n\tconstructor(config: {\n\t\t/** Optional unique identifier for the store */\n\t\tid?: string\n\t\t/** The store's initial data to populate on creation */\n\t\tinitialData?: SerializedStore<R>\n\t\t/** The schema defining record types, validation, and migrations */\n\t\tschema: StoreSchema<R, Props>\n\t\t/** Custom properties for the store instance */\n\t\tprops: Props\n\t}) {\n\t\tconst { initialData, schema, id } = config\n\n\t\tthis.id = id ?? uniqueId()\n\t\tthis.schema = schema\n\t\tthis.props = config.props\n\n\t\tif (initialData) {\n\t\t\tthis.records = new AtomMap(\n\t\t\t\t'store',\n\t\t\t\tobjectMapEntries(initialData).map(([id, record]) => [\n\t\t\t\t\tid,\n\t\t\t\t\tdevFreeze(this.schema.validateRecord(this, record, 'initialize', null)),\n\t\t\t\t])\n\t\t\t)\n\t\t} else {\n\t\t\tthis.records = new AtomMap('store')\n\t\t}\n\n\t\tthis.query = new StoreQueries<R>(this.records, this.history)\n\n\t\tthis.historyReactor = reactor(\n\t\t\t'Store.historyReactor',\n\t\t\t() => {\n\t\t\t\t// deref to make sure we're subscribed regardless of whether we need to propagate\n\t\t\t\tthis.history.get()\n\t\t\t\t// If we have accumulated history, flush it and update listeners\n\t\t\t\tthis._flushHistory()\n\t\t\t},\n\t\t\t{ scheduleEffect: (cb) => (this.cancelHistoryReactor = throttleToNextFrame(cb)) }\n\t\t)\n\t\tthis.scopedTypes = {\n\t\t\tdocument: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'document')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tsession: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'session')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t\tpresence: new Set(\n\t\t\t\tobjectMapValues(this.schema.types)\n\t\t\t\t\t.filter((t) => t.scope === 'presence')\n\t\t\t\t\t.map((t) => t.typeName)\n\t\t\t),\n\t\t}\n\t}\n\n\tpublic _flushHistory() {\n\t\t// If we have accumulated history, flush it and update listeners\n\t\tif (this.historyAccumulator.hasChanges()) {\n\t\t\tconst entries = this.historyAccumulator.flush()\n\t\t\tfor (const { changes, source } of entries) {\n\t\t\t\tlet instanceChanges = null as null | RecordsDiff<R>\n\t\t\t\tlet documentChanges = null as null | RecordsDiff<R>\n\t\t\t\tlet presenceChanges = null as null | RecordsDiff<R>\n\t\t\t\tfor (const { onHistory, filters } of this.listeners) {\n\t\t\t\t\tif (filters.source !== 'all' && filters.source !== source) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (filters.scope !== 'all') {\n\t\t\t\t\t\tif (filters.scope === 'document') {\n\t\t\t\t\t\t\tdocumentChanges ??= this.filterChangesByScope(changes, 'document')\n\t\t\t\t\t\t\tif (!documentChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: documentChanges, source })\n\t\t\t\t\t\t} else if (filters.scope === 'session') {\n\t\t\t\t\t\t\tinstanceChanges ??= this.filterChangesByScope(changes, 'session')\n\t\t\t\t\t\t\tif (!instanceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: instanceChanges, source })\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpresenceChanges ??= this.filterChangesByScope(changes, 'presence')\n\t\t\t\t\t\t\tif (!presenceChanges) continue\n\t\t\t\t\t\t\tonHistory({ changes: presenceChanges, source })\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tonHistory({ changes, source })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.cancelHistoryReactor()\n\t}\n\n\t/**\n\t * Filters out non-document changes from a diff. Returns null if there are no changes left.\n\t * @param change - the records diff\n\t * @param scope - the records scope\n\t * @returns\n\t */\n\tfilterChangesByScope(change: RecordsDiff<R>, scope: RecordScope) {\n\t\tconst result = {\n\t\t\tadded: filterEntries(change.added, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t\tupdated: filterEntries(change.updated, (_, r) => this.scopedTypes[scope].has(r[1].typeName)),\n\t\t\tremoved: filterEntries(change.removed, (_, r) => this.scopedTypes[scope].has(r.typeName)),\n\t\t}\n\t\tif (\n\t\t\tObject.keys(result.added).length === 0 &&\n\t\t\tObject.keys(result.updated).length === 0 &&\n\t\t\tObject.keys(result.removed).length === 0\n\t\t) {\n\t\t\treturn null\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Update the history with a diff of changes.\n\t *\n\t * @param changes - The changes to add to the history.\n\t */\n\tprivate updateHistory(changes: RecordsDiff<R>): void {\n\t\tthis.historyAccumulator.add({\n\t\t\tchanges,\n\t\t\tsource: this.isMergingRemoteChanges ? 'remote' : 'user',\n\t\t})\n\t\tif (this.listeners.size === 0) {\n\t\t\tthis.historyAccumulator.clear()\n\t\t}\n\t\tthis.history.set(this.history.get() + 1, changes)\n\t}\n\n\tvalidate(phase: 'initialize' | 'createRecord' | 'updateRecord' | 'tests') {\n\t\tthis.allRecords().forEach((record) => this.schema.validateRecord(this, record, phase, null))\n\t}\n\n\t/**\n\t * Add or update records in the store. If a record with the same ID already exists, it will be updated.\n\t * Otherwise, a new record will be created.\n\t *\n\t * @example\n\t * ```ts\n\t * // Add new records\n\t * const book = Book.create({ title: 'Lathe Of Heaven', author: 'Le Guin' })\n\t * store.put([book])\n\t *\n\t * // Update existing record\n\t * store.put([{ ...book, title: 'The Lathe of Heaven' }])\n\t * ```\n\t *\n\t * @param records - The records to add or update\n\t * @param phaseOverride - Override the validation phase (used internally)\n\t * @public\n\t */\n\tput(records: R[], phaseOverride?: 'initialize'): void {\n\t\tthis.atomic(() => {\n\t\t\tconst updates: Record<IdOf<UnknownRecord>, [from: R, to: R]> = {}\n\t\t\tconst additions: Record<IdOf<UnknownRecord>, R> = {}\n\n\t\t\t// Iterate through all records, creating, updating or removing as needed\n\t\t\tlet record: R\n\n\t\t\t// There's a chance that, despite having records, all of the values are\n\t\t\t// identical to what they were before; and so we'd end up with an \"empty\"\n\t\t\t// history entry. Let's keep track of whether we've actually made any\n\t\t\t// changes (e.g. additions, deletions, or updates that produce a new value).\n\t\t\tlet didChange = false\n\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tfor (let i = 0, n = records.length; i < n; i++) {\n\t\t\t\trecord = records[i]\n\n\t\t\t\tconst initialValue = this.records.__unsafe__getWithoutCapture(record.id)\n\t\t\t\t// If we already have an atom for this record, update its value.\n\t\t\t\tif (initialValue) {\n\t\t\t\t\t// If we have a beforeUpdate callback, run it against the initial and next records\n\t\t\t\t\trecord = this.sideEffects.handleBeforeChange(initialValue, record, source)\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\tconst validated = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord,\n\t\t\t\t\t\tphaseOverride ?? 'updateRecord',\n\t\t\t\t\t\tinitialValue\n\t\t\t\t\t)\n\n\t\t\t\t\tif (validated === initialValue) continue\n\n\t\t\t\t\trecord = devFreeze(record)\n\t\t\t\t\tthis.records.set(record.id, record)\n\n\t\t\t\t\tdidChange = true\n\t\t\t\t\tupdates[record.id] = [initialValue, record]\n\t\t\t\t\tthis.addDiffForAfterEvent(initialValue, record)\n\t\t\t\t} else {\n\t\t\t\t\trecord = this.sideEffects.handleBeforeCreate(record, source)\n\n\t\t\t\t\tdidChange = true\n\n\t\t\t\t\t// If we don't have an atom, create one.\n\n\t\t\t\t\t// Validate the record\n\t\t\t\t\trecord = this.schema.validateRecord(\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\trecord as R,\n\t\t\t\t\t\tphaseOverride ?? 'createRecord',\n\t\t\t\t\t\tnull\n\t\t\t\t\t)\n\n\t\t\t\t\t// freeze it\n\t\t\t\t\trecord = devFreeze(record)\n\n\t\t\t\t\t// Mark the change as a new addition.\n\t\t\t\t\tadditions[record.id] = record\n\t\t\t\t\tthis.addDiffForAfterEvent(null, record)\n\n\t\t\t\t\tthis.records.set(record.id, record)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we did change, update the history\n\t\t\tif (!didChange) return\n\t\t\tthis.updateHistory({\n\t\t\t\tadded: additions,\n\t\t\t\tupdated: updates,\n\t\t\t\tremoved: {} as Record<IdOf<R>, R>,\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Remove records from the store by their IDs.\n\t *\n\t * @example\n\t * ```ts\n\t * // Remove a single record\n\t * store.remove([book.id])\n\t *\n\t * // Remove multiple records\n\t * store.remove([book1.id, book2.id, book3.id])\n\t * ```\n\t *\n\t * @param ids - The IDs of the records to remove\n\t * @public\n\t */\n\tremove(ids: IdOf<R>[]): void {\n\t\tthis.atomic(() => {\n\t\t\tconst toDelete = new Set<IdOf<R>>(ids)\n\t\t\tconst source = this.isMergingRemoteChanges ? 'remote' : 'user'\n\n\t\t\tif (this.sideEffects.isEnabled()) {\n\t\t\t\tfor (const id of ids) {\n\t\t\t\t\tconst record = this.records.__unsafe__getWithoutCapture(id)\n\t\t\t\t\tif (!record) continue\n\n\t\t\t\t\tif (this.sideEffects.handleBeforeDelete(record, source) === false) {\n\t\t\t\t\t\ttoDelete.delete(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst actuallyDeleted = this.records.deleteMany(toDelete)\n\t\t\tif (actuallyDeleted.length === 0) return\n\n\t\t\tconst removed = {} as RecordsDiff<R>['removed']\n\t\t\tfor (const [id, record] of actuallyDeleted) {\n\t\t\t\tremoved[id] = record\n\t\t\t\tthis.addDiffForAfterEvent(record, null)\n\t\t\t}\n\n\t\t\t// Update the history with the removed records.\n\t\t\tthis.updateHistory({ added: {}, updated: {}, removed } as RecordsDiff<R>)\n\t\t})\n\t}\n\n\t/**\n\t * Get a record by its ID. This creates a reactive subscription to the record.\n\t *\n\t * @example\n\t * ```ts\n\t * const book = store.get(bookId)\n\t * if (book) {\n\t * console.log(book.title)\n\t * }\n\t * ```\n\t *\n\t * @param id - The ID of the record to get\n\t * @returns The record if it exists, undefined otherwise\n\t * @public\n\t */\n\tget<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined {\n\t\treturn this.records.get(id) as RecordFromId<K> | undefined\n\t}\n\n\t/**\n\t * Get a record by its ID without creating a reactive subscription.\n\t * Use this when you need to access a record but don't want reactive updates.\n\t *\n\t * @example\n\t * ```ts\n\t * // Won't trigger reactive updates when this record changes\n\t * const book = store.unsafeGetWithoutCapture(bookId)\n\t * ```\n\t *\n\t * @param id - The ID of the record to get\n\t * @returns The record if it exists, undefined otherwise\n\t * @public\n\t */\n\tunsafeGetWithoutCapture<K extends IdOf<R>>(id: K): RecordFromId<K> | undefined {\n\t\treturn this.records.__unsafe__getWithoutCapture(id) as RecordFromId<K> | undefined\n\t}\n\n\t/**\n\t * Serialize the store's records to a plain JavaScript object.\n\t * Only includes records matching the specified scope.\n\t *\n\t * @example\n\t * ```ts\n\t * // Serialize only document records (default)\n\t * const documentData = store.serialize('document')\n\t *\n\t * // Serialize all records\n\t * const allData = store.serialize('all')\n\t * ```\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'\n\t * @returns The serialized store data\n\t * @public\n\t */\n\tserialize(scope: RecordScope | 'all' = 'document'): SerializedStore<R> {\n\t\tconst result = {} as SerializedStore<R>\n\t\tfor (const [id, record] of this.records) {\n\t\t\tif (scope === 'all' || this.scopedTypes[scope].has(record.typeName)) {\n\t\t\t\tresult[id as IdOf<R>] = record\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\t/**\n\t * Get a serialized snapshot of the store and its schema.\n\t * This includes both the data and schema information needed for proper migration.\n\t *\n\t * @example\n\t * ```ts\n\t * const snapshot = store.getStoreSnapshot()\n\t * localStorage.setItem('myApp', JSON.stringify(snapshot))\n\t *\n\t * // Later...\n\t * const saved = JSON.parse(localStorage.getItem('myApp'))\n\t * store.loadStoreSnapshot(saved)\n\t * ```\n\t *\n\t * @param scope - The scope of records to serialize. Defaults to 'document'\n\t * @returns A snapshot containing both store data and schema information\n\t * @public\n\t */\n\tgetStoreSnapshot(scope: RecordScope | 'all' = 'document'): StoreSnapshot<R> {\n\t\treturn {\n\t\t\tstore: this.serialize(scope),\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * Migrate a serialized snapshot to the current schema version.\n\t * This applies any necessary migrations to bring old data up to date.\n\t *\n\t * @example\n\t * ```ts\n\t * const oldSnapshot = JSON.parse(localStorage.getItem('myApp'))\n\t * const migratedSnapshot = store.migrateSnapshot(oldSnapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to migrate\n\t * @returns The migrated snapshot with current schema version\n\t * @throws Error if migration fails\n\t * @public\n\t */\n\tmigrateSnapshot(snapshot: StoreSnapshot<R>): StoreSnapshot<R> {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\treturn {\n\t\t\tstore: migrationResult.value,\n\t\t\tschema: this.schema.serialize(),\n\t\t}\n\t}\n\n\t/**\n\t * Load a serialized snapshot into the store, replacing all current data.\n\t * The snapshot will be automatically migrated to the current schema version if needed.\n\t *\n\t * @example\n\t * ```ts\n\t * const snapshot = JSON.parse(localStorage.getItem('myApp'))\n\t * store.loadStoreSnapshot(snapshot)\n\t * ```\n\t *\n\t * @param snapshot - The snapshot to load\n\t * @throws Error if migration fails or snapshot is invalid\n\t * @public\n\t */\n\tloadStoreSnapshot(snapshot: StoreSnapshot<R>): void {\n\t\tconst migrationResult = this.schema.migrateStoreSnapshot(snapshot)\n\n\t\tif (migrationResult.type === 'error') {\n\t\t\tthrow new Error(`Failed to migrate snapshot: ${migrationResult.reason}`)\n\t\t}\n\n\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\ttry {\n\t\t\tthis.sideEffects.setIsEnabled(false)\n\t\t\tthis.atomic(() => {\n\t\t\t\tthis.clear()\n\t\t\t\tthis.put(Object.values(migrationResult.value))\n\t\t\t\tthis.ensureStoreIsUsable()\n\t\t\t})\n\t\t} finally {\n\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t}\n\t}\n\n\t/**\n\t * Get an array of all records in the store.\n\t *\n\t * @example\n\t * ```ts\n\t * const allRecords = store.allRecords()\n\t * const books = allRecords.filter(r => r.typeName === 'book')\n\t * ```\n\t *\n\t * @returns An array containing all records in the store\n\t * @public\n\t */\n\tallRecords(): R[] {\n\t\treturn Array.from(this.records.values())\n\t}\n\n\t/**\n\t * Remove all records from the store.\n\t *\n\t * @example\n\t * ```ts\n\t * store.clear()\n\t * console.log(store.allRecords().length) // 0\n\t * ```\n\t *\n\t * @public\n\t */\n\tclear(): void {\n\t\tthis.remove(Array.from(this.records.keys()))\n\t}\n\n\t/**\n\t * Update a single record using an updater function. To update multiple records at once,\n\t * use the `update` method of the `TypedStore` class.\n\t *\n\t * @example\n\t * ```ts\n\t * store.update(book.id, (book) => ({\n\t * ...book,\n\t * title: 'Updated Title'\n\t * }))\n\t * ```\n\t *\n\t * @param id - The ID of the record to update\n\t * @param updater - A function that receives the current record and returns the updated record\n\t * @public\n\t */\n\tupdate<K extends IdOf<R>>(id: K, updater: (record: RecordFromId<K>) => RecordFromId<K>) {\n\t\tconst existing = this.unsafeGetWithoutCapture(id)\n\t\tif (!existing) {\n\t\t\tconsole.error(`Record ${id} not found. This is probably an error`)\n\t\t\treturn\n\t\t}\n\n\t\tthis.put([updater(existing) as any])\n\t}\n\n\t/**\n\t * Check whether a record with the given ID exists in the store.\n\t *\n\t * @example\n\t * ```ts\n\t * if (store.has(bookId)) {\n\t * console.log('Book exists!')\n\t * }\n\t * ```\n\t *\n\t * @param id - The ID of the record to check\n\t * @returns True if the record exists, false otherwise\n\t * @public\n\t */\n\thas<K extends IdOf<R>>(id: K): boolean {\n\t\treturn this.records.has(id)\n\t}\n\n\t/**\n\t * Add a listener that will be called when the store changes.\n\t * Returns a function to remove the listener.\n\t *\n\t * @example\n\t * ```ts\n\t * const removeListener = store.listen((entry) => {\n\t * console.log('Changes:', entry.changes)\n\t * console.log('Source:', entry.source)\n\t * })\n\t *\n\t * // Listen only to user changes to document records\n\t * const removeDocumentListener = store.listen(\n\t * (entry) => console.log('Document changed:', entry),\n\t * { source: 'user', scope: 'document' }\n\t * )\n\t *\n\t * // Later, remove the listener\n\t * removeListener()\n\t * ```\n\t *\n\t * @param onHistory - The listener function to call when changes occur\n\t * @param filters - Optional filters to control when the listener is called\n\t * @returns A function that removes the listener when called\n\t * @public\n\t */\n\tlisten(onHistory: StoreListener<R>, filters?: Partial<StoreListenerFilters>) {\n\t\t// flush history so that this listener's history starts from exactly now\n\t\tthis._flushHistory()\n\n\t\tconst listener = {\n\t\t\tonHistory,\n\t\t\tfilters: {\n\t\t\t\tsource: filters?.source ?? 'all',\n\t\t\t\tscope: filters?.scope ?? 'all',\n\t\t\t},\n\t\t}\n\n\t\tif (!this.historyReactor.scheduler.isActivelyListening) {\n\t\t\tthis.historyReactor.start()\n\t\t\tthis.historyReactor.scheduler.execute()\n\t\t}\n\n\t\tthis.listeners.add(listener)\n\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener)\n\n\t\t\tif (this.listeners.size === 0) {\n\t\t\t\tthis.historyReactor.stop()\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isMergingRemoteChanges = false\n\n\t/**\n\t * Merge changes from a remote source. Changes made within the provided function\n\t * will be marked with source 'remote' instead of 'user'.\n\t *\n\t * @example\n\t * ```ts\n\t * // Changes from sync/collaboration\n\t * store.mergeRemoteChanges(() => {\n\t * store.put(remoteRecords)\n\t * store.remove(deletedIds)\n\t * })\n\t * ```\n\t *\n\t * @param fn - A function that applies the remote changes\n\t * @public\n\t */\n\tmergeRemoteChanges(fn: () => void) {\n\t\tif (this.isMergingRemoteChanges) {\n\t\t\treturn fn()\n\t\t}\n\n\t\tif (this._isInAtomicOp) {\n\t\t\tthrow new Error('Cannot merge remote changes while in atomic operation')\n\t\t}\n\n\t\ttry {\n\t\t\tthis.atomic(fn, true, true)\n\t\t} finally {\n\t\t\tthis.ensureStoreIsUsable()\n\t\t}\n\t}\n\n\t/**\n\t * Run `fn` and return a {@link RecordsDiff} of the changes that occurred as a result.\n\t */\n\textractingChanges(fn: () => void): RecordsDiff<R> {\n\t\tconst changes: Array<RecordsDiff<R>> = []\n\t\tconst dispose = this.historyAccumulator.addInterceptor((entry) => changes.push(entry.changes))\n\t\ttry {\n\t\t\ttransact(fn)\n\t\t\treturn squashRecordDiffs(changes)\n\t\t} finally {\n\t\t\tdispose()\n\t\t}\n\t}\n\n\tapplyDiff(\n\t\tdiff: RecordsDiff<R>,\n\t\t{\n\t\t\trunCallbacks = true,\n\t\t\tignoreEphemeralKeys = false,\n\t\t}: { runCallbacks?: boolean; ignoreEphemeralKeys?: boolean } = {}\n\t) {\n\t\tthis.atomic(() => {\n\t\t\tconst toPut = objectMapValues(diff.added)\n\n\t\t\tfor (const [_from, to] of objectMapValues(diff.updated)) {\n\t\t\t\tconst type = this.schema.getType(to.typeName)\n\t\t\t\tif (ignoreEphemeralKeys && type.ephemeralKeySet.size) {\n\t\t\t\t\tconst existing = this.get(to.id)\n\t\t\t\t\tif (!existing) {\n\t\t\t\t\t\ttoPut.push(to)\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tlet changed: R | null = null\n\t\t\t\t\tfor (const [key, value] of Object.entries(to)) {\n\t\t\t\t\t\tif (type.ephemeralKeySet.has(key) || Object.is(value, getOwnProperty(existing, key))) {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!changed) changed = { ...existing } as R\n\t\t\t\t\t\t;(changed as any)[key] = value\n\t\t\t\t\t}\n\t\t\t\t\tif (changed) toPut.push(changed)\n\t\t\t\t} else {\n\t\t\t\t\ttoPut.push(to)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst toRemove = objectMapKeys(diff.removed)\n\t\t\tif (toPut.length) {\n\t\t\t\tthis.put(toPut)\n\t\t\t}\n\t\t\tif (toRemove.length) {\n\t\t\t\tthis.remove(toRemove)\n\t\t\t}\n\t\t}, runCallbacks)\n\t}\n\n\t/**\n\t * Create a cache based on values in the store. Pass in a function that takes and ID and a\n\t * signal for the underlying record. Return a signal (usually a computed) for the cached value.\n\t * For simple derivations, use {@link Store.createComputedCache}. This function is useful if you\n\t * need more precise control over intermediate values.\n\t */\n\tcreateCache<Result, Record extends R = R>(\n\t\tcreate: (id: IdOf<Record>, recordSignal: Signal<R>) => Signal<Result>\n\t) {\n\t\tconst cache = new WeakCache<Atom<any>, Signal<Result>>()\n\t\treturn {\n\t\t\tget: (id: IdOf<Record>) => {\n\t\t\t\tconst atom = this.records.getAtom(id)\n\t\t\t\tif (!atom) return undefined\n\t\t\t\treturn cache.get(atom, () => create(id, atom as Signal<R>)).get()\n\t\t\t},\n\t\t}\n\t}\n\n\t/**\n\t * Create a computed cache.\n\t *\n\t * @param name - The name of the derivation cache.\n\t * @param derive - A function used to derive the value of the cache.\n\t * @param opts - Options for the computed cache.\n\t * @public\n\t */\n\tcreateComputedCache<Result, Record extends R = R>(\n\t\tname: string,\n\t\tderive: (record: Record) => Result | undefined,\n\t\topts?: CreateComputedCacheOpts<Result, Record>\n\t): ComputedCache<Result, Record> {\n\t\treturn this.createCache((id, record) => {\n\t\t\tconst recordSignal = opts?.areRecordsEqual\n\t\t\t\t? computed(`${name}:${id}:isEqual`, () => record.get(), { isEqual: opts.areRecordsEqual })\n\t\t\t\t: record\n\n\t\t\treturn computed<Result | undefined>(\n\t\t\t\tname + ':' + id,\n\t\t\t\t() => {\n\t\t\t\t\treturn derive(recordSignal.get() as Record)\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tisEqual: opts?.areResultsEqual,\n\t\t\t\t}\n\t\t\t)\n\t\t})\n\t}\n\n\tprivate _integrityChecker?: () => void | undefined\n\n\t/** @internal */\n\tensureStoreIsUsable() {\n\t\tthis.atomic(() => {\n\t\t\tthis._integrityChecker ??= this.schema.createIntegrityChecker(this)\n\t\t\tthis._integrityChecker?.()\n\t\t})\n\t}\n\n\tprivate _isPossiblyCorrupted = false\n\t/** @internal */\n\tmarkAsPossiblyCorrupted() {\n\t\tthis._isPossiblyCorrupted = true\n\t}\n\t/** @internal */\n\tisPossiblyCorrupted() {\n\t\treturn this._isPossiblyCorrupted\n\t}\n\n\tprivate pendingAfterEvents: Map<IdOf<R>, { before: R | null; after: R | null }> | null = null\n\tprivate addDiffForAfterEvent(before: R | null, after: R | null) {\n\t\tassert(this.pendingAfterEvents, 'must be in event operation')\n\t\tif (before === after) return\n\t\tif (before && after) assert(before.id === after.id)\n\t\tif (!before && !after) return\n\t\tconst id = (before || after)!.id\n\t\tconst existing = this.pendingAfterEvents.get(id)\n\t\tif (existing) {\n\t\t\texisting.after = after\n\t\t} else {\n\t\t\tthis.pendingAfterEvents.set(id, { before, after })\n\t\t}\n\t}\n\tprivate flushAtomicCallbacks(isMergingRemoteChanges: boolean) {\n\t\tlet updateDepth = 0\n\t\tlet source: ChangeSource = isMergingRemoteChanges ? 'remote' : 'user'\n\t\twhile (this.pendingAfterEvents) {\n\t\t\tconst events = this.pendingAfterEvents\n\t\t\tthis.pendingAfterEvents = null\n\n\t\t\tif (!this.sideEffects.isEnabled()) continue\n\n\t\t\tupdateDepth++\n\t\t\tif (updateDepth > 100) {\n\t\t\t\tthrow new Error('Maximum store update depth exceeded, bailing out')\n\t\t\t}\n\n\t\t\tfor (const { before, after } of events.values()) {\n\t\t\t\tif (before && after && before !== after && !isEqual(before, after)) {\n\t\t\t\t\tthis.sideEffects.handleAfterChange(before, after, source)\n\t\t\t\t} else if (before && !after) {\n\t\t\t\t\tthis.sideEffects.handleAfterDelete(before, source)\n\t\t\t\t} else if (!before && after) {\n\t\t\t\t\tthis.sideEffects.handleAfterCreate(after, source)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.pendingAfterEvents) {\n\t\t\t\tthis.sideEffects.handleOperationComplete(source)\n\t\t\t} else {\n\t\t\t\t// if the side effects triggered by a remote operation resulted in more effects,\n\t\t\t\t// those extra effects should not be marked as originating remotely.\n\t\t\t\tsource = 'user'\n\t\t\t}\n\t\t}\n\t}\n\tprivate _isInAtomicOp = false\n\t/** @internal */\n\tatomic<T>(fn: () => T, runCallbacks = true, isMergingRemoteChanges = false): T {\n\t\treturn transact(() => {\n\t\t\tif (this._isInAtomicOp) {\n\t\t\t\tif (!this.pendingAfterEvents) this.pendingAfterEvents = new Map()\n\t\t\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\t\t\tassert(!isMergingRemoteChanges, 'cannot call mergeRemoteChanges while in atomic operation')\n\t\t\t\ttry {\n\t\t\t\t\t// if we are in an atomic context with side effects ON allow switching before* callbacks OFF.\n\t\t\t\t\t// but don't allow switching them ON if they had been marked OFF before.\n\t\t\t\t\tif (prevSideEffectsEnabled && !runCallbacks) {\n\t\t\t\t\t\tthis.sideEffects.setIsEnabled(false)\n\t\t\t\t\t}\n\t\t\t\t\treturn fn()\n\t\t\t\t} finally {\n\t\t\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.pendingAfterEvents = new Map()\n\t\t\tconst prevSideEffectsEnabled = this.sideEffects.isEnabled()\n\t\t\tthis.sideEffects.setIsEnabled(runCallbacks ?? prevSideEffectsEnabled)\n\t\t\tthis._isInAtomicOp = true\n\n\t\t\tif (isMergingRemoteChanges) {\n\t\t\t\tthis.isMergingRemoteChanges = true\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = fn()\n\t\t\t\tthis.isMergingRemoteChanges = false\n\n\t\t\t\tthis.flushAtomicCallbacks(isMergingRemoteChanges)\n\n\t\t\t\treturn result\n\t\t\t} finally {\n\t\t\t\tthis.pendingAfterEvents = null\n\t\t\t\tthis.sideEffects.setIsEnabled(prevSideEffectsEnabled)\n\t\t\t\tthis._isInAtomicOp = false\n\t\t\t\tthis.isMergingRemoteChanges = false\n\t\t\t}\n\t\t})\n\t}\n\n\t/** @internal */\n\taddHistoryInterceptor(fn: (entry: HistoryEntry<R>, source: ChangeSource) => void) {\n\t\treturn this.historyAccumulator.addInterceptor((entry) =>\n\t\t\tfn(entry, this.isMergingRemoteChanges ? 'remote' : 'user')\n\t\t)\n\t}\n}\n\n/**\n * Collect and squash history entries by their adjacent sources.\n * Adjacent entries from the same source are combined into a single entry.\n *\n * For example: [user, user, remote, remote, user] becomes [user, remote, user]\n *\n * @example\n * ```ts\n * const entries = [\n * { source: 'user', changes: userChanges1 },\n * { source: 'user', changes: userChanges2 },\n * { source: 'remote', changes: remoteChanges }\n * ]\n *\n * const squashed = squashHistoryEntries(entries)\n * // Results in 2 entries: combined user changes + remote changes\n * ```\n *\n * @param entries - The array of history entries to squash\n * @returns An array of squashed history entries\n * @public\n */\nfunction squashHistoryEntries<T extends UnknownRecord>(\n\tentries: HistoryEntry<T>[]\n): HistoryEntry<T>[] {\n\tif (entries.length === 0) return []\n\n\tconst chunked: HistoryEntry<T>[][] = []\n\tlet chunk: HistoryEntry<T>[] = [entries[0]]\n\tlet entry: HistoryEntry<T>\n\n\tfor (let i = 1, n = entries.length; i < n; i++) {\n\t\tentry = entries[i]\n\t\tif (chunk[0].source !== entry.source) {\n\t\t\tchunked.push(chunk)\n\t\t\tchunk = []\n\t\t}\n\t\tchunk.push(entry)\n\t}\n\t// Push the last chunk\n\tchunked.push(chunk)\n\n\treturn devFreeze(\n\t\tchunked.map((chunk) => ({\n\t\t\tsource: chunk[0].source,\n\t\t\tchanges: squashRecordDiffs(chunk.map((e) => e.changes)),\n\t\t}))\n\t)\n}\n\n/**\n * Internal class that accumulates history entries before they are flushed to listeners.\n * Handles batching and squashing of adjacent entries from the same source.\n *\n * @internal\n */\nclass HistoryAccumulator<T extends UnknownRecord> {\n\tprivate _history: HistoryEntry<T>[] = []\n\n\tprivate _interceptors: Set<(entry: HistoryEntry<T>) => void> = new Set()\n\n\t/**\n\t * Add an interceptor that will be called for each history entry.\n\t * Returns a function to remove the interceptor.\n\t */\n\taddInterceptor(fn: (entry: HistoryEntry<T>) => void) {\n\t\tthis._interceptors.add(fn)\n\t\treturn () => {\n\t\t\tthis._interceptors.delete(fn)\n\t\t}\n\t}\n\n\t/**\n\t * Add a history entry to the accumulator.\n\t * Calls all registered interceptors with the entry.\n\t */\n\tadd(entry: HistoryEntry<T>) {\n\t\tthis._history.push(entry)\n\t\tfor (const interceptor of this._interceptors) {\n\t\t\tinterceptor(entry)\n\t\t}\n\t}\n\n\t/**\n\t * Flush all accumulated history entries, squashing adjacent entries from the same source.\n\t * Clears the internal history buffer.\n\t */\n\tflush() {\n\t\tconst history = squashHistoryEntries(this._history)\n\t\tthis._history = []\n\t\treturn history\n\t}\n\n\t/**\n\t * Clear all accumulated history entries without flushing.\n\t */\n\tclear() {\n\t\tthis._history = []\n\t}\n\n\t/**\n\t * Check if there are any accumulated history entries.\n\t */\n\thasChanges() {\n\t\treturn this._history.length > 0\n\t}\n}\n\n/**\n * A store or an object containing a store.\n * This type is used for APIs that can accept either a store directly or an object with a store property.\n *\n * @example\n * ```ts\n * function useStore(storeOrObject: StoreObject<MyRecord>) {\n * const store = storeOrObject instanceof Store ? storeOrObject : storeOrObject.store\n * return store\n * }\n * ```\n *\n * @public\n */\nexport type StoreObject<R extends UnknownRecord> = Store<R> | { store: Store<R> }\n/**\n * Extract the record type from a StoreObject.\n *\n * @example\n * ```ts\n * type MyStoreObject = { store: Store<Book | Author> }\n * type Records = StoreObjectRecordType<MyStoreObject> // Book | Author\n * ```\n *\n * @public\n */\nexport type StoreObjectRecordType<Context extends StoreObject<any>> =\n\tContext extends Store<infer R> ? R : Context extends { store: Store<infer R> } ? R : never\n\n/**\n * Create a computed cache that works with any StoreObject (store or object containing a store).\n * This is a standalone version of Store.createComputedCache that can work with multiple store instances.\n *\n * @example\n * ```ts\n * const expensiveCache = createComputedCache(\n * 'expensiveData',\n * (context: { store: Store<Book> }, book: Book) => {\n * return performExpensiveCalculation(book)\n * }\n * )\n *\n * // Use with different store instances\n * const result1 = expensiveCache.get(storeObject1, bookId)\n * const result2 = expensiveCache.get(storeObject2, bookId)\n * ```\n *\n * @param name - A unique name for the cache (used for debugging)\n * @param derive - Function that derives a value from the context and record\n * @param opts - Optional configuration for equality checks\n * @returns A cache that can be used with multiple store instances\n * @public\n */\nexport function createComputedCache<\n\tContext extends StoreObject<any>,\n\tResult,\n\tRecord extends StoreObjectRecordType<Context> = StoreObjectRecordType<Context>,\n>(\n\tname: string,\n\tderive: (context: Context, record: Record) => Result | undefined,\n\topts?: CreateComputedCacheOpts<Result, Record>\n) {\n\tconst cache = new WeakCache<Context, ComputedCache<Result, Record>>()\n\treturn {\n\t\tget(context: Context, id: IdOf<Record>) {\n\t\t\tconst computedCache = cache.get(context, () => {\n\t\t\t\tconst store = (context instanceof Store ? context : context.store) as Store<Record>\n\t\t\t\treturn store.createComputedCache(name, (record) => derive(context, record), opts)\n\t\t\t})\n\t\t\treturn computedCache.get(id)\n\t\t},\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["id", "atom", "prevSideEffectsEnabled", "chunk"]
|
|
7
7
|
}
|