opshot 0.3.3 → 0.4.0

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 (4) hide show
  1. package/README.md +33 -33
  2. package/dist/index.d.ts +435 -42
  3. package/dist/index.js +2993 -1241
  4. package/package.json +20 -10
package/README.md CHANGED
@@ -82,23 +82,23 @@ This is how you optimize re-rendering across your component tree: place `scope`
82
82
  ## Creating State
83
83
 
84
84
  ```tsx
85
- import { ignore, unsafeTrack, useMutableState, type Ignored, type UnsafeTracked } from "opshot";
85
+ import { ignore, unsafeTrack, useMutableState } from "opshot";
86
86
 
87
87
  interface PlayerState {
88
88
  position: number;
89
- element: Ignored<HTMLAudioElement>;
90
- queue: UnsafeTracked<Playlist>;
89
+ element: HTMLAudioElement;
90
+ queue: Playlist;
91
91
  seek: (position: number) => void;
92
92
  }
93
93
 
94
94
  const Player = () => {
95
- const player = useMutableState<PlayerState>({
95
+ const player: PlayerState = useMutableState({
96
96
  position: 0,
97
97
 
98
- // ignore() keeps a value out of reactivity and ops.
98
+ // ignore() on a value in the factory argument makes the edge at that path untracked.
99
99
  element: ignore(new Audio()),
100
100
 
101
- // unsafeTrack() tracks all the values it can, even if there is weird behaviour
101
+ // unsafeTrack() on a value in the factory argument disables strict at and under that path.
102
102
  queue: unsafeTrack(new Playlist()),
103
103
 
104
104
  seek(position: number) {
@@ -120,13 +120,14 @@ opshot tracks plain data.
120
120
 
121
121
  It can't track:
122
122
 
123
- - Internal slots (language level features like in Map)
124
- - #private fields (hidden at the language level)
125
- - Array subclasses (the prototype is lost when copied)
123
+ - Hidden stores (language-level features like in Map)
124
+ - #private fields
125
+ - Own function properties on class instances
126
+ - Non-writable properties that hold an object
126
127
 
127
- And `this` for arrow methods on classes refers to the original and **not** the tracked state.
128
+ `strict: true` throws at a dangerous edge, at the cause.
128
129
 
129
- Use `ignore` or `unsafeTrack` when dealing with these.
130
+ Use `ignore` on a value in the factory argument to make the edge at that path untracked. Use `unsafeTrack` on a value in the factory argument to disable strict at and under that path.
130
131
 
131
132
  ## Tracked collections
132
133
 
@@ -155,8 +156,8 @@ const Counter = () => {
155
156
  () =>
156
157
  subscribe(counter, (ops, meta) => {
157
158
  // ops: [{
158
- // do: { op: "replace", path: ["count"], value: 1 },
159
- // undo: { op: "replace", path: ["count"], value: 0 },
159
+ // do: { verb: "assign", path: ["count"], value: 1 },
160
+ // undo: { verb: "assign", path: ["count"], value: 0 },
160
161
  // }]
161
162
  // meta: whatever the writer passed, or undefined for bare writes
162
163
  }),
@@ -169,33 +170,36 @@ const Counter = () => {
169
170
 
170
171
  ## Ops
171
172
 
172
- An op is an invertible pair of `Operation` halves. Every half uses one of three verbs:
173
+ An op is an invertible pair of halves. Every half uses one of three verbs:
173
174
 
174
175
  ```ts
175
176
  type OperationPath = ReadonlyArray<string | number>;
176
177
 
