@tldraw/store 5.4.0-next.ef99ab47e5ce → 5.5.0-next.6d9e51e9f3f7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/DOCS.md +50 -50
  2. package/dist-cjs/index.d.ts +38 -8
  3. package/dist-cjs/index.js +1 -1
  4. package/dist-cjs/lib/AtomMap.js +45 -3
  5. package/dist-cjs/lib/AtomMap.js.map +3 -3
  6. package/dist-cjs/lib/ImmutableMap.js +11 -8
  7. package/dist-cjs/lib/ImmutableMap.js.map +2 -2
  8. package/dist-cjs/lib/IncrementalSetConstructor.js +2 -0
  9. package/dist-cjs/lib/IncrementalSetConstructor.js.map +2 -2
  10. package/dist-cjs/lib/RecordsDiff.js +11 -1
  11. package/dist-cjs/lib/RecordsDiff.js.map +2 -2
  12. package/dist-cjs/lib/Store.js +6 -2
  13. package/dist-cjs/lib/Store.js.map +2 -2
  14. package/dist-cjs/lib/StoreQueries.js +1 -1
  15. package/dist-cjs/lib/StoreQueries.js.map +2 -2
  16. package/dist-cjs/lib/StoreSchema.js +5 -1
  17. package/dist-cjs/lib/StoreSchema.js.map +2 -2
  18. package/dist-cjs/lib/migrate.js +6 -5
  19. package/dist-cjs/lib/migrate.js.map +2 -2
  20. package/dist-esm/index.d.mts +38 -8
  21. package/dist-esm/index.mjs +1 -1
  22. package/dist-esm/lib/AtomMap.mjs +45 -3
  23. package/dist-esm/lib/AtomMap.mjs.map +3 -3
  24. package/dist-esm/lib/ImmutableMap.mjs +11 -8
  25. package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
  26. package/dist-esm/lib/IncrementalSetConstructor.mjs +2 -0
  27. package/dist-esm/lib/IncrementalSetConstructor.mjs.map +2 -2
  28. package/dist-esm/lib/RecordsDiff.mjs +11 -1
  29. package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
  30. package/dist-esm/lib/Store.mjs +6 -2
  31. package/dist-esm/lib/Store.mjs.map +2 -2
  32. package/dist-esm/lib/StoreQueries.mjs +1 -1
  33. package/dist-esm/lib/StoreQueries.mjs.map +2 -2
  34. package/dist-esm/lib/StoreSchema.mjs +5 -1
  35. package/dist-esm/lib/StoreSchema.mjs.map +2 -2
  36. package/dist-esm/lib/migrate.mjs +6 -5
  37. package/dist-esm/lib/migrate.mjs.map +2 -2
  38. package/package.json +9 -3
  39. package/src/lib/AtomMap.test.ts +69 -0
  40. package/src/lib/AtomMap.ts +52 -3
  41. package/src/lib/ImmutableMap.test.ts +33 -0
  42. package/src/lib/ImmutableMap.ts +16 -8
  43. package/src/lib/IncrementalSetConstructor.test.ts +10 -0
  44. package/src/lib/IncrementalSetConstructor.ts +4 -0
  45. package/src/lib/RecordsDiff.test.ts +27 -0
  46. package/src/lib/RecordsDiff.ts +19 -1
  47. package/src/lib/Store.ts +9 -4
  48. package/src/lib/StoreListeners.test.ts +22 -0
  49. package/src/lib/StoreQueries.test.ts +14 -0
  50. package/src/lib/StoreQueries.ts +4 -1
  51. package/src/lib/StoreSchema.test.ts +45 -0
  52. package/src/lib/StoreSchema.ts +6 -1
  53. package/src/lib/StoreSideEffects.test.ts +31 -0
  54. package/src/lib/migrate.test.ts +15 -0
  55. package/src/lib/migrate.ts +9 -5
package/DOCS.md CHANGED
@@ -17,9 +17,9 @@ The store provides:
17
17
  - **Side effects** - Lifecycle hooks for implementing business logic
18
18
  - **Queries** - Reactive indexes and filtering for efficient data access
