@loomwork/ui-changes 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +134 -2
  4. package/dist/conformance.d.ts +18 -0
  5. package/dist/conformance.d.ts.map +1 -0
  6. package/dist/conformance.js +243 -0
  7. package/dist/conformance.js.map +1 -0
  8. package/dist/cursor.d.ts +43 -0
  9. package/dist/cursor.d.ts.map +1 -0
  10. package/dist/cursor.js +50 -0
  11. package/dist/cursor.js.map +1 -0
  12. package/dist/esm/conformance.js +239 -0
  13. package/dist/esm/conformance.js.map +1 -0
  14. package/dist/esm/cursor.js +44 -0
  15. package/dist/esm/cursor.js.map +1 -0
  16. package/dist/esm/feed.js +301 -0
  17. package/dist/esm/feed.js.map +1 -0
  18. package/dist/esm/index.js +6 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/signal.js +141 -0
  21. package/dist/esm/signal.js.map +1 -0
  22. package/dist/esm/untrusted.js +14 -0
  23. package/dist/esm/untrusted.js.map +1 -0
  24. package/dist/feed.d.ts +125 -0
  25. package/dist/feed.d.ts.map +1 -0
  26. package/dist/feed.js +305 -0
  27. package/dist/feed.js.map +1 -0
  28. package/dist/index.d.ts +10 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +20 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/signal.d.ts +33 -0
  33. package/dist/signal.d.ts.map +1 -0
  34. package/dist/signal.js +145 -0
  35. package/dist/signal.js.map +1 -0
  36. package/dist/untrusted.d.ts +5 -0
  37. package/dist/untrusted.d.ts.map +1 -0
  38. package/dist/untrusted.js +17 -0
  39. package/dist/untrusted.js.map +1 -0
  40. package/package.json +60 -3
  41. package/src/conformance.ts +248 -0
  42. package/src/cursor.ts +89 -0
  43. package/src/feed.ts +446 -0
  44. package/src/index.ts +18 -0
  45. package/src/signal.ts +200 -0
  46. package/src/untrusted.ts +16 -0