177
- type Operation =
178
- | { readonly op: "add"; readonly path: OperationPath; readonly value: unknown }
179
- | { readonly op: "replace"; readonly path: OperationPath; readonly value: unknown }
180
- | { readonly op: "remove"; readonly path: OperationPath };
181
-
182
- interface Op {
183
- readonly do: Operation;
184
- readonly undo: Operation;
178
+ interface Operation {
179
+ readonly do:
180
+ | {
181
+ readonly verb: "assign";
182
+ readonly path: OperationPath;
183
+ readonly value: unknown;
184
+ readonly ids?: ReadonlyArray<number>;
185
+ }
186
+ | { readonly verb: "delete"; readonly path: OperationPath }
187
+ | { readonly verb: "link"; readonly path: OperationPath; readonly ref: number };
188
+ readonly undo: Operation["do"];
185
189
  }
186
190
  ```
187
191
 
188
- `applyOps` puts them back on a state, so a history is a list of ops and an undo is their `undo` halves in reverse.
192
+ Ids vend in admission-walk order over the emitted artifact; a departure's undo assign may carry `ids` to rebind that walk, the one naming fact construction cannot re-derive. `applyOperations` puts them back on a state, so a history is a list of ops and an undo is `applyOperations` with `"undo"`.
189
193
 
190
194
  ```tsx
191
195
  import { useEffect, useRef } from "react";
192
- import { applyOps, subscribe, useMutableState, type Op } from "opshot";
196
+ import { applyOperations, subscribe, useMutableState, type Operation } from "opshot";
193
197
 
194
198
  const replay = {};
195
199
 
196
200
  const Counter = () => {
197
201
  const counter = useMutableState({ count: 0 });
198
- const history = useRef<Array<ReadonlyArray<Op>>>([]);
202
+ const history = useRef<Array<ReadonlyArray<Operation>>>([]);
199
203
 
200
204
  useEffect(
201
205
  () =>
@@ -213,11 +217,7 @@ const Counter = () => {
213
217
 
214
218
  if (!ops) return;
215
219
 
216
- applyOps(
217
- counter,
218
- [...ops].reverse().map((op) => op.undo),
219
- replay,
220
- );
220
+ applyOperations(counter, ops, "undo", replay);
221
221
  };
222
222
 
223
223
  return (
@@ -245,8 +245,8 @@ const Editor = () => {
245
245
  const group = useGroup();
246
246
 
247
247
  // Created through the group, so their ops reach the group's subscribers.
248
- const doc = useMutableState({ items: new Array<string>() }, group);
249
- const selection = useMutableState({ index: 0 }, group);
248
+ const doc = useMutableState({ items: new Array<string>() }, { group });
249
+ const selection = useMutableState({ index: 0 }, { group });
250
250
 
251
251
  useEffect(
252
252
  () =>
@@ -264,7 +264,7 @@ const Editor = () => {
264
264
 
265
265
  ## Channels
266
266
 
267
- A channel binds `transact`, `subscribe`, and `applyOps` to a typed meta convention, so a listener can tell its own writes from everyone else's.
267
+ A channel binds `transact`, `subscribe`, and `applyOperations` to a typed meta convention, so a listener can tell its own writes from everyone else's.
268
268
 
269
269
  ```tsx
270
270
  import { useEffect } from "react";
package/dist/index.d.ts CHANGED
@@ -1,75 +1,424 @@
1
1
  import { ComponentType, FC } from 'react';
2
2
 
3
+ declare const ignoreMarker: unique symbol;
4
+ /**
5
+ * A factory-argument marker wrapping `T`.
6
+ *
7
+ * @typeParam T - Value type.
8
+ */
9
+ interface Ignored<T> {
10
+ readonly [ignoreMarker]: T;
11
+ }
12
+ /**
13
+ * Marks a factory-argument value so the edge at that path is untracked in that state.
14
+ *
15
+ * @typeParam T - Value type.
16
+ * @param value - Value to ignore.
17
+ * @returns A marker consumed at create.
18
+ */
19
+ declare function ignore<T>(value: T): Ignored<T>;
20
+
21
+ declare const unsafeMarker: unique symbol;
22
+ /**
23
+ * A factory-argument marker wrapping `T`.
24
+ *
25
+ * @typeParam T - Value type.
26
+ */
27
+ interface UnsafeTracked<T> {
28
+ readonly [unsafeMarker]: T;
29
+ }
30
+ /**
31
+ * Marks a factory-argument value so strict is disabled at and under that path.
32
+ *
33
+ * @typeParam T - Value type.
34
+ * @param value - Value to track without strict.
35
+ * @returns A marker consumed at create.
36
+ */
37
+ declare function unsafeTrack<T>(value: T): UnsafeTracked<T>;
38
+
39
+ /**
40
+ * Schedules when bare writes notify listeners. Call `flush` once.
41
+ *
42
+ * @param flush - Delivers pending ops.
43
+ * @returns Nothing.
44
+ */
45
+ type EmissionScheduler = (flush: () => void) => void;
46
+ /**
47
+ * State creation options.
48
+ *
49
+ * @example
50
+ * createMutableState({ x: 0 }, { emitOn: (flush) => requestAnimationFrame(flush), strict: false })
51
+ */
52
+ interface MutableNodeOptions {
53
+ /**
54
+ * When bare writes notify listeners. Defaults to a microtask.
55
+ */
56
+ readonly emitOn?: EmissionScheduler;
57
+ /**
58
+ * When true, throws at a dangerous edge, at the cause. Defaults to true.
59
+ */
60
+ readonly strict?: boolean;
61
+ }
62
+
63
+ /**
64
+ * Options for `createMutableState`.
65
+ *
66
+ * @example
67
+ * createMutableState({ count: 0 }, { group, emitOn, strict: false })
68
+ */
69
+ interface MutableStateOptions extends MutableNodeOptions {
70
+ /**
71
+ * Group that receives this state's changes.
72
+ */
73
+ readonly group?: Group;
74
+ }
75
+ /**
76
+ * The live state shape after factory-argument markers are collapsed.
77
+ *
78
+ * @typeParam T - Factory argument type.
79
+ */
80
+ type Unmarked<T> = T extends Ignored<infer Inner> ? Unmarked<Inner> : T extends UnsafeTracked<infer Inner> ? Unmarked<Inner> : T extends (...args: never) => unknown ? T : T extends ReadonlyArray<infer Element> ? Array<Unmarked<Element>> : T extends object ? {
81
+ [Key in keyof T]: Unmarked<T[Key]>;
82
+ } : T;
83
+ /**
84
+ * Creates a mutable state object.
85
+ *
86
+ * `ignore()` on a value in the factory argument makes the edge at that path untracked in that state.
87
+ * `unsafeTrack()` on a value in the factory argument disables strict at and under that path.
88
+ *
89
+ * @typeParam T - State shape.
90
+ * @param properties - Initial fields.
91
+ * @param options - Creation options.
92
+ * @returns The state, with factory-argument markers collapsed.
93
+ */
94
+ declare function createMutableState<T extends object>(properties: T, options?: MutableStateOptions): Unmarked<T>;
95
+
96
+ /**
97
+ * Path segments to a value in state.
98
+ *
99
+ * @example
100
+ * ["document", "items", 0, "title"]
101
+ */
3
102
  type OperationPath = ReadonlyArray<string | number>;
4
103
 
5
- interface AddOperation {
6
- readonly op: "add";
104
+ interface DeclarationTrie {
105
+ readonly ignored: boolean;
106
+ readonly unsafe: boolean;
107
+ readonly children: ReadonlyMap<string, DeclarationTrie>;
108
+ }
109
+
110
+ interface InEdge {
111
+ readonly parent: object;
112
+ readonly key: string | number;
113
+ }
114
+ interface NodeRecord {
115
+ edges: Array<InEdge>;
116
+ id: number | undefined;
117
+ }
118
+
119
+ interface CaptureTables {
120
+ mints: Array<{
121
+ readonly node: object;
122
+ readonly id: number;
123
+ }>;
124
+ binds: Array<{
125
+ readonly node: object;
126
+ readonly id: number;
127
+ }>;
128
+ bindIdByNode: Map<object, number>;
129
+ bindNodeById: Map<number, object>;
130
+ mintIdByNode: Map<object, number>;
131
+ mintNodeById: Map<number, object>;
132
+ nextStagedId: number;
133
+ }
134
+
135
+ interface DirtyIndex {
136
+ readonly edges: WeakMap<object, Set<string | symbol>>;
137
+ readonly nodes: WeakSet<object>;
138
+ }
139
+ interface Handle {
140
+ proxy: {
141
+ readonly root: object;
142
+ };
143
+ lastSnapshot: object;
144
+ hasPendingWrites: boolean;
145
+ isFlushScheduled: boolean;
146
+ isFlushHeld: boolean;
147
+ flushGeneration: number;
148
+ subscribers: StateListeners;
149
+ groups?: ReadonlyArray<GroupListeners>;
150
+ disarmWatch?: () => void;
151
+ emitOn?: EmissionScheduler;
152
+ strict: boolean;
153
+ declarations: DeclarationTrie | undefined;
154
+ nodes: WeakMap<object, NodeRecord>;
155
+ byId: Map<number, object>;
156
+ nextInternId: number;
157
+ lastDirty?: DirtyIndex;
158
+ stamp: object;
159
+ version: number;
160
+ replaying: boolean;
161
+ transactionCapture?: CaptureTables;
162
+ }
163
+
164
+ /**
165
+ * Assigns a value at a path.
166
+ *
167
+ * @example
168
+ * { verb: "assign", path: ["count"], value: 1 }
169
+ */
170
+ interface AssignMutation {
171
+ /**
172
+ * `"assign"`.
173
+ */
174
+ readonly verb: "assign";
175
+ /**
176
+ * Path to assign.
177
+ */
7
178
  readonly path: OperationPath;
179
+ /**
180
+ * Value to assign.
181
+ */
8
182
  readonly value: unknown;
183
+ /**
184
+ * Walk-ordered intern ids that override deterministic vending when this half re-admits departed material.
185
+ */
186
+ readonly ids?: ReadonlyArray<number>;
9
187
  }
10
- interface ReplaceOperation {
11
- readonly op: "replace";
188
+ /**
189
+ * Deletes the value at a path.
190
+ *
191
+ * @example
192
+ * { verb: "delete", path: ["temp"] }
193
+ */
194
+ interface DeleteMutation {
195
+ /**
196
+ * `"delete"`.
197
+ */
198
+ readonly verb: "delete";
199
+ /**
200
+ * Path to delete.
201
+ */
12
202
  readonly path: OperationPath;
13
- readonly value: unknown;
14
203
  }
15
- interface RemoveOperation {
16
- readonly op: "remove";
204
+ /**
205
+ * Links the interned node `ref` into `path`.
206
+ *
207
+ * @example
208
+ * { verb: "link", path: ["alias"], ref: 0 }
209
+ */
210
+ interface LinkMutation {
211
+ /**
212
+ * `"link"`.
213
+ */
214
+ readonly verb: "link";
215
+ /**
216
+ * Path to place the linked node.
217
+ */
17
218
  readonly path: OperationPath;
219
+ /**
220
+ * Intern id of the node to link.
221
+ */
222
+ readonly ref: number;
18
223
  }
19
- type Operation = AddOperation | ReplaceOperation | RemoveOperation;
20
- interface Op {
21
- readonly do: Operation;
22
- readonly undo: Operation;
224
+ /**
225
+ * An assign, a delete, or a link.
226
+ *
227
+ * @example
228
+ * { verb: "assign", path: ["profile"], value: { name: "Ada" } }
229
+ */
230
+ type Mutation = AssignMutation | DeleteMutation | LinkMutation;
231
+ /**
232
+ * A change with do and undo halves.
233
+ *
234
+ * @example
235
+ * { do: { verb: "assign", path: ["count"], value: 1 }, undo: { verb: "assign", path: ["count"], value: 0 } }
236
+ */
237
+ interface Operation {
238
+ /**
239
+ * Forward operation.
240
+ */
241
+ readonly do: Mutation;
242
+ /**
243
+ * Reverse operation.
244
+ */
245
+ readonly undo: Mutation;
23
246
  }
24
247
 
25
- type StateListener = (ops: ReadonlyArray<Op>, meta: unknown) => void;
26
- type GroupListener = (state: object, ops: ReadonlyArray<Op>, meta: unknown) => void;
248
+ /**
249
+ * Listener for one state's changes.
250
+ *
251
+ * @param ops - Ops for the change.
252
+ * @param meta - Writer meta, if any.
253
+ * @returns Nothing.
254
+ */
255
+ type StateListener = (ops: ReadonlyArray<Operation>, meta: unknown) => void;
256
+ /**
257
+ * Listener for a group's changes.
258
+ *
259
+ * @param state - State that changed.
260
+ * @param ops - Ops for the change.
261
+ * @param meta - Writer meta, if any.
262
+ * @returns Nothing.
263
+ */
264
+ type GroupListener = (state: object, ops: ReadonlyArray<Operation>, meta: unknown) => void;
265
+ type StateDeliver = (ops: ReadonlyArray<Operation>, meta: unknown, channelId: object | undefined) => void;
266
+ type GroupDeliver = (state: object, ops: ReadonlyArray<Operation>, meta: unknown, channelId: object | undefined) => void;
267
+ type StateListeners = Map<Function, Map<object | undefined, StateDeliver>>;
268
+ type GroupListeners = Map<Function, Map<object | undefined, GroupDeliver>>;
27
269
 
270
+ /**
271
+ * Creates states and receives their changes on one stream.
272
+ *
273
+ * @example
274
+ * const group = createGroup()
275
+ * const doc = group.createMutableState({ title: "" })
276
+ * subscribe(group, (state, ops, meta) => {})
277
+ */
28
278
  interface Group {
29
- createMutableState<T extends object>(properties: T): T;
279
+ /**
280
+ * Creates a state in this group.
281
+ *
282
+ * @typeParam T - State shape.
283
+ * @param properties - Initial fields.
284
+ * @param options - Creation options.
285
+ * @returns The state.
286
+ */
287
+ createMutableState<T extends object>(properties: T, options?: MutableNodeOptions): Unmarked<T>;
30
288
  }
31
- declare function createGroup(): Group;
289
+ /**
290
+ * Creates a group.
291
+ *
292
+ * @param parent - Optional parent group whose listeners hear this group's states.
293
+ * @returns A new group.
294
+ */
295
+ declare function createGroup(parent?: Group): Group;
32
296
 
33
- type Context<M> = {
297
+ /**
298
+ * Listener context from a channel subscription.
299
+ *
300
+ * @typeParam M - Meta type for this channel.
301
+ */
302
+ type EmissionContext<M> = {
34
303
  readonly isTransaction: true;
35
304
  readonly meta: M;
36
305
  } | {
37
306
  readonly isTransaction: false;
38
307
  readonly meta: unknown;
39
308
  };
309
+ /**
310
+ * Listens for changes from a group's states.
311
+ *
312
+ * @param group - Group to listen to.
313
+ * @param listener - Called on each change.
314
+ * @returns Unsubscribe function.
315
+ */
40
316
  declare function subscribe(group: Group, listener: GroupListener): () => void;
317
+ /**
318
+ * Listens for changes to a state.
319
+ *
320
+ * @param state - State to listen to.
321
+ * @param listener - Called on each change.
322
+ * @returns Unsubscribe function.
323
+ */
41
324
  declare function subscribe(state: object, listener: StateListener): () => void;
42
325
 
326
+ type ApplyDirection = "do" | "undo";
327
+
328
+ /**
329
+ * Channel-bound `transact`, `subscribe`, and `applyOperations`.
330
+ *
331
+ * @typeParam M - Meta type for this channel.
332
+ */
43
333
  interface Channel<M extends object> {
334
+ /**
335
+ * Runs a transaction with this channel's meta.
336
+ *
337
+ * @param state - State to change.
338
+ * @param mutate - Function that writes the state.
339
+ * @param meta - Meta for this write.
340
+ * @returns Nothing.
341
+ */
44
342
  transact(state: object, mutate: () => void, meta?: Partial<M>): void;
45
- subscribe(group: Group, listener: (state: object, ops: ReadonlyArray<Op>, context: Context<M>) => void): () => void;
46
- subscribe(state: object, listener: (ops: ReadonlyArray<Op>, context: Context<M>) => void): () => void;
47
- applyOps(state: object, operations: ReadonlyArray<Operation>, meta?: Partial<M>): void;
343
+ /**
344
+ * Listens for changes from a group's states.
345
+ *
346
+ * @param group - Group to listen to.
347
+ * @param listener - Called on each change.
348
+ * @returns Unsubscribe function.
349
+ */
350
+ subscribe(group: Group, listener: (state: object, ops: ReadonlyArray<Operation>, context: EmissionContext<M>) => void): () => void;
351
+ /**
352
+ * Listens for changes to a state.
353
+ *
354
+ * @param state - State to listen to.
355
+ * @param listener - Called on each change.
356
+ * @returns Unsubscribe function.
357
+ */
358
+ subscribe(state: object, listener: (ops: ReadonlyArray<Operation>, context: EmissionContext<M>) => void): () => void;
359
+ /**
360
+ * Applies operations with this channel's meta.
361
+ *
362
+ * @param state - State to change.
363
+ * @param operations - Operations to apply.
364
+ * @param direction - `"do"` or `"undo"`.
365
+ * @param meta - Meta for this write.
366
+ * @returns Nothing.
367
+ */
368
+ applyOperations(state: object, operations: ReadonlyArray<Operation>, direction: ApplyDirection, meta?: Partial<M>): void;
48
369
  }
370
+ /**
371
+ * Creates a channel with a typed meta convention.
372
+ *
373
+ * @typeParam M - Meta type for this channel.
374
+ * @param defaults - Default meta for this channel's writes.
375
+ * @returns The channel.
376
+ */
49
377
  declare function createChannel<M extends object>(defaults?: M): Channel<M>;
50
378
 
51
- declare function createMutableState<T extends object>(properties: T, group?: Group): T;
52
-
379
+ /**
380
+ * Returns a stable identity key for a value.
381
+ *
382
+ * @param value - Value to identify.
383
+ * @returns Identity key.
384
+ */
53
385
  declare function identify(value: object): object;
386
+ /**
387
+ * Returns whether two values share the same identity.
388
+ *
389
+ * @param first - First value.
390
+ * @param second - Second value.
391
+ * @returns True if they match.
392
+ */
54
393
  declare function isSameIdentity(first: object, second: object): boolean;
55
394
 
395
+ /**
396
+ * Returns whether a value is an opshot state.
397
+ *
398
+ * @param value - Value to test.
399
+ * @returns True if it is a state.
400
+ */
56
401
  declare function isState(value: unknown): value is object;
57
402
 
58
- declare function applyOps(state: object, operations: ReadonlyArray<Operation>, meta?: unknown): void;
59
-
60
- declare function diffSnapshots(before: object, after: object): Array<Op>;
61
-
62
- declare const ignoredMarker: unique symbol;
63
- type Ignored<T extends object> = T & {
64
- readonly [ignoredMarker]: true;
65
- };
66
- declare const ignore: <T extends object>(value: T) => Ignored<T>;
403
+ /**
404
+ * Applies operations to a state.
405
+ *
406
+ * @param state - State to change.
407
+ * @param operations - Operations to apply.
408
+ * @param direction - `"do"` or `"undo"`.
409
+ * @param meta - Passed to listeners.
410
+ * @returns Nothing.
411
+ */
412
+ declare function applyOperations(state: object, operations: ReadonlyArray<Operation>, direction: ApplyDirection, meta?: unknown): void;
67
413
 
68
- declare const unsafeTrackedBrand: unique symbol;
69
- type UnsafeTracked<T extends object> = T & {
70
- readonly [unsafeTrackedBrand]: true;
71
- };
72
- declare function unsafeTrack<T extends object>(value: T): UnsafeTracked<T>;
414
+ /**
415
+ * Diffs two plain objects into ops.
416
+ *
417
+ * @param before - Earlier value.
418
+ * @param after - Later value.
419
+ * @returns Ops from before to after.
420
+ */
421
+ declare function diffObjects(before: object, after: object, handle?: Handle, dirty?: DirtyIndex, capture?: CaptureTables): Array<Operation>;
73
422
 
74
423
  type DateConstructorArgs = [] | [value: number | string] | [
75
424
  year: number,
@@ -80,10 +429,17 @@ type DateConstructorArgs = [] | [value: number | string] | [
80
429
  seconds?: number,
81
430
  milliseconds?: number
82
431
  ];
432
+ /**
433
+ * Tracked `Date` for use in state.
434
+ *
435
+ * @example
436
+ * createMutableState({ when: new TrackedDate() })
437
+ */
83
438
  declare class TrackedDate {
84
439
  private epochMs;
85
440
  constructor(...args: DateConstructorArgs);
86
441
  private readDate;
442
+ private readEpochMs;
87
443
  private write;
88
444
  toString(): string;
89
445
  toDateString(): string;
@@ -134,6 +490,12 @@ declare class TrackedDate {
134
490
  readonly [Symbol.toStringTag]: "TrackedDate";
135
491
  }
136
492
 
493
+ /**
494
+ * Tracked `Map` for use in state.
495
+ *
496
+ * @typeParam K - Key type.
497
+ * @typeParam V - Value type.
498
+ */
137
499
  declare class TrackedMap<K, V> {
138
500
  private slots;
139
501
  private index;
@@ -153,6 +515,11 @@ declare class TrackedMap<K, V> {
153
515
  readonly [Symbol.toStringTag]: "TrackedMap";
154
516
  }
155
517
 
518
+ /**
519
+ * Tracked `Set` for use in state.
520
+ *
521
+ * @typeParam T - Member type.
522
+ */
156
523
  declare class TrackedSet<T> {
157
524
  private slots;
158
525
  private index;
@@ -171,15 +538,41 @@ declare class TrackedSet<T> {
171
538
  readonly [Symbol.toStringTag]: "TrackedSet";
172
539
  }
173
540
 
541
+ /**
542
+ * Runs changes in one batch and notifies listeners with optional `meta`.
543
+ *
544
+ * @param state - State to change.
545
+ * @param mutate - Function that writes the state.
546
+ * @param meta - Passed to listeners.
547
+ * @returns Nothing.
548
+ */
174
549
  declare function transact(state: object, mutate: () => void, meta?: unknown): void;
175
550
 
176
- interface ScopeOptions {
177
- readonly maxDepth?: number;
178
- }
179
- declare function scope<P extends object>(Component: ComponentType<P>, options?: ScopeOptions): FC<P>;
551
+ /**
552
+ * Wraps a component so it re-renders only when fields it read change.
553
+ *
554
+ * @typeParam P - Props type.
555
+ * @param Component - Component to wrap.
556
+ * @returns The wrapped component.
557
+ */
558
+ declare function scope<P extends object>(Component: ComponentType<P>): FC<P>;
180
559
 
181
- declare function useGroup(): Group;
560
+ /**
561
+ * Creates a group for a component.
562
+ *
563
+ * @param parent - Optional parent group whose listeners hear this group's states.
564
+ * @returns The group.
565
+ */
566
+ declare function useGroup(parent?: Group): Group;
182
567
 
183
- declare function useMutableState<T extends object>(properties: T, group?: Group): T;
568
+ /**
569
+ * Creates mutable state for a component.
570
+ *
571
+ * @typeParam T - State shape.
572
+ * @param properties - Initial fields, or a function that returns them.
573
+ * @param options - Creation options.
574
+ * @returns The state.
575
+ */
576
+ declare function useMutableState<T extends object>(properties: (() => T) | T, options?: MutableStateOptions): Unmarked<T>;
184
577
 
185
- export { type AddOperation, type Channel, type Context, type Group, type GroupListener, type Ignored, type Op, type Operation, type OperationPath, type RemoveOperation, type ReplaceOperation, type ScopeOptions, type StateListener, TrackedDate, TrackedMap, TrackedSet, type UnsafeTracked, applyOps, createChannel, createGroup, createMutableState, diffSnapshots, identify, ignore, isSameIdentity, isState, scope, subscribe, transact, unsafeTrack, useGroup, useMutableState };
578
+ export { type Channel, type EmissionContext, type EmissionScheduler, type Group, type GroupListener, type Ignored, type MutableNodeOptions, type MutableStateOptions, type Operation, type OperationPath, type StateListener, TrackedDate, TrackedMap, TrackedSet, type UnsafeTracked, applyOperations, createChannel, createGroup, createMutableState, diffObjects, identify, ignore, isSameIdentity, isState, scope, subscribe, transact, unsafeTrack, useGroup, useMutableState };