19
19
 
20
- ## 2. Core Concepts
20
+ ## 2. Core concepts
21
21
 
22
- ### Records: The Foundation
22
+ ### Records: the foundation
23
23
 
24
24
  **Records** are immutable data objects that extend the `BaseRecord` interface. Every record has an `id` and a `typeName` that identifies its type:
25
25
 
@@ -34,7 +34,7 @@ interface Book extends BaseRecord<'book', RecordId<Book>> {
34
34
  }
35
35
  ```
36
36
 
37
- ### Record Types: Factories for Records
37
+ ### Record types: factories for records
38
38
 
39
39
  A **RecordType** is a factory that creates and manages records of a specific type. You define how records are created, validated, and what their default properties are:
40
40
 
@@ -52,9 +52,9 @@ const Book = createRecordType<Book>('book', {
52
52
 
53
53
  // Create a new book
54
54
 
55
- ## 2. Core Concepts
55
+ ## 2. Core concepts
56
56
 
57
- ### Records: The Foundation
57
+ ### Records: the foundation
58
58
 
59
59
  **Records** are immutable data objects that extend the `BaseRecord` interface. Every record has an `id` and a `typeName` that identifies its type:
60
60
 
@@ -73,7 +73,7 @@ interface Book extends BaseRecord<'book', RecordId<Book>> {
73
73
  }
74
74
  ```
75
75
 
76
- ### Record Types: Factories for Records
76
+ ### Record types: factories for records
77
77
 
78
78
  A **RecordType** is a factory that creates and manages records of a specific type. You define how records are created, validated, and what their default properties are:
79
79
 
