@tldraw/state 4.0.2 → 4.1.0-canary.0259516ffb8c

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 (56) hide show
  1. package/dist-cjs/index.d.ts +358 -43
  2. package/dist-cjs/index.js +3 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/ArraySet.js +90 -6
  5. package/dist-cjs/lib/ArraySet.js.map +2 -2
  6. package/dist-cjs/lib/Atom.js +70 -0
  7. package/dist-cjs/lib/Atom.js.map +2 -2
  8. package/dist-cjs/lib/Computed.js +1 -1
  9. package/dist-cjs/lib/Computed.js.map +2 -2
  10. package/dist-cjs/lib/HistoryBuffer.js +57 -9
  11. package/dist-cjs/lib/HistoryBuffer.js.map +2 -2
  12. package/dist-cjs/lib/capture.js.map +2 -2
  13. package/dist-cjs/lib/constants.js.map +2 -2
  14. package/dist-cjs/lib/helpers.js.map +2 -2
  15. package/dist-cjs/lib/isSignal.js.map +2 -2
  16. package/dist-cjs/lib/localStorageAtom.js +60 -0
  17. package/dist-cjs/lib/localStorageAtom.js.map +7 -0
  18. package/dist-cjs/lib/transactions.js.map +2 -2
  19. package/dist-cjs/lib/types.js.map +2 -2
  20. package/dist-cjs/lib/warnings.js.map +2 -2
  21. package/dist-esm/index.d.mts +358 -43
  22. package/dist-esm/index.mjs +3 -1
  23. package/dist-esm/index.mjs.map +2 -2
  24. package/dist-esm/lib/ArraySet.mjs +90 -6
  25. package/dist-esm/lib/ArraySet.mjs.map +2 -2
  26. package/dist-esm/lib/Atom.mjs +70 -0
  27. package/dist-esm/lib/Atom.mjs.map +2 -2
  28. package/dist-esm/lib/Computed.mjs +1 -1
  29. package/dist-esm/lib/Computed.mjs.map +2 -2
  30. package/dist-esm/lib/HistoryBuffer.mjs +57 -9
  31. package/dist-esm/lib/HistoryBuffer.mjs.map +2 -2
  32. package/dist-esm/lib/capture.mjs.map +2 -2
  33. package/dist-esm/lib/constants.mjs.map +2 -2
  34. package/dist-esm/lib/helpers.mjs.map +2 -2
  35. package/dist-esm/lib/isSignal.mjs.map +2 -2
  36. package/dist-esm/lib/localStorageAtom.mjs +40 -0
  37. package/dist-esm/lib/localStorageAtom.mjs.map +7 -0
  38. package/dist-esm/lib/transactions.mjs.map +2 -2
  39. package/dist-esm/lib/types.mjs.map +2 -2
  40. package/dist-esm/lib/warnings.mjs.map +2 -2
  41. package/package.json +2 -2
  42. package/src/index.ts +1 -0
  43. package/src/lib/ArraySet.ts +101 -8
  44. package/src/lib/Atom.ts +92 -0
  45. package/src/lib/Computed.ts +169 -19
  46. package/src/lib/HistoryBuffer.ts +76 -10
  47. package/src/lib/__tests__/helpers.test.ts +168 -0
  48. package/src/lib/__tests__/localStorageAtom.test.ts +183 -0
  49. package/src/lib/capture.ts +56 -1
  50. package/src/lib/constants.ts +25 -1
  51. package/src/lib/helpers.ts +137 -13
  52. package/src/lib/isSignal.ts +24 -0
  53. package/src/lib/localStorageAtom.ts +87 -0
  54. package/src/lib/transactions.ts +79 -10
  55. package/src/lib/types.ts +173 -19
  56. package/src/lib/warnings.ts +36 -0
package/src/lib/Atom.ts CHANGED
@@ -66,6 +66,8 @@ export interface Atom<Value, Diff = unknown> extends Signal<Value, Diff> {
66
66
  }
67
67
 
68
68
  /**
69
+ * Internal implementation of the Atom interface. This class should not be used directly - use the {@link atom} function instead.
70
+ *
69
71
  * @internal
70
72
  */