package/dist/feed.js ADDED
@@ -0,0 +1,305 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LineageChangeFeed = exports.MAX_PAGE = exports.DEFAULT_PAGE = void 0;
4
+ const ui_core_1 = require("@loomwork/ui-core");
5
+ const ui_lineage_1 = require("@loomwork/ui-lineage");
6
+ exports.DEFAULT_PAGE = 100;
7
+ exports.MAX_PAGE = 1000;
8
+ const err = (code, message) => ({
9
+ ok: false,
10
+ finding: { code, severity: "error", message },
11
+ });
12
+ const asCursor = (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0 ? v : undefined;
13
+ /**
14
+ * A `ChangeFeed` over a `Lineage`. `read` folds the whole line (validating it: a malformed log is a
15
+ * finding, never partial events) so it is O(log length) per call; a deployment with very long lines
16
+ * pages with `limit` but still pays the fold: cache above this seam, not inside it.
17
+ */
18
+ class LineageChangeFeed {
19
+ lineage;
20
+ events;
21
+ signal;
22
+ policy;
23
+ constructor(opts) {
24
+ this.policy = (0, ui_core_1.mergeReadPolicy)(opts.lineage.readPolicy, opts.readPolicy, opts);
25
+ this.lineage = opts.lineage;
26
+ this.events = opts.events;
27
+ this.signal = opts.signal;
28
+ }
29
+ async read(experienceId, opts = {}) {
30
+ const after = opts.after === undefined ? 0 : asCursor(opts.after);
31
+ if (after === undefined)
32
+ return err("cursor-invalid", "after is not a non-negative integer");
33
+ const limit = opts.limit === undefined
34
+ ? exports.DEFAULT_PAGE
35
+ : Number.isSafeInteger(opts.limit) && opts.limit >= 1
36
+ ? Math.min(opts.limit, exports.MAX_PAGE)
37
+ : undefined;
38
+ if (limit === undefined)
39
+ return err("limit-invalid", "limit is not a positive integer");
40
+ let records;
41
+ try {
42
+ records = await this.events.read(experienceId);
43
+ }
44
+ catch (e) {
45
+ // The feed INHERITS the lineage's `confirmErased` hook (it classifies through `lineage.block`):
46
+ // a confirmed erasure is `line-erased`, any other unreadable line is `line-unreadable` (or
47
+ // `artifact-unsealed`); both fail closed. Anything else propagates unchanged.
48
+ const b = await this.lineage.block(experienceId, e);
49
+ if (b === undefined)
50
+ throw e;
51
+ return err(b instanceof ui_lineage_1.LineErasedError ? "line-erased" : b.reason, b instanceof ui_lineage_1.LineErasedError
52
+ ? `lineage "${experienceId}" is erased: its key is destroyed (confirmed)`
53
+ : `lineage "${experienceId}" is unreadable: its key is unavailable on this node or its ciphertext does not open; not confirmed erased`);
54
+ }
55
+ const fold = (0, ui_lineage_1.foldLineage)(experienceId, records);
56
+ if (!fold.ok)
57
+ return { ok: false, finding: fold.finding };
58
+ const out = [];
59
+ let promoted = null;
60
+ let more = false;
61
+ for (const rec of records) {
62
+ // The fold validated every record, so these payload reads are of checked shapes.
63
+ const p = rec.payload;
64
+ const version = fold.state.versions.get(p.versionHash);
65
+ let kind;
66
+ let base;
67
+ if (rec.type === ui_lineage_1.EXPERIENCE_PROMOTED) {
68
+ kind = "promoted";
69
+ base = promoted === null ? null : { experienceId, versionHash: promoted };
70
+ promoted = p.versionHash;
71
+ }
72
+ else {
73
+ kind =
74
+ rec.type === ui_lineage_1.EXPERIENCE_REVERTED
75
+ ? "reverted"
76
+ : rec.type === ui_lineage_1.EXPERIENCE_BRANCHED
77
+ ? "branched"
78
+ : "composed";
79
+ const parent = version?.parents[0];
80
+ base =
81
+ kind === "branched" && version?.from !== undefined
82
+ ? { experienceId: version.from.experienceId, versionHash: version.from.versionHash }
83
+ : parent === undefined
84
+ ? null
85
+ : { experienceId, versionHash: parent };
86
+ }
87
+ if (rec.sequence <= after)
88
+ continue;
89
+ if (out.length === limit) {
90
+ more = true;
91
+ break;
92
+ }
93
+ out.push({
94
+ id: `${experienceId}#${rec.sequence}`,
95
+ experienceId,
96
+ sequence: rec.sequence,
97
+ at: rec.at,
98
+ kind,
99
+ versionHash: p.versionHash,
100
+ base,
101
+ });
102
+ }
103
+ return {
104
+ ok: true,
105
+ events: out,
106
+ cursor: out.at(-1)?.sequence ?? after,
107
+ more,
108
+ tip: fold.state.sequence,
109
+ };
110
+ }
111
+ subscribe(experienceId, handler, opts = {}) {
112
+ let cursor = asCursor(opts.after) ?? 0;
113
+ let stopped = false;
114
+ let running = false;
115
+ let again = false;
116
+ let timer;
117
+ let failures = 0; // consecutive failed passes, for the backoff
118
+ let poisonSeq = 0;
119
+ let poisonAttempts = 0;
120
+ const baseMs = Math.max(1, finite(opts.retry?.baseMs, 250));
121
+ const maxMs = Math.max(baseMs, finite(opts.retry?.maxMs, 30_000));
122
+ const report = (e) => {
123
+ try {
124
+ opts.onError?.(e);
125
+ }
126
+ catch {
127
+ // a reporting hook must not break delivery
128
+ }
129
+ };
130
+ // The cursor is behind the tip whenever a pass failed: retry on a timer, since a quiet line
131
+ // raises no signal. Delay = min(max, base * 2^n), jittered into [50%, 100%].
132
+ const arm = () => {
133
+ if (stopped || timer !== undefined)
134
+ return;
135
+ const delay = Math.min(maxMs, baseMs * 2 ** Math.min(failures, 30));
136
+ failures += 1;
137
+ timer = setTimeout(() => {
138
+ timer = undefined;
139
+ void pump();
140
+ }, Math.max(1, Math.round(delay * (0.5 + Math.random() / 2))));
141
+ timer.unref?.();
142
+ };
143
+ const skipPoison = async (e) => {
144
+ if (poisonSeq !== e.sequence) {
145
+ poisonSeq = e.sequence;
146
+ poisonAttempts = 0;
147
+ }
148
+ poisonAttempts += 1;
149
+ if (opts.onPoison === undefined)
150
+ return false;
151
+ try {
152
+ return (await opts.onPoison(e, poisonAttempts)) === true;
153
+ }
154
+ catch (thrown) {
155
+ report(thrown);
156
+ return false;
157
+ }
158
+ };
159
+ const pump = async () => {
160
+ if (running) {
161
+ again = true;
162
+ return;
163
+ }
164
+ running = true;
165
+ let failed = false;
166
+ try {
167
+ do {
168
+ again = false;
169
+ for (;;) {
170
+ if (stopped)
171
+ return;
172
+ const r = await this.read(experienceId, { after: cursor });
173
+ if (!r.ok) {
174
+ report(r.finding);
175
+ // A CONFIRMED erasure is terminal: report once and stop (no retry, no further wakes).
176
+ // An unconfirmed `line-unreadable` keeps retrying: the key may come back to this node.
177
+ if (r.finding.code === "line-erased") {
178
+ terminate();
179
+ return;
180
+ }
181
+ failed = true;
182
+ return;
183
+ }
184
+ for (const e of r.events) {
185
+ if (stopped)
186
+ return;
187
+ try {
188
+ await handler(e);
189
+ }
190
+ catch (thrown) {
191
+ report(thrown);
192
+ if (await skipPoison(e)) {
193
+ cursor = e.sequence;
194
+ continue;
195
+ }
196
+ failed = true;
197
+ return; // not advanced: redelivered by the retry timer or the next wake
198
+ }
199
+ cursor = e.sequence;
200
+ failures = 0;
201
+ }
202
+ if (!r.more)
203
+ break;
204
+ }
205
+ } while (again && !stopped);
206
+ }
207
+ catch (thrown) {
208
+ report(thrown);
209
+ failed = true;
210
+ }
211
+ finally {
212
+ running = false;
213
+ if (failed)
214
+ arm();
215
+ else
216
+ failures = 0;
217
+ }
218
+ };
219
+ let unwatch;
220
+ const terminate = () => {
221
+ stopped = true;
222
+ if (timer !== undefined)
223
+ clearTimeout(timer);
224
+ timer = undefined;
225
+ unwatch?.();
226
+ unwatch = undefined;
227
+ };
228
+ unwatch = this.signal.watch(experienceId, () => void pump());
229
+ void pump();
230
+ return terminate;
231
+ }
232
+ async describe(event, opts = {}) {
233
+ // The caller's event is a CLAIM about the log, not the log: its experience and sequence are
234
+ // used only to find the recorded event, and `kind`/`base`/`versionHash` come from the fold.
235
+ // An event that does not match the record at its position is refused (a forged `base` would
236
+ // otherwise describe a different line's nodes: a confused deputy).
237
+ const seq = event?.sequence;
238
+ if (typeof event?.experienceId !== "string" || !Number.isSafeInteger(seq) || seq < 1)
239
+ return err("event-invalid", "the event has no readable line and sequence");
240
+ const at = await this.read(event.experienceId, { after: seq - 1, limit: 1 });
241
+ if (!at.ok)
242
+ return { ok: false, finding: at.finding };
243
+ const truth = at.events[0];
244
+ if (truth === undefined || truth.sequence !== seq)
245
+ return err("event-unknown", "the event is not in the line's log");
246
+ if (truth.versionHash !== event.versionHash ||
247
+ truth.kind !== event.kind ||
248
+ JSON.stringify(truth.base) !== JSON.stringify(event.base ?? null))
249
+ return err("event-mismatch", "the event does not match the log's record at its sequence");
250
+ const versions = await this.lineage.versions(truth.experienceId);
251
+ if (!versions.ok)
252
+ return refusal(versions.refusal);
253
+ const record = versions.value.find((v) => v.versionHash === truth.versionHash);
254
+ if (record === undefined)
255
+ return err("version-unknown", `"${truth.versionHash}" is not a version of the line`);
256
+ const next = await this.lineage.get(truth.experienceId, truth.versionHash);
257
+ if (!next.ok)
258
+ return refusal(next.refusal);
259
+ let prev = null;
260
+ if (truth.base !== null) {
261
+ const p = await this.lineage.get(truth.base.experienceId, truth.base.versionHash);
262
+ if (!p.ok)
263
+ return refusal(p.refusal);
264
+ prev = p.value;
265
+ }
266
+ // The ops and the summary belong to ONE version. They describe this event when it IS that
267
+ // version's creation, or when a promotion spans exactly that one step.
268
+ const own = truth.kind !== "promoted" || record.parents.includes(truth.base?.versionHash ?? "");
269
+ // The bound policy first: a per-call value can only ADD to it (a table is joined strictest-wins,
270
+ // `"deny"` sticks, a bound projection catalogue is not replaced), so `{}` or an explicit
271
+ // `undefined` per call cannot lower what the host bound at construction.
272
+ const policy = (0, ui_core_1.mergeReadPolicy)(this.policy, opts);
273
+ return {
274
+ ok: true,
275
+ description: (0, ui_core_1.describeChange)(prev, next.value, {
276
+ ...opts,
277
+ // AFTER `...opts`: the joined policy wins over every per-call spelling of these fields.
278
+ ...(policy.projections !== undefined && { projections: policy.projections }),
279
+ ...(policy.hydrationProjectionId !== undefined && {
280
+ hydrationProjectionId: policy.hydrationProjectionId,
281
+ }),
282
+ ...(policy.declaredToolClasses !== undefined && {
283
+ declaredToolClasses: policy.declaredToolClasses,
284
+ }),
285
+ ...(policy.undeclared !== undefined && { undeclared: policy.undeclared }),
286
+ ...(own && record.ops.length > 0 && { ops: record.ops }),
287
+ ...(own && record.summary !== undefined && { summary: record.summary }),
288
+ ...(own && record.summaryClass !== undefined && { summaryClass: record.summaryClass }),
289
+ }),
290
+ };
291
+ }
292
+ }
293
+ exports.LineageChangeFeed = LineageChangeFeed;
294
+ const finite = (v, dflt) => typeof v === "number" && Number.isFinite(v) ? v : dflt;
295
+ function refusal(r) {
296
+ return {
297
+ ok: false,
298
+ finding: r.finding ?? {
299
+ code: r.kind,
300
+ severity: "error",
301
+ message: `the lineage refused: ${r.kind}`,
302
+ },
303
+ };
304
+ }
305
+ //# sourceMappingURL=feed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feed.js","sourceRoot":"","sources":["../src/feed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { LineageChangeFeed, DEFAULT_PAGE, MAX_PAGE } from "./feed";
2
+ export type { ChangeEvent, ChangeEventKind, ChangeFeed, DescribeResult, LineageChangeFeedOptions, ReadResult, RetryOptions, SubscribeOptions, } from "./feed";
3
+ export { InMemoryUnreadStore, markRead, unreadChanges } from "./cursor";
4
+ export type { UnreadResult, UnreadStore } from "./cursor";
5
+ export { eventStoreHeadSignal, pollingHeadSignal } from "./signal";
6
+ export type { PollingOptions, PushOptions, SignalOptions } from "./signal";
7
+ export { checkChangeFeedConformance, checkUnreadStoreConformance } from "./conformance";
8
+ export type { FeedHarness } from "./conformance";
9
+ export { summaryAsTainted } from "./untrusted";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACnE,YAAY,EACV,WAAW,EACX,eAAe,EACf,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,UAAU,EACV,YAAY,EACZ,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACnE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.summaryAsTainted = exports.checkUnreadStoreConformance = exports.checkChangeFeedConformance = exports.pollingHeadSignal = exports.eventStoreHeadSignal = exports.unreadChanges = exports.markRead = exports.InMemoryUnreadStore = exports.MAX_PAGE = exports.DEFAULT_PAGE = exports.LineageChangeFeed = void 0;
4
+ var feed_1 = require("./feed");
5
+ Object.defineProperty(exports, "LineageChangeFeed", { enumerable: true, get: function () { return feed_1.LineageChangeFeed; } });
6
+ Object.defineProperty(exports, "DEFAULT_PAGE", { enumerable: true, get: function () { return feed_1.DEFAULT_PAGE; } });
7
+ Object.defineProperty(exports, "MAX_PAGE", { enumerable: true, get: function () { return feed_1.MAX_PAGE; } });
8
+ var cursor_1 = require("./cursor");
9
+ Object.defineProperty(exports, "InMemoryUnreadStore", { enumerable: true, get: function () { return cursor_1.InMemoryUnreadStore; } });
10
+ Object.defineProperty(exports, "markRead", { enumerable: true, get: function () { return cursor_1.markRead; } });
11
+ Object.defineProperty(exports, "unreadChanges", { enumerable: true, get: function () { return cursor_1.unreadChanges; } });
12
+ var signal_1 = require("./signal");
13
+ Object.defineProperty(exports, "eventStoreHeadSignal", { enumerable: true, get: function () { return signal_1.eventStoreHeadSignal; } });
14
+ Object.defineProperty(exports, "pollingHeadSignal", { enumerable: true, get: function () { return signal_1.pollingHeadSignal; } });
15
+ var conformance_1 = require("./conformance");
16
+ Object.defineProperty(exports, "checkChangeFeedConformance", { enumerable: true, get: function () { return conformance_1.checkChangeFeedConformance; } });
17
+ Object.defineProperty(exports, "checkUnreadStoreConformance", { enumerable: true, get: function () { return conformance_1.checkUnreadStoreConformance; } });
18
+ var untrusted_1 = require("./untrusted");
19
+ Object.defineProperty(exports, "summaryAsTainted", { enumerable: true, get: function () { return untrusted_1.summaryAsTainted; } });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+BAAmE;AAA1D,yGAAA,iBAAiB,OAAA;AAAE,oGAAA,YAAY,OAAA;AAAE,gGAAA,QAAQ,OAAA;AAWlD,mCAAwE;AAA/D,6GAAA,mBAAmB,OAAA;AAAE,kGAAA,QAAQ,OAAA;AAAE,uGAAA,aAAa,OAAA;AAErD,mCAAmE;AAA1D,8GAAA,oBAAoB,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAEhD,6CAAwF;AAA/E,yHAAA,0BAA0B,OAAA;AAAE,0HAAA,2BAA2B,OAAA;AAEhE,yCAA+C;AAAtC,6GAAA,gBAAgB,OAAA"}
@@ -0,0 +1,33 @@
1
+ import type { EventStore } from "@loomwork/event-runtime";
2
+ import type { HeadSignal } from "@loomwork/ui-core";
3
+ import { type LineageStore } from "@loomwork/ui-lineage";
4
+ export interface SignalOptions {
5
+ /** A read or fold that failed. The watcher keeps going: the next trigger tries again. */
6
+ readonly onError?: (err: unknown) => void;
7
+ /**
8
+ * Has this line's erasure been confirmed? (The same host hook as `LineageOptions.confirmErased`;
9
+ * a signal is built over a store, not a lineage, so it takes its own.) A CONFIRMED erasure reports
10
+ * one `LineErasedError` and the watcher goes terminal (no more checks). An unconfirmed unreadable
11
+ * line reports `LineUnreadableError` on every check and keeps retrying.
12
+ */
13
+ readonly confirmErased?: (experienceId: string) => Promise<boolean>;
14
+ }
15
+ export interface PollingOptions extends SignalOptions {
16
+ /** Milliseconds between checks (default 2000; floor 10). */
17
+ readonly intervalMs?: number;
18
+ /** Injectable timer: run `fn` every `ms`, return a canceller. Default `setInterval` (unref'd). */
19
+ readonly schedule?: (fn: () => void, ms: number) => () => void;
20
+ }
21
+ export declare function pollingHeadSignal(store: LineageStore, opts?: PollingOptions): HeadSignal;
22
+ export interface PushOptions extends SignalOptions {
23
+ /**
24
+ * A safety-net poll (ms; floor 10) beside the push subscription: a push can be missed (the
25
+ * subscription failed to attach, a notify was dropped), and the fallback bounds that to one
26
+ * interval. Absent = push only.
27
+ */
28
+ readonly fallbackIntervalMs?: number;
29
+ /** Injectable timer for the fallback; default `setInterval` (unref'd). */
30
+ readonly schedule?: (fn: () => void, ms: number) => () => void;
31
+ }
32
+ export declare function eventStoreHeadSignal(events: EventStore, store: LineageStore, opts?: PushOptions): HeadSignal;
33
+ //# sourceMappingURL=signal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal.d.ts","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,sBAAsB,CAAC;AAmB9B,MAAM,WAAW,aAAa;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACrE;AAwED,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;CAChE;AAQD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,GAAE,cAAmB,GAAG,UAAU,CAsB5F;AAED,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,MAAM,IAAI,CAAC;CAChE;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,WAAgB,GACrB,UAAU,CAuCZ"}
package/dist/signal.js ADDED
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pollingHeadSignal = pollingHeadSignal;
4
+ exports.eventStoreHeadSignal = eventStoreHeadSignal;
5
+ const ui_lineage_1 = require("@loomwork/ui-lineage");
6
+ const ui_lineage_2 = require("@loomwork/ui-lineage");
7
+ /** One watcher's check: at most one read in flight, reports each new tip once. */
8
+ function checker(store, experienceId, onChange, onError, confirmErased, onTerminal) {
9
+ let seen = 0;
10
+ let stopped = false;
11
+ let busy = false;
12
+ let rerun = false;
13
+ const fail = (e) => {
14
+ try {
15
+ onError?.(e);
16
+ }
17
+ catch {
18
+ // never break the signal
19
+ }
20
+ };
21
+ const check = async () => {
22
+ if (stopped)
23
+ return;
24
+ if (busy) {
25
+ rerun = true;
26
+ return;
27
+ }
28
+ busy = true;
29
+ try {
30
+ do {
31
+ rerun = false;
32
+ const records = await store.read(experienceId);
33
+ if (stopped || records.length <= seen)
34
+ continue;
35
+ seen = records.length;
36
+ const fold = (0, ui_lineage_1.foldLineage)(experienceId, records);
37
+ if (!fold.ok) {
38
+ fail(fold.finding);
39
+ continue;
40
+ }
41
+ try {
42
+ onChange({
43
+ experienceId,
44
+ sequence: fold.state.sequence,
45
+ head: fold.state.head,
46
+ promoted: fold.state.promoted,
47
+ });
48
+ }
49
+ catch (e) {
50
+ fail(e);
51
+ }
52
+ } while (rerun && !stopped);
53
+ }
54
+ catch (e) {
55
+ // an unreadable line reports a typed error; anything else is reported unchanged
56
+ const b = await (0, ui_lineage_1.classifyLineFailure)(experienceId, e, confirmErased);
57
+ fail(b ?? e);
58
+ if (b instanceof ui_lineage_1.LineErasedError) {
59
+ // confirmed erased: terminal, reported once
60
+ stopped = true;
61
+ onTerminal();
62
+ }
63
+ }
64
+ finally {
65
+ busy = false;
66
+ }
67
+ };
68
+ return {
69
+ check,
70
+ stop: () => {
71
+ stopped = true;
72
+ },
73
+ };
74
+ }
75
+ const defaultSchedule = (fn, ms) => {
76
+ const t = setInterval(fn, ms);
77
+ t.unref?.();
78
+ return () => clearInterval(t);
79
+ };
80
+ function pollingHeadSignal(store, opts = {}) {
81
+ const intervalMs = Math.max(10, Number.isFinite(opts.intervalMs) ? opts.intervalMs : 2000);
82
+ const schedule = opts.schedule ?? defaultSchedule;
83
+ return {
84
+ watch(experienceId, onChange) {
85
+ let cancel;
86
+ let ended = false;
87
+ const c = checker(store, experienceId, onChange, opts.onError, opts.confirmErased, () => {
88
+ ended = true;
89
+ cancel?.();
90
+ });
91
+ void c.check();
92
+ if (!ended)
93
+ cancel = schedule(() => void c.check(), intervalMs);
94
+ return () => {
95
+ c.stop();
96
+ cancel?.();
97
+ };
98
+ },
99
+ };
100
+ }
101
+ function eventStoreHeadSignal(events, store, opts = {}) {
102
+ const fallback = Number.isFinite(opts.fallbackIntervalMs)
103
+ ? Math.max(10, opts.fallbackIntervalMs)
104
+ : undefined;
105
+ const schedule = opts.schedule ?? defaultSchedule;
106
+ const report = (e) => {
107
+ try {
108
+ opts.onError?.(e);
109
+ }
110
+ catch {
111
+ // never break the signal
112
+ }
113
+ };
114
+ return {
115
+ watch(experienceId, onChange) {
116
+ let cancel;
117
+ let off;
118
+ let stopped = false;
119
+ const c = checker(store, experienceId, onChange, opts.onError, opts.confirmErased, () => {
120
+ stopped = true;
121
+ cancel?.();
122
+ off?.();
123
+ });
124
+ events
125
+ .subscribe(`${ui_lineage_2.LINEAGE_STREAM_PREFIX}${experienceId}`, () => void c.check())
126
+ .then((u) => {
127
+ if (stopped)
128
+ u();
129
+ else
130
+ off = u;
131
+ })
132
+ .catch(report);
133
+ void c.check();
134
+ if (!stopped && fallback !== undefined)
135
+ cancel = schedule(() => void c.check(), fallback);
136
+ return () => {
137
+ stopped = true;
138
+ c.stop();
139
+ cancel?.();
140
+ off?.();
141
+ };
142
+ },
143
+ };
144
+ }
145
+ //# sourceMappingURL=signal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signal.js","sourceRoot":"","sources":["../src/signal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type TaintedValue } from "@loomwork/classify";
2
+ import type { UntrustedText } from "@loomwork/ui-core";
3
+ /** The summary as an ADR 0085 tainted value, origin `loom-ui:change-summary`. */
4
+ export declare function summaryAsTainted(summary: UntrustedText): TaintedValue<string>;
5
+ //# sourceMappingURL=untrusted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrusted.d.ts","sourceRoot":"","sources":["../src/untrusted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAW,MAAM,oBAAoB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAWvD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,CAE7E"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.summaryAsTainted = summaryAsTainted;
4
+ const classify_1 = require("@loomwork/classify");
5
+ // ── The summary as loom's untrusted value ─────────────────────────────────────
6
+ // A change summary is model text. `UntrustedText` marks it for DISPLAY; when a host feeds it to
7
+ // another model (a digest, a notification writer) it must cross as loom's ADR 0085 taint
8
+ // (`@loomwork/classify` `TaintedValue`), which `@loomwork/llm`'s `guardRequest` refuses in any instruction
9
+ // position and fences in a data position. This is a server-side helper: the taint package is a
10
+ // loom kernel-side dependency and must not enter a client bundle.
11
+ //
12
+ // NEVER put a summary in a prompt's instruction (system) position, tainted or not.
13
+ /** The summary as an ADR 0085 tainted value, origin `loom-ui:change-summary`. */
14
+ function summaryAsTainted(summary) {
15
+ return (0, classify_1.tainted)(summary.text, "loom-ui:change-summary");
16
+ }
17
+ //# sourceMappingURL=untrusted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrusted.js","sourceRoot":"","sources":["../src/untrusted.ts"],"names":[],"mappings":";;AAaA,4CAEC;AAfD,iDAAgE;AAGhE,iFAAiF;AACjF,gGAAgG;AAChG,yFAAyF;AACzF,2GAA2G;AAC3G,+FAA+F;AAC/F,kEAAkE;AAClE,EAAE;AACF,mFAAmF;AAEnF,iFAAiF;AACjF,SAAgB,gBAAgB,CAAC,OAAsB;IACrD,OAAO,IAAA,kBAAO,EAAC,OAAO,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC;AACzD,CAAC"}