@@ -100,9 +100,9 @@ const book = Book.create({
100
100
  // Results in: { id: 'book:abc123', typeName: 'book', title: '1984', authorId: 'author:xyz789', publishedYear: 2025, inStock: true }
101
101
  ```
102
102
 
103
- ## 3. Basic Usage
103
+ ## 3. Basic usage
104
104
 
105
- ### Creating and Storing Records
105
+ ### Creating and storing records
106
106
 
107
107
  You add records to the store using the `put` method:
108
108
 
@@ -123,7 +123,7 @@ store.put([orwell, huxley, ...books])
123
123
 
124
124
  > Tip: The `put` method handles both creating new records and updating existing ones. If a record with the same ID already exists, it will be updated.
125
125
 
126
- ### Reading Records
126
+ ### Reading records
127
127
 
128
128
  You can read individual records or access all records of a type:
129
129
 
@@ -139,7 +139,7 @@ const allRecords = store.allRecords()
139
139
  const hasBook = store.has(books[0].id) // true
140
140
  ```
141
141
 
142
- ### Updating Records
142
+ ### Updating records
143
143
 
144
144
  Use the `update` method to modify existing records:
145
145
 
@@ -153,7 +153,7 @@ store.update(book.id, (currentBook) => ({
153
153
 
154
154
  The update function receives the current record and returns a new record with your changes applied.
155
155
 
156
- ### Removing Records
156
+ ### Removing records
157
157
 
158
158
  Remove records using their IDs:
159
159
 
@@ -165,9 +165,9 @@ store.remove([book.id])
165
165
  store.remove([book1.id, book2.id, book3.id])
166
166
  ```
167
167
 
168
- ## 4. Reactive Queries and Indexing
168
+ ## 4. Reactive queries and indexing
169
169
 
170
- ### Understanding Reactive Indexes
170
+ ### Understanding reactive indexes
171
171
 
172
172
  The store automatically maintains **reactive indexes** that allow efficient querying of your data. These indexes update automatically when records change:
173
173
 
@@ -183,7 +183,7 @@ console.log(orwellBooks) // Set<RecordId<Book>>
183
183
 
184
184
  The index returns a `Map` where keys are property values and values are `Set`s of record IDs that have that property value.
185
185
 
186
- ### Reactive Queries with Computed Values
186
+ ### Reactive queries with computed values
187
187
 
188
188
  Combine indexes with computed values to create reactive queries:
189
189
 
@@ -210,7 +210,7 @@ const inStockBooksByAuthor = computed('inStockBooksByAuthor', () => {
210
210
  console.log(inStockBooksByAuthor.get()) // Map<RecordId<Author>, Book[]>
211
211
  ```
212
212
 
213
- ### The Store: Your Reactive Database
213
+ ### The store: your reactive database
214
214
 
215
215
  The **Store** is the central container that manages all your records. It provides reactive access to data and automatically tracks changes:
216
216
 
@@ -230,9 +230,9 @@ const store = new Store({
230
230
  })
231
231
  ```
232
232
 
233
- ## 3. Basic Usage
233
+ ## 3. Basic usage
234
234
 
235
- ### Creating and Storing Records
235
+ ### Creating and storing records
236
236
 
237
237
  You add records to the store using the `put` method:
238
238
 
@@ -250,7 +250,7 @@ store.put(books)
250
250
 
251
251
  > Tip: The `put` method handles both creating new records and updating existing ones. If a record with the same ID already exists, it will be updated.
252
252
 
253
- ### Reading Records
253
+ ### Reading records
254
254
 
255
255
  You can read individual records or access all records of a type:
256
256
 
@@ -266,7 +266,7 @@ const allRecords = store.allRecords()
266
266
  const hasBook = store.has(books[0].id) // true
267
267
  ```
268
268
 
269
- ### Updating Records
269
+ ### Updating records
270
270
 
271
271
  Use the `update` method to modify existing records:
272
272
 
@@ -280,7 +280,7 @@ store.update(book.id, (currentBook) => ({
280
280
 
281
281
  The update function receives the current record and returns a new record with your changes applied.
282
282
 
283
- ### Removing Records
283
+ ### Removing records
284
284
 
285
285
  Remove records using their IDs:
286
286
 
@@ -292,9 +292,9 @@ store.remove([book.id])
292
292
  store.remove([book1.id, book2.id, book3.id])
293
293
  ```
294
294
 
295
- ## 4. Reactive Queries and Indexing
295
+ ## 4. Reactive queries and indexing
296
296
 
297
- ### Understanding Reactive Indexes
297
+ ### Understanding reactive indexes
298
298
 
299
299
  The store automatically maintains **reactive indexes** that allow efficient querying of your data. These indexes update automatically when records change:
300
300
 
@@ -309,7 +309,7 @@ console.log(orwellBooks) // Set<RecordId<Book>>
309
309
 
310
310
  The index returns a `Map` where keys are property values and values are `Set`s of record IDs that have that property value.
311
311
 
312
- ### Reactive Queries with Computed Values
312
+ ### Reactive queries with computed values
313
313
 
314
314
  Combine indexes with computed values to create reactive queries:
315
315
 
@@ -336,7 +336,7 @@ const inStockBooksByAuthor = computed('inStockBooksByAuthor', () => {
336
336
  console.log(inStockBooksByAuthor.get()) // Map<string, Book[]>
337
337
  ```
338
338
 
339
- ### Filtering History for Specific Record Types
339
+ ### Filtering history for specific record types
340
340
 
341
341
  You can create reactive computations that track changes to specific record types:
342
342
 
@@ -358,9 +358,9 @@ const dispose = react('book-changes', () => {
358
358
 
359
359
  > Tip: The `filterHistory` method returns a `Computed` that tracks changes to records of a specific type. Use it with `react()` from `@tldraw/state` to respond to changes.
360
360
 
361
- ## 5. Record Scopes and Persistence
361
+ ## 5. Record scopes and persistence
362
362
 
363
- ### Understanding Record Scopes
363
+ ### Understanding record scopes
364
364
 
365
365
  Records have different **scopes** that determine how they're persisted and synchronized:
366
366
 
@@ -382,7 +382,7 @@ const PresenceRecord = createRecordType<PresenceData>('presence', {
382
382
  - **`session`** - Per-instance data that might be saved locally
383
383
  - **`presence`** - Temporary data that's shared but not saved
384
384
 
385
- ### Serialization and Snapshots
385
+ ### Serialization and snapshots
386
386
 
387
387
  You can serialize the store's data for persistence:
388
388
 
@@ -400,9 +400,9 @@ store.loadStoreSnapshot(saved)
400
400
 
401
401
  > Note: The store automatically handles migrations when loading snapshots from older versions of your schema.
402
402
 
403
- ## 6. Side Effects and Business Logic
403
+ ## 6. Side effects and business logic
404
404
 
405
- ### Understanding Side Effects
405
+ ### Understanding side effects
406
406
 
407
407
  **Side effects** are hooks that let you implement business logic in response to record changes. They run automatically when records are created, updated, or deleted:
408
408
 
@@ -431,7 +431,7 @@ store.sideEffects.registerAfterDeleteHandler('book', (book, source) => {
431
431
  })
432
432
  ```
433
433
 
434
- ### Change Sources
434
+ ### Change sources
435
435
 
436
436
  Side effects receive a `source` parameter that tells you where the change originated:
437
437
 
@@ -447,7 +447,7 @@ store.sideEffects.registerAfterCreateHandler('book', (book, source) => {
447
447
  })
448
448
  ```
449
449
 
450
- ### Before Handlers: Validation and Transformation
450
+ ### Before handlers: validation and transformation
451
451
 
452
452
  **Before handlers** run before changes are applied and can validate or transform the data:
453
453
 
@@ -470,9 +470,9 @@ store.sideEffects.registerBeforeCreateHandler('book', (book, source) => {
470
470
  })
471
471
  ```
472
472
 
473
- ## 7. Schema Evolution with Migrations
473
+ ## 7. Schema evolution with migrations
474
474
 
475
- ### Creating Migration Sequences
475
+ ### Creating migration sequences
476
476
 
477
477
  As your application evolves, you'll need to update your data structure. **Migrations** handle this automatically:
478
478
 
@@ -527,7 +527,7 @@ const schema = StoreSchema.create(
527
527
  )
528
528
  ```
529
529
 
530
- ### Migration Safety
530
+ ### Migration safety
531
531
 
532
532
  The store automatically applies migrations when loading data from older versions:
533
533
 
@@ -542,13 +542,13 @@ store.loadStoreSnapshot(oldSnapshot)
542
542
 
543
543
  > Tip: Always test your migrations thoroughly with real data before deploying to production.
544
544
 
545
- ## 8. Advanced Topics
545
+ ## 8. Advanced topics
546
546
 
547
- ### Transactional Operations
547
+ ### Transactional operations
548
548
 
549
549
  The store automatically ensures that related operations happen atomically. When you perform multiple operations in response to user actions or side effects, they are automatically grouped together for consistency and performance.
550
550
 
551
- ### Custom Computed Caches
551
+ ### Custom computed caches
552
552
 
553
553
  Create **computed caches** for expensive derivations that should be memoized per record:
554
554
 
@@ -564,7 +564,7 @@ const analysis = expensiveBookData.get(book.id)
564
564
 
565
565
  The cache automatically updates when the underlying record changes and cleans up when records are deleted.
566
566
 
567
- ### Extracting Changes
567
+ ### Extracting changes
568
568
 
569
569
  You can capture changes that occur within a function:
570
570
 
@@ -585,7 +585,7 @@ This is useful for implementing undo/redo systems or understanding what changed
585
585
 
586
586
  The store provides several tools for understanding what's happening in your application.
587
587
 
588
- ### Store Listeners
588
+ ### Store listeners
589
589
 
590
590
  Add listeners to react to changes in your store:
591
591
 
@@ -608,7 +608,7 @@ const removeDocumentListener = store.listen(
608
608
  )
609
609
  ```
610
610
 
611
- ### Understanding Record Validation
611
+ ### Understanding record validation
612
612
 
613
613
  The store validates all records when they're created or updated. Validation errors provide detailed information:
614
614
 
@@ -625,7 +625,7 @@ try {
625
625
 
626
626
  ## 10. Integration
627
627
 
628
- ### Framework Integration
628
+ ### Framework integration
629
629
 
630
630
  The store is framework-agnostic but integrates well with React through `@tldraw/state-react`:
631
631
 
@@ -647,7 +647,7 @@ const BookList = track(() => {
647
647
 
648
648
  The `track` function automatically subscribes the component to relevant store changes.
649
649
 
650
- ### Persistence Strategies
650
+ ### Persistence strategies
651
651
 
652
652
  Implement different persistence strategies based on your needs:
653
653
 
@@ -685,9 +685,9 @@ store.mergeRemoteChanges(() => {
685
685
 
686
686
  Changes merged this way are marked with `source: 'remote'` so your side effects can handle them appropriately.
687
687
 
688
- ## 11. Performance Considerations
688
+ ## 11. Performance considerations
689
689
 
690
- ### Memory Management
690
+ ### Memory management
691
691
 
692
692
  The store uses several strategies to maintain good performance:
693
693
 
@@ -696,7 +696,7 @@ The store uses several strategies to maintain good performance:
696
696
  - **Efficient indexes** - Reactive indexes use incremental updates rather than full rebuilds
697
697
  - **Change batching** - Multiple changes are batched together before notifying listeners
698
698
 
699
- ### Query Optimization
699
+ ### Query optimization
700
700
 
701
701
  For best performance with large datasets:
702
702
 
@@ -712,7 +712,7 @@ const book = store.unsafeGetWithoutCapture(bookId) // No reactive subscription
712
712
  const expensiveData = store.createComputedCache('expensive', computeExpensiveData)
713
713
  ```
714
714
 
715
- ### Side Effect Performance
715
+ ### Side effect performance
716
716
 
717
717
  Keep side effects fast since they run synchronously:
718
718
 
@@ -728,9 +728,9 @@ store.sideEffects.registerAfterCreateHandler('book', (book) => {
728
728
  })
729
729
  ```
730
730
 
731
- ## 12. Common Patterns
731
+ ## 12. Common patterns
732
732
 
733
- ### Repository Pattern
733
+ ### Repository pattern
734
734
 
735
735
  Create typed repositories for cleaner APIs:
736
736
 
@@ -754,7 +754,7 @@ class BookRepository {
754
754
  }
755
755
  ```
756
756
 
757
- ### State Machines with Records
757
+ ### State machines with records
758
758
 
759
759
  Use records to represent state machine states:
760
760
 
@@ -775,7 +775,7 @@ store.sideEffects.registerAfterChangeHandler('orderState', (prev, next) => {
775
775
  })
776
776
  ```
777
777
 
778
- ### Computed Relationships
778
+ ### Computed relationships
779
779
 
780
780
  Model relationships between records using efficient queries:
781
781
 
@@ -116,6 +116,36 @@ export declare class AtomMap<K, V> implements Map<K, V> {
116
116
  * ```
117
117
  */
118
118
  set(key: K, value: V): this;
119
+ /**
120
+ * Gets the value associated with a key, inserting `defaultValue` first if the key doesn't exist.
121
+ * This method is reactive and will cause reactive contexts to update when the value changes.
122
+ *
123
+ * @param key - The key to retrieve the value for
124
+ * @param defaultValue - The value to insert if the key doesn't exist
125
+ * @returns The existing value, or `defaultValue` if the key was missing
126
+ * @example
127
+ * ```ts
128
+ * const map = new AtomMap('myMap')
129
+ * console.log(map.getOrInsert('count', 0)) // 0, and 'count' is now set
130
+ * console.log(map.getOrInsert('count', 10)) // 0
131
+ * ```
132
+ */
133
+ getOrInsert(key: K, defaultValue: V): V;
134
+ /**
135
+ * Gets the value associated with a key, inserting the result of `callback` first if the key
136
+ * doesn't exist. The callback only runs when the key is missing.
137
+ * This method is reactive and will cause reactive contexts to update when the value changes.
138
+ *
139
+ * @param key - The key to retrieve the value for
140
+ * @param callback - Called with the key to produce the value to insert
141
+ * @returns The existing value, or the newly computed value if the key was missing
142
+ * @example
143
+ * ```ts
144
+ * const map = new AtomMap<string, string[]>('myMap')
145
+ * map.getOrInsertComputed('tags', () => []).push('new')
146
+ * ```
147
+ */
148
+ getOrInsertComputed(key: K, callback: (key: K) => V): V;
119
149
  /**
120
150
  * Updates an existing value using an updater function.
121
151
  *
@@ -503,7 +533,7 @@ export declare function createMigrationIds<const ID extends string, const Versio
503
533
  * ```
504
534
  * @public
505
535
  */
506
- export declare function createMigrationSequence({ sequence, sequenceId, retroactive }: {
536
+ export declare function createMigrationSequence({ sequence, sequenceId, retroactive, }: {
507
537
  retroactive?: boolean;
508
538
  sequence: Array<Migration | StandaloneDependsOn>;
509
539
  sequenceId: string;
@@ -709,12 +739,12 @@ export declare type Migration = {
709
739
 
710
740
  /** @public */
711
741
  export declare const MigrationFailureReason: {
712
- readonly IncompatibleSubtype: "incompatible-subtype";
713
- readonly MigrationError: "migration-error";
714
- readonly TargetVersionTooNew: "target-version-too-new";
715
- readonly TargetVersionTooOld: "target-version-too-old";
716
- readonly UnknownType: "unknown-type";
717
- readonly UnrecognizedSubtype: "unrecognized-subtype";
742
+ readonly IncompatibleSubtype: 'incompatible-subtype';
743
+ readonly MigrationError: 'migration-error';
744
+ readonly TargetVersionTooNew: 'target-version-too-new';
745
+ readonly TargetVersionTooOld: 'target-version-too-old';
746
+ readonly UnknownType: 'unknown-type';
747
+ readonly UnrecognizedSubtype: 'unrecognized-subtype';
718
748
  };
719
749
 
720
750
  /** @public */
@@ -1769,7 +1799,7 @@ export declare class Store<R extends UnknownRecord = UnknownRecord, Props = unkn
1769
1799
  * Run `fn` and return a {@link RecordsDiff} of the changes that occurred as a result.
1770
1800
  */
1771
1801
  extractingChanges(fn: () => void): RecordsDiff<R>;
1772
- applyDiff(diff: RecordsDiff<R>, { runCallbacks, ignoreEphemeralKeys }?: {
1802
+ applyDiff(diff: RecordsDiff<R>, { runCallbacks, ignoreEphemeralKeys, }?: {
1773
1803
  ignoreEphemeralKeys?: boolean;
1774
1804
  runCallbacks?: boolean;
1775
1805
  }): void;
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
- "5.4.0-next.ef99ab47e5ce",
59
+ "5.5.0-next.6d9e51e9f3f7",
60
60
  "cjs"
61
61
  );
62
62
  //# sourceMappingURL=index.js.map
@@ -172,6 +172,47 @@ class AtomMap {
172
172
  }
173
173
  return this;
174
174
  }
175
+ /**
176
+ * Gets the value associated with a key, inserting `defaultValue` first if the key doesn't exist.
177
+ * This method is reactive and will cause reactive contexts to update when the value changes.
178
+ *
179
+ * @param key - The key to retrieve the value for
180
+ * @param defaultValue - The value to insert if the key doesn't exist
181
+ * @returns The existing value, or `defaultValue` if the key was missing
182
+ * @example
183
+ * ```ts
184
+ * const map = new AtomMap('myMap')
185
+ * console.log(map.getOrInsert('count', 0)) // 0, and 'count' is now set
186
+ * console.log(map.getOrInsert('count', 10)) // 0
187
+ * ```
188
+ */
189
+ getOrInsert(key, defaultValue) {
190
+ return this.getOrInsertComputed(key, () => defaultValue);
191
+ }
192
+ /**
193
+ * Gets the value associated with a key, inserting the result of `callback` first if the key
194
+ * doesn't exist. The callback only runs when the key is missing.
195
+ * This method is reactive and will cause reactive contexts to update when the value changes.
196
+ *
197
+ * @param key - The key to retrieve the value for
198
+ * @param callback - Called with the key to produce the value to insert
199
+ * @returns The existing value, or the newly computed value if the key was missing
200
+ * @example
201
+ * ```ts
202
+ * const map = new AtomMap<string, string[]>('myMap')
203
+ * map.getOrInsertComputed('tags', () => []).push('new')
204
+ * ```
205
+ */
206
+ getOrInsertComputed(key, callback) {
207
+ const valueAtom = this.getAtom(key);
208
+ if (valueAtom) {
209
+ const value2 = valueAtom.get();
210
+ if (value2 !== import_state.UNINITIALIZED) return value2;
211
+ }
212
+ const value = callback(key);
213
+ this.set(key, value);
214
+ return value;
215
+ }
175
216
  /**
176
217
  * Updates an existing value using an updater function.
177
218
  *
@@ -289,7 +330,7 @@ class AtomMap {
289
330
  *entries() {
290
331
  for (const [key, valueAtom] of this.atoms.get()) {
291
332
  const value = valueAtom.get();
292
- (0, import_utils.assert)(value !== import_state.UNINITIALIZED);
333
+ if (value === import_state.UNINITIALIZED) continue;
293
334
  yield [key, value];
294
335
  }
295
336
  }
@@ -308,7 +349,8 @@ class AtomMap {
308
349
  * ```
309
350
  */
310
351
  *keys() {
311
- for (const key of this.atoms.get().keys()) {
352
+ for (const [key, valueAtom] of this.atoms.get()) {
353
+ if (valueAtom.__unsafe__getWithoutCapture() === import_state.UNINITIALIZED) continue;
312
354
  yield key;
313
355
  }
314
356
  }
@@ -329,7 +371,7 @@ class AtomMap {
329
371
  *values() {
330
372
  for (const valueAtom of this.atoms.get().values()) {
331
373
  const value = valueAtom.get();
332
- (0, import_utils.assert)(value !== import_state.UNINITIALIZED);
374
+ if (value === import_state.UNINITIALIZED) continue;
333
375
  yield value;
334
376
  }
335
377
  }
@@ -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 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
- "mappings": "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",
6
- "names": ["atoms"]
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 * Gets the value associated with a key, inserting `defaultValue` first 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 * @param defaultValue - The value to insert if the key doesn't exist\n\t * @returns The existing value, or `defaultValue` if the key was missing\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap('myMap')\n\t * console.log(map.getOrInsert('count', 0)) // 0, and 'count' is now set\n\t * console.log(map.getOrInsert('count', 10)) // 0\n\t * ```\n\t */\n\tgetOrInsert(key: K, defaultValue: V): V {\n\t\treturn this.getOrInsertComputed(key, () => defaultValue)\n\t}\n\n\t/**\n\t * Gets the value associated with a key, inserting the result of `callback` first if the key\n\t * doesn't exist. The callback only runs when the key is missing.\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 * @param callback - Called with the key to produce the value to insert\n\t * @returns The existing value, or the newly computed value if the key was missing\n\t * @example\n\t * ```ts\n\t * const map = new AtomMap<string, string[]>('myMap')\n\t * map.getOrInsertComputed('tags', () => []).push('new')\n\t * ```\n\t */\n\tgetOrInsertComputed(key: K, callback: (key: K) => V): V {\n\t\tconst valueAtom = this.getAtom(key)\n\t\tif (valueAtom) {\n\t\t\tconst value = valueAtom.get()\n\t\t\tif (value !== UNINITIALIZED) return value\n\t\t}\n\n\t\tconst value = callback(key)\n\t\tthis.set(key, value)\n\t\treturn value\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\t// The key set is a snapshot taken when iteration started, so a key deleted mid-iteration\n\t\t\t// still appears in it; skip it, as `Map` skips entries deleted before they are visited.\n\t\t\tif (value === UNINITIALIZED) continue\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, valueAtom] of this.atoms.get()) {\n\t\t\t// see entries(): skip keys deleted mid-iteration\n\t\t\tif (valueAtom.__unsafe__getWithoutCapture() === UNINITIALIZED) continue\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\t// see entries(): skip keys deleted mid-iteration\n\t\t\tif (value === UNINITIALIZED) continue\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
+ "mappings": "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",
6
+ "names": ["atoms", "value"]
7
7
  }