@openlfcp/shared-objects 0.1.1 → 0.1.2

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/dist/replica.d.ts DELETED
@@ -1,277 +0,0 @@
1
- import * as A from "@automerge/automerge";
2
- import { LfcpError, type ObjectId, type PrincipalId, type ResourceId } from "@openlfcp/core";
3
- import { type CheckedChange } from "./automerge-bytes.js";
4
- import { type SnapshotLimits } from "./chunk-limits.js";
5
- import { type Task, type TaskIntent } from "./task.js";
6
- import { type Json, type ProfileProblem, type RootValidation } from "./validate.js";
7
- /**
8
- * The Automerge binding of SHARED-OBJECTS-PROFILE-01 (LFCP-031): one
9
- * Resource's replica of the org.openlfcp.shared-objects.v1 document.
10
- *
11
- * - The actor is always the §8 actor of (Resource, Principal), set
12
- * explicitly; §9 actor state safety is enforced with `minSeq`.
13
- * - One semantic intent is exactly one Automerge change (§10, §12), with
14
- * time 0 (informational, and a wall clock would leak edit times) and the
15
- * intent name as message. An intent that changes nothing makes no change.
16
- * - Writes touch single properties only, so unknown fields, extension
17
- * namespaces and object types survive (§70-§72). Objects are never
18
- * removed: deletion is the lifecycle tombstone (§54-§56).
19
- * - Scalar conflicts stay visible (§44-§47) and are resolved by a new
20
- * causal write (§69); tags and assignees are add-wins maps (§39-§43).
21
- *
22
- * Receiving is pure profile work: LFCP verification, decryption and
23
- * authorization come first (§95, LFCP-033).
24
- */
25
- /** The conflict-preserving scalar registers of a Task (§44). */
26
- export declare const SCALAR_FIELDS: readonly ["lifecycle", "title", "status", "due", "scheduled", "completion_date", "priority"];
27
- export type ScalarField = (typeof SCALAR_FIELDS)[number];
28
- /** §69 task.resolve_field_conflict: write `value` (null clears a date) after the merged conflicts. */
29
- export interface ResolveFieldConflict {
30
- readonly intent: "task.resolve_field_conflict";
31
- readonly id: ObjectId;
32
- readonly field: ScalarField;
33
- readonly value: string | null;
34
- }
35
- export type ReplicaIntent = TaskIntent | ResolveFieldConflict;
36
- /** task.resolve_field_conflict (§69). */
37
- export declare function resolveFieldConflict(id: ObjectId, field: ScalarField, value: string | null): ResolveFieldConflict;
38
- /** §21: two concurrent objects under one Object ID: OBJECT_ID_COLLISION, a profile error of its own, not PROFILE_INVALID. */
39
- export declare class ObjectIdCollisionError extends LfcpError {
40
- readonly objectId: string;
41
- constructor(objectId: string);
42
- }
43
- /** §99: a scalar register's provisional value and every concurrent value. */
44
- export interface ScalarView {
45
- /** Automerge's deterministic visible value; provisional while conflicted. Undefined when absent. */
46
- readonly value: Json | undefined;
47
- /** Every concurrent value, sorted by JSON: none when absent, one when resolved. */
48
- readonly values: readonly Json[];
49
- readonly conflicted: boolean;
50
- }
51
- export type ObjectStatus = "ready" | "profile_invalid" | "object_id_collision";
52
- /** §99: a Task with its conflict metadata. */
53
- export interface TaskView {
54
- readonly id: string;
55
- readonly status: ObjectStatus;
56
- readonly problems: readonly ProfileProblem[];
57
- /** The provisional Task, when every visible value is valid. */
58
- readonly task: Task | undefined;
59
- readonly fields: {
60
- readonly [F in ScalarField]: ScalarView;
61
- };
62
- readonly tags: readonly string[];
63
- readonly assignees: readonly string[];
64
- }
65
- /** §100: what one change did to one object. */
66
- export interface ObjectChange {
67
- readonly resource: ResourceId;
68
- readonly objectId: string;
69
- readonly objectType: string | undefined;
70
- /** Top-level fields written, sorted. */
71
- readonly fields: readonly string[];
72
- readonly conflictsAppeared: readonly string[];
73
- readonly conflictsDisappeared: readonly string[];
74
- /** "rebuild": the state was rebuilt without some changes (§14.1, G-EP7). */
75
- readonly origin: "local" | "remote" | "rebuild";
76
- }
77
- /** A local intent's Automerge change, ready to become a Data Unit. */
78
- export interface LocalChange {
79
- readonly intent: string;
80
- /** The exact Automerge change bytes. */
81
- readonly change: Uint8Array;
82
- /** §11: the Data Unit plaintext [1, change]. */
83
- readonly plaintext: Uint8Array;
84
- readonly hash: string;
85
- readonly seq: number;
86
- readonly objects: readonly ObjectChange[];
87
- }
88
- /**
89
- * The outcome of receiving one change. A change whose dependencies are not
90
- * all here is not applied and not invalid: the caller buffers it and offers
91
- * it again later (LFCP-033).
92
- */
93
- export type ReceiveResult = {
94
- readonly status: "applied";
95
- readonly change: CheckedChange;
96
- readonly objects: readonly ObjectChange[];
97
- } | {
98
- readonly status: "duplicate";
99
- readonly change: CheckedChange;
100
- } | {
101
- readonly status: "missing_dependencies";
102
- readonly change: CheckedChange;
103
- readonly missing: readonly string[];
104
- };
105
- /**
106
- * The outcome of receiving many changes at once (receiveChanges): the
107
- * changes merged, those already held, those still missing a dependency
108
- * (not handed to Automerge, §14.1), and those refused with their error.
109
- */
110
- export interface BatchReceiveResult {
111
- readonly applied: readonly CheckedChange[];
112
- readonly duplicates: readonly CheckedChange[];
113
- readonly waiting: readonly CheckedChange[];
114
- readonly refused: readonly {
115
- readonly change: CheckedChange;
116
- readonly error: LfcpError;
117
- }[];
118
- /** §100 notifications for everything the batch changed. */
119
- readonly objects: readonly ObjectChange[];
120
- }
121
- /** Root validation plus §21 collisions and the G-SC3 scalar-string rule. */
122
- export interface ReplicaValidation extends RootValidation {
123
- /** Object IDs with concurrent objects (OBJECT_ID_COLLISION, §21). */
124
- readonly collisions: readonly string[];
125
- }
126
- export interface ReplicaOptions {
127
- readonly resource: ResourceId;
128
- /** The writing Principal; with the Resource it fixes the §8 actor. */
129
- readonly principal: PrincipalId;
130
- /**
131
- * §9: the highest change sequence this actor is known to have used
132
- * (persisted by the caller, LFCP-035). If the loaded state is behind it,
133
- * local writes are refused: they would start an unrelated history under
134
- * sequences already used.
135
- */
136
- readonly minSeq?: number;
137
- }
138
- /** A replica built from a change set; `unapplied` lacks dependencies in that set. */
139
- export interface BuiltReplica {
140
- readonly replica: SharedObjectsReplica;
141
- readonly unapplied: readonly CheckedChange[];
142
- }
143
- type Doc = A.Doc<Record<string, unknown>>;
144
- /** §30: an object's maps and lists nest at most this many levels (the field's own map is 1). */
145
- export declare const MAX_VALUE_DEPTH = 64;
146
- /**
147
- * Applies one change that passed the receive checks. Automerge can throw
148
- * after changing the document in place (a change that skips a sequence
149
- * number stays in its graph without its operations), so on any engine error
150
- * the handle is dropped: the document is rebuilt from the changes it held,
151
- * which must give back the heads it had. A wasm trap is rethrown as it
152
- * is: the module is dead, and only a restart recovers. Exported for tests.
153
- */
154
- export declare function applyChecked(doc: Doc, bytes: Uint8Array): {
155
- readonly next: Doc;
156
- } | {
157
- readonly restored: Doc;
158
- readonly error: Error;
159
- };
160
- /**
161
- * applyChecked for a batch of admitted changes, in one engine call. On any
162
- * engine error the handle is dropped and the document as it was before is
163
- * rebuilt from the changes it held minus the batch, checked against the
164
- * heads it had. Exported for tests.
165
- */
166
- export declare function applyBatchChecked(doc: Doc, batch: readonly CheckedChange[]): {
167
- readonly next: Doc;
168
- } | {
169
- readonly restored: Doc;
170
- readonly error: Error;
171
- };
172
- export declare class SharedObjectsReplica {
173
- #private;
174
- readonly resource: ResourceId;
175
- /** The §8 Automerge actor ID. */
176
- readonly actorId: Uint8Array;
177
- private constructor();
178
- /** §16: a new Resource document. The initial change is the Resource's first Data Unit. */
179
- static create(opts: ReplicaOptions): {
180
- replica: SharedObjectsReplica;
181
- change: LocalChange;
182
- };
183
- /** A replica with no state yet, that receives the Resource's changes. */
184
- static empty(opts: ReplicaOptions): SharedObjectsReplica;
185
- /**
186
- * Loads an Automerge full save: a received Snapshot image (§13), checked
187
- * against `limits` (§13.1, at least the floor) before Automerge loads it,
188
- * or this device's own persisted state ("local-state", not limited).
189
- * Throws PROFILE_INVALID / INVALID_AUTOMERGE_BYTES.
190
- */
191
- static fromSave(save: Uint8Array, opts: ReplicaOptions, limits?: SnapshotLimits | "local-state"): SharedObjectsReplica;
192
- /** §13: loads a Snapshot plaintext [1, save]; later Data Units are received after it. */
193
- static fromSnapshot(plaintext: Uint8Array, opts: ReplicaOptions): SharedObjectsReplica;
194
- /**
195
- * The replica of exactly an accepted change set: its state depends only
196
- * on the set, not on the order. Changes whose dependencies are not in the
197
- * set are returned as unapplied.
198
- */
199
- static fromChanges(changes: Iterable<Uint8Array>, opts: ReplicaOptions): BuiltReplica;
200
- /**
201
- * §14.1 (G-EP7): this replica rebuilt from its own changes minus
202
- * `exclude` (change hashes). Changes that depend on an excluded change are
203
- * unapplied too. An excluded change of this actor is not lost state (§9):
204
- * the rebuilt replica writes on from its own sequence, reusing the
205
- * sequence numbers of the removed changes. A replica that was already
206
- * behind its persisted sequence stays refused.
207
- */
208
- rebuildWithout(exclude: Iterable<string>): BuiltReplica;
209
- /**
210
- * This replica merged with an Automerge full save (a loaded Snapshot,
211
- * §13): the save's document plus every change of this replica, so local
212
- * work the Snapshot does not hold is kept. The §9 sequence carries over.
213
- * Throws PROFILE_INVALID / INVALID_AUTOMERGE_BYTES when the save does not load.
214
- */
215
- mergeSave(save: Uint8Array): BuiltReplica;
216
- /** An empty replica of the same Resource and actor that keeps the §9 sequence (nothing reused). */
217
- emptied(): SharedObjectsReplica;
218
- /** The highest change sequence of this replica's own actor in its state. */
219
- get actorSeq(): number;
220
- /** §9: false when the state is behind the persisted sequence, so local writes are refused. */
221
- get writable(): boolean;
222
- /** Hex hashes of the current heads, sorted. */
223
- heads(): string[];
224
- hasChange(hash: string): boolean;
225
- /** Every change of the state, dependencies first. */
226
- changes(): Uint8Array[];
227
- /** The Automerge full save of the state. */
228
- save(): Uint8Array;
229
- /** §13: the Snapshot plaintext [1, save]. */
230
- snapshot(): Uint8Array;
231
- /**
232
- * The logical root: scalar strings (and Text) read as strings, object keys
233
- * in canonical order, so JSON.stringify(root()) is comparable across
234
- * replicas holding the same state.
235
- */
236
- root(): Json;
237
- /** The logical object stored under `id` (its visible value), if any. */
238
- getObject(id: string): Json | undefined;
239
- objectIds(): string[];
240
- /** §45: every conflicted top-level field of every object, with its concurrent values sorted. */
241
- conflicts(): Record<string, Record<string, Json[]>>;
242
- /** §21: Object IDs under which concurrent objects were created. */
243
- collisions(): string[];
244
- /** §73-§77 validation of the visible state, every concurrent scalar value and G-SC3, plus §21 collisions. */
245
- validate(): ReplicaValidation;
246
- /** §99: the Task under `id` with conflict metadata, or undefined if there is no object or it is not a Task. */
247
- task(id: string): TaskView | undefined;
248
- /**
249
- * Applies one intent as exactly one Automerge change (§10) and returns it,
250
- * or null when the intent changes nothing (removing an absent tag,
251
- * clearing an absent date). The resulting object must be profile-valid;
252
- * an object already invalid or collided is not written (§76, §21) unless
253
- * the write repairs it.
254
- */
255
- apply(intent: ReplicaIntent): LocalChange | null;
256
- /** §11: receives a Data Unit plaintext [1, change]. Throws PROFILE_INVALID / INVALID_AUTOMERGE_BYTES for invalid bytes. */
257
- receive(plaintext: Uint8Array): ReceiveResult;
258
- /** Receives one bare Automerge change (persisted or reference bytes). */
259
- receiveChange(bytes: Uint8Array): ReceiveResult;
260
- /**
261
- * Receives many changes at once: store replay, catch-up, a Snapshot's
262
- * remainder. Same rules as receiveChange (§14.1: no change with a
263
- * missing dependency reaches Automerge; a taken sequence is
264
- * ACTOR_EQUIVOCATION; a skipped one INVALID_AUTOMERGE_BYTES), but the
265
- * admitted changes go to Automerge in ONE call: one change per call is
266
- * quadratic (10 000 changes: ~12 s against ~70 ms as one batch).
267
- *
268
- * The changes may come in any order, duplicated: each is admitted once
269
- * its dependencies inside the batch are (Kahn's order). A refused change
270
- * does not stop the others; changes that depend on it wait. If Automerge
271
- * fails anyway, the document is restored and the admitted changes are
272
- * received one at a time, which isolates the failing one.
273
- */
274
- receiveChanges(changes: Iterable<Uint8Array | CheckedChange>): BatchReceiveResult;
275
- }
276
- export {};
277
- //# sourceMappingURL=replica.d.ts.map