opshot 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matt Cavender
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # opshot
4
4
 
5
- Mutable state for React, with re-render for only the components that read what changed. (It's [valtio](https://github.com/pmndrs/valtio), but not a footgun.)
5
+ Mutable state for React, with re-render for only the components that read what changed. (It's like [valtio](https://github.com/pmndrs/valtio), but not a footgun.)
6
6
 
7
7
  ## Install
8
8
 
@@ -20,12 +20,12 @@ const [user, setUser] = useState({ name: "Ada", age: 36 });
20
20
  setUser((prev) => ({ ...prev, age: 37 }));
21
21
  ```
22
22
 
23
- opshot state is mutable: you assign the field.
23
+ **opshot** state is a live mutable object: you assign the field.
24
24
 
25
25
  ```tsx
26
- const user = useTrackedState({ name: "Ada", age: 36 });
26
+ const user = useMutableState({ name: "Ada", age: 36 });
27
27
 
28
- user.mutate((mutable) => (mutable.age = 37));
28
+ user.age = 37;
29
29
  ```
30
30
 
31
31
  ## Bounded re-renders
@@ -55,13 +55,15 @@ const Parent = () => {
55
55
  const Child = ({ user }: { user: User }) => <p>{user.age}</p>;
56
56
  ```
57
57
 
58
- opshot re-renders only what read the change. Wrap a child in `retrack` and it subscribes to the fields it reads. **Where the mutation happens doesn't matter** — here Parent writes, and only Child re-renders, because renders follow reads, not writes.
58
+ **opshot** re-renders only what read the change. Wrap a child in `scope` and it subscribes to the fields it reads. **Where the mutation happens doesn't matter** — here Parent writes, and only Child re-renders, because renders follow reads, not writes.
59
59
 
60
60
  ```tsx
61
61
  const Parent = () => {
62
- const user = useTrackedState<User>({ name: "Ada", age: 36 });
62
+ const user = useMutableState<User>({ name: "Ada", age: 36 });
63
63
 
64
- const birthday = () => user.mutate((mutable) => mutable.age++);
64
+ const birthday = () => {
65
+ user.age++;
66
+ };
65
67
 
66
68
  // A click re-renders only Child.
67
69
  return (
@@ -72,145 +74,235 @@ const Parent = () => {
72
74
  );
73
75
  };
74
76
 
75
- const Child = retrack<{ user: State<User> }>(({ user }) => <p>{user.age}</p>);
77
+ const Child = scope<{ user: User }>(({ user }) => <p>{user.age}</p>);
76
78
  ```
77
79
 
78
- This is how you optimize re-rendering across your component tree: place `retrack` boundaries where you want re-renders contained, and each boundary re-renders only when a field it read changes. `useTrackedState` is a boundary itself.
80
+ This is how you optimize re-rendering across your component tree: place `scope` boundaries where you want re-renders contained, and each boundary re-renders only when a field it read changes. `useMutableState` is a boundary itself.
79
81
 
80
82
  ## Creating State
81
83
 
82
84
  ```tsx
83
- import { ref } from "opshot";
84
- import { useTrackedState } from "opshot/react";
85
+ import { ignore, unsafeTrack, useMutableState, type Ignored, type UnsafeTracked } from "opshot";
86
+
87
+ interface PlayerState {
88
+ position: number;
89
+ element: Ignored<HTMLAudioElement>;
90
+ queue: UnsafeTracked<Playlist>;
91
+ seek: (position: number) => void;
92
+ }
85
93
 
86
94
  const Player = () => {
87
- const player = useTrackedState((mutate, get) => ({
95
+ const player = useMutableState<PlayerState>({
88
96
  position: 0,
89
97
 
90
- // ref() keeps a value out of reactivity and ops.
91
- element: ref(new Audio()),
98
+ // ignore() keeps a value out of reactivity and ops.
99
+ element: ignore(new Audio()),
100
+
101
+ // unsafeTrack() tracks all the values it can, even if there is weird behaviour
102
+ queue: unsafeTrack(new Playlist()),
92
103
 
93
- // get() reads the current values.
94
- seek: (position: number) => {
95
- get().element.currentTime = position;
104
+ seek(position: number) {
105
+ this.element.currentTime = position;
96
106
 
97
- mutate((mutable) => (mutable.position = position));
107
+ if (this.position === position) return;
108
+
109
+ this.position = position;
98
110
  },
99
- }));
111
+ });
100
112
 
101
113
  // ...
102
114
  };
103
115
  ```
104
116
 
105
- ## Tracked State
117
+ ## Constraints
118
+
119
+ opshot tracks plain data.
120
+
121
+ It can't track:
122
+
123
+ - Internal slots (language level features like in Map)
124
+ - #private fields (hidden at the language level)
125
+ - Arrow methods on classes (they write to the original object, not the tracked one)
126
+ - Array subclasses (the prototype is lost when copied)
127
+
128
+ Use `ignore` or `unsafeTrack` when dealing with these.
129
+
130
+ ## Tracked collections
106
131
 
107
- Everything opshot attaches lives under two reserved keys, `mutate` and `op`.
132
+ `TrackedMap`, `TrackedSet`, and `TrackedDate` stand in for the built-ins opshot rejects. They have the exact same API as their counterparts.
108
133
 
109
134
  ```ts
110
- // The write path. An optional second argument is passed to every subscriber.
111
- counter.mutate((mutable) => mutable.count++, { transactionKey: "drag" });
135
+ import { TrackedMap, useMutableState } from "opshot";
112
136
 
113
- // Hears every op this state emits; returns an unsubscribe.
114
- const unsubscribe = counter.op.subscribe((state, ops, meta) => {
115
- // ...
116
- });
137
+ const state = useMutableState({ index: new TrackedMap<string, number>() });
138
+
139
+ state.index.set("a", 1);
140
+ ```
141
+
142
+ ## Subscribe
117
143
 
118
- // State references are not reliable for equality: every mutation produces a new one. Use this instead.
119
- counter.op.isSameState(other);
144
+ `subscribe` hears every change to a state.
120
145
 
121
- // True while a mutate callback is running.
122
- counter.op.isMutating;
146
+ ```tsx
147
+ import { useEffect } from "react";
148
+ import { subscribe, useMutableState } from "opshot";
123
149
 
124
- // The current values as your plain object, op stripped: for serializing and reads outside render.
125
- counter.op.unwrap();
150
+ const Counter = () => {
151
+ const counter = useMutableState({ count: 0 });
152
+
153
+ useEffect(
154
+ () =>
155
+ subscribe(counter, (ops, meta) => {
156
+ // ops: [{
157
+ // do: { op: "replace", path: ["count"], value: 1 },
158
+ // undo: { op: "replace", path: ["count"], value: 0 },
159
+ // }]
160
+ // meta: whatever the writer passed, or undefined for bare writes
161
+ }),
162
+ [counter],
163
+ );
126
164
 
127
- // The underlying valtio proxy, typed object: an escape hatch.
128
- counter.op.unsafeMutable;
165
+ // ...
166
+ };
129
167
  ```
130
168
 
131
169
  ## Ops
132
170
 
171
+ An op is an invertible pair of `Operation` halves. Every half uses one of three verbs:
172
+
133
173
  ```ts
134
- const unsubscribe = counter.op.subscribe((state, ops, meta) => {
135
- // state: the snapshot these ops produced
136
- // ops: [{
137
- // do: { op: "replace", path: "/count", value: 1 },
138
- // undo: { op: "replace", path: "/count", value: 0 },
139
- // }]
140
- });
174
+ type OperationPath = ReadonlyArray<string | number>;
175
+
176
+ type Operation =
177
+ | { readonly op: "add"; readonly path: OperationPath; readonly value: unknown }
178
+ | { readonly op: "replace"; readonly path: OperationPath; readonly value: unknown }
179
+ | { readonly op: "remove"; readonly path: OperationPath };
180
+
181
+ interface Op {
182
+ readonly do: Operation;
183
+ readonly undo: Operation;
184
+ }
141
185
  ```
142
186
 
143
- An op is a pair of [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) patch operations, each half carrying its own value, so any JSON Patch tool applies and inverts them.
187
+ `applyOps` puts them back on a state, so a history is a list of ops and an undo is their `undo` halves in reverse.
144
188
 
145
- A subscriber must not write to the state it subscribes to; writing to a different state is fine.
189
+ ```tsx
190
+ import { useEffect, useRef } from "react";
191
+ import { applyOps, subscribe, useMutableState, type Op } from "opshot";
146
192
 
147
- Ops cost nothing until someone listens: a state with no subscribers, on itself or its group, skips computing them entirely.
193
+ const replay = {};
148
194
 
149
- ## Meta
195
+ const Counter = () => {
196
+ const counter = useMutableState({ count: 0 });
197
+ const history = useRef<Array<ReadonlyArray<Op>>>([]);
150
198
 
151
- `mutate`'s optional second argument is delivered to every subscriber alongside the ops.
199
+ useEffect(
200
+ () =>
201
+ subscribe(counter, (ops, meta) => {
202
+ // Skip our own replays, so undo doesn't record itself.
203
+ if (meta === replay) return;
152
204
 
153
- To type it, declare a meta token once and pass it in.
205
+ history.current.push(ops);
206
+ }),
207
+ [counter],
208
+ );
154
209
 
155
- ```tsx
156
- import { useEffect } from "react";
157
- import { createMeta } from "opshot";
158
- import { useTrackedState } from "opshot/react";
210
+ const undo = () => {
211
+ const ops = history.current.pop();
159
212
 
160
- interface DocumentMeta {
161
- replay?: boolean;
162
- }
213
+ if (!ops) return;
214
+
215
+ applyOps(
216
+ counter,
217
+ [...ops].reverse().map((op) => op.undo),
218
+ replay,
219
+ );
220
+ };
163
221
 
164
- // Declared once, at module scope.
165
- const documentMeta = createMeta<DocumentMeta>();
222
+ return (
223
+ <>
224
+ <button onClick={() => counter.count++}>+</button>
225
+ <button onClick={undo}>Undo</button>
226
+ </>
227
+ );
228
+ };
229
+ ```
230
+
231
+ Replay is exact for anything opshot can see: plain data. State behind a constraint is the exception.
232
+
233
+ If your state is JSON serializable, **then ops are too**.
234
+
235
+ ## Groups
236
+
237
+ A group creates states and hears every op from the states it created: one stream for history, sync, persistence, etc.
238
+
239
+ ```tsx
240
+ import { useEffect } from "react";
241
+ import { subscribe, useGroup, useMutableState } from "opshot";
166
242
 
167
243
  const Editor = () => {
168
- const doc = useTrackedState({ title: "Untitled" }, documentMeta);
244
+ const group = useGroup();
169
245
 
170
- // A history replaying an undone op marks the write, so recorders can tell it apart.
171
- // The meta argument is typed DocumentMeta.
172
- const undo = () => doc.mutate((mutable) => (mutable.title = "Untitled"), { replay: true });
246
+ // Created through the group, so their ops reach the group's subscribers.
247
+ const doc = useMutableState({ items: new Array<string>() }, group);
248
+ const selection = useMutableState({ index: 0 }, group);
173
249
 
174
250
  useEffect(
175
251
  () =>
176
- // The subscriber's meta parameter is typed DocumentMeta.
177
- doc.op.subscribe((state, ops, meta) => {
178
- // A recorder skips its own replays.
179
- if (meta.replay) return;
180
-
252
+ // Fires for doc, selection, and every other state the group created.
253
+ // state is whichever one changed.
254
+ subscribe(group, (state, ops, meta) => {
181
255
  // ...
182
256
  }),
183
- [doc.op],
257
+ [group],
184
258
  );
185
259
 
186
260
  // ...
187
261
  };
188
262
  ```
189
263
 
190
- ## Groups
264
+ ## Channels
191
265
 
192
- A group creates states and hears every op from the states it created: one stream for history, sync, and persistence.
266
+ A channel binds `transact`, `subscribe`, and `applyOps` to a typed meta convention, so a listener can tell its own writes from everyone else's.
193
267
 
194
268
  ```tsx
195
269
  import { useEffect } from "react";
196
- import { useGroup, useTrackedState } from "opshot/react";
270
+ import { createChannel, useMutableState } from "opshot";
197
271
 
198
- const Editor = () => {
199
- // A lifetime-stable group.
200
- const group = useGroup();
272
+ interface DocumentMeta {
273
+ replay?: boolean;
274
+ source?: string;
275
+ }
276
+
277
+ const docChannel = createChannel<DocumentMeta>({ source: "editor" }); // set defaults
201
278
 
202
- // Created through the group, so its ops reach the group's subscribers.
203
- const doc = useTrackedState({ items: new Array<string>() }, group);
279
+ const TitleBar = () => {
280
+ const doc = useMutableState({ title: "Untitled" });
204
281
 
205
282
  useEffect(
206
283
  () =>
207
- // Fires for doc and every other state the group created.
208
- group.subscribe((state, ops, meta) => {
284
+ docChannel.subscribe(doc, (ops, context) => {
285
+ // A bare write, or a transact from another channel: meta is unknown.
286
+ if (!context.isTransaction) return;
287
+
288
+ // Own-channel transaction: meta is typed, with defaults merged.
289
+ if (context.meta.replay) return;
290
+
209
291
  // ...
210
292
  }),
211
- [group],
293
+ [doc],
212
294
  );
213
295
 
296
+ const rename = () => {
297
+ docChannel.transact(doc, () => {
298
+ doc.title = "Draft";
299
+ });
300
+ };
301
+
214
302
  // ...
215
303
  };
216
304
  ```
305
+
306
+ ## License
307
+
308
+ [MIT](LICENSE)
package/dist/index.d.ts CHANGED
@@ -1,56 +1,185 @@
1
- import { Snapshot } from 'valtio/vanilla';
2
- export { Snapshot, ref } from 'valtio/vanilla';
1
+ import { ComponentType, FC } from 'react';
3
2
 
4
- type PatchOperation = {
3
+ type OperationPath = ReadonlyArray<string | number>;
4
+
5
+ interface AddOperation {
5
6
  readonly op: "add";
6
- readonly path: string;
7
+ readonly path: OperationPath;
7
8
  readonly value: unknown;
8
- } | {
9
+ }
10
+ interface ReplaceOperation {
9
11
  readonly op: "replace";
10
- readonly path: string;
12
+ readonly path: OperationPath;
11
13
  readonly value: unknown;
12
- } | {
14
+ }
15
+ interface RemoveOperation {
13
16
  readonly op: "remove";
14
- readonly path: string;
15
- };
17
+ readonly path: OperationPath;
18
+ }
19
+ type Operation = AddOperation | ReplaceOperation | RemoveOperation;
16
20
  interface Op {
17
- readonly do: PatchOperation;
18
- readonly undo: PatchOperation;
19
- }
20
- declare function diffSnapshots(before: unknown, after: unknown): Array<Op>;
21
-
22
- type MetaRecord = Record<string, unknown>;
23
- declare const metaIn: unique symbol;
24
- interface Meta<In extends object = MetaRecord, Out extends object = MetaRecord> {
25
- readonly defaults?: Out;
26
- readonly [metaIn]?: (value: In) => void;
27
- }
28
- type Mutate<T extends object, In extends object = MetaRecord> = (callback: (mutable: T) => void, ...meta: {} extends In ? [meta?: In] : [meta: In]) => void;
29
- type StateListener<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = (state: State<T, In, Out>, ops: Array<Op>, meta: Out) => void;
30
- interface OpshotHandle<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> {
31
- readonly unsafeMutable: object;
32
- readonly isMutating: boolean;
33
- readonly subscribe: (listener: StateListener<T, In, Out>) => () => void;
34
- readonly isSameState: (other: unknown) => boolean;
35
- readonly unwrap: () => Snapshot<T>;
36
- }
37
- type State<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = Snapshot<T> & {
38
- readonly mutate: Mutate<T, In>;
39
- readonly op: OpshotHandle<T, In, Out>;
40
- };
41
- type DefineCallback<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = (mutate: Mutate<T, In>, get: () => State<T, In, Out>) => T;
42
- type Define<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = DefineCallback<T, In, Out> | T;
43
- declare function createMeta<M extends object>(): Meta<M, M>;
44
- declare function createMeta<M extends object>(defaults: M): Meta<Partial<M>, M>;
45
- declare function createState<T extends object>(define: Define<T>): State<T>;
46
- declare function createState<T extends object, In extends object, Out extends object>(define: Define<T, In, Out>, meta: Meta<In, Out>): State<T, In, Out>;
47
- declare function isState(value: unknown): value is State<object>;
48
-
49
- interface Group<In extends object = MetaRecord, Out extends object = MetaRecord> {
50
- createState<T extends object>(define: Define<T, In, Out>): State<T, In, Out>;
51
- subscribe(listener: StateListener<object, In, Out>): () => void;
21
+ readonly do: Operation;
22
+ readonly undo: Operation;
23
+ }
24
+
25
+ type StateListener = (ops: ReadonlyArray<Op>, meta: unknown) => void;
26
+ type GroupListener = (state: object, ops: ReadonlyArray<Op>, meta: unknown) => void;
27
+
28
+ interface Group {
29
+ createMutableState<T extends object>(properties: T): T;
52
30
  }
53
31
  declare function createGroup(): Group;
54
- declare function createGroup<In extends object, Out extends object>(meta: Meta<In, Out>): Group<In, Out>;
55
32
 
56
- export { type Define, type DefineCallback, type Group, type Meta, type MetaRecord, type Mutate, type Op, type OpshotHandle, type PatchOperation, type State, type StateListener, createGroup, createMeta, createState, diffSnapshots, isState };
33
+ type Context<M> = {
34
+ readonly isTransaction: true;
35
+ readonly meta: M;
36
+ } | {
37
+ readonly isTransaction: false;
38
+ readonly meta: unknown;
39
+ };
40
+ declare function subscribe(group: Group, listener: GroupListener): () => void;
41
+ declare function subscribe(state: object, listener: StateListener): () => void;
42
+
43
+ interface Channel<M extends object> {
44
+ 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;
48
+ }
49
+ declare function createChannel<M extends object>(defaults?: M): Channel<M>;
50
+
51
+ declare function createMutableState<T extends object>(properties: T, group?: Group): T;
52
+
53
+ declare function identify(value: object): object;
54
+ declare function isSameIdentity(first: object, second: object): boolean;
55
+
56
+ declare function isState(value: unknown): value is object;
57
+
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>;
67
+
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>;
73
+
74
+ type DateConstructorArgs = [] | [value: number | string] | [
75
+ year: number,
76
+ monthIndex: number,
77
+ date?: number,
78
+ hours?: number,
79
+ minutes?: number,
80
+ seconds?: number,
81
+ milliseconds?: number
82
+ ];
83
+ declare class TrackedDate {
84
+ private epochMs;
85
+ constructor(...args: DateConstructorArgs);
86
+ private readDate;
87
+ private write;
88
+ toString(): string;
89
+ toDateString(): string;
90
+ toTimeString(): string;
91
+ toLocaleString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
92
+ toLocaleDateString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
93
+ toLocaleTimeString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
94
+ valueOf(): number;
95
+ getTime(): number;
96
+ getFullYear(): number;
97
+ getYear(): number;
98
+ getUTCFullYear(): number;
99
+ getMonth(): number;
100
+ getUTCMonth(): number;
101
+ getDate(): number;
102
+ getUTCDate(): number;
103
+ getDay(): number;
104
+ getUTCDay(): number;
105
+ getHours(): number;
106
+ getUTCHours(): number;
107
+ getMinutes(): number;
108
+ getUTCMinutes(): number;
109
+ getSeconds(): number;
110
+ getUTCSeconds(): number;
111
+ getMilliseconds(): number;
112
+ getUTCMilliseconds(): number;
113
+ getTimezoneOffset(): number;
114
+ setYear(year: number): number;
115
+ setTime(...args: [time: number]): number;
116
+ setMilliseconds(...args: [milliseconds: number]): number;
117
+ setUTCMilliseconds(...args: [milliseconds: number]): number;
118
+ setSeconds(...args: [seconds: number, milliseconds?: number]): number;
119
+ setUTCSeconds(...args: [seconds: number, milliseconds?: number]): number;
120
+ setMinutes(...args: [minutes: number, seconds?: number, milliseconds?: number]): number;
121
+ setUTCMinutes(...args: [minutes: number, seconds?: number, milliseconds?: number]): number;
122
+ setHours(...args: [hours: number, minutes?: number, seconds?: number, milliseconds?: number]): number;
123
+ setUTCHours(...args: [hours: number, minutes?: number, seconds?: number, milliseconds?: number]): number;
124
+ setDate(...args: [dateValue: number]): number;
125
+ setUTCDate(...args: [dateValue: number]): number;
126
+ setMonth(...args: [month: number, dateValue?: number]): number;
127
+ setUTCMonth(...args: [month: number, dateValue?: number]): number;
128
+ setFullYear(...args: [year: number, month?: number, dateValue?: number]): number;
129
+ setUTCFullYear(...args: [year: number, month?: number, dateValue?: number]): number;
130
+ toUTCString(): string;
131
+ toGMTString(): string;
132
+ toISOString(): string;
133
+ [Symbol.toPrimitive](hint: "default" | "string" | "number"): string | number;
134
+ readonly [Symbol.toStringTag]: "TrackedDate";
135
+ }
136
+
137
+ declare class TrackedMap<K, V> {
138
+ private slots;
139
+ private index;
140
+ private count;
141
+ constructor(entries?: Iterable<readonly [K, V]>);
142
+ get size(): number;
143
+ has(key: K): boolean;
144
+ get(key: K): V | undefined;
145
+ set(key: K, value: V): this;
146
+ delete(key: K): boolean;
147
+ clear(): void;
148
+ entries(): IterableIterator<[K, V]>;
149
+ keys(): IterableIterator<K>;
150
+ values(): IterableIterator<V>;
151
+ forEach(callback: (value: V, key: K, map: TrackedMap<K, V>) => void): void;
152
+ [Symbol.iterator](): IterableIterator<[K, V]>;
153
+ readonly [Symbol.toStringTag]: "TrackedMap";
154
+ }
155
+
156
+ declare class TrackedSet<T> {
157
+ private slots;
158
+ private index;
159
+ private count;
160
+ constructor(values?: Iterable<T>);
161
+ get size(): number;
162
+ has(value: T): boolean;
163
+ add(value: T): this;
164
+ delete(value: T): boolean;
165
+ clear(): void;
166
+ entries(): IterableIterator<[T, T]>;
167
+ keys(): IterableIterator<T>;
168
+ values(): IterableIterator<T>;
169
+ forEach(callback: (value: T, key: T, set: TrackedSet<T>) => void): void;
170
+ [Symbol.iterator](): IterableIterator<T>;
171
+ readonly [Symbol.toStringTag]: "TrackedSet";
172
+ }
173
+
174
+ declare function transact(state: object, mutate: () => void, meta?: unknown): void;
175
+
176
+ interface ScopeOptions {
177
+ readonly maxDepth?: number;
178
+ }
179
+ declare function scope<P extends object>(Component: ComponentType<P>, options?: ScopeOptions): FC<P>;
180
+
181
+ declare function useGroup(): Group;
182
+
183
+ declare function useMutableState<T extends object>(properties: T, group?: Group): T;
184
+
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 };