@loomwork/ui-lineage 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +471 -2
  4. package/dist/conformance.d.ts +4 -0
  5. package/dist/conformance.d.ts.map +1 -0
  6. package/dist/conformance.js +143 -0
  7. package/dist/conformance.js.map +1 -0
  8. package/dist/derive.d.ts +15 -0
  9. package/dist/derive.d.ts.map +1 -0
  10. package/dist/derive.js +35 -0
  11. package/dist/derive.js.map +1 -0
  12. package/dist/esm/conformance.js +140 -0
  13. package/dist/esm/conformance.js.map +1 -0
  14. package/dist/esm/derive.js +29 -0
  15. package/dist/esm/derive.js.map +1 -0
  16. package/dist/esm/events.js +101 -0
  17. package/dist/esm/events.js.map +1 -0
  18. package/dist/esm/index.js +12 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/lineage.js +1376 -0
  21. package/dist/esm/lineage.js.map +1 -0
  22. package/dist/esm/retention.js +73 -0
  23. package/dist/esm/retention.js.map +1 -0
  24. package/dist/esm/rootsFor.js +49 -0
  25. package/dist/esm/rootsFor.js.map +1 -0
  26. package/dist/esm/seen.js +733 -0
  27. package/dist/esm/seen.js.map +1 -0
  28. package/dist/esm/seenCrypto.js +197 -0
  29. package/dist/esm/seenCrypto.js.map +1 -0
  30. package/dist/esm/seenGc.js +122 -0
  31. package/dist/esm/seenGc.js.map +1 -0
  32. package/dist/esm/state.js +185 -0
  33. package/dist/esm/state.js.map +1 -0
  34. package/dist/esm/store.js +172 -0
  35. package/dist/esm/store.js.map +1 -0
  36. package/dist/events.d.ts +781 -0
  37. package/dist/events.d.ts.map +1 -0
  38. package/dist/events.js +106 -0
  39. package/dist/events.js.map +1 -0
  40. package/dist/index.d.ts +23 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +60 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/lineage.d.ts +394 -0
  45. package/dist/lineage.d.ts.map +1 -0
  46. package/dist/lineage.js +1383 -0
  47. package/dist/lineage.js.map +1 -0
  48. package/dist/retention.d.ts +45 -0
  49. package/dist/retention.d.ts.map +1 -0
  50. package/dist/retention.js +78 -0
  51. package/dist/retention.js.map +1 -0
  52. package/dist/rootsFor.d.ts +33 -0
  53. package/dist/rootsFor.d.ts.map +1 -0
  54. package/dist/rootsFor.js +52 -0
  55. package/dist/rootsFor.js.map +1 -0
  56. package/dist/seen.d.ts +375 -0
  57. package/dist/seen.d.ts.map +1 -0
  58. package/dist/seen.js +739 -0
  59. package/dist/seen.js.map +1 -0
  60. package/dist/seenCrypto.d.ts +72 -0
  61. package/dist/seenCrypto.d.ts.map +1 -0
  62. package/dist/seenCrypto.js +210 -0
  63. package/dist/seenCrypto.js.map +1 -0
  64. package/dist/seenGc.d.ts +73 -0
  65. package/dist/seenGc.d.ts.map +1 -0
  66. package/dist/seenGc.js +126 -0
  67. package/dist/seenGc.js.map +1 -0
  68. package/dist/state.d.ts +66 -0
  69. package/dist/state.d.ts.map +1 -0
  70. package/dist/state.js +190 -0
  71. package/dist/state.js.map +1 -0
  72. package/dist/store.d.ts +93 -0
  73. package/dist/store.d.ts.map +1 -0
  74. package/dist/store.js +177 -0
  75. package/dist/store.js.map +1 -0
  76. package/package.json +60 -3
  77. package/src/conformance.ts +148 -0
  78. package/src/derive.ts +57 -0
  79. package/src/events.ts +125 -0
  80. package/src/index.ts +79 -0
  81. package/src/lineage.ts +1655 -0
  82. package/src/retention.ts +118 -0
  83. package/src/rootsFor.ts +75 -0
  84. package/src/seen.ts +965 -0
  85. package/src/seenCrypto.ts +271 -0
  86. package/src/seenGc.ts +233 -0
  87. package/src/state.ts +268 -0
  88. package/src/store.ts +274 -0