71
73
  class __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {
@@ -85,25 +87,76 @@ class __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {
85
87
  this.computeDiff = options.computeDiff
86
88
  }
87
89
 
90
+ /**
91
+ * Custom equality function for comparing values, or null to use default equality.
92
+ * @internal
93
+ */
88
94
  readonly isEqual: null | ((a: any, b: any) => boolean)
89
95
 
96
+ /**
97
+ * Optional function to compute diffs between old and new values.
98
+ * @internal
99
+ */
90
100
  computeDiff?: ComputeDiff<Value, Diff>
91
101
 
102
+ /**
103
+ * The global epoch when this atom was last changed.
104
+ * @internal
105
+ */
92
106
  lastChangedEpoch = getGlobalEpoch()
93
107
 
108
+ /**
109
+ * Set of child signals that depend on this atom.
110
+ * @internal
111
+ */
94
112
  children = new ArraySet<Child>()
95
113
 
114
+ /**
115
+ * Optional history buffer for tracking changes over time.
116
+ * @internal
117
+ */
96
118
  historyBuffer?: HistoryBuffer<Diff>
97
119
 
120
+ /**
121
+ * Gets the current value without capturing it as a dependency in the current reactive context.
122
+ * This is unsafe because it breaks the reactivity chain - use with caution.
123
+ *
124
+ * @param _ignoreErrors - Unused parameter for API compatibility
125
+ * @returns The current value
126
+ * @internal
127
+ */
98
128
  __unsafe__getWithoutCapture(_ignoreErrors?: boolean): Value {
99
129
  return this.current
100
130
  }
101
131
 
132
+ /**
133
+ * Gets the current value of this atom. When called within a computed signal or reaction,
134
+ * this atom will be automatically captured as a dependency.
135
+ *
136
+ * @returns The current value
137
+ * @example
138
+ * ```ts
139
+ * const count = atom('count', 5)
140
+ * console.log(count.get()) // 5
141
+ * ```
142
+ */
102
143
  get() {
103
144
  maybeCaptureParent(this)
104
145
  return this.current
105
146
  }
106
147
 
148
+ /**
149
+ * Sets the value of this atom to the given value. If the value is the same as the current value, this is a no-op.
150
+ *
151
+ * @param value - The new value to set
152
+ * @param diff - The diff to use for the update. If not provided, the diff will be computed using {@link AtomOptions.computeDiff}
153
+ * @returns The new value
154
+ * @example
155
+ * ```ts
156
+ * const count = atom('count', 0)
157
+ * count.set(5) // count.get() is now 5
158
+ * ```
159
+ */
107
160
  set(value: Value, diff?: Diff): Value {
108
161
  // If the value has not changed, do nothing.
109
162
  if (this.isEqual?.(this.current, value) ?? equals(this.current, value)) {
@@ -136,10 +189,29 @@ class __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {
136
189
  return value
137
190
  }
138
191
 
192
+ /**
193
+ * Updates the value of this atom using the given updater function. If the returned value is the same as the current value, this is a no-op.
194
+ *
195
+ * @param updater - A function that takes the current value and returns the new value
196
+ * @returns The new value
197
+ * @example
198
+ * ```ts
199
+ * const count = atom('count', 5)
200
+ * count.update(n => n + 1) // count.get() is now 6
201
+ * ```
202
+ */
139
203
  update(updater: (value: Value) => Value): Value {
140
204
  return this.set(updater(this.current))
141
205
  }
142
206
 
207
+ /**
208
+ * Gets all the diffs that have occurred since the given epoch. When called within a computed
209
+ * signal or reaction, this atom will be automatically captured as a dependency.
210
+ *
211
+ * @param epoch - The epoch to get changes since
212
+ * @returns An array of diffs, or RESET_VALUE if history is insufficient
213
+ * @internal
214
+ */
143
215
  getDiffSince(epoch: number): RESET_VALUE | Diff[] {
144
216
  maybeCaptureParent(this)
145
217
 
@@ -152,7 +224,16 @@ class __Atom__<Value, Diff = unknown> implements Atom<Value, Diff> {
152
224
  }
153
225
  }
154
226
 
227
+ /**
228
+ * Singleton reference to the Atom constructor. Used internally to create atom instances.
229
+ * @internal
230
+ */
155
231
  export const _Atom = singleton('Atom', () => __Atom__)
232
+
233
+ /**
234
+ * Type alias for instances of the internal Atom class.
235
+ * @internal
236
+ */
156
237
  export type _Atom = InstanceType<typeof _Atom>
157
238
 
158
239
  /**
@@ -192,6 +273,17 @@ export function atom<Value, Diff = unknown>(
192
273
 
193
274
  /**
194
275
  * Returns true if the given value is an {@link Atom}.
276
+ *
277
+ * @param value - The value to check
278
+ * @returns True if the value is an Atom, false otherwise
279
+ * @example
280
+ * ```ts
281
+ * const myAtom = atom('test', 42)
282
+ * const notAtom = 'hello'
283
+ *
284
+ * console.log(isAtom(myAtom)) // true
285
+ * console.log(isAtom(notAtom)) // false
286
+ * ```
195
287
  * @public
196
288
  */
197
289
  export function isAtom(value: unknown): value is Atom<unknown> {
@@ -10,13 +10,28 @@ import { Child, ComputeDiff, RESET_VALUE, Signal } from './types'
10
10
  import { logComputedGetterWarning } from './warnings'
11
11
 
12
12
  /**
13
+ * A special symbol used to indicate that a computed signal has not been initialized yet.
14
+ * This is passed as the `previousValue` parameter to a computed signal function on its first run.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const count = atom('count', 0)
19
+ * const double = computed('double', (prevValue) => {
20
+ * if (isUninitialized(prevValue)) {
21
+ * console.log('First computation!')
22
+ * }
23
+ * return count.get() * 2
24
+ * })
25
+ * ```
26
+ *
13
27
  * @public
14
28
  */
15
29
  export const UNINITIALIZED = Symbol.for('com.tldraw.state/UNINITIALIZED')
16
30
  /**
17
31
  * The type of the first value passed to a computed signal function as the 'prevValue' parameter.
32
+ * This type represents the uninitialized state of a computed signal before its first calculation.
18
33
  *
19
- * @see {@link isUninitialized}.
34
+ * @see {@link isUninitialized}
20
35
  * @public
21
36
  */
22
37
  export type UNINITIALIZED = typeof UNINITIALIZED
@@ -44,7 +59,25 @@ export function isUninitialized(value: any): value is UNINITIALIZED {
44
59
  return value === UNINITIALIZED
45
60
  }
46
61
 
47
- /** @public */
62
+ /**
63
+ * A singleton class used to wrap computed signal values along with their diffs.
64
+ * This class is used internally by the {@link withDiff} function to provide both
65
+ * the computed value and its diff to the signal system.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const count = atom('count', 0)
70
+ * const double = computed('double', (prevValue) => {
71
+ * const nextValue = count.get() * 2
72
+ * if (isUninitialized(prevValue)) {
73
+ * return nextValue
74
+ * }
75
+ * return withDiff(nextValue, nextValue - prevValue)
76
+ * })
77
+ * ```
78
+ *
79
+ * @public
80
+ */
48
81
  export const WithDiff = singleton(
49
82
  'WithDiff',
50
83
  () =>
@@ -56,9 +89,20 @@ export const WithDiff = singleton(
56
89
  }
57
90
  )
58
91
 
59
- /** @public */
92
+ /**
93
+ * Interface representing a value wrapped with its corresponding diff.
94
+ * Used in incremental computation to provide both the new value and the diff from the previous value.
95
+ *
96
+ * @public
97
+ */
60
98
  export interface WithDiff<Value, Diff> {
99
+ /**
100
+ * The computed value.
101
+ */
61
102
  value: Value
103
+ /**
104
+ * The diff between the previous and current value.
105
+ */
62
106
  diff: Diff
63
107
  }
64
108
 
@@ -89,7 +133,17 @@ export function withDiff<Value, Diff>(value: Value, diff: Diff): WithDiff<Value,
89
133
  }
90
134
 
91
135
  /**
92
- * Options for creating computed signals. Used when calling `computed`.
136
+ * Options for configuring computed signals. Used when calling `computed` or using the `@computed` decorator.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const greeting = computed('greeting', () => `Hello ${name.get()}!`, {
141
+ * historyLength: 10,
142
+ * isEqual: (a, b) => a === b,
143
+ * computeDiff: (oldVal, newVal) => ({ type: 'change', from: oldVal, to: newVal })
144
+ * })
145
+ * ```
146
+ *
93
147
  * @public
94
148
  */
95
149
  export interface ComputedOptions<Value, Diff> {
@@ -119,13 +173,27 @@ export interface ComputedOptions<Value, Diff> {
119
173
  }
120
174
 
121
175
  /**
122
- * A computed signal created via `computed`.
176
+ * A computed signal created via the `computed` function or `@computed` decorator.
177
+ * Computed signals derive their values from other signals and automatically update when their dependencies change.
178
+ * They use lazy evaluation, only recalculating when accessed and dependencies have changed.
179
+ *
180
+ * @example
181
+ * ```ts
182
+ * const firstName = atom('firstName', 'John')
183
+ * const lastName = atom('lastName', 'Doe')
184
+ * const fullName = computed('fullName', () => `${firstName.get()} ${lastName.get()}`)
185
+ *
186
+ * console.log(fullName.get()) // "John Doe"
187
+ * firstName.set('Jane')
188
+ * console.log(fullName.get()) // "Jane Doe"
189
+ * ```
123
190
  *
124
191
  * @public
125
192
  */
126
193
  export interface Computed<Value, Diff = unknown> extends Signal<Value, Diff> {
127
194
  /**
128
- * Whether this computed child is involved in an actively-running effect graph.
195
+ * Whether this computed signal is involved in an actively-running effect graph.
196
+ * Returns true if there are any reactions or other computed signals depending on this one.
129
197
  * @public
130
198
  */
131
199
  readonly isActivelyListening: boolean
@@ -286,7 +354,19 @@ class __UNSAFE__Computed<Value, Diff = unknown> implements Computed<Value, Diff>
286
354
  }
287
355
  }
288
356
 
357
+ /**
358
+ * Singleton reference to the computed signal implementation class.
359
+ * Used internally by the library to create computed signal instances.
360
+ *
361
+ * @internal
362
+ */
289
363
  export const _Computed = singleton('Computed', () => __UNSAFE__Computed)
364
+
365
+ /**
366
+ * Type alias for the computed signal implementation class.
367
+ *
368
+ * @internal
369
+ */
290
370
  export type _Computed = InstanceType<typeof __UNSAFE__Computed>
291
371
 
292
372
  function computedMethodLegacyDecorator(
@@ -437,7 +517,9 @@ export function getComputedInstance<Obj extends object, Prop extends keyof Obj>(
437
517
  }
438
518
 
439
519
  /**
440
- * Creates a computed signal.
520
+ * Creates a computed signal that derives its value from other signals.
521
+ * Computed signals automatically update when their dependencies change and use lazy evaluation
522
+ * for optimal performance.
441
523
  *
442
524
  * @example
443
525
  * ```ts
@@ -475,10 +557,10 @@ export function getComputedInstance<Obj extends object, Prop extends keyof Obj>(
475
557
  * }
476
558
  * ```
477
559
  *
478
- * @param name - The name of the signal.
479
- * @param compute - The function that computes the value of the signal.
480
- * @param options - Options for the signal.
481
- *
560
+ * @param name - The name of the signal for debugging purposes
561
+ * @param compute - The function that computes the value of the signal. Receives the previous value and last computed epoch
562
+ * @param options - Optional configuration for the computed signal
563
+ * @returns A new computed signal
482
564
  * @public
483
565
  */
484
566
  export function computed<Value, Diff = unknown>(
@@ -490,7 +572,23 @@ export function computed<Value, Diff = unknown>(
490
572
  options?: ComputedOptions<Value, Diff>
491
573
  ): Computed<Value, Diff>
492
574
  /**
493
- * `@computed` decorator (TC39 decorators).
575
+ * TC39 decorator for creating computed methods in classes.
576
+ *
577
+ * @example
578
+ * ```ts
579
+ * class MyClass {
580
+ * value = atom('value', 10)
581
+ *
582
+ * @computed
583
+ * doubled() {
584
+ * return this.value.get() * 2
585
+ * }
586
+ * }
587
+ * ```
588
+ *
589
+ * @param compute - The method to be decorated
590
+ * @param context - The decorator context provided by TypeScript
591
+ * @returns The decorated method
494
592
  * @public
495
593
  */
496
594
  export function computed<This extends object, Value>(
@@ -498,16 +596,48 @@ export function computed<This extends object, Value>(
498
596
  context: ClassMethodDecoratorContext<This, () => Value>
499
597
  ): () => Value
500
598
  /**
501
- * `@computed` decorator (legacy typescript decorator syntax).
599
+ * Legacy TypeScript decorator for creating computed methods in classes.
502
600
  *
503
- * @public */
601
+ * @example
602
+ * ```ts
603
+ * class MyClass {
604
+ * value = atom('value', 10)
605
+ *
606
+ * @computed
607
+ * doubled() {
608
+ * return this.value.get() * 2
609
+ * }
610
+ * }
611
+ * ```
612
+ *
613
+ * @param target - The class prototype
614
+ * @param key - The property key
615
+ * @param descriptor - The property descriptor
616
+ * @returns The modified property descriptor
617
+ * @public
618
+ */
504
619
  export function computed(
505
620
  target: any,
506
621
  key: string,
507
622
  descriptor: PropertyDescriptor
508
623
  ): PropertyDescriptor
509
624
  /**
510
- * `@computed` decorator with options.
625
+ * Decorator factory for creating computed methods with options.
626
+ *
627
+ * @example
628
+ * ```ts
629
+ * class MyClass {
630
+ * items = atom('items', [1, 2, 3])
631
+ *
632
+ * @computed({ historyLength: 10 })
633
+ * sum() {
634
+ * return this.items.get().reduce((a, b) => a + b, 0)
635
+ * }
636
+ * }
637
+ * ```
638
+ *
639
+ * @param options - Configuration options for the computed signal
640
+ * @returns A decorator function that can be applied to methods
511
641
  * @public
512
642
  */
513
643
  export function computed<Value, Diff = unknown>(
@@ -518,7 +648,17 @@ export function computed<Value, Diff = unknown>(
518
648
  context: ClassMethodDecoratorContext<This, () => Value>
519
649
  ) => () => Value)
520
650
 
521
- /** @public */
651
+ /**
652
+ * Implementation function that handles all computed signal creation and decoration scenarios.
653
+ * This function is overloaded to support multiple usage patterns:
654
+ * - Creating computed signals directly
655
+ * - Using as a TC39 decorator
656
+ * - Using as a legacy decorator
657
+ * - Using as a decorator factory with options
658
+ *
659
+ * @returns Either a computed signal instance or a decorator function depending on usage
660
+ * @public
661
+ */
522
662
  export function computed() {
523
663
  if (arguments.length === 1) {
524
664
  const options = arguments[0]
@@ -532,11 +672,21 @@ export function computed() {
532
672
 
533
673
  /**
534
674
  * Returns true if the given value is a computed signal.
675
+ * This is a type guard function that can be used to check if a value is a computed signal instance.
676
+ *
677
+ * @example
678
+ * ```ts
679
+ * const count = atom('count', 0)
680
+ * const double = computed('double', () => count.get() * 2)
681
+ *
682
+ * console.log(isComputed(count)) // false
683
+ * console.log(isComputed(double)) // true
684
+ * ```
535
685
  *
536
- * @param value
537
- * @returns {value is Computed<any>}
686
+ * @param value - The value to check
687
+ * @returns True if the value is a computed signal, false otherwise
538
688
  * @public
539
689
  */
540
690
  export function isComputed(value: any): value is Computed<any> {
541
- return value && value instanceof _Computed
691
+ return !!(value && value instanceof _Computed)
542
692
  }
@@ -1,28 +1,71 @@
1
1
  import { RESET_VALUE } from './types'
2
2
 
3
+ /**
4
+ * A tuple representing a range of epochs and the associated diff.
5
+ * Used internally by HistoryBuffer to store change information.
6
+ *
7
+ * @internal
8
+ */
3
9
  type RangeTuple<Diff> = [fromEpoch: number, toEpoch: number, diff: Diff]
4
10
 
5
11
  /**
6
- * A structure that stores diffs between values of an atom.
12
+ * A circular buffer that stores diffs between sequential values of an atom or computed signal.
13
+ * This enables efficient change tracking and history retrieval for features like undo/redo.
14
+ *
15
+ * The buffer uses a wrap-around strategy to maintain a fixed-size history of the most recent
16
+ * changes, automatically overwriting older entries when the capacity is exceeded.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const buffer = new HistoryBuffer<string>(5)
21
+ * buffer.pushEntry(0, 1, 'first change')
22
+ * buffer.pushEntry(1, 2, 'second change')
23
+ * const changes = buffer.getChangesSince(0) // ['first change', 'second change']
24
+ * ```
7
25
  *
8
26
  * @internal
9
27
  */
10
28
  export class HistoryBuffer<Diff> {
29
+ /**
30
+ * Current write position in the circular buffer.
31
+ * @internal
32
+ */
11
33
  private index = 0
12
34
 
13
- // use a wrap around buffer to store the last N values
35
+ /**
36
+ * Circular buffer storing range tuples. Uses undefined to represent empty slots.
37
+ * @internal
38
+ */
14
39
  buffer: Array<RangeTuple<Diff> | undefined>
15
40
 
41
+ /**
42
+ * Creates a new HistoryBuffer with the specified capacity.
43
+ *
44
+ * capacity - Maximum number of diffs to store in the buffer
45
+ * @example
46
+ * ```ts
47
+ * const buffer = new HistoryBuffer<number>(10) // Store up to 10 diffs
48
+ * ```
49
+ */
16
50
  constructor(private readonly capacity: number) {
17
51
  this.buffer = new Array(capacity)
18
52
  }
19
53
 
20
54
  /**
21
- * Add a diff to the history buffer.
55
+ * Adds a diff entry to the history buffer, representing a change between two epochs.
56
+ *
57
+ * If the diff is undefined, the operation is ignored. If the diff is RESET_VALUE,
58
+ * the entire buffer is cleared to indicate that historical tracking should restart.
22
59
  *
23
- * @param lastComputedEpoch - The epoch when the diff was computed.
24
- * @param currentEpoch - The current epoch.
25
- * @param diff - The diff to add, or else a reset value.
60
+ * @param lastComputedEpoch - The epoch when the previous value was computed
61
+ * @param currentEpoch - The epoch when the current value was computed
62
+ * @param diff - The diff representing the change, or RESET_VALUE to clear history
63
+ * @example
64
+ * ```ts
65
+ * const buffer = new HistoryBuffer<string>(5)
66
+ * buffer.pushEntry(0, 1, 'added text')
67
+ * buffer.pushEntry(1, 2, RESET_VALUE) // Clears the buffer
68
+ * ```
26
69
  */
27
70
  pushEntry(lastComputedEpoch: number, currentEpoch: number, diff: Diff | RESET_VALUE) {
28
71
  if (diff === undefined) {
@@ -42,7 +85,16 @@ export class HistoryBuffer<Diff> {
42
85
  }
43
86
 
44
87
  /**
45
- * Clear the history buffer.
88
+ * Clears all entries from the history buffer and resets the write position.
89
+ * This is called when a RESET_VALUE diff is encountered.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * const buffer = new HistoryBuffer<string>(5)
94
+ * buffer.pushEntry(0, 1, 'change')
95
+ * buffer.clear()
96
+ * console.log(buffer.getChangesSince(0)) // RESET_VALUE
97
+ * ```
46
98
  */
47
99
  clear() {
48
100
  this.index = 0
@@ -50,10 +102,24 @@ export class HistoryBuffer<Diff> {
50
102
  }
51
103
 
52
104
  /**
53
- * Get the diffs since the given epoch.
105
+ * Retrieves all diffs that occurred since the specified epoch.
106
+ *
107
+ * The method searches backwards through the circular buffer to find changes
108
+ * that occurred after the given epoch. If insufficient history is available
109
+ * or the requested epoch is too old, returns RESET_VALUE indicating that
110
+ * a complete state rebuild is required.
54
111
  *
55
- * @param sinceEpoch - The epoch to get diffs since.
56
- * @returns An array of diffs or a flag to reset the history buffer.
112
+ * @param sinceEpoch - The epoch from which to retrieve changes
113
+ * @returns Array of diffs since the epoch, or RESET_VALUE if history is insufficient
114
+ * @example
115
+ * ```ts
116
+ * const buffer = new HistoryBuffer<string>(5)
117
+ * buffer.pushEntry(0, 1, 'first')
118
+ * buffer.pushEntry(1, 2, 'second')
119
+ * const changes = buffer.getChangesSince(0) // ['first', 'second']
120
+ * const recentChanges = buffer.getChangesSince(1) // ['second']
121
+ * const tooOld = buffer.getChangesSince(-100) // RESET_VALUE
122
+ * ```
57
123
  */
58
124
  getChangesSince(sinceEpoch: number): RESET_VALUE | Diff[] {
59
125
  const { index, capacity, buffer } = this