doxum 0.1.5 → 0.1.7

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 (53) hide show
  1. package/README.md +75 -9
  2. package/dist/{contract-4E3moCbY.d.ts → contract-DNZ4D53r.d.ts} +87 -76
  3. package/dist/{contract-uYJTmT8o.d.cts → contract-j3SLGAwh.d.cts} +87 -76
  4. package/dist/index.cjs +284 -947
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +3 -64
  7. package/dist/index.d.ts +3 -64
  8. package/dist/index.js +218 -872
  9. package/dist/index.js.map +1 -1
  10. package/dist/integration-B56u1l9V.js +30 -0
  11. package/dist/integration-B56u1l9V.js.map +1 -0
  12. package/dist/integration-CZwCwFBS.cjs +35 -0
  13. package/dist/integration-CZwCwFBS.cjs.map +1 -0
  14. package/dist/integration.cjs +12 -14
  15. package/dist/integration.d.cts +3 -2
  16. package/dist/integration.d.ts +3 -2
  17. package/dist/integration.js +3 -14
  18. package/dist/local-sync.cjs +57 -18
  19. package/dist/local-sync.cjs.map +1 -1
  20. package/dist/local-sync.d.cts +2 -2
  21. package/dist/local-sync.d.ts +2 -2
  22. package/dist/local-sync.js +57 -18
  23. package/dist/local-sync.js.map +1 -1
  24. package/dist/{ownership-CU-9DKJQ.cjs → ownership-CY0nPXGF.cjs} +4 -1
  25. package/dist/ownership-CY0nPXGF.cjs.map +1 -0
  26. package/dist/{ownership-B-VAPcce.js → ownership-CduRygE7.js} +4 -1
  27. package/dist/ownership-CduRygE7.js.map +1 -0
  28. package/dist/react.cjs +27 -19
  29. package/dist/react.cjs.map +1 -1
  30. package/dist/react.js +27 -19
  31. package/dist/react.js.map +1 -1
  32. package/dist/runtime-0mOFbe_H.cjs +2439 -0
  33. package/dist/runtime-0mOFbe_H.cjs.map +1 -0
  34. package/dist/runtime-B22tuj9A.d.cts +150 -0
  35. package/dist/runtime-BFmhzPpZ.d.ts +150 -0
  36. package/dist/runtime-DF1q9Gje.js +2129 -0
  37. package/dist/runtime-DF1q9Gje.js.map +1 -0
  38. package/package.json +1 -1
  39. package/skills/doxum-runtime/SKILL.md +2 -1
  40. package/skills/doxum-runtime/references/guide.en.md +38 -26
  41. package/skills/doxum-runtime/references/guide.zh-CN.md +24 -21
  42. package/skills/doxum-runtime/references/invariants.en.md +13 -10
  43. package/skills/doxum-runtime/references/invariants.zh-CN.md +3 -3
  44. package/skills/doxum-runtime/references/patterns.en.md +26 -64
  45. package/skills/doxum-runtime/references/patterns.zh-CN.md +15 -52
  46. package/dist/dependency-C5_R1tvQ.js +0 -496
  47. package/dist/dependency-C5_R1tvQ.js.map +0 -1
  48. package/dist/dependency-Dfzs3khk.cjs +0 -722
  49. package/dist/dependency-Dfzs3khk.cjs.map +0 -1
  50. package/dist/integration.cjs.map +0 -1
  51. package/dist/integration.js.map +0 -1
  52. package/dist/ownership-B-VAPcce.js.map +0 -1
  53. package/dist/ownership-CU-9DKJQ.cjs.map +0 -1
package/README.md CHANGED
@@ -100,8 +100,8 @@ in that update is rolled back.
100
100
 
101
101
  Mutation failure codes are a closed public `MutationIssueCode` union. For
102
102
  application validation, use `tx.report` or `tx.reject` with a
103
- `DocumentDiagnostic`; published diagnostic arrays and addresses are copied and
104
- frozen.
103
+ diagnostic `{ code, message, address? }`; Doxum adds `source: 'application'`.
104
+ Published diagnostic arrays and addresses are copied and frozen.
105
105
 
106
106
  ## Read And Subscribe
107
107
 
@@ -141,6 +141,13 @@ runtime.history.redo();
141
141
  runtime.apply([{ type: 'field.set', at: ['title'], value: 'Ship Doxum' }]);
142
142
  ```
143
143
 
144
+ Use `runtime.history.group()` for one action spanning multiple synchronous
145
+ updates, such as a drag. Keep its handle until the action ends, then call
146
+ `end()` to retain one undo entry or `cancel()` to apply its inverses atomically.
147
+ Groups cannot nest. Undo, redo, clear, remote/replace commits, and committed
148
+ updates with `history: false` end the current group. History implements
149
+ `Readable<HistoryState>` and can be used with `useReadable` or `fromReadable`.
150
+
144
151
  `apply` is the boundary for replaying operations from persistence or a network
145
152
  adapter. Doxum does not provide those adapters. A `replace` or a commit marked
146
153
  as `remote` invalidates local history because its prior inverse sequence is no
@@ -177,7 +184,7 @@ the log can faithfully append. `flush()` is the explicit point that waits for
177
184
  commits observed before the call to persist (or, in a follower, waits to catch
178
185
  up to the durable head). A browser crash, quota failure, or malformed JSON
179
186
  payload can therefore leave an already visible leader commit unpersisted;
180
- inspect `state()` or use `onError` to surface that condition.
187
+ observe `state` or use `onError` to surface that condition.
181
188
 
182
189
  ```ts
183
190
  import { createDocument, select } from 'doxum';
@@ -197,7 +204,7 @@ const localSync = await attachLocalSync({
197
204
  documentId: 'project-1',
198
205
  });
199
206
 