@@ -0,0 +1,66 @@
1
+ import { type Finding, type Provenance, type RecordedOperation } from "@loomwork/ui-core";
2
+ import { type SummaryClass } from "./events";
3
+ import type { StoredLineageRecord } from "./store";
4
+ export type VersionKind = "composed" | "reverted" | "branched";
5
+ export interface VersionRecord {
6
+ readonly experienceId: string;
7
+ readonly versionHash: string;
8
+ readonly ref: {
9
+ readonly __loomContent: string;
10
+ };
11
+ readonly parents: readonly string[];
12
+ readonly kind: VersionKind;
13
+ /** Position in the line's event log. */
14
+ readonly sequence: number;
15
+ readonly at: string;
16
+ readonly by: Provenance;
17
+ /** The ops folded onto the parent (`composed` only; `[]` otherwise and for a genesis). */
18
+ readonly ops: readonly RecordedOperation[];
19
+ /** `composed`: what the author said about the change; untrusted text, already bounded. */
20
+ readonly summary?: string;
21
+ /** `composed`: the class of what the summary was written from (host-stamped); see `ComposedPayload`. */
22
+ readonly summaryClass?: SummaryClass;
23
+ /** `reverted`: the version whose content this restores. */
24
+ readonly revertedTo?: string;
25
+ /** `branched`: the version of another line this forked, and the source head classes came from. */
26
+ readonly from?: {
27
+ readonly experienceId: string;
28
+ readonly versionHash: string;
29
+ };
30
+ readonly carriedFrom?: string;
31
+ }
32
+ export interface LineageState {
33
+ readonly experienceId: string;
34
+ /** The event log's tip (0 = empty): the compare-and-set token of the STORE. */
35
+ readonly sequence: number;
36
+ readonly versions: ReadonlyMap<string, VersionRecord>;
37
+ /** Version hashes in append order. */
38
+ readonly order: readonly string[];
39
+ /** The latest version (the CAS token of `advance`); null = the line has no version yet. */
40
+ readonly head: string | null;
41
+ /** The version the app chose to show; null = none promoted. */
42
+ readonly promoted: string | null;
43
+ }
44
+ /** Most ops one version may record. A longer array is a finding before the schema ever walks it. */
45
+ export declare const MAX_OPS_PER_VERSION = 10000;
46
+ /** How deep `prompt` ops may nest their `materialized` ops while being checked. */
47
+ export declare const MAX_OP_NESTING = 16;
48
+ /**
49
+ * The WRITE-SIDE twin of the fold's payload check: why `payload` would make the line unreadable
50
+ * (`lineage-event-invalid` on every later read), or undefined when it folds. A write that fails this
51
+ * must be refused BEFORE the append — the fold stays strict, the log has no delete, and one bad event
52
+ * would brick the line for everyone. `by` marks a provenance problem (the caller gives it its own code).
53
+ */
54
+ export declare function payloadRefusal(type: string, payload: unknown): {
55
+ readonly code: "provenance-invalid" | "event-payload-invalid";
56
+ readonly message: string;
57
+ } | undefined;
58
+ export type Fold = {
59
+ ok: true;
60
+ state: LineageState;
61
+ } | {
62
+ ok: false;
63
+ finding: Finding;
64
+ };
65
+ export declare function foldLineage(experienceId: string, records: readonly StoredLineageRecord[]): Fold;
66
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAEZ,KAAK,UAAU,EACf,KAAK,iBAAiB,EAGvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EASL,KAAK,YAAY,EAElB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAQnD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE;QAAE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,0FAA0F;IAC1F,QAAQ,CAAC,GAAG,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,wGAAwG;IACxG,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,kGAAkG;IAClG,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtD,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,oGAAoG;AACpG,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,mFAAmF;AACnF,eAAO,MAAM,cAAc,KAAK,CAAC;AAmCjC;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GAEd;IAAE,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,uBAAuB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3F,SAAS,CAiBZ;AAED,MAAM,MAAM,IAAI,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAOvF,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,mBAAmB,EAAE,GAAG,IAAI,CAQ/F"}
package/dist/state.js ADDED
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_OP_NESTING = exports.MAX_OPS_PER_VERSION = void 0;
4
+ exports.payloadRefusal = payloadRefusal;
5
+ exports.foldLineage = foldLineage;
6
+ const ui_core_1 = require("@loomwork/ui-core");
7
+ const events_1 = require("./events");
8
+ /** Most ops one version may record. A longer array is a finding before the schema ever walks it. */
9
+ exports.MAX_OPS_PER_VERSION = 10_000;
10
+ /** How deep `prompt` ops may nest their `materialized` ops while being checked. */
11
+ exports.MAX_OP_NESTING = 16;
12
+ /**
13
+ * Why a stored ops array must not reach the (recursive) zod `Operation` schema, or undefined when
14
+ * it may. The schema recurses through `insertNode.node` and `prompt.materialized`, so a payload
15
+ * nested past the caps would blow the stack inside `safeParse` instead of returning an issue;
16
+ * a log is untrusted input (anyone with append access to the stream wrote it).
17
+ */
18
+ function opsRefusal(ops) {
19
+ if (!Array.isArray(ops))
20
+ return undefined; // the schema reports the wrong shape
21
+ if (ops.length > exports.MAX_OPS_PER_VERSION)
22
+ return `records ${ops.length} ops, over the ${exports.MAX_OPS_PER_VERSION} limit`;
23
+ const stack = [];
24
+ for (const r of ops)
25
+ stack.push({ op: r?.op, nest: 1 });
26
+ let seen = 0;
27
+ for (let top = stack.pop(); top !== undefined; top = stack.pop()) {
28
+ const { op, nest } = top;
29
+ if (typeof op !== "object" || op === null)
30
+ continue;
31
+ if (++seen > exports.MAX_OPS_PER_VERSION * 2)
32
+ return "nests too many ops";
33
+ const node = op.node;
34
+ if (node !== undefined) {
35
+ const depth = (0, ui_core_1.treeDepth)(node);
36
+ if (depth > ui_core_1.MAX_TREE_DEPTH)
37
+ return `an op's node nests ${depth} levels, over the ${ui_core_1.MAX_TREE_DEPTH} limit`;
38
+ }
39
+ const inner = op.materialized;
40
+ if (Array.isArray(inner)) {
41
+ if (nest >= exports.MAX_OP_NESTING)
42
+ return `prompt ops nest over ${exports.MAX_OP_NESTING} levels`;
43
+ if (inner.length > exports.MAX_OPS_PER_VERSION)
44
+ return "a prompt op materializes too many ops";
45
+ for (const i of inner)
46
+ stack.push({ op: i, nest: nest + 1 });
47
+ }
48
+ }
49
+ return undefined;
50
+ }
51
+ /**
52
+ * The WRITE-SIDE twin of the fold's payload check: why `payload` would make the line unreadable
53
+ * (`lineage-event-invalid` on every later read), or undefined when it folds. A write that fails this
54
+ * must be refused BEFORE the append — the fold stays strict, the log has no delete, and one bad event
55
+ * would brick the line for everyone. `by` marks a provenance problem (the caller gives it its own code).
56
+ */
57
+ function payloadRefusal(type, payload) {
58
+ if (!(0, events_1.isLineageEventType)(type))
59
+ return { code: "event-payload-invalid", message: `unknown event type ${String(type)}` };
60
+ try {
61
+ const tooBig = opsRefusal(payload?.ops);
62
+ if (tooBig !== undefined)
63
+ return { code: "event-payload-invalid", message: tooBig };
64
+ const parsed = events_1.PAYLOAD_SCHEMAS[type].safeParse(payload);
65
+ if (parsed.success)
66
+ return undefined;
67
+ const issue = parsed.error.issues[0];
68
+ const inBy = parsed.error.issues.some((i) => i.path.includes("by"));
69
+ return {
70
+ code: inBy ? "provenance-invalid" : "event-payload-invalid",
71
+ message: `${inBy ? "a provenance (`by`) is invalid" : "the event payload is malformed"}: ${issue?.message ?? "invalid"}${issue ? ` at ${issue.path.join(".")}` : ""}`,
72
+ };
73
+ }
74
+ catch (err) {
75
+ return { code: "event-payload-invalid", message: errMessage(err) };
76
+ }
77
+ }
78
+ const bad = (code, message) => ({
79
+ ok: false,
80
+ finding: { code, severity: "error", message },
81
+ });
82
+ function foldLineage(experienceId, records) {
83
+ try {
84
+ return foldChecked(experienceId, records);
85
+ }
86
+ catch (err) {
87
+ // Total by construction: whatever a hostile record does (a throwing getter, a shape the
88
+ // checks above did not anticipate) is a finding, never an exception out of every read.
89
+ return bad("lineage-event-invalid", `lineage "${experienceId}": ${errMessage(err)}`);
90
+ }
91
+ }
92
+ const errMessage = (err) => {
93
+ try {
94
+ return err instanceof Error ? err.message : String(err);
95
+ }
96
+ catch {
97
+ return "unreadable record";
98
+ }
99
+ };
100
+ function foldChecked(experienceId, records) {
101
+ const versions = new Map();
102
+ const order = [];
103
+ let head = null;
104
+ let promoted = null;
105
+ let expectedSequence = 0;
106
+ for (const rec of records) {
107
+ expectedSequence += 1;
108
+ if (typeof rec !== "object" || rec === null)
109
+ return bad("lineage-event-invalid", `lineage "${experienceId}" event #${expectedSequence}: the record is not an object`);
110
+ const where = `lineage "${experienceId}" event #${rec.sequence} (${rec.type})`;
111
+ if (rec.sequence !== expectedSequence)
112
+ return bad("lineage-sequence-gap", `${where}: expected sequence ${expectedSequence} — the log has a hole or a reorder`);
113
+ if (!(0, events_1.isLineageEventType)(rec.type))
114
+ return bad("lineage-event-unknown", `${where}: unknown type`);
115
+ const tooBig = opsRefusal(rec.payload?.ops);
116
+ if (tooBig !== undefined)
117
+ return bad("lineage-event-invalid", `${where}: ${tooBig}`);
118
+ const parsed = events_1.PAYLOAD_SCHEMAS[rec.type].safeParse(rec.payload);
119
+ if (!parsed.success)
120
+ return bad("lineage-event-invalid", `${where}: ${parsed.error.issues[0]?.message ?? "payload is malformed"}`);
121
+ const p = parsed.data;
122
+ if (p.experienceId !== experienceId)
123
+ return bad("lineage-event-foreign", `${where}: names experience "${p.experienceId}"`);
124
+ if (rec.type === events_1.EXPERIENCE_PROMOTED) {
125
+ if (!versions.has(p.versionHash))
126
+ return bad("lineage-promote-unknown", `${where}: promotes unknown version ${p.versionHash}`);
127
+ promoted = p.versionHash;
128
+ continue;
129
+ }
130
+ const v = p;
131
+ if (versions.has(v.versionHash))
132
+ return bad("lineage-version-duplicate", `${where}: version ${v.versionHash} already exists`);
133
+ if (rec.type === events_1.EXPERIENCE_BRANCHED) {
134
+ if (head !== null)
135
+ return bad("lineage-branch-midline", `${where}: only a line's first event`);
136
+ }
137
+ else if (head === null) {
138
+ if (rec.type !== events_1.EXPERIENCE_COMPOSED || v.parents.length !== 0)
139
+ return bad("lineage-genesis-invalid", `${where}: a line starts with a parentless composition`);
140
+ }
141
+ else if (v.parents.length !== 1 || v.parents[0] !== head) {
142
+ return bad("lineage-parent-mismatch", `${where}: parents ${JSON.stringify(v.parents)} are not the head ${head} it was appended on`);
143
+ }
144
+ const base = {
145
+ experienceId,
146
+ versionHash: v.versionHash,
147
+ ref: v.ref,
148
+ parents: v.parents,
149
+ sequence: rec.sequence,
150
+ at: rec.at,
151
+ by: v.by,
152
+ };
153
+ const record = rec.type === events_1.EXPERIENCE_COMPOSED
154
+ ? {
155
+ ...base,
156
+ kind: "composed",
157
+ ops: v.ops,
158
+ ...summaryOf(v.summary),
159
+ ...(v.summaryClass !== undefined && {
160
+ summaryClass: v.summaryClass,
161
+ }),
162
+ }
163
+ : rec.type === events_1.EXPERIENCE_REVERTED
164
+ ? {
165
+ ...base,
166
+ kind: "reverted",
167
+ ops: [],
168
+ revertedTo: v.revertedTo,
169
+ }
170
+ : {
171
+ ...base,
172
+ kind: "branched",
173
+ ops: [],
174
+ from: v.from,
175
+ carriedFrom: v.carriedFrom,
176
+ };
177
+ versions.set(v.versionHash, record);
178
+ order.push(v.versionHash);
179
+ head = v.versionHash;
180
+ }
181
+ return {
182
+ ok: true,
183
+ state: { experienceId, sequence: expectedSequence, versions, order, head, promoted },
184
+ };
185
+ }
186
+ const summaryOf = (raw) => {
187
+ const summary = (0, ui_core_1.boundSummary)(raw);
188
+ return summary === undefined ? {} : { summary };
189
+ };
190
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { type EventStore } from "@loomwork/event-runtime";
2
+ export interface LineageRecord {
3
+ readonly type: string;
4
+ readonly payload: unknown;
5
+ /** ISO-8601 time the event was recorded. */
6
+ readonly at: string;
7
+ }
8
+ export interface StoredLineageRecord extends LineageRecord {
9
+ /** 1-based position in this line. Dense: 1..n with no gaps. */
10
+ readonly sequence: number;
11
+ }
12
+ export type AppendOutcome = {
13
+ readonly ok: true;
14
+ readonly sequence: number;
15
+ }
16
+ /** The tip was not `expectedSequence`; `tip` is what it is now. Nothing was written. */
17
+ | {
18
+ readonly ok: false;
19
+ readonly tip: number;
20
+ };
21
+ export interface LineageStore {
22
+ /**
23
+ * Append `record` as sequence `expectedSequence + 1` iff the line's tip is EXACTLY
24
+ * `expectedSequence` (0 = the line is empty). Atomic: of N concurrent appends at the same
25
+ * `expectedSequence` exactly one wins and the rest get `{ ok: false }`. NEVER overwrites,
26
+ * never skips a sequence, and a refusal is a returned outcome, not a throw (a throw is an
27
+ * infrastructure failure and leaves the line untouched).
28
+ */
29
+ append(experienceId: string, expectedSequence: number, record: LineageRecord): Promise<AppendOutcome>;
30
+ /** Every record of the line in sequence order; `[]` for an unknown line. The caller owns the result. */
31
+ read(experienceId: string): Promise<readonly StoredLineageRecord[]>;
32
+ /**
33
+ * OPTIONAL — the newest `limit` records of the line, in sequence order (`[]` for an unknown line).
34
+ * Lets a long-lived per-viewer log answer "what is the tip?" without reading its whole history.
35
+ * Implement it together with {@link readAfter}; absent, callers fall back to `read` (O(log length)).
36
+ */
37
+ readTail?(experienceId: string, limit: number): Promise<readonly StoredLineageRecord[]>;
38
+ /**
39
+ * OPTIONAL — the records with `sequence > afterSequence`, in sequence order, at most `limit` of
40
+ * them (default: all). The retention window of a per-viewer log is read this way, so a read costs
41
+ * the size of the window, not the age of the log.
42
+ */
43
+ readAfter?(experienceId: string, afterSequence: number, limit?: number): Promise<readonly StoredLineageRecord[]>;
44
+ /**
45
+ * OPTIONAL — enumerate the ids of every line this store holds, in bounded pages. A collector
46
+ * (`SeenLog.collectGarbage`) needs it to find every root; a store that omits it cannot be
47
+ * garbage-collected (the collector refuses rather than guess a root set). Ids are exactly what
48
+ * `read` takes. Concurrent creation during a scan may be missed (a maintenance pass, not a snapshot).
49
+ */
50
+ listStreams?(): AsyncIterable<string>;
51
+ }
52
+ /** Reference in-memory store. Copies on the way in and out, so no caller can mutate the log. */
53
+ export declare class InMemoryLineageStore implements LineageStore {
54
+ private readonly lines;
55
+ append(experienceId: string, expectedSequence: number, record: LineageRecord): Promise<AppendOutcome>;
56
+ read(experienceId: string): Promise<readonly StoredLineageRecord[]>;
57
+ readTail(experienceId: string, limit: number): Promise<readonly StoredLineageRecord[]>;
58
+ readAfter(experienceId: string, afterSequence: number, limit?: number): Promise<readonly StoredLineageRecord[]>;
59
+ listStreams(): AsyncGenerator<string, void, void>;
60
+ }
61
+ /** The reserved-stream namespace a lineage's events live under in an `EventStore`. */
62
+ export declare const LINEAGE_STREAM_PREFIX = "__loom_ui_lineage__:";
63
+ /** The `workflowId` a lineage event is written under unless `eventStoreLineageStore` is given another. */
64
+ export declare const LINEAGE_WORKFLOW_ID = "loom-ui.lineage";
65
+ /** Every stream prefix this package may write under; the kernel's own reserved prefixes are not ours. */
66
+ export declare const LOOM_UI_STREAM_NAMESPACE = "__loom_ui_";
67
+ /** A `LineageStore` that knows which stream prefix it writes under (see {@link eventStoreLineageStore}). */
68
+ export interface PrefixedLineageStore extends LineageStore {
69
+ readonly streamPrefix: string;
70
+ /**
71
+ * The `workflowId` its events are written under. A `Lineage` passes it, with the stream id, as the
72
+ * `ContentAccess` of every artifact blob, so one host `subjectOf` covers events and blobs alike.
73
+ */
74
+ readonly workflowId?: string;
75
+ }
76
+ /**
77
+ * A `LineageStore` over loom's `EventStore`. One stream per experience
78
+ * (`__loom_ui_lineage__:<experienceId>`, a RESERVED stream so enumerators of real executions skip
79
+ * it; see the README for what a reserved stream costs); the lineage sequence IS the envelope sequence, so the CAS is the log's own
80
+ * `(executionId, sequence)` uniqueness. The adapter checks the tip first (a store enforces a
81
+ * taken slot, not a skipped one) and treats a `DuplicateSequenceError` from a racing writer as a
82
+ * lost CAS. Fencing, tenancy and sharding decorators wrap `store` as usual.
83
+ *
84
+ * `streamPrefix` must start with `__loom_ui_` (and say more): it is the namespace this package owns
85
+ * inside loom's reserved `__loom_` space, so a configuration can never write into the kernel's own
86
+ * control streams (`__loom_lifecycle__`, `__loom_erasure__`) or an execution's id space. `workflowId`
87
+ * is a short identifier. A bad value THROWS at construction (a misconfiguration, found at startup).
88
+ */
89
+ export declare function eventStoreLineageStore(store: EventStore, opts?: {
90
+ readonly streamPrefix?: string;
91
+ readonly workflowId?: string;
92
+ }): PrefixedLineageStore;
93
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,yBAAyB,CAAC;AASjC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AAClD,wFAAwF;GACtF;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1B,wGAAwG;IACxG,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAC;IACpE;;;;OAIG;IACH,QAAQ,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAC;IACxF;;;;OAIG;IACH,SAAS,CAAC,CACR,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC,CAAC;IAC3C;;;;;OAKG;IACH,WAAW,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;CACvC;AAgBD,gGAAgG;AAChG,qBAAa,oBAAqB,YAAW,YAAY;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4C;IAE5D,MAAM,CACV,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC;IASnB,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAInE,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAKtF,SAAS,CACb,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,KAAK,SAA2B,GAC/B,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAOnC,WAAW,IAAI,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;CAGzD;AAED,sFAAsF;AACtF,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAC5D,0GAA0G;AAC1G,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAGrD,yGAAyG;AACzG,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAGrD,4GAA4G;AAC5G,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1E,oBAAoB,CAuFtB"}
package/dist/store.js ADDED
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOOM_UI_STREAM_NAMESPACE = exports.LINEAGE_WORKFLOW_ID = exports.LINEAGE_STREAM_PREFIX = exports.InMemoryLineageStore = void 0;
4
+ exports.eventStoreLineageStore = eventStoreLineageStore;
5
+ const event_runtime_1 = require("@loomwork/event-runtime");
6
+ /**
7
+ * A lost slot, by class OR name (a store decorator or a second copy of the package throws an error
8
+ * that is not `instanceof` ours); mirrors the kernel's `isWriteConflict`.
9
+ */
10
+ function isWriteConflict(err) {
11
+ if (err instanceof event_runtime_1.DuplicateSequenceError || err instanceof event_runtime_1.DuplicateEnvelopeIdError)
12
+ return true;
13
+ const name = err?.name;
14
+ return name === "DuplicateSequenceError" || name === "DuplicateEnvelopeIdError";
15
+ }
16
+ const clone = (v) => structuredClone(v);
17
+ /** Reference in-memory store. Copies on the way in and out, so no caller can mutate the log. */
18
+ class InMemoryLineageStore {
19
+ lines = new Map();
20
+ async append(experienceId, expectedSequence, record) {
21
+ const line = this.lines.get(experienceId) ?? [];
22
+ if (line.length !== expectedSequence)
23
+ return { ok: false, tip: line.length };
24
+ const sequence = line.length + 1;
25
+ line.push(clone({ ...record, sequence }));
26
+ this.lines.set(experienceId, line);
27
+ return { ok: true, sequence };
28
+ }
29
+ async read(experienceId) {
30
+ return clone(this.lines.get(experienceId) ?? []);
31
+ }
32
+ async readTail(experienceId, limit) {
33
+ const line = this.lines.get(experienceId) ?? [];
34
+ return clone(limit >= line.length ? line : line.slice(line.length - Math.max(0, limit)));
35
+ }
36
+ async readAfter(experienceId, afterSequence, limit = Number.POSITIVE_INFINITY) {
37
+ // dense 1..n: the records after `a` start at index `a`
38
+ const line = this.lines.get(experienceId) ?? [];
39
+ const from = Math.max(0, afterSequence);
40
+ return clone(line.slice(from, Number.isFinite(limit) ? from + Math.max(0, limit) : undefined));
41
+ }
42
+ async *listStreams() {
43
+ for (const id of [...this.lines.keys()])
44
+ yield id;
45
+ }
46
+ }
47
+ exports.InMemoryLineageStore = InMemoryLineageStore;
48
+ /** The reserved-stream namespace a lineage's events live under in an `EventStore`. */
49
+ exports.LINEAGE_STREAM_PREFIX = "__loom_ui_lineage__:";
50
+ /** The `workflowId` a lineage event is written under unless `eventStoreLineageStore` is given another. */
51
+ exports.LINEAGE_WORKFLOW_ID = "loom-ui.lineage";
52
+ const WORKFLOW_ID = exports.LINEAGE_WORKFLOW_ID;
53
+ /** Every stream prefix this package may write under; the kernel's own reserved prefixes are not ours. */
54
+ exports.LOOM_UI_STREAM_NAMESPACE = "__loom_ui_";
55
+ const WORKFLOW_ID_SHAPE = /^[A-Za-z0-9._:-]{1,128}$/;
56
+ /**
57
+ * A `LineageStore` over loom's `EventStore`. One stream per experience
58
+ * (`__loom_ui_lineage__:<experienceId>`, a RESERVED stream so enumerators of real executions skip
59
+ * it; see the README for what a reserved stream costs); the lineage sequence IS the envelope sequence, so the CAS is the log's own
60
+ * `(executionId, sequence)` uniqueness. The adapter checks the tip first (a store enforces a
61
+ * taken slot, not a skipped one) and treats a `DuplicateSequenceError` from a racing writer as a
62
+ * lost CAS. Fencing, tenancy and sharding decorators wrap `store` as usual.
63
+ *
64
+ * `streamPrefix` must start with `__loom_ui_` (and say more): it is the namespace this package owns
65
+ * inside loom's reserved `__loom_` space, so a configuration can never write into the kernel's own
66
+ * control streams (`__loom_lifecycle__`, `__loom_erasure__`) or an execution's id space. `workflowId`
67
+ * is a short identifier. A bad value THROWS at construction (a misconfiguration, found at startup).
68
+ */
69
+ function eventStoreLineageStore(store, opts = {}) {
70
+ const prefix = opts.streamPrefix ?? exports.LINEAGE_STREAM_PREFIX;
71
+ const workflowId = opts.workflowId ?? WORKFLOW_ID;
72
+ if (typeof prefix !== "string" ||
73
+ !prefix.startsWith(exports.LOOM_UI_STREAM_NAMESPACE) ||
74
+ prefix.length <= exports.LOOM_UI_STREAM_NAMESPACE.length ||
75
+ prefix.length > 128)
76
+ throw new Error(`streamPrefix must start with "${exports.LOOM_UI_STREAM_NAMESPACE}" and name its stream (got ${JSON.stringify(String(prefix).slice(0, 40))})`);
77
+ if (typeof workflowId !== "string" || !WORKFLOW_ID_SHAPE.test(workflowId))
78
+ throw new Error("workflowId must be 1-128 characters of [A-Za-z0-9._:-]");
79
+ const streamOf = (experienceId) => `${prefix}${experienceId}`;
80
+ return {
81
+ streamPrefix: prefix,
82
+ workflowId,
83
+ async append(experienceId, expectedSequence, record) {
84
+ const executionId = streamOf(experienceId);
85
+ const tip = (await (0, event_runtime_1.headOf)(store, executionId)) ?? 0;
86
+ if (tip !== expectedSequence)
87
+ return { ok: false, tip };
88
+ const sequence = expectedSequence + 1;
89
+ try {
90
+ await store.append({
91
+ id: `${executionId}#${sequence}`,
92
+ workflowId,
93
+ executionId,
94
+ eventType: record.type,
95
+ sequence,
96
+ timestamp: Date.parse(record.at) || 0,
97
+ payload: clone(record.payload),
98
+ metadata: { at: record.at },
99
+ });
100
+ }
101
+ catch (err) {
102
+ if (isWriteConflict(err))
103
+ return { ok: false, tip: (await (0, event_runtime_1.headOf)(store, executionId)) ?? sequence };
104
+ throw err;
105
+ }
106
+ return { ok: true, sequence };
107
+ },
108
+ async read(experienceId) {
109
+ return toRecords(await store.read(streamOf(experienceId)));
110
+ },
111
+ async readTail(experienceId, limit) {
112
+ const id = streamOf(experienceId);
113
+ const tip = (await (0, event_runtime_1.headOf)(store, id)) ?? 0;
114
+ if (tip === 0 || limit <= 0)
115
+ return [];
116
+ return toRecords(await readWindow(store, id, Math.max(1, tip - limit + 1), tip));
117
+ },
118
+ async readAfter(experienceId, afterSequence, limit = Number.POSITIVE_INFINITY) {
119
+ const id = streamOf(experienceId);
120
+ const tip = (await (0, event_runtime_1.headOf)(store, id)) ?? 0;
121
+ const from = Math.max(1, afterSequence + 1);
122
+ const to = Number.isFinite(limit) ? Math.min(tip, from + Math.max(0, limit) - 1) : tip;
123
+ if (to < from)
124
+ return [];
125
+ return toRecords(await readWindow(store, id, from, to));
126
+ },
127
+ ...(store.listExecutionsPage !== undefined || store.listExecutions !== undefined
128
+ ? {
129
+ async *listStreams() {
130
+ // Reserved streams ARE surfaced by the SPI's enumeration (`__loom_*`), so ours are found
131
+ // by prefix. Pages are keyset-ordered by code point, so with pages the scan starts just
132
+ // before our prefix and stops once past it; the unpaged fallback filters the full list.
133
+ if (store.listExecutionsPage === undefined) {
134
+ for (const id of (await store.listExecutions?.()) ?? [])
135
+ if (id.startsWith(prefix))
136
+ yield id.slice(prefix.length);
137
+ return;
138
+ }
139
+ let cursor = prefix.slice(0, -1);
140
+ for (;;) {
141
+ const page = await store.listExecutionsPage({
142
+ ...(cursor !== undefined && { cursor }),
143
+ limit: 500,
144
+ });
145
+ for (const id of page.executionIds) {
146
+ if (id.startsWith(prefix))
147
+ yield id.slice(prefix.length);
148
+ else if (id > prefix)
149
+ return;
150
+ }
151
+ if (page.nextCursor === undefined || page.nextCursor === cursor)
152
+ return;
153
+ cursor = page.nextCursor;
154
+ }
155
+ },
156
+ }
157
+ : {}),
158
+ };
159
+ }
160
+ function toRecords(events) {
161
+ return events
162
+ .slice()
163
+ .sort((a, b) => a.sequence - b.sequence)
164
+ .map((e) => ({
165
+ sequence: e.sequence,
166
+ type: e.eventType,
167
+ payload: clone(e.payload),
168
+ at: typeof e.metadata?.at === "string" ? e.metadata.at : new Date(e.timestamp).toISOString(),
169
+ }));
170
+ }
171
+ /** Sequences `from..to` (inclusive) of a stream: the store's `readRange`, else `readFrom`/`read` filtered. */
172
+ async function readWindow(store, id, from, to) {
173
+ if (store.readRange !== undefined)
174
+ return store.readRange(id, from, to);
175
+ return (await store.read(id)).filter((e) => e.sequence >= from && e.sequence <= to);
176
+ }
177
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@loomwork/ui-lineage",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Experience lineage runtime for loom-ui: a head pointer per experience with compare-and-set advance, version walk, branch and revert as new versions, and the EXPERIENCE_COMPOSED/PROMOTED protocol with replay verification, over loom's ContentStore and an EventStore-shaped seam",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "module": "./dist/esm/index.js",
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "node": "./dist/index.js",
13
+ "import": "./dist/esm/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "@loomwork/event-runtime": "^0.1.0",
19
+ "@loomwork/plugin-content": "^0.1.0",
20
+ "zod": "^3.23.8",
21
+ "@loomwork/ui-core": "^0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@loomwork/plugin-crypto": "^0.1.0",
25
+ "@types/node": "^22.0.0",
26
+ "typescript": "^5.6.3",
27
+ "vitest": "^2.1.8",
28
+ "@loomwork/ui-planner": "^0.1.0"
29
+ },
30
+ "license": "Apache-2.0",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/chhetrisushil/loom-ui.git",
34
+ "directory": "packages/lineage"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "src",
39
+ "!src/**/*.test.ts",
40
+ "!src/**/*.test.tsx",
41
+ "!src/**/*.test-support.ts",
42
+ "!src/**/__tests__",
43
+ "!src/**/__fixtures__",
44
+ "!src/**/__snapshots__",
45
+ "!src/**/__golden__",
46
+ "LICENSE",
47
+ "NOTICE"
48
+ ],
49
+ "publishConfig": {
50
+ "access": "public",
51
+ "tag": "next"
52
+ },
53
+ "engines": {
54
+ "node": ">=20.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc --build && rm -rf dist/esm && tsc -p tsconfig.esm.json",
58
+ "typecheck": "tsc --noEmit",
59
+ "typecheck:tests": "tsc -p tsconfig.test.json",
60
+ "test": "vitest run",
61
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
62
+ }
6
63
  }