@ifc-lite/collab 0.2.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.
- package/LICENSE +373 -0
- package/README.md +92 -0
- package/dist/awareness/agent.d.ts +36 -0
- package/dist/awareness/agent.d.ts.map +1 -0
- package/dist/awareness/agent.js +39 -0
- package/dist/awareness/agent.js.map +1 -0
- package/dist/awareness/color.d.ts +31 -0
- package/dist/awareness/color.d.ts.map +1 -0
- package/dist/awareness/color.js +61 -0
- package/dist/awareness/color.js.map +1 -0
- package/dist/awareness/index.d.ts +6 -0
- package/dist/awareness/index.d.ts.map +1 -0
- package/dist/awareness/index.js +9 -0
- package/dist/awareness/index.js.map +1 -0
- package/dist/awareness/overlay.d.ts +59 -0
- package/dist/awareness/overlay.d.ts.map +1 -0
- package/dist/awareness/overlay.js +110 -0
- package/dist/awareness/overlay.js.map +1 -0
- package/dist/awareness/presence.d.ts +95 -0
- package/dist/awareness/presence.d.ts.map +1 -0
- package/dist/awareness/presence.js +114 -0
- package/dist/awareness/presence.js.map +1 -0
- package/dist/awareness/render.d.ts +58 -0
- package/dist/awareness/render.d.ts.map +1 -0
- package/dist/awareness/render.js +66 -0
- package/dist/awareness/render.js.map +1 -0
- package/dist/branch/branch-tree.d.ts +40 -0
- package/dist/branch/branch-tree.d.ts.map +1 -0
- package/dist/branch/branch-tree.js +66 -0
- package/dist/branch/branch-tree.js.map +1 -0
- package/dist/branch/branch.d.ts +44 -0
- package/dist/branch/branch.d.ts.map +1 -0
- package/dist/branch/branch.js +109 -0
- package/dist/branch/branch.js.map +1 -0
- package/dist/branch/history-automerge.d.ts +31 -0
- package/dist/branch/history-automerge.d.ts.map +1 -0
- package/dist/branch/history-automerge.js +237 -0
- package/dist/branch/history-automerge.js.map +1 -0
- package/dist/branch/history.d.ts +147 -0
- package/dist/branch/history.d.ts.map +1 -0
- package/dist/branch/history.js +223 -0
- package/dist/branch/history.js.map +1 -0
- package/dist/branch/index.d.ts +5 -0
- package/dist/branch/index.d.ts.map +1 -0
- package/dist/branch/index.js +8 -0
- package/dist/branch/index.js.map +1 -0
- package/dist/conflicts/detector.d.ts +52 -0
- package/dist/conflicts/detector.d.ts.map +1 -0
- package/dist/conflicts/detector.js +226 -0
- package/dist/conflicts/detector.js.map +1 -0
- package/dist/conflicts/index.d.ts +3 -0
- package/dist/conflicts/index.d.ts.map +1 -0
- package/dist/conflicts/index.js +6 -0
- package/dist/conflicts/index.js.map +1 -0
- package/dist/conflicts/ui-bridge.d.ts +80 -0
- package/dist/conflicts/ui-bridge.d.ts.map +1 -0
- package/dist/conflicts/ui-bridge.js +126 -0
- package/dist/conflicts/ui-bridge.js.map +1 -0
- package/dist/doc/entity.d.ts +84 -0
- package/dist/doc/entity.d.ts.map +1 -0
- package/dist/doc/entity.js +345 -0
- package/dist/doc/entity.js.map +1 -0
- package/dist/doc/geometry.d.ts +39 -0
- package/dist/doc/geometry.d.ts.map +1 -0
- package/dist/doc/geometry.js +99 -0
- package/dist/doc/geometry.js.map +1 -0
- package/dist/doc/index.d.ts +8 -0
- package/dist/doc/index.d.ts.map +1 -0
- package/dist/doc/index.js +11 -0
- package/dist/doc/index.js.map +1 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.d.ts +21 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.d.ts.map +1 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.js +55 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.js.map +1 -0
- package/dist/doc/relationship.d.ts +27 -0
- package/dist/doc/relationship.d.ts.map +1 -0
- package/dist/doc/relationship.js +110 -0
- package/dist/doc/relationship.js.map +1 -0
- package/dist/doc/schema-version.d.ts +47 -0
- package/dist/doc/schema-version.d.ts.map +1 -0
- package/dist/doc/schema-version.js +41 -0
- package/dist/doc/schema-version.js.map +1 -0
- package/dist/doc/schema.d.ts +131 -0
- package/dist/doc/schema.d.ts.map +1 -0
- package/dist/doc/schema.js +117 -0
- package/dist/doc/schema.js.map +1 -0
- package/dist/doc/units.d.ts +45 -0
- package/dist/doc/units.d.ts.map +1 -0
- package/dist/doc/units.js +120 -0
- package/dist/doc/units.js.map +1 -0
- package/dist/federation/bridge.d.ts +34 -0
- package/dist/federation/bridge.d.ts.map +1 -0
- package/dist/federation/bridge.js +52 -0
- package/dist/federation/bridge.js.map +1 -0
- package/dist/federation/index.d.ts +4 -0
- package/dist/federation/index.d.ts.map +1 -0
- package/dist/federation/index.js +7 -0
- package/dist/federation/index.js.map +1 -0
- package/dist/federation/resolver.d.ts +58 -0
- package/dist/federation/resolver.d.ts.map +1 -0
- package/dist/federation/resolver.js +43 -0
- package/dist/federation/resolver.js.map +1 -0
- package/dist/federation/session.d.ts +79 -0
- package/dist/federation/session.d.ts.map +1 -0
- package/dist/federation/session.js +126 -0
- package/dist/federation/session.js.map +1 -0
- package/dist/geometry/blob-store.d.ts +106 -0
- package/dist/geometry/blob-store.d.ts.map +1 -0
- package/dist/geometry/blob-store.js +266 -0
- package/dist/geometry/blob-store.js.map +1 -0
- package/dist/geometry/csg.d.ts +63 -0
- package/dist/geometry/csg.d.ts.map +1 -0
- package/dist/geometry/csg.js +101 -0
- package/dist/geometry/csg.js.map +1 -0
- package/dist/geometry/determinism.d.ts +45 -0
- package/dist/geometry/determinism.d.ts.map +1 -0
- package/dist/geometry/determinism.js +92 -0
- package/dist/geometry/determinism.js.map +1 -0
- package/dist/geometry/gc.d.ts +63 -0
- package/dist/geometry/gc.d.ts.map +1 -0
- package/dist/geometry/gc.js +109 -0
- package/dist/geometry/gc.js.map +1 -0
- package/dist/geometry/index.d.ts +6 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.js +9 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/geometry/parametric.d.ts +92 -0
- package/dist/geometry/parametric.d.ts.map +1 -0
- package/dist/geometry/parametric.js +200 -0
- package/dist/geometry/parametric.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/mutations/bind.d.ts +56 -0
- package/dist/mutations/bind.d.ts.map +1 -0
- package/dist/mutations/bind.js +68 -0
- package/dist/mutations/bind.js.map +1 -0
- package/dist/mutations/index.d.ts +2 -0
- package/dist/mutations/index.d.ts.map +1 -0
- package/dist/mutations/index.js +5 -0
- package/dist/mutations/index.js.map +1 -0
- package/dist/perf/benchmark.d.ts +25 -0
- package/dist/perf/benchmark.d.ts.map +1 -0
- package/dist/perf/benchmark.js +97 -0
- package/dist/perf/benchmark.js.map +1 -0
- package/dist/perf/index.d.ts +3 -0
- package/dist/perf/index.d.ts.map +1 -0
- package/dist/perf/index.js +6 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/latency.d.ts +39 -0
- package/dist/perf/latency.d.ts.map +1 -0
- package/dist/perf/latency.js +79 -0
- package/dist/perf/latency.js.map +1 -0
- package/dist/privacy.d.ts +45 -0
- package/dist/privacy.d.ts.map +1 -0
- package/dist/privacy.js +66 -0
- package/dist/privacy.js.map +1 -0
- package/dist/providers/indexeddb.d.ts +37 -0
- package/dist/providers/indexeddb.d.ts.map +1 -0
- package/dist/providers/indexeddb.js +45 -0
- package/dist/providers/indexeddb.js.map +1 -0
- package/dist/providers/webrtc.d.ts +40 -0
- package/dist/providers/webrtc.d.ts.map +1 -0
- package/dist/providers/webrtc.js +81 -0
- package/dist/providers/webrtc.js.map +1 -0
- package/dist/providers/websocket.d.ts +45 -0
- package/dist/providers/websocket.d.ts.map +1 -0
- package/dist/providers/websocket.js +56 -0
- package/dist/providers/websocket.js.map +1 -0
- package/dist/security/e2e.d.ts +54 -0
- package/dist/security/e2e.d.ts.map +1 -0
- package/dist/security/e2e.js +147 -0
- package/dist/security/e2e.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +5 -0
- package/dist/security/index.js.map +1 -0
- package/dist/session.d.ts +79 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +112 -0
- package/dist/session.js.map +1 -0
- package/dist/snapshot/from-ifcx.d.ts +24 -0
- package/dist/snapshot/from-ifcx.d.ts.map +1 -0
- package/dist/snapshot/from-ifcx.js +93 -0
- package/dist/snapshot/from-ifcx.js.map +1 -0
- package/dist/snapshot/index.d.ts +6 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +9 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/snapshot/layers.d.ts +56 -0
- package/dist/snapshot/layers.d.ts.map +1 -0
- package/dist/snapshot/layers.js +82 -0
- package/dist/snapshot/layers.js.map +1 -0
- package/dist/snapshot/minimal-layer.d.ts +40 -0
- package/dist/snapshot/minimal-layer.d.ts.map +1 -0
- package/dist/snapshot/minimal-layer.js +123 -0
- package/dist/snapshot/minimal-layer.js.map +1 -0
- package/dist/snapshot/to-ifcx.d.ts +26 -0
- package/dist/snapshot/to-ifcx.d.ts.map +1 -0
- package/dist/snapshot/to-ifcx.js +54 -0
- package/dist/snapshot/to-ifcx.js.map +1 -0
- package/dist/snapshot/worker.d.ts +45 -0
- package/dist/snapshot/worker.d.ts.map +1 -0
- package/dist/snapshot/worker.js +73 -0
- package/dist/snapshot/worker.js.map +1 -0
- package/dist/sync/room.d.ts +15 -0
- package/dist/sync/room.d.ts.map +1 -0
- package/dist/sync/room.js +20 -0
- package/dist/sync/room.js.map +1 -0
- package/dist/undo.d.ts +25 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +37 -0
- package/dist/undo.js.map +1 -0
- package/dist/viewer-bridge.d.ts +27 -0
- package/dist/viewer-bridge.d.ts.map +1 -0
- package/dist/viewer-bridge.js +82 -0
- package/dist/viewer-bridge.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch-tree.js","sourceRoot":"","sources":["../../src/branch/branch-tree.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAuC/D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAuB;IAC3D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACZ,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAElF,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAG,UAAU,MAAM,CAAC,IAAI,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC;YACT,EAAE,EAAE,QAAQ;YACZ,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,EAAE,EAAE,MAAM,CAAC,SAAS;SACrB,CAAC,CAAC;QAEH,iDAAiD;QACjD,IAAI,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,iBAAiB,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,IAAI,MAAM,GAAW,QAAQ,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,iEAAiE;YACjE,iEAAiE;YACjE,oDAAoD;YACpD,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,gBAAgB,KAAK,QAAQ,CAAC;YACvD,MAAM,IAAI,GAAmB;gBAC3B,EAAE,EAAE,CAAC,CAAC,OAAO;gBACb,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;gBACjC,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,QAAQ,EAAE,MAAM;aACjB,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,gBAAgB,CAAC;YAC7C,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAC7D,iEAAiE;YACjE,8DAA8D;YAC9D,kDAAkD;YAClD,IAAI,OAAO,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;gBACnC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,iBAAiB,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1E,CAAC;YACD,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type CollabSession, type CollabSessionOptions } from '../session.js';
|
|
2
|
+
export interface ForkOptions {
|
|
3
|
+
/** New room id for the branch. Defaults to `<parent.roomId>/branches/<name>`. */
|
|
4
|
+
roomId?: string;
|
|
5
|
+
/** Branch name; stored in branch's meta for UI. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Override the user identity on the branch session. Defaults to parent's. */
|
|
8
|
+
user?: CollabSessionOptions['user'];
|
|
9
|
+
/** Provider for the branch (default: parent's provider). */
|
|
10
|
+
provider?: CollabSessionOptions['provider'];
|
|
11
|
+
/** Forwarded to the new session. */
|
|
12
|
+
serverUrl?: CollabSessionOptions['serverUrl'];
|
|
13
|
+
token?: CollabSessionOptions['token'];
|
|
14
|
+
WebSocketPolyfill?: CollabSessionOptions['WebSocketPolyfill'];
|
|
15
|
+
}
|
|
16
|
+
export interface BranchSession {
|
|
17
|
+
readonly session: CollabSession;
|
|
18
|
+
readonly parentRoomId: string;
|
|
19
|
+
readonly branchName: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function forkSession(parent: CollabSession, opts: ForkOptions): Promise<BranchSession>;
|
|
22
|
+
export type MergeStrategy = 'ops' | 'layer';
|
|
23
|
+
export interface MergeReport {
|
|
24
|
+
strategy: MergeStrategy;
|
|
25
|
+
/** Bytes of the merged update payload. */
|
|
26
|
+
bytes: number;
|
|
27
|
+
/** ISO timestamp of when the merge transaction landed on `parent`. */
|
|
28
|
+
mergedAt: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Merge `branch` back into `parent`. Returns a small report.
|
|
32
|
+
*
|
|
33
|
+
* The branch session is NOT disposed by this call — the caller decides
|
|
34
|
+
* whether to keep it around (e.g. for diff inspection) or `dispose()`
|
|
35
|
+
* it after merge.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mergeBranch(parent: CollabSession, branch: BranchSession, strategy?: MergeStrategy): MergeReport;
|
|
38
|
+
/** Read branch metadata back off a session's Y.Doc. */
|
|
39
|
+
export declare function readBranchMeta(session: CollabSession): {
|
|
40
|
+
parentRoomId?: string;
|
|
41
|
+
branchName?: string;
|
|
42
|
+
forkedAt?: string;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=branch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"AA6BA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,IAAI,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC5C,oCAAoC;IACpC,SAAS,CAAC,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAMD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAiCxB;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,aAAqB,GAC9B,WAAW,CA2Bb;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,GACrB;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAOnE"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Branching (spec §12.4 — v0.7 starter).
|
|
6
|
+
*
|
|
7
|
+
* `forkSession(parent, opts)` — snapshot the parent Y.Doc, seed a new
|
|
8
|
+
* Y.Doc with the snapshot, and wrap it as a fresh `CollabSession`. The
|
|
9
|
+
* branch carries `meta.parentRoomId` + `meta.branchName` for round-trip
|
|
10
|
+
* tooling.
|
|
11
|
+
*
|
|
12
|
+
* `mergeBranch(parent, branch, strategy)` — bring the branch's edits
|
|
13
|
+
* back. Two strategies ship in v0.7:
|
|
14
|
+
* - `'ops'` : encode the branch's full state as a Y update and
|
|
15
|
+
* `applyUpdate` it into the parent. Works for any pair
|
|
16
|
+
* of CRDT docs; concurrent parent edits LWW-merge with
|
|
17
|
+
* the branch's edits per Yjs semantics.
|
|
18
|
+
* - `'layer'` : extract the branch contents as an IFCX layer and
|
|
19
|
+
* re-seed the parent with parent + branch composed.
|
|
20
|
+
* Useful when the branch was edited by tools that only
|
|
21
|
+
* speak IFCX, not the live Y.Doc.
|
|
22
|
+
*
|
|
23
|
+
* The proper differential layer composer lands later in v0.7 — for now
|
|
24
|
+
* `'layer'` produces a snapshot-of-branch layer, which is the same
|
|
25
|
+
* trade-off documented in `snapshot/layers.ts`.
|
|
26
|
+
*/
|
|
27
|
+
import * as Y from 'yjs';
|
|
28
|
+
import { createCollabSession, } from '../session.js';
|
|
29
|
+
import { metaMap } from '../doc/schema.js';
|
|
30
|
+
import { snapshotToIfcx } from '../snapshot/to-ifcx.js';
|
|
31
|
+
import { seedFromIfcx } from '../snapshot/from-ifcx.js';
|
|
32
|
+
const META_PARENT = 'branch.parentRoomId';
|
|
33
|
+
const META_NAME = 'branch.name';
|
|
34
|
+
const META_FORKED_AT = 'branch.forkedAt';
|
|
35
|
+
export async function forkSession(parent, opts) {
|
|
36
|
+
// 1. Snapshot the parent Y.Doc as a binary update.
|
|
37
|
+
const update = Y.encodeStateAsUpdate(parent.doc);
|
|
38
|
+
// 2. Build the branch session.
|
|
39
|
+
const branchRoomId = opts.roomId ?? `${parent.roomId}/branches/${opts.name}`;
|
|
40
|
+
const branchUser = opts.user ?? parent.presence.getSelf()?.user ?? {
|
|
41
|
+
id: 'forker',
|
|
42
|
+
name: 'forker',
|
|
43
|
+
};
|
|
44
|
+
const branch = await createCollabSession({
|
|
45
|
+
roomId: branchRoomId,
|
|
46
|
+
user: branchUser,
|
|
47
|
+
provider: opts.provider ?? parent.provider,
|
|
48
|
+
serverUrl: opts.serverUrl,
|
|
49
|
+
token: opts.token,
|
|
50
|
+
WebSocketPolyfill: opts.WebSocketPolyfill,
|
|
51
|
+
});
|
|
52
|
+
// 3. Seed the branch doc with the parent state, then stamp branch metadata.
|
|
53
|
+
Y.applyUpdate(branch.doc, update, { source: 'fork', parentRoomId: parent.roomId });
|
|
54
|
+
branch.transact(() => {
|
|
55
|
+
const meta = metaMap(branch.doc);
|
|
56
|
+
meta.set(META_PARENT, parent.roomId);
|
|
57
|
+
meta.set(META_NAME, opts.name);
|
|
58
|
+
meta.set(META_FORKED_AT, new Date().toISOString());
|
|
59
|
+
});
|
|
60
|
+
return {
|
|
61
|
+
session: branch,
|
|
62
|
+
parentRoomId: parent.roomId,
|
|
63
|
+
branchName: opts.name,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Merge `branch` back into `parent`. Returns a small report.
|
|
68
|
+
*
|
|
69
|
+
* The branch session is NOT disposed by this call — the caller decides
|
|
70
|
+
* whether to keep it around (e.g. for diff inspection) or `dispose()`
|
|
71
|
+
* it after merge.
|
|
72
|
+
*/
|
|
73
|
+
export function mergeBranch(parent, branch, strategy = 'ops') {
|
|
74
|
+
if (strategy === 'ops') {
|
|
75
|
+
const update = Y.encodeStateAsUpdate(branch.session.doc);
|
|
76
|
+
Y.applyUpdate(parent.doc, update, {
|
|
77
|
+
source: 'merge-branch',
|
|
78
|
+
branchName: branch.branchName,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
strategy,
|
|
82
|
+
bytes: update.byteLength,
|
|
83
|
+
mergedAt: new Date().toISOString(),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// 'layer' strategy: snapshot the branch as IFCX, then re-seed the
|
|
87
|
+
// parent with reset:false so existing parent state is preserved and
|
|
88
|
+
// branch nodes overlay (composition is left to the caller's IFCX
|
|
89
|
+
// layer stack — for now we fall back to "set everything we have").
|
|
90
|
+
const ifcx = snapshotToIfcx(branch.session.doc);
|
|
91
|
+
const before = Y.encodeStateAsUpdate(parent.doc);
|
|
92
|
+
seedFromIfcx(parent.doc, ifcx, { reset: false });
|
|
93
|
+
const after = Y.encodeStateAsUpdate(parent.doc);
|
|
94
|
+
return {
|
|
95
|
+
strategy,
|
|
96
|
+
bytes: Math.max(0, after.byteLength - before.byteLength),
|
|
97
|
+
mergedAt: new Date().toISOString(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** Read branch metadata back off a session's Y.Doc. */
|
|
101
|
+
export function readBranchMeta(session) {
|
|
102
|
+
const meta = metaMap(session.doc);
|
|
103
|
+
return {
|
|
104
|
+
parentRoomId: meta.get(META_PARENT),
|
|
105
|
+
branchName: meta.get(META_NAME),
|
|
106
|
+
forkedAt: meta.get(META_FORKED_AT),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=branch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
2
|
+
import type { BranchInfo, HistoryDiff, HistoryEntry, HistorySidecar } from './history.js';
|
|
3
|
+
export interface AutomergeHistorySidecarOptions {
|
|
4
|
+
/** Restore from a previously-saved binary doc. */
|
|
5
|
+
serialised?: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
export declare class AutomergeHistorySidecar implements HistorySidecar {
|
|
8
|
+
private doc;
|
|
9
|
+
private counter;
|
|
10
|
+
constructor(opts?: AutomergeHistorySidecarOptions);
|
|
11
|
+
/** Serialise the entire history doc. Use to persist across restarts. */
|
|
12
|
+
save(): Uint8Array;
|
|
13
|
+
/** Replace the internal doc. Used by tests + restore flows. */
|
|
14
|
+
load(serialised: Uint8Array): void;
|
|
15
|
+
private nextEntryId;
|
|
16
|
+
record(input: {
|
|
17
|
+
branch?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
snapshot: IfcxFile;
|
|
20
|
+
diff?: IfcxFile;
|
|
21
|
+
authorClientId?: number;
|
|
22
|
+
}): Promise<HistoryEntry>;
|
|
23
|
+
entries(branch?: string): Promise<HistoryEntry[]>;
|
|
24
|
+
at(at: Date | string, branch?: string): Promise<HistoryEntry | null>;
|
|
25
|
+
diff(fromEntryId: string, toEntryId: string): Promise<HistoryDiff>;
|
|
26
|
+
branches(): Promise<BranchInfo[]>;
|
|
27
|
+
branch(name: string, fromEntryId?: string): Promise<BranchInfo>;
|
|
28
|
+
merge(branch: string, into: string, mergedSnapshot: IfcxFile): Promise<HistoryEntry>;
|
|
29
|
+
clear(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=history-automerge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-automerge.d.ts","sourceRoot":"","sources":["../../src/branch/history-automerge.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACf,MAAM,cAAc,CAAC;AA0BtB,MAAM,WAAW,8BAA8B;IAC7C,kDAAkD;IAClD,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,qBAAa,uBAAwB,YAAW,cAAc;IAC5D,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,OAAO,CAAK;gBAER,IAAI,GAAE,8BAAmC;IAiBrD,wEAAwE;IACxE,IAAI,IAAI,UAAU;IAIlB,+DAA+D;IAC/D,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAIlC,OAAO,CAAC,WAAW;IAKb,MAAM,CAAC,KAAK,EAAE;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,QAAQ,CAAC;QACnB,IAAI,CAAC,EAAE,QAAQ,CAAC;QAChB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,YAAY,CAAC;IAgCnB,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAcjD,EAAE,CAAC,EAAE,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAWpE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoClE,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAOjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA2B/D,KAAK,CACT,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,QAAQ,GACvB,OAAO,CAAC,YAAY,CAAC;IAwClB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Automerge-backed `HistorySidecar` (spec §4 + §12.4).
|
|
6
|
+
*
|
|
7
|
+
* Same interface as `MemoryHistorySidecar`, but every entry lives
|
|
8
|
+
* inside an Automerge document. That gives us:
|
|
9
|
+
* - first-class branching / merging at the storage layer
|
|
10
|
+
* - a binary `save()` representation we can persist
|
|
11
|
+
* - cheap time-travel via Automerge `view(heads)` and `getHistory()`
|
|
12
|
+
*
|
|
13
|
+
* The trade-off (per spec §4) is bundle size: Automerge is Rust+WASM.
|
|
14
|
+
* For deployments where that's unacceptable, `MemoryHistorySidecar`
|
|
15
|
+
* remains the default. Both satisfy `HistorySidecar`.
|
|
16
|
+
*/
|
|
17
|
+
import * as A from '@automerge/automerge';
|
|
18
|
+
export class AutomergeHistorySidecar {
|
|
19
|
+
doc;
|
|
20
|
+
counter = 0;
|
|
21
|
+
constructor(opts = {}) {
|
|
22
|
+
if (opts.serialised && opts.serialised.byteLength > 0) {
|
|
23
|
+
this.doc = A.load(opts.serialised);
|
|
24
|
+
// Recompute counter so newly-recorded ids don't collide.
|
|
25
|
+
const ids = Object.keys(this.doc.entries ?? {});
|
|
26
|
+
this.counter = ids.length;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.doc = A.from({
|
|
30
|
+
entries: {},
|
|
31
|
+
branches: {
|
|
32
|
+
main: { name: 'main', createdAt: new Date().toISOString() },
|
|
33
|
+
},
|
|
34
|
+
byBranch: { main: [] },
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Serialise the entire history doc. Use to persist across restarts. */
|
|
39
|
+
save() {
|
|
40
|
+
return A.save(this.doc);
|
|
41
|
+
}
|
|
42
|
+
/** Replace the internal doc. Used by tests + restore flows. */
|
|
43
|
+
load(serialised) {
|
|
44
|
+
this.doc = A.load(serialised);
|
|
45
|
+
}
|
|
46
|
+
nextEntryId() {
|
|
47
|
+
this.counter += 1;
|
|
48
|
+
return `e${this.counter}-${Date.now().toString(36)}`;
|
|
49
|
+
}
|
|
50
|
+
async record(input) {
|
|
51
|
+
const branch = input.branch ?? 'main';
|
|
52
|
+
const entryId = this.nextEntryId();
|
|
53
|
+
const at = new Date().toISOString();
|
|
54
|
+
const snapshotJson = JSON.stringify(input.snapshot);
|
|
55
|
+
const diffJson = input.diff ? JSON.stringify(input.diff) : undefined;
|
|
56
|
+
this.doc = A.change(this.doc, `record ${entryId}`, (d) => {
|
|
57
|
+
if (!d.branches[branch]) {
|
|
58
|
+
d.branches[branch] = { name: branch, createdAt: at };
|
|
59
|
+
d.byBranch[branch] = [];
|
|
60
|
+
}
|
|
61
|
+
// Automerge rejects `undefined` — only set defined fields.
|
|
62
|
+
const entry = { entryId, at, branch, snapshotJson };
|
|
63
|
+
if (input.authorClientId !== undefined)
|
|
64
|
+
entry.authorClientId = input.authorClientId;
|
|
65
|
+
if (input.label !== undefined)
|
|
66
|
+
entry.label = input.label;
|
|
67
|
+
if (diffJson !== undefined)
|
|
68
|
+
entry.diffJson = diffJson;
|
|
69
|
+
d.entries[entryId] = entry;
|
|
70
|
+
d.byBranch[branch].push(entryId);
|
|
71
|
+
});
|
|
72
|
+
return revive({
|
|
73
|
+
entryId,
|
|
74
|
+
at,
|
|
75
|
+
branch,
|
|
76
|
+
authorClientId: input.authorClientId,
|
|
77
|
+
label: input.label,
|
|
78
|
+
snapshotJson,
|
|
79
|
+
diffJson,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async entries(branch) {
|
|
83
|
+
const shape = this.doc;
|
|
84
|
+
if (branch) {
|
|
85
|
+
const ids = shape.byBranch[branch] ?? [];
|
|
86
|
+
return ids
|
|
87
|
+
.map((id) => shape.entries[id])
|
|
88
|
+
.filter((e) => Boolean(e))
|
|
89
|
+
.map(revive);
|
|
90
|
+
}
|
|
91
|
+
return Object.values(shape.entries)
|
|
92
|
+
.map(revive)
|
|
93
|
+
.sort((a, b) => a.at.localeCompare(b.at));
|
|
94
|
+
}
|
|
95
|
+
async at(at, branch) {
|
|
96
|
+
const target = at instanceof Date ? at.toISOString() : at;
|
|
97
|
+
const list = await this.entries(branch);
|
|
98
|
+
let best = null;
|
|
99
|
+
for (const e of list) {
|
|
100
|
+
if (e.at <= target)
|
|
101
|
+
best = e;
|
|
102
|
+
else
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
return best;
|
|
106
|
+
}
|
|
107
|
+
async diff(fromEntryId, toEntryId) {
|
|
108
|
+
const shape = this.doc;
|
|
109
|
+
const from = shape.entries[fromEntryId];
|
|
110
|
+
const to = shape.entries[toEntryId];
|
|
111
|
+
if (!from || !to) {
|
|
112
|
+
return { from: fromEntryId, to: toEntryId, added: [], removed: [], changed: [] };
|
|
113
|
+
}
|
|
114
|
+
const fromIfcx = JSON.parse(from.snapshotJson);
|
|
115
|
+
const toIfcx = JSON.parse(to.snapshotJson);
|
|
116
|
+
const fromPaths = new Map();
|
|
117
|
+
const toPaths = new Map();
|
|
118
|
+
for (const n of fromIfcx.data ?? [])
|
|
119
|
+
fromPaths.set(n.path, n);
|
|
120
|
+
for (const n of toIfcx.data ?? [])
|
|
121
|
+
toPaths.set(n.path, n);
|
|
122
|
+
const added = [];
|
|
123
|
+
const removed = [];
|
|
124
|
+
const changed = [];
|
|
125
|
+
for (const path of toPaths.keys()) {
|
|
126
|
+
if (!fromPaths.has(path))
|
|
127
|
+
added.push(path);
|
|
128
|
+
else if (JSON.stringify(toPaths.get(path)) !== JSON.stringify(fromPaths.get(path))) {
|
|
129
|
+
changed.push(path);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const path of fromPaths.keys()) {
|
|
133
|
+
if (!toPaths.has(path))
|
|
134
|
+
removed.push(path);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
from: fromEntryId,
|
|
138
|
+
to: toEntryId,
|
|
139
|
+
added: added.sort(),
|
|
140
|
+
removed: removed.sort(),
|
|
141
|
+
changed: changed.sort(),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async branches() {
|
|
145
|
+
const shape = this.doc;
|
|
146
|
+
return Object.values(shape.branches).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
147
|
+
}
|
|
148
|
+
async branch(name, fromEntryId) {
|
|
149
|
+
const shape = this.doc;
|
|
150
|
+
if (shape.branches[name]) {
|
|
151
|
+
throw new Error(`@ifc-lite/collab: branch "${name}" already exists`);
|
|
152
|
+
}
|
|
153
|
+
// Default fork point = current head of main when no explicit
|
|
154
|
+
// entry is supplied, matching `MemoryHistorySidecar` + the documented
|
|
155
|
+
// interface.
|
|
156
|
+
let resolvedFork = fromEntryId;
|
|
157
|
+
if (!resolvedFork) {
|
|
158
|
+
const mainIds = shape.byBranch.main ?? [];
|
|
159
|
+
resolvedFork = mainIds[mainIds.length - 1];
|
|
160
|
+
}
|
|
161
|
+
const info = {
|
|
162
|
+
name,
|
|
163
|
+
forkedFromEntryId: resolvedFork,
|
|
164
|
+
createdAt: new Date().toISOString(),
|
|
165
|
+
};
|
|
166
|
+
this.doc = A.change(this.doc, `branch ${name}`, (d) => {
|
|
167
|
+
const stored = { name, createdAt: info.createdAt };
|
|
168
|
+
if (resolvedFork !== undefined)
|
|
169
|
+
stored.forkedFromEntryId = resolvedFork;
|
|
170
|
+
d.branches[name] = stored;
|
|
171
|
+
d.byBranch[name] = [];
|
|
172
|
+
});
|
|
173
|
+
return info;
|
|
174
|
+
}
|
|
175
|
+
async merge(branch, into, mergedSnapshot) {
|
|
176
|
+
const shape = this.doc;
|
|
177
|
+
// Validate the source branch up front (matches MemoryHistorySidecar).
|
|
178
|
+
if (!shape.branches[branch]) {
|
|
179
|
+
throw new Error(`@ifc-lite/collab: source branch "${branch}" not found`);
|
|
180
|
+
}
|
|
181
|
+
if (!shape.branches[into]) {
|
|
182
|
+
throw new Error(`@ifc-lite/collab: target branch "${into}" not found`);
|
|
183
|
+
}
|
|
184
|
+
const sourceIds = shape.byBranch[branch] ?? [];
|
|
185
|
+
const sourceTipId = sourceIds[sourceIds.length - 1];
|
|
186
|
+
const entryId = this.nextEntryId();
|
|
187
|
+
const at = new Date().toISOString();
|
|
188
|
+
const snapshotJson = JSON.stringify(mergedSnapshot);
|
|
189
|
+
const label = `merge ${branch} → ${into}`;
|
|
190
|
+
this.doc = A.change(this.doc, `merge ${branch} → ${into}`, (d) => {
|
|
191
|
+
// Automerge rejects `undefined` — only set defined fields.
|
|
192
|
+
const entry = {
|
|
193
|
+
entryId,
|
|
194
|
+
at,
|
|
195
|
+
branch: into,
|
|
196
|
+
label,
|
|
197
|
+
snapshotJson,
|
|
198
|
+
mergedFromBranch: branch,
|
|
199
|
+
};
|
|
200
|
+
if (sourceTipId !== undefined)
|
|
201
|
+
entry.mergedFromEntryId = sourceTipId;
|
|
202
|
+
d.entries[entryId] = entry;
|
|
203
|
+
d.byBranch[into].push(entryId);
|
|
204
|
+
});
|
|
205
|
+
return revive({
|
|
206
|
+
entryId,
|
|
207
|
+
at,
|
|
208
|
+
branch: into,
|
|
209
|
+
label,
|
|
210
|
+
snapshotJson,
|
|
211
|
+
mergedFromBranch: branch,
|
|
212
|
+
mergedFromEntryId: sourceTipId,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
async clear() {
|
|
216
|
+
this.doc = A.from({
|
|
217
|
+
entries: {},
|
|
218
|
+
branches: { main: { name: 'main', createdAt: new Date().toISOString() } },
|
|
219
|
+
byBranch: { main: [] },
|
|
220
|
+
});
|
|
221
|
+
this.counter = 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function revive(entry) {
|
|
225
|
+
return {
|
|
226
|
+
entryId: entry.entryId,
|
|
227
|
+
at: entry.at,
|
|
228
|
+
branch: entry.branch,
|
|
229
|
+
authorClientId: entry.authorClientId,
|
|
230
|
+
label: entry.label,
|
|
231
|
+
snapshot: JSON.parse(entry.snapshotJson),
|
|
232
|
+
diff: entry.diffJson ? JSON.parse(entry.diffJson) : undefined,
|
|
233
|
+
mergedFromBranch: entry.mergedFromBranch,
|
|
234
|
+
mergedFromEntryId: entry.mergedFromEntryId,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=history-automerge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history-automerge.js","sourceRoot":"","sources":["../../src/branch/history-automerge.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,CAAC,MAAM,sBAAsB,CAAC;AAsC1C,MAAM,OAAO,uBAAuB;IAC1B,GAAG,CAAwB;IAC3B,OAAO,GAAG,CAAC,CAAC;IAEpB,YAAY,OAAuC,EAAE;QACnD,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAiB,IAAI,CAAC,UAAU,CAAC,CAAC;YACnD,yDAAyD;YACzD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,GAAiC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAiB;gBAChC,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE;oBACR,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;iBAC5D;gBACD,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;aACvB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,IAAI;QACF,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,+DAA+D;IAC/D,IAAI,CAAC,UAAsB;QACzB,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAiB,UAAU,CAAC,CAAC;IAChD,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QAClB,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAMZ;QACC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAErE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YACvD,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;gBACrD,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAC1B,CAAC;YACD,2DAA2D;YAC3D,MAAM,KAAK,GAA4B,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;YAC7E,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;gBAAE,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;YACpF,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;gBAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YACzD,IAAI,QAAQ,KAAK,SAAS;gBAAE,KAAK,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACtD,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,KAAkC,CAAC;YACxD,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;YACZ,OAAO;YACP,EAAE;YACF,MAAM;YACN,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,YAAY;YACZ,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAe;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAgC,CAAC;QACpD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACzC,OAAO,GAAG;iBACP,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;iBAC9B,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;iBAC9C,GAAG,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;aAChC,GAAG,CAAC,MAAM,CAAC;aACX,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,EAAE,CAAC,EAAiB,EAAE,MAAe;QACzC,MAAM,MAAM,GAAG,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,IAAI,GAAwB,IAAI,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,CAAC,EAAE,IAAI,MAAM;gBAAE,IAAI,GAAG,CAAC,CAAC;;gBACxB,MAAM;QACb,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAmB,EAAE,SAAiB;QAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAgC,CAAC;QACpD,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACnF,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAa,CAAC;QAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAa,CAAC;QAEvD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,IAAI,IAAI,EAAE;YAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9D,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAE1D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;iBACtC,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBACnF,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,EAAE,EAAE,SAAS;YACb,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE;YACnB,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;YACvB,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;SACxB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,GAAgC,CAAC;QACpD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACjD,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CACvC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY,EAAE,WAAoB;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAgC,CAAC;QACpD,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,kBAAkB,CAAC,CAAC;QACvE,CAAC;QACD,6DAA6D;QAC7D,sEAAsE;QACtE,aAAa;QACb,IAAI,YAAY,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC;YAC1C,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,MAAM,IAAI,GAAe;YACvB,IAAI;YACJ,iBAAiB,EAAE,YAAY;YAC/B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YACpD,MAAM,MAAM,GAA4B,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5E,IAAI,YAAY,KAAK,SAAS;gBAAE,MAAM,CAAC,iBAAiB,GAAG,YAAY,CAAC;YACxE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,MAA+B,CAAC;YACnD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,KAAK,CACT,MAAc,EACd,IAAY,EACZ,cAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAgC,CAAC;QACpD,sEAAsE;QACtE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,aAAa,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,aAAa,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,WAAW,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,SAAS,MAAM,MAAM,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,MAAM,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YAC/D,2DAA2D;YAC3D,MAAM,KAAK,GAA4B;gBACrC,OAAO;gBACP,EAAE;gBACF,MAAM,EAAE,IAAI;gBACZ,KAAK;gBACL,YAAY;gBACZ,gBAAgB,EAAE,MAAM;aACzB,CAAC;YACF,IAAI,WAAW,KAAK,SAAS;gBAAE,KAAK,CAAC,iBAAiB,GAAG,WAAW,CAAC;YACrE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,KAAkC,CAAC;YACxD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;YACZ,OAAO;YACP,EAAE;YACF,MAAM,EAAE,IAAI;YACZ,KAAK;YACL,YAAY;YACZ,gBAAgB,EAAE,MAAM;YACxB,iBAAiB,EAAE,WAAW;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAiB;YAChC,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE;YACzE,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;IACnB,CAAC;CACF;AAED,SAAS,MAAM,CAAC,KAAqB;IACnC,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAa;QACpD,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAc,CAAC,CAAC,CAAC,SAAS;QAC3E,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* History sidecar (spec §4 + §12.4).
|
|
3
|
+
*
|
|
4
|
+
* The Yjs runtime is optimized for live editing — it doesn't ship a
|
|
5
|
+
* first-class history / branch / time-travel UI. Per spec §4, we run an
|
|
6
|
+
* Automerge-shaped sidecar that records periodic snapshots of the live
|
|
7
|
+
* doc so apps can navigate `(branch, timestamp)` space.
|
|
8
|
+
*
|
|
9
|
+
* To avoid forcing every consumer to take the heavy `@automerge/automerge`
|
|
10
|
+
* Rust+WASM dep, this module ships:
|
|
11
|
+
*
|
|
12
|
+
* - `HistorySidecar` interface — `record(snapshot)`, `entries()`,
|
|
13
|
+
* `at(t)`, `diff(a, b)`, `branches()`, `branch(name, fromEntryId)`,
|
|
14
|
+
* `merge(branch, into)`.
|
|
15
|
+
* - `MemoryHistorySidecar` — keeps every snapshot + per-entry diff
|
|
16
|
+
* in RAM. Good for tests and short-lived sessions.
|
|
17
|
+
* - `IndexedDbHistorySidecar` — same shape, persisted to IDB.
|
|
18
|
+
* - `attachHistorySidecar(session, sidecar, opts)` — drives a sidecar
|
|
19
|
+
* from a `CollabSession` by snapshotting on a timer and on demand.
|
|
20
|
+
*
|
|
21
|
+
* A future `AutomergeHistorySidecar` (pending the heavy dep) will
|
|
22
|
+
* satisfy the same interface.
|
|
23
|
+
*/
|
|
24
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
25
|
+
import type { CollabSession } from '../session.js';
|
|
26
|
+
import { type SnapshotOptions } from '../snapshot/to-ifcx.js';
|
|
27
|
+
export interface HistoryEntry {
|
|
28
|
+
/** Stable id (UUIDv4-like or timestamp-based). */
|
|
29
|
+
entryId: string;
|
|
30
|
+
/** ISO timestamp. */
|
|
31
|
+
at: string;
|
|
32
|
+
/** Branch this entry belongs to. */
|
|
33
|
+
branch: string;
|
|
34
|
+
/** clientID of the author at snapshot time, if known. */
|
|
35
|
+
authorClientId?: number;
|
|
36
|
+
/** Free-form label (commit-message-style). */
|
|
37
|
+
label?: string;
|
|
38
|
+
/** Composed IFCX snapshot — full state at this entry. */
|
|
39
|
+
snapshot: IfcxFile;
|
|
40
|
+
/** Optional minimal layer relative to the previous entry on this branch. */
|
|
41
|
+
diff?: IfcxFile;
|
|
42
|
+
/**
|
|
43
|
+
* Immutable merge metadata. Set ONLY by `merge()` — never by
|
|
44
|
+
* `record()`. UI layers (e.g. `branch-tree`) rely on these instead of
|
|
45
|
+
* parsing `label` so user-authored labels can't be misclassified as
|
|
46
|
+
* structural metadata, and so the merge edge always points at the
|
|
47
|
+
* commit that was actually merged (not the source branch's current tip).
|
|
48
|
+
*/
|
|
49
|
+
mergedFromBranch?: string;
|
|
50
|
+
mergedFromEntryId?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface HistoryDiff {
|
|
53
|
+
/** Entry IDs of `from` and `to`. */
|
|
54
|
+
from: string;
|
|
55
|
+
to: string;
|
|
56
|
+
/**
|
|
57
|
+
* Per-entity differences as observed by walking IFCX nodes:
|
|
58
|
+
* - `added` — entity exists in `to` but not in `from`
|
|
59
|
+
* - `removed` — entity exists in `from` but not in `to`
|
|
60
|
+
* - `changed` — both, with at least one attribute / child differing
|
|
61
|
+
*/
|
|
62
|
+
added: string[];
|
|
63
|
+
removed: string[];
|
|
64
|
+
changed: string[];
|
|
65
|
+
}
|
|
66
|
+
export interface BranchInfo {
|
|
67
|
+
name: string;
|
|
68
|
+
/** entryId on the parent branch where this branch forked. */
|
|
69
|
+
forkedFromEntryId?: string;
|
|
70
|
+
/** Wall-clock time of branch creation. */
|
|
71
|
+
createdAt: string;
|
|
72
|
+
}
|
|
73
|
+
export interface HistorySidecar {
|
|
74
|
+
/** Append a new entry to a branch (default `'main'`). */
|
|
75
|
+
record(input: {
|
|
76
|
+
branch?: string;
|
|
77
|
+
label?: string;
|
|
78
|
+
snapshot: IfcxFile;
|
|
79
|
+
diff?: IfcxFile;
|
|
80
|
+
authorClientId?: number;
|
|
81
|
+
}): Promise<HistoryEntry>;
|
|
82
|
+
/** All entries, oldest first, optionally filtered to one branch. */
|
|
83
|
+
entries(branch?: string): Promise<HistoryEntry[]>;
|
|
84
|
+
/** The entry whose `at` is closest to (and not after) `at`. */
|
|
85
|
+
at(at: Date | string, branch?: string): Promise<HistoryEntry | null>;
|
|
86
|
+
/** Per-entity-id diff between two entries. */
|
|
87
|
+
diff(fromEntryId: string, toEntryId: string): Promise<HistoryDiff>;
|
|
88
|
+
/** All known branches, in creation order. */
|
|
89
|
+
branches(): Promise<BranchInfo[]>;
|
|
90
|
+
/** Create a new branch off `fromEntryId` (defaults to head of `main`). */
|
|
91
|
+
branch(name: string, fromEntryId?: string): Promise<BranchInfo>;
|
|
92
|
+
/**
|
|
93
|
+
* Merge `branch` into `into`. Returns a synthetic merge entry — apps
|
|
94
|
+
* compute the merged snapshot themselves (typically by replaying
|
|
95
|
+
* Y-update logs through `mergeBranch`).
|
|
96
|
+
*/
|
|
97
|
+
merge(branch: string, into: string, mergedSnapshot: IfcxFile): Promise<HistoryEntry>;
|
|
98
|
+
/** Remove all entries / branches. */
|
|
99
|
+
clear(): Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
export declare class MemoryHistorySidecar implements HistorySidecar {
|
|
102
|
+
private readonly entriesByBranch;
|
|
103
|
+
private readonly branchInfo;
|
|
104
|
+
private counter;
|
|
105
|
+
constructor();
|
|
106
|
+
private nextEntryId;
|
|
107
|
+
record(input: {
|
|
108
|
+
branch?: string;
|
|
109
|
+
label?: string;
|
|
110
|
+
snapshot: IfcxFile;
|
|
111
|
+
diff?: IfcxFile;
|
|
112
|
+
authorClientId?: number;
|
|
113
|
+
}): Promise<HistoryEntry>;
|
|
114
|
+
entries(branch?: string): Promise<HistoryEntry[]>;
|
|
115
|
+
at(at: Date | string, branch?: string): Promise<HistoryEntry | null>;
|
|
116
|
+
diff(fromEntryId: string, toEntryId: string): Promise<HistoryDiff>;
|
|
117
|
+
branches(): Promise<BranchInfo[]>;
|
|
118
|
+
branch(name: string, fromEntryId?: string): Promise<BranchInfo>;
|
|
119
|
+
merge(branch: string, into: string, mergedSnapshot: IfcxFile): Promise<HistoryEntry>;
|
|
120
|
+
clear(): Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
export interface AttachHistoryOptions {
|
|
123
|
+
/** How often to record a snapshot, ms. Default 60_000. */
|
|
124
|
+
intervalMs?: number;
|
|
125
|
+
/** Branch to record on. Default 'main'. */
|
|
126
|
+
branch?: string;
|
|
127
|
+
/** Forwarded to `snapshotToIfcx`. */
|
|
128
|
+
snapshot?: SnapshotOptions;
|
|
129
|
+
/**
|
|
130
|
+
* If true (default), include a minimal-layer diff against the
|
|
131
|
+
* previous entry on the same branch. Diffs make `historySidecar.diff(a, b)`
|
|
132
|
+
* cheaper to compute.
|
|
133
|
+
*/
|
|
134
|
+
includeDiff?: boolean;
|
|
135
|
+
}
|
|
136
|
+
export interface HistoryDriver {
|
|
137
|
+
/** Force a snapshot now. */
|
|
138
|
+
capture(label?: string): Promise<HistoryEntry>;
|
|
139
|
+
/** Stop the timer. */
|
|
140
|
+
detach(): void;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Drive a `HistorySidecar` from a live `CollabSession`. Records a
|
|
144
|
+
* snapshot every `intervalMs`, plus on-demand via `capture(label)`.
|
|
145
|
+
*/
|
|
146
|
+
export declare function attachHistorySidecar(session: CollabSession, sidecar: HistorySidecar, options?: AttachHistoryOptions): HistoryDriver;
|
|
147
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/branch/history.ts"],"names":[],"mappings":"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"}
|