200
- if (localSync.state().status === 'leader') {
207
+ if (localSync.state.current().status === 'leader') {
201
208
  runtime.update(tx => {
202
209
  tx.write.title.set('Ship Doxum');
203
210
  });
@@ -211,6 +218,10 @@ await localSync.flush(); // persist observed leader commands / catch up a follow
211
218
  await localSync.dispose();
212
219
  ```
213
220
 
221
+ `localSync.state` is a `Readable`: `state.current()` returns a stable snapshot,
222
+ `state.subscribe(listener)` observes persistence, leadership and error changes,
223
+ and React can consume it with `useReadable(localSync.state)`.
224
+
214
225
  `attachLocalSync` first hydrates the passed runtime from IndexedDB; await it
215
226
  before allowing reads or edits. It does not make runtime mutation asynchronous,
216
227
  does not own `runtime.dispose()`, and does not expose a second undo API. Runtime
@@ -239,11 +250,66 @@ views, materialized views, and history state.
239
250
 
240
251
  ## Derived Views
241
252
 
242
- `createCollectionView` incrementally projects one table or map into `ids`,
243
- `all`, and cached `item(id)` readables. `createMaterializedView` is for
244
- indexes and aggregates that need custom incremental update logic. A materialized
245
- view may depend on earlier views from the same runtime; Doxum settles that graph
246
- before notifying external listeners.
253
+ `createProjectionRuntime` owns an explicit graph of derived values and keyed
254
+ collections. It combines document runtimes and external values without owning
255
+ their mutations or history.
256
+
257
+ ```ts
258
+ const projection = createProjectionRuntime({ onError: error => console.error(error) });
259
+ const document = projection.document(runtime);
260
+ const taskTitles = projection.map(
261
+ document.collection(path => path.tasks),
262
+ (_id, task) => task.title.get()
263
+ );
264
+ const taskCount = projection.value({ tasks: taskTitles }, ({ tasks }) => tasks.ids().length);
265
+ const labels = projection.map(taskTitles, (id, title) => `${id}: ${title}`);
266
+ ```
267
+
268
+ `projection.value(sources, compute, { isEqual }?)` is the ordinary pure-compute
269
+ entry. Stateful algorithms use `projection.value({ sources, build }, { isEqual }?)`,
270
+ where build returns `{ value, update }`. Both use the same scheduler and lifecycle.
271
+
272
+ `projection.collection<Item>()(spec)` handles custom incremental algorithms. Its scoped
273
+ writer supports `set`, `remove`, `order`, and `replace`; `previous` and `next`
274
+ provide scoped reads. Declare all sources and use their native commit impacts
275
+ or upstream collection changes to choose candidate keys. A document collection
276
+ context also provides `candidates.keys`, `candidates.orderDirty` and `reset`,
277
+ aggregated across the entire batch. Candidates include net-zero changes; read
278
+ final state to decide the output. Doxum stages writes,
279
+ applies equality, and publishes exact `CollectionImpact` changes. It does not
280
+ automatically track item dependencies. `ids`, lazy `all`, and cached `item(id)`
281
+ implement `Readable` and work with `useReadable`.
282
+
283
+ `map` accepts document collections and upstream projection collections while
284
+ preserving keys and order. Source dependencies stay explicit.
285
+
286
+ Use `projection.input(initial, { isEqual })` for boundary values such as container
287
+ size. Its application-owned `set` updates a read-only `source`. Use
288
+ `projection.fromReadable(existing, { isEqual })` for an existing external source.
289
+ Neither replaces a document with domain mutation semantics.
290
+
291
+ Wrap the entire synchronous application action in `projection.batch(() => ...)`
292
+ before its first document commit to combine document changes and editor cleanup.
293
+ Batches nest, preserve committed source changes on exceptions, and provide no
294
+ cross-document rollback. Projection reads inside a batch return the last
295
+ published state. Document listeners still run synchronously.
296
+
297
+ All affected nodes settle before listeners. Output revisions change only when
298
+ their output changes. Update failures discard the processor instance and attempt
299
+ one fresh build; persistent faults block descendants, while independent branches
300
+ continue. Errors reach `onError` and, when inside document notification, the
301
+ committed result's `observerErrors`. Manual `rebuild()` uses the same graph.
302
+ Dispose the projection with its service; component unmount only unsubscribes.
303
+ Disposing a node with consumers is rejected, and disposed handles throw.
304
+
305
+ Schema access uses `object` for structured entities and `dict` for keyed values.
306
+ Variants expose `reader.get()` as a discriminated union and `writer.replace()`
307
+ for replacement. Optional presence is supported by field, variant, dict, list
308
+ and tree nodes. Dictionaries expose `get(key)`, `has(key)`, `keys()` and
309
+ `values()`; lists additionally support `get(key)` and `has(key)` using `keyOf`.
310
+ Tree insert/move accept `{ parentId, index }`, with index denoting the final
311
+ position after removing a moved node. See [API migration](docs/api-migration.md)
312
+ for breaking changes and the public surface.
247
313
 
248
314
  ## Data Ownership
249
315
 
@@ -40,19 +40,12 @@ type VariantNode<TTag extends string, TVariants extends VariantShape> = BaseNode
40
40
  readonly tag: TTag;
41
41
  readonly variants: TVariants;
42
42
  };
43
- type SingleNode<TValue extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = BaseNode<'single'> & {
44
- readonly value: TValue;
45
- };
46
43
  type TableNode<TValue extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = BaseNode<'table'> & {
47
44
  readonly value: TValue;
48
45
  };
49
46
  type MapNode<TValue extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = BaseNode<'map'> & {
50
47
  readonly value: TValue;
51
48
  };
52
- type RecordNode<TId extends string, TValue> = BaseNode<'record'> & {
53
- readonly __id?: TId;
54
- readonly __value?: TValue;
55
- };
56
49
  type DictNode<TKey extends string, TValue> = BaseNode<'dict'> & {
57
50
  readonly __key?: TKey;
58
51
  readonly __value?: TValue;
@@ -64,12 +57,12 @@ type ListNode<TItem> = BaseNode<'list'> & {
64
57
  type TreeNode<TValue> = BaseNode<'tree'> & {
65
58
  readonly __value?: TValue;
66
59
  };
67
- type DocumentNode = FieldNode<unknown, false> | FieldNode<unknown, true> | ObjectNode<ObjectShape> | VariantNode<string, VariantShape> | SingleNode<ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> | TableNode<ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> | MapNode<ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> | RecordNode<string, unknown> | DictNode<string, unknown> | ListNode<unknown> | TreeNode<unknown>;
60
+ type DocumentNode = FieldNode<unknown, false> | FieldNode<unknown, true> | ObjectNode<ObjectShape> | VariantNode<string, VariantShape> | TableNode<ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> | MapNode<ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> | DictNode<string, unknown> | ListNode<unknown> | TreeNode<unknown>;
68
61
  type EntityValue<N extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = N extends ObjectNode<infer S> ? DocumentValueOfShape<S> : N extends VariantNode<infer T, infer V> ? { [K in keyof V & string]: { [P in T]: K } & DocumentValueOfShape<V[K] extends ObjectNode<infer S> ? S : never> }[keyof V & string] : never;
69
- type DocumentValueOfNode<N> = N extends FieldNode<infer T, infer O> ? O extends true ? T | undefined : T : N extends ObjectNode<infer S> ? DocumentValueOfShape<S> : N extends VariantNode<infer T, infer V> ? EntityValue<VariantNode<T, V>> : N extends SingleNode<infer V> ? EntityValue<V> : N extends TableNode<infer V> ? {
62
+ type DocumentValueOfNode<N> = N extends FieldNode<infer T, infer O> ? O extends true ? T | undefined : T : N extends ObjectNode<infer S> ? DocumentValueOfShape<S> : N extends VariantNode<infer T, infer V> ? EntityValue<VariantNode<T, V>> : N extends TableNode<infer V> ? {
70
63
  readonly ids: readonly string[];
71
64
  readonly byId: Readonly<Record<string, EntityValue<V>>>;
72
- } : N extends MapNode<infer V> ? Readonly<Record<string, EntityValue<V>>> : N extends RecordNode<infer I, infer T> ? Readonly<Record<I, T>> : N extends DictNode<infer K, infer T> ? Readonly<Partial<Record<K, T>>> : N extends ListNode<infer I> ? readonly I[] : N extends TreeNode<infer T> ? DocumentTreeValue<T> : never;
65
+ } : N extends MapNode<infer V> ? Readonly<Record<string, EntityValue<V>>> : N extends DictNode<infer K, infer T> ? Readonly<Partial<Record<K, T>>> : N extends ListNode<infer I> ? readonly I[] : N extends TreeNode<infer T> ? DocumentTreeValue<T> : never;
73
66
  type OptionalKeys<S extends ObjectShape> = { [K in keyof S]: S[K] extends {
74
67
  readonly optional: true;
75
68
  } ? K : never }[keyof S];
@@ -98,43 +91,35 @@ type ImpactTarget<T = unknown> = {
98
91
  readonly at: DocumentAddress;
99
92
  readonly id?: string;
100
93
  } | CollectionSelector<string>;
94
+ declare const pathValue: unique symbol;
95
+ declare const collectionNode: unique symbol;
101
96
  type PathMarker<TValue> = {
102
- readonly __value?: TValue;
97
+ readonly [pathValue]: TValue;
103
98
  };
104
- type SchemaPathFor<S extends ObjectShape = ObjectShape, TValue = unknown> = { readonly [K in keyof S]: PathValue<S[K]> } & {
105
- readonly item: (id: string) => SchemaPathFor<{}, unknown>;
106
- } & PathMarker<TValue>;
99
+ type SchemaPathFor<S extends ObjectShape = ObjectShape, TValue = unknown> = { readonly [K in keyof S]: PathValue<S[K]> } & PathMarker<TValue>;
107
100
  type DocumentSchema<TShape extends ObjectShape = {}> = {
108
101
  readonly kind: 'schema';
109
102
  readonly shape: TShape;
110
- collection<TPath extends PathMarker<unknown>>(pick: (path: SchemaPath<TShape>) => TPath): CollectionSelector<CollectionId<TPath>, CollectionNode<TPath>>;
103
+ collection<TPath extends CollectionPath>(pick: (path: SchemaPath<TShape>) => TPath): CollectionSelector<CollectionId<TPath>, CollectionNode<TPath>>;
111
104
  value<TPath extends PathMarker<unknown>>(pick: (path: SchemaPath<TShape>) => TPath): ValueSelector<PathValueResult<TPath>>;
112
105
  };
113
106
  type SchemaPath<S extends ObjectShape = {}> = SchemaPathFor<S, DocumentValueOfShape<S>>;
114
107
  type VariantKeys<V extends VariantShape> = { [K in keyof V & string]: keyof (V[K] extends ObjectNode<infer S> ? S : {}) }[keyof V & string] & string;
115
108
  type VariantFieldPath<V extends VariantShape, K extends string> = { [P in keyof V & string]: V[P] extends ObjectNode<infer S> ? K extends keyof S ? PathValue<S[K]> : never : never }[keyof V & string];
116
- type VariantPath<V extends VariantShape> = { readonly [K in VariantKeys<V>]: VariantFieldPath<V, K> } & {
117
- readonly item: (id: string) => SchemaPathFor<{}, unknown>;
118
- } & PathMarker<EntityValue<VariantNode<string, V>>>;
109
+ type VariantPath<T extends string, V extends VariantShape> = { readonly [K in VariantKeys<V>]: VariantFieldPath<V, K> } & { readonly [K in T]: PathMarker<keyof V & string> } & PathMarker<EntityValue<VariantNode<T, V>>>;
119
110
  type PathNodeValue<N extends DocumentNode> = N extends {
120
111
  readonly optional: true;
121
112
  } ? DocumentValueOfNode<N> | undefined : DocumentValueOfNode<N>;
122
- type EntityPath<N extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = N extends ObjectNode<infer S> ? SchemaPathFor<S, PathNodeValue<N>> : N extends VariantNode<string, infer V> ? VariantPath<V> : never;
123
- type CollectionPath<N extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = Omit<EntityPath<N>, 'item'> & {
113
+ type EntityPath<N extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>> = N extends ObjectNode<infer S> ? SchemaPathFor<S, PathNodeValue<N>> : N extends VariantNode<infer T, infer V> ? VariantPath<T, V> : never;
114
+ type CollectionPath<N extends EntitySchemaNode = EntitySchemaNode, TValue = unknown> = PathMarker<TValue> & {
124
115
  readonly item: (id: string) => EntityPath<N>;
125
- readonly __collection?: {
126
- readonly id: string;
127
- readonly node: N;
128
- };
116
+ readonly [collectionNode]: N;
129
117
  };
130
- type PathValue<N extends DocumentNode> = N extends ObjectNode<infer S> ? SchemaPathFor<S, PathNodeValue<N>> : N extends VariantNode<infer _TTag, infer V> ? VariantPath<V> : N extends TableNode<infer V> | MapNode<infer V> ? CollectionPath<V> : N extends SingleNode<infer V> ? EntityPath<V> : SchemaPathFor<{}, PathNodeValue<N>>;
118
+ type PathValue<N extends DocumentNode> = N extends ObjectNode<infer S> ? SchemaPathFor<S, PathNodeValue<N>> : N extends VariantNode<infer TTag, infer V> ? VariantPath<TTag, V> : N extends TableNode<infer V> | MapNode<infer V> ? CollectionPath<V, PathNodeValue<N>> : PathMarker<PathNodeValue<N>>;
131
119
  type CollectionInfo<T> = T extends {
132
- readonly __collection?: {
133
- readonly id: infer TId;
134
- readonly node: infer TNode extends EntitySchemaNode;
135
- };
120
+ readonly [collectionNode]: infer TNode extends EntitySchemaNode;
136
121
  } ? {
137
- readonly id: TId;
122
+ readonly id: string;
138
123
  readonly node: TNode;
139
124
  } : never;
140
125
  type CollectionId<T> = CollectionInfo<T> extends {
@@ -145,13 +130,12 @@ type CollectionNode<T> = CollectionInfo<T> extends {
145
130
  } ? TNode : EntitySchemaNode;
146
131
  type PathValueResult<T> = T extends PathMarker<infer TValue> ? TValue : unknown;
147
132
  declare const field: <T>() => FieldNode<T>;
148
- declare const optional: <T extends DocumentNode>(value: T) => OptionalNode<T>;
133
+ type OptionalLeaf = FieldNode<unknown, boolean> | VariantNode<string, VariantShape> | DictNode<string, unknown> | ListNode<unknown> | TreeNode<unknown>;
134
+ declare const optional: <T extends OptionalLeaf>(value: T) => OptionalNode<T>;
149
135
  declare const object: <S extends ObjectShape>(shape: S) => ObjectNode<S>;
150
136
  declare const variant: <T extends string, V extends VariantShape>(tag: T, variants: V) => VariantNode<T, V>;
151
- declare const single: <V extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>>(value: V) => SingleNode<V>;
152
137
  declare const table: <V extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>>(value: V) => TableNode<V>;
153
138
  declare const map: <V extends ObjectNode<ObjectShape> | VariantNode<string, VariantShape>>(value: V) => MapNode<V>;
154
- declare const record: <TId extends string = string, TValue = unknown>() => RecordNode<TId, TValue>;
155
139
  declare const dict: <TKey extends string = string, TValue = unknown>() => DictNode<TKey, TValue>;
156
140
  declare const list: <TItem>(config: DocumentListConfig<TItem>) => ListNode<TItem>;
157
141
  declare const tree: <TValue = unknown>() => TreeNode<TValue>;
@@ -168,34 +152,34 @@ type DocumentAnchor = {
168
152
  type OperationBase = {
169
153
  readonly at: DocumentAddress;
170
154
  };
171
- type FieldSetOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
155
+ type FieldSetOperation = OperationBase & {
172
156
  readonly type: 'field.set';
173
157
  readonly value: unknown;
174
158
  };
175
- type FieldClearOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
159
+ type FieldClearOperation = OperationBase & {
176
160
  readonly type: 'field.clear';
177
161
  };
178
- type ValueClearOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
162
+ type ValueClearOperation = OperationBase & {
179
163
  readonly type: 'value.clear';
180
164
  };
181
- type VariantReplaceOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
165
+ type VariantReplaceOperation = OperationBase & {
182
166
  readonly type: 'variant.replace';
183
167
  readonly value: unknown;
184
168
  };
185
- type DictSetOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
169
+ type DictSetOperation = OperationBase & {
186
170
  readonly type: 'dict.set';
187
171
  readonly key: string;
188
172
  readonly value: unknown;
189
173
  };
190
- type DictDeleteOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
174
+ type DictDeleteOperation = OperationBase & {
191
175
  readonly type: 'dict.delete';
192
176
  readonly key: string;
193
177
  };
194
- type DictReplaceOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
178
+ type DictReplaceOperation = OperationBase & {
195
179
  readonly type: 'dict.replace';
196
180
  readonly value: Readonly<Record<string, unknown>>;
197
181
  };
198
- type EntityCreateOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
182
+ type EntityCreateOperation = OperationBase & {
199
183
  readonly type: 'entity.create';
200
184
  readonly entries: readonly EntityEntry[];
201
185
  readonly anchor?: DocumentAnchor; /** Generated inverse metadata with strictly increasing final indices. Normal creates omit it. */
@@ -205,74 +189,81 @@ type EntityEntry = {
205
189
  readonly id: string;
206
190
  readonly value: unknown;
207
191
  };
208
- type EntityRemoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
192
+ type EntityRemoveOperation = OperationBase & {
209
193
  readonly type: 'entity.remove';
210
194
  readonly ids: readonly string[];
211
195
  };
212
- type EntityMoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
196
+ type EntityMoveOperation = OperationBase & {
213
197
  readonly type: 'entity.move';
214
198
  readonly id: string;
215
199
  readonly anchor?: DocumentAnchor;
216
200
  };
217
- type ListInsertOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
201
+ type ListInsertOperation = OperationBase & {
218
202
  readonly type: 'list.insert';
219
203
  readonly key: string;
220
204
  readonly value: unknown;
221
205
  readonly anchor?: DocumentAnchor;
222
206
  };
223
- type ListMoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
207
+ type ListMoveOperation = OperationBase & {
224
208
  readonly type: 'list.move';
225
209
  readonly key: string;
226
210
  readonly anchor?: DocumentAnchor;
227
211
  };
228
- type ListRemoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
212
+ type ListRemoveOperation = OperationBase & {
229
213
  readonly type: 'list.remove';
230
214
  readonly key: string;
231
215
  };
232
- type ListReplaceOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
216
+ type ListReplaceOperation = OperationBase & {
233
217
  readonly type: 'list.replace';
234
218
  readonly value: readonly unknown[];
235
219
  readonly keys: readonly string[];
236
220
  };
237
- type TreeInsertOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
221
+ type TreeInsertOperation = OperationBase & {
238
222
  readonly type: 'tree.insert';
239
223
  readonly treeNodeId: string;
240
224
  readonly parentId?: string;
241
225
  readonly index?: number;
242
226
  readonly value?: unknown;
243
227
  };
244
- type TreeMoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
228
+ type TreeMoveOperation = OperationBase & {
245
229
  readonly type: 'tree.move';
246
230
  readonly treeNodeId: string;
247
231
  readonly parentId?: string;
248
232
  readonly index?: number;
249
233
  };
250
- type TreeRemoveOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
234
+ type TreeRemoveOperation = OperationBase & {
251
235
  readonly type: 'tree.remove';
252
236
  readonly treeNodeId: string;
253
237
  };
254
- type TreeSetOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
238
+ type TreeSetOperation = OperationBase & {
255
239
  readonly type: 'tree.set';
256
240
  readonly treeNodeId: string;
257
241
  readonly value: unknown;
258
242
  };
259
- type TreeReplaceOperation<TSchema extends DocumentSchema = DocumentSchema> = OperationBase & {
243
+ type TreeReplaceOperation = OperationBase & {
260
244
  readonly type: 'tree.replace';
261
245
  readonly value: unknown;
262
246
  };
263
- type DocumentOperationUnion<TSchema extends DocumentSchema = DocumentSchema> = FieldSetOperation<TSchema> | FieldClearOperation<TSchema> | ValueClearOperation<TSchema> | VariantReplaceOperation<TSchema> | DictSetOperation<TSchema> | DictDeleteOperation<TSchema> | DictReplaceOperation<TSchema> | EntityCreateOperation<TSchema> | EntityRemoveOperation<TSchema> | EntityMoveOperation<TSchema> | ListInsertOperation<TSchema> | ListMoveOperation<TSchema> | ListRemoveOperation<TSchema> | ListReplaceOperation<TSchema> | TreeInsertOperation<TSchema> | TreeMoveOperation<TSchema> | TreeRemoveOperation<TSchema> | TreeSetOperation<TSchema> | TreeReplaceOperation<TSchema>;
264
- type DocumentOperation<TSchema extends DocumentSchema = DocumentSchema> = DocumentOperationUnion<TSchema>;
247
+ type DocumentOperation = FieldSetOperation | FieldClearOperation | ValueClearOperation | VariantReplaceOperation | DictSetOperation | DictDeleteOperation | DictReplaceOperation | EntityCreateOperation | EntityRemoveOperation | EntityMoveOperation | ListInsertOperation | ListMoveOperation | ListRemoveOperation | ListReplaceOperation | TreeInsertOperation | TreeMoveOperation | TreeRemoveOperation | TreeSetOperation | TreeReplaceOperation;
265
248
  //#endregion
266
249
  //#region core/src/access/reader.d.ts
267
250
  type FieldReader<T> = {
268
251
  readonly get: () => T;
269
252
  };
253
+ type DictionaryReader<K extends string, V> = {
254
+ get(key: K): V | undefined;
255
+ has(key: K): boolean;
256
+ keys(): readonly K[];
257
+ values(): Readonly<Partial<Record<K, V>>>;
258
+ };
270
259
  type CollectionReader<TId, TNode extends EntitySchemaNode> = {
271
260
  readonly ids: () => readonly TId[];
272
261
  readonly has: (id: TId) => boolean;
273
262
  readonly get: (id: TId) => ReaderOfNode<TNode> | undefined;
274
263
  };
275
264
  type ListReader<T> = {
265
+ readonly get: (key: string) => T | undefined;
266
+ readonly has: (key: string) => boolean;
276
267
  readonly values: () => readonly T[];
277
268
  readonly length: () => number;
278
269
  readonly at: (index: number) => T | undefined;
@@ -286,7 +277,9 @@ type TreeReader<T> = {
286
277
  };
287
278
  type ReaderOfNode<TNode extends DocumentNode> = TNode extends {
288
279
  kind: 'field';
289
- } ? FieldReader<DocumentValueOfNode<TNode>> : TNode extends ObjectNode<infer TShape> ? { readonly [K in keyof TShape]: ReaderOfNode<TShape[K]> } : TNode extends VariantNode<string, infer TVariants> ? { readonly [K in keyof TVariants]: ReaderOfNode<TVariants[K]> } : TNode extends SingleNode<infer TValue> ? ReaderOfNode<TValue> : TNode extends TableNode<infer TValue> ? CollectionReader<string, TValue> : TNode extends MapNode<infer TValue> ? CollectionReader<string, TValue> : TNode extends DictNode<infer TKey, infer TValue> ? FieldReader<Readonly<Partial<Record<TKey, TValue>>>> : TNode extends ListNode<infer TItem> ? ListReader<TItem> : TNode extends TreeNode<infer TValue> ? TreeReader<TValue> : FieldReader<DocumentValueOfNode<TNode>>;
280
+ } ? FieldReader<DocumentValueOfNode<TNode>> : TNode extends ObjectNode<infer TShape> ? { readonly [K in keyof TShape]: ReaderOfNode<TShape[K]> } : TNode extends VariantNode<string, infer _TVariants> ? FieldReader<DocumentValueOfNode<TNode> | (TNode extends {
281
+ readonly optional: true;
282
+ } ? undefined : never)> : TNode extends TableNode<infer TValue> ? CollectionReader<string, TValue> : TNode extends MapNode<infer TValue> ? CollectionReader<string, TValue> : TNode extends DictNode<infer TKey, infer TValue> ? DictionaryReader<TKey, TValue> : TNode extends ListNode<infer TItem> ? ListReader<TItem> : TNode extends TreeNode<infer TValue> ? TreeReader<TValue> : FieldReader<DocumentValueOfNode<TNode>>;
290
283
  type DocumentReader<TSchema extends DocumentSchema> = ReaderOfNode<ObjectNode<TSchema['shape']>>;
291
284
  //#endregion
292
285
  //#region core/src/access/writer.d.ts
@@ -330,8 +323,14 @@ type ListWriter<T> = {
330
323
  readonly replace: (value: readonly T[]) => void;
331
324
  };
332
325
  type TreeWriter<T> = {
333
- readonly insert: (id: string, value: T, parentId?: string, index?: number) => void;
334
- readonly move: (id: string, parentId?: string, index?: number) => void;
326
+ readonly insert: (id: string, value: T, position?: {
327
+ readonly parentId?: string;
328
+ readonly index?: number;
329
+ }) => void;
330
+ readonly move: (id: string, position?: {
331
+ readonly parentId?: string;
332
+ readonly index?: number;
333
+ }) => void;
335
334
  readonly remove: (id: string) => void;
336
335
  readonly set: (id: string, value: T) => void;
337
336
  readonly replace: (value: DocumentTreeValue<T>) => void;
@@ -347,7 +346,7 @@ type WriterOfNode<TNode extends DocumentNode> = TNode extends {
347
346
  readonly optional: true;
348
347
  } ? FieldWriter<DocumentValueOfNode<TNode>, true> : FieldWriter<DocumentValueOfNode<TNode>> : TNode extends ObjectNode<infer TShape> ? { readonly [K in keyof TShape]: WriterOfNode<TShape[K]> } : TNode extends VariantNode<string, infer _TVariants> ? OptionalClear<TNode, {
349
348
  readonly replace: (value: DocumentValueOfNode<TNode>) => void;
350
- }> : TNode extends SingleNode<infer TValue> ? WriterOfNode<TValue> : TNode extends TableNode<infer TValue> ? CollectionWriter<string, TValue> : TNode extends MapNode<infer TValue> ? MapWriter<string, TValue> : TNode extends DictNode<infer TKey, infer TValue> ? OptionalClear<TNode, DictionaryWriter<TKey, TValue>> : TNode extends ListNode<infer TItem> ? OptionalClear<TNode, ListWriter<TItem>> : TNode extends TreeNode<infer TValue> ? OptionalClear<TNode, TreeWriter<TValue>> : FieldWriter<DocumentValueOfNode<TNode>>;
349
+ }> : TNode extends TableNode<infer TValue> ? CollectionWriter<string, TValue> : TNode extends MapNode<infer TValue> ? MapWriter<string, TValue> : TNode extends DictNode<infer TKey, infer TValue> ? OptionalClear<TNode, DictionaryWriter<TKey, TValue>> : TNode extends ListNode<infer TItem> ? OptionalClear<TNode, ListWriter<TItem>> : TNode extends TreeNode<infer TValue> ? OptionalClear<TNode, TreeWriter<TValue>> : FieldWriter<DocumentValueOfNode<TNode>>;
351
350
  type DocumentWriter<TSchema extends DocumentSchema> = WriterOfNode<ObjectNode<TSchema['shape']>>;
352
351
  //#endregion
353
352
  //#region core/src/mutation/issue.d.ts
@@ -357,7 +356,7 @@ type MutationIssue = {
357
356
  readonly code: MutationIssueCode;
358
357
  readonly address: DocumentAddress;
359
358
  readonly message: string;
360
- readonly operation?: DocumentOperationUnion['type'];
359
+ readonly operation?: DocumentOperation['type'];
361
360
  };
362
361
  //#endregion
363
362
  //#region core/src/impact.d.ts
@@ -374,7 +373,7 @@ type DocumentImpact<TSchema extends DocumentSchema> = {
374
373
  readonly kind: 'incremental' | 'reset';
375
374
  readonly affects: (target: ImpactTarget<unknown>) => boolean;
376
375
  readonly collection: <TId extends string>(selector: CollectionSelector<TId>) => CollectionImpact<TId>;
377
- readonly operations: readonly DocumentOperationUnion<TSchema>[];
376
+ readonly operations: readonly DocumentOperation[];
378
377
  };
379
378
  //#endregion
380
379
  //#region core/src/address.d.ts
@@ -423,12 +422,20 @@ type CommandFootprintTarget = {
423
422
  readonly id: string;
424
423
  };
425
424
  type CommandFootprint = readonly CommandFootprintTarget[];
426
- declare const commandFootprint: (operations: readonly DocumentOperationUnion[]) => CommandFootprint;
425
+ declare const commandFootprint: (operations: readonly DocumentOperation[]) => CommandFootprint;
427
426
  declare const footprintsOverlap: (left: CommandFootprint, right: CommandFootprint) => boolean;
428
427
  declare const decodeCommandFootprint: (value: unknown) => CommandFootprint | undefined;
429
428
  //#endregion
429
+ //#region core/src/projection/readable.d.ts
430
+ type Readable<TValue> = {
431
+ current(): TValue;
432
+ revision(): number;
433
+ subscribe(listener: () => void): Unsubscribe;
434
+ };
435
+ //#endregion
430
436
  //#region core/src/runtime/contract.d.ts
431
437
  type Unsubscribe = () => void;
438
+ type Synchronous<T> = T extends PromiseLike<unknown> ? never : T;
432
439
  type CommitSource = 'local' | 'system' | 'history' | 'remote';
433
440
  declare class DocumentReentrancyError extends Error {
434
441
  constructor();
@@ -440,16 +447,18 @@ type DocumentCommit<TSchema extends DocumentSchema> = {
440
447
  readonly revision: number;
441
448
  readonly kind: 'operations' | 'replace';
442
449
  readonly source: CommitSource;
443
- readonly operations: readonly DocumentOperationUnion<TSchema>[];
444
- readonly inverse: readonly DocumentOperationUnion<TSchema>[];
450
+ readonly operations: readonly DocumentOperation[];
451
+ readonly inverse: readonly DocumentOperation[];
445
452
  readonly impact: DocumentImpact<TSchema>;
446
453
  };
447
- type DocumentDiagnostic = {
448
- readonly source: 'application';
454
+ type DiagnosticInput = {
449
455
  readonly code: string;
450
456
  readonly message: string;
451
457
  readonly address?: DocumentAddress;
452
458
  };
459
+ type DocumentDiagnostic = DiagnosticInput & {
460
+ readonly source: 'application';
461
+ };
453
462
  type DocumentProblem = DocumentDiagnostic | MutationIssue;
454
463
  type ObserverError = {
455
464
  readonly phase: 'processor' | 'flush' | 'listener';
@@ -474,8 +483,8 @@ type TransactionResult<TValue, TCommit> = {
474
483
  type PreparedUpdateResult<TValue, TSchema extends DocumentSchema> = {
475
484
  readonly status: 'prepared';
476
485
  readonly value: TValue;
477
- readonly operations: readonly DocumentOperationUnion<TSchema>[];
478
- readonly inverse: readonly DocumentOperationUnion<TSchema>[];
486
+ readonly operations: readonly DocumentOperation[];
487
+ readonly inverse: readonly DocumentOperation[];
479
488
  readonly impact: DocumentImpact<TSchema>;
480
489
  readonly footprint: CommandFootprint;
481
490
  readonly reports: readonly DocumentDiagnostic[];
@@ -503,18 +512,20 @@ type HistoryState = {
503
512
  readonly undoDepth: number;
504
513
  readonly redoDepth: number;
505
514
  };
506
- type LocalHistory<TCommit> = {
507
- current(): HistoryState;
508
- subscribe(listener: () => void): Unsubscribe;
515
+ type LocalHistory<TCommit> = Readable<HistoryState> & {
509
516
  undo(): OperationResult<TCommit>;
510
517
  redo(): OperationResult<TCommit>;
511
518
  clear(): void;
519
+ group(): {
520
+ end(): void;
521
+ cancel(): OperationResult<TCommit>;
522
+ };
512
523
  };
513
524
  type DocumentTransaction<TSchema extends DocumentSchema> = {
514
525
  readonly read: DocumentReader<TSchema>;
515
526
  readonly write: DocumentWriter<TSchema>;
516
- readonly reject: (issue: DocumentDiagnostic | readonly DocumentDiagnostic[]) => never;
517
- readonly report: (issue: DocumentDiagnostic) => void;
527
+ readonly reject: (issue: DiagnosticInput | readonly DiagnosticInput[]) => never;
528
+ readonly report: (issue: DiagnosticInput) => void;
518
529
  };
519
530
  type CommitListener<TSchema extends DocumentSchema> = (commit: DocumentCommit<TSchema>) => void;
520
531
  type DocumentReadable<TSchema extends DocumentSchema> = {
@@ -531,11 +542,11 @@ type DocumentReadable<TSchema extends DocumentSchema> = {
531
542
  };
532
543
  type DocumentRuntime<TSchema extends DocumentSchema> = DocumentReadable<TSchema> & {
533
544
  /** Schema configuration captured when this runtime was created. */readonly schema: TSchema;
534
- update<TResult>(run: (transaction: DocumentTransaction<TSchema>) => TResult, options?: {
545
+ update<TResult>(run: (transaction: DocumentTransaction<TSchema>) => Synchronous<TResult>, options?: {
535
546
  readonly source?: Extract<CommitSource, 'local' | 'system'>;
536
547
  readonly history?: boolean;
537
548
  }): TransactionResult<TResult, DocumentCommit<TSchema>>;
538
- prepare<TResult>(run: (transaction: DocumentTransaction<TSchema>) => TResult): PreparedUpdateResult<TResult, TSchema>;
549
+ prepare<TResult>(run: (transaction: DocumentTransaction<TSchema>) => Synchronous<TResult>): PreparedUpdateResult<TResult, TSchema>;
539
550
  apply(operations: unknown, options?: {
540
551
  readonly source?: Exclude<CommitSource, 'history'>;
541
552
  readonly history?: boolean;
@@ -548,5 +559,5 @@ type DocumentRuntime<TSchema extends DocumentSchema> = DocumentReadable<TSchema>
548
559
  dispose(): void;
549
560
  };
550
561
  //#endregion
551
- export { EntityEntry as $, tree as $t, MutationIssue as A, MapNode as At, CollectionReader as B, ValueSelector as Bt, contains as C, DocumentTreeValue as Ct, resolveAddress as D, FieldNode as Dt, read as E, EntitySchemaNode as Et, FieldWriter as F, RecordNode as Ft, TreeReader as G, list as Gt, FieldReader as H, VariantShape as Ht, ListWriter as I, SchemaPath as It, DictSetOperation as J, optional as Jt, DictDeleteOperation as K, map as Kt, MapWriter as L, SingleNode as Lt, CollectionWriter as M, ObjectShape as Mt, DictionaryWriter as N, OptionalNode as Nt, CollectionImpact as O, ImpactTarget as Ot, DocumentWriter as P, ReadonlyDocument as Pt, EntityCreateOperation as Q, table as Qt, TreeWriter as R, TableNode as Rt, AddressRef as S, DocumentTreeNode as St, overlaps as T, DocumentValueOfShape as Tt, ListReader as U, dict as Ut, DocumentReader as V, VariantNode as Vt, ReaderOfNode as W, field as Wt, DocumentOperation as X, schema as Xt, DocumentAnchor as Y, record as Yt, DocumentOperationUnion as Z, single as Zt, CommandFootprint as _, DictNode as _t, DocumentProblem as a, ListMoveOperation as at, decodeCommandFootprint as b, DocumentNode as bt, DocumentRuntime as c, TreeInsertOperation as ct, LocalHistory as d, TreeReplaceOperation as dt, variant as en, EntityMoveOperation as et, ObserverError as f, TreeSetOperation as ft, Unsubscribe as g, CollectionSelector as gt, TransactionResult as h, CollectionNode as ht, DocumentDisposedError as i, ListInsertOperation as it, MutationIssueCode as j, ObjectNode as jt, DocumentImpact as k, ListNode as kt, DocumentTransaction as l, TreeMoveOperation as lt, PreparedUpdateResult as m, VariantReplaceOperation as mt, DocumentCommit as n, FieldClearOperation as nt, DocumentReadable as o, ListRemoveOperation as ot, OperationResult as p, ValueClearOperation as pt, DictReplaceOperation as q, object as qt, DocumentDiagnostic as r, FieldSetOperation as rt, DocumentReentrancyError as s, ListReplaceOperation as st, CommitSource as t, EntityRemoveOperation as tt, HistoryState as u, TreeRemoveOperation as ut, CommandFootprintTarget as v, DocumentAddress as vt, debugKey as w, DocumentValueOfNode as wt, footprintsOverlap as x, DocumentSchema as xt, commandFootprint as y, DocumentListConfig as yt, WriterOfNode as z, TreeNode as zt };
552
- //# sourceMappingURL=contract-4E3moCbY.d.ts.map
562
+ export { DocumentOperation as $, variant as $t, CollectionImpact as A, FieldNode as At, TreeWriter as B, TreeNode as Bt, footprintsOverlap as C, DocumentNode as Ct, overlaps as D, DocumentValueOfNode as Dt, debugKey as E, DocumentTreeValue as Et, DictionaryWriter as F, ObjectShape as Ft, FieldReader as G, field as Gt, CollectionReader as H, VariantNode as Ht, DocumentWriter as I, OptionalNode as It, TreeReader as J, object as Jt, ListReader as K, list as Kt, FieldWriter as L, ReadonlyDocument as Lt, MutationIssue as M, ListNode as Mt, MutationIssueCode as N, MapNode as Nt, read as O, DocumentValueOfShape as Ot, CollectionWriter as P, ObjectNode as Pt, DocumentAnchor as Q, tree as Qt, ListWriter as R, SchemaPath as Rt, decodeCommandFootprint as S, DocumentListConfig as St, contains as T, DocumentTreeNode as Tt, DictionaryReader as U, VariantShape as Ut, WriterOfNode as V, ValueSelector as Vt, DocumentReader as W, dict as Wt, DictReplaceOperation as X, schema as Xt, DictDeleteOperation as Y, optional as Yt, DictSetOperation as Z, table as Zt, Unsubscribe as _, CollectionNode as _t, DocumentProblem as a, FieldSetOperation as at, CommandFootprintTarget as b, DictNode as bt, DocumentRuntime as c, ListRemoveOperation as ct, LocalHistory as d, TreeMoveOperation as dt, EntityCreateOperation as et, ObserverError as f, TreeRemoveOperation as ft, TransactionResult as g, VariantReplaceOperation as gt, Synchronous as h, ValueClearOperation as ht, DocumentDisposedError as i, FieldClearOperation as it, DocumentImpact as j, ImpactTarget as jt, resolveAddress as k, EntitySchemaNode as kt, DocumentTransaction as l, ListReplaceOperation as lt, PreparedUpdateResult as m, TreeSetOperation as mt, DocumentCommit as n, EntityMoveOperation as nt, DocumentReadable as o, ListInsertOperation as ot, OperationResult as p, TreeReplaceOperation as pt, ReaderOfNode as q, map as qt, DocumentDiagnostic as r, EntityRemoveOperation as rt, DocumentReentrancyError as s, ListMoveOperation as st, CommitSource as t, EntityEntry as tt, HistoryState as u, TreeInsertOperation as ut, Readable as v, CollectionPath as vt, AddressRef as w, DocumentSchema as wt, commandFootprint as x, DocumentAddress as xt, CommandFootprint as y, CollectionSelector as yt, MapWriter as z, TableNode as zt };
563
+ //# sourceMappingURL=contract-DNZ4D53r.d.ts.map