@loomwork/middleware 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 (59) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +82 -2
  4. package/dist/claimCheck.d.ts +179 -0
  5. package/dist/claimCheck.d.ts.map +1 -0
  6. package/dist/claimCheck.js +241 -0
  7. package/dist/claimCheck.js.map +1 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +48 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/killSwitchRegistry.d.ts +74 -0
  13. package/dist/killSwitchRegistry.d.ts.map +1 -0
  14. package/dist/killSwitchRegistry.js +108 -0
  15. package/dist/killSwitchRegistry.js.map +1 -0
  16. package/dist/metering.d.ts +81 -0
  17. package/dist/metering.d.ts.map +1 -0
  18. package/dist/metering.js +153 -0
  19. package/dist/metering.js.map +1 -0
  20. package/dist/nestedBudget.d.ts +60 -0
  21. package/dist/nestedBudget.d.ts.map +1 -0
  22. package/dist/nestedBudget.js +134 -0
  23. package/dist/nestedBudget.js.map +1 -0
  24. package/dist/profile.d.ts +38 -0
  25. package/dist/profile.d.ts.map +1 -0
  26. package/dist/profile.js +70 -0
  27. package/dist/profile.js.map +1 -0
  28. package/dist/rateLimit.d.ts +40 -0
  29. package/dist/rateLimit.d.ts.map +1 -0
  30. package/dist/rateLimit.js +83 -0
  31. package/dist/rateLimit.js.map +1 -0
  32. package/dist/redaction.d.ts +66 -0
  33. package/dist/redaction.d.ts.map +1 -0
  34. package/dist/redaction.js +141 -0
  35. package/dist/redaction.js.map +1 -0
  36. package/dist/retry.d.ts +50 -0
  37. package/dist/retry.d.ts.map +1 -0
  38. package/dist/retry.js +98 -0
  39. package/dist/retry.js.map +1 -0
  40. package/dist/safety.d.ts +93 -0
  41. package/dist/safety.d.ts.map +1 -0
  42. package/dist/safety.js +152 -0
  43. package/dist/safety.js.map +1 -0
  44. package/dist/streamTokenBudget.d.ts +58 -0
  45. package/dist/streamTokenBudget.d.ts.map +1 -0
  46. package/dist/streamTokenBudget.js +47 -0
  47. package/dist/streamTokenBudget.js.map +1 -0
  48. package/package.json +55 -3
  49. package/src/claimCheck.ts +410 -0
  50. package/src/index.ts +79 -0
  51. package/src/killSwitchRegistry.ts +168 -0
  52. package/src/metering.ts +226 -0
  53. package/src/nestedBudget.ts +200 -0
  54. package/src/profile.ts +86 -0
  55. package/src/rateLimit.ts +126 -0
  56. package/src/redaction.ts +184 -0
  57. package/src/retry.ts +133 -0
  58. package/src/safety.ts +235 -0
  59. package/src/streamTokenBudget.ts +98 -0
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.streamResult = streamResult;
4
+ exports.isStreamResult = isStreamResult;
5
+ exports.isClaimCheck = isClaimCheck;
6
+ exports.claimCheckMiddleware = claimCheckMiddleware;
7
+ exports.previewDigest = previewDigest;
8
+ exports.resolveClaimCheck = resolveClaimCheck;
9
+ exports.resolveClaimCheckBytes = resolveClaimCheckBytes;
10
+ exports.resolveClaimChecks = resolveClaimChecks;
11
+ const classify_1 = require("@loomwork/classify");
12
+ /** Wrap a byte stream as a tool result; Node `Readable`s satisfy the iterable directly. */
13
+ function streamResult(stream, opts = {}) {
14
+ return {
15
+ __loomStreamResult: true,
16
+ stream,
17
+ ...(opts.digest !== undefined && { digest: opts.digest }),
18
+ ...(opts.codec !== undefined && { codec: opts.codec }),
19
+ };
20
+ }
21
+ function isStreamResult(value) {
22
+ return (typeof value === "object" &&
23
+ value !== null &&
24
+ value.__loomStreamResult === true &&
25
+ typeof value.stream === "object");
26
+ }
27
+ function isClaimCheck(value) {
28
+ return (typeof value === "object" &&
29
+ value !== null &&
30
+ value.__loomClaimCheck === true &&
31
+ typeof value.ref?.__loomContent === "string");
32
+ }
33
+ /**
34
+ * CC-1 — claim-check middleware on the ADR 0006 seam. Runs only when the effect
35
+ * actually executes (replayed/completed steps short-circuit upstream), so replay
36
+ * determinism is automatic: the envelope is the recorded value. Crash-recovery
37
+ * re-runs re-offload the same bytes to the same content address (`put` is
38
+ * idempotent by hash), reproducing an identical envelope.
39
+ *
40
+ * Results that JSON cannot encode (circular, undefined) pass through untouched —
41
+ * offload is impossible for what the journal could not record anyway.
42
+ */
43
+ function claimCheckMiddleware(options) {
44
+ const cap = options.inlineCapBytes ?? 16 * 1024;
45
+ const encoder = new TextEncoder();
46
+ return async (ctx, _input, next) => {
47
+ const result = await next();
48
+ const access = { executionId: ctx.executionId, workflowId: ctx.workflowId };
49
+ if (options.passThrough?.(result, ctx.toolId) === true)
50
+ return result;
51
+ // already an envelope (stacked wiring) — never double-wrap; unless envelopes are DATA (ADR 0140 M7)
52
+ const forged = options.envelopesAreData === true && isClaimCheck(result);
53
+ if (!forged && isClaimCheck(result))
54
+ return result;
55
+ const retain = typeof options.retain === "function" ? options.retain(ctx.toolId) : options.retain === true;
56
+ // ST-2 — stream-typed result: ALWAYS offloads (a stream is a declared-big
57
+ // payload), never buffered by the middleware (a counting wrapper is the only
58
+ // thing between the tool and the store).
59
+ if (isStreamResult(result)) {
60
+ if (options.store.putStream === undefined) {
61
+ throw new TypeError(`claim-check: tool "${ctx.toolId ?? ctx.stepId}" returned a streamed result but the content store does not implement putStream() (ST-1, ADR 0059)`);
62
+ }
63
+ let size = 0;
64
+ const source = result.stream;
65
+ const counted = (async function* () {
66
+ for await (const chunk of source) {
67
+ size += chunk.byteLength;
68
+ yield chunk;
69
+ }
70
+ })();
71
+ let streamedRef;
72
+ try {
73
+ streamedRef = await options.store.putStream(counted, access);
74
+ }
75
+ finally {
76
+ // W-audit leak fix: if putStream threw mid-consumption, `counted` is
77
+ // suspended at a yield and nobody would ever finalize it — resuming it
78
+ // with a return completion propagates through its for-await to the
79
+ // SOURCE iterator's return(), closing whatever the tool handed us
80
+ // (file handle, socket). A no-op when the stream was fully consumed.
81
+ await counted.return(undefined).then(() => { }, () => { } // the offload is already failing; source cleanup errors don't mask it
82
+ );
83
+ }
84
+ const envelope = {
85
+ __loomClaimCheck: true,
86
+ ref: { __loomContent: streamedRef.__loomContent },
87
+ size,
88
+ codec: result.codec ?? "bytes",
89
+ ...(result.digest !== undefined && { digest: result.digest }),
90
+ ...(retain && { retain: true }),
91
+ };
92
+ options.onOffload?.({
93
+ ...(ctx.toolId !== undefined && { toolId: ctx.toolId }),
94
+ stepId: ctx.stepId,
95
+ executionId: ctx.executionId,
96
+ workflowId: ctx.workflowId,
97
+ size,
98
+ contentAddress: streamedRef.__loomContent,
99
+ });
100
+ return envelope;
101
+ }
102
+ let json;
103
+ try {
104
+ json = JSON.stringify(result);
105
+ }
106
+ catch {
107
+ return result;
108
+ }
109
+ if (json === undefined)
110
+ return result;
111
+ const bytes = encoder.encode(json);
112
+ // ADR 0140 D11: under `envelopesAreData` a lookalike envelope NESTED anywhere in the result is data
113
+ // too: the whole result is force-offloaded, so the log never records a tool-authored
114
+ // `{ __loomClaimCheck, ref, retain }` the sweep or erasure could mistake for one this middleware wrote.
115
+ const nestedForged = options.envelopesAreData === true && json.includes('"__loomClaimCheck"');
116
+ if (!forged && !nestedForged && bytes.byteLength <= cap)
117
+ return result;
118
+ const ref = await options.store.put(bytes, access);
119
+ const declared = ctx.toolId === undefined ? undefined : options.digests?.[ctx.toolId];
120
+ const projected = declared !== undefined ? declared(result) : options.defaultDigest?.(result, ctx.toolId);
121
+ const envelope = {
122
+ __loomClaimCheck: true,
123
+ ref: { __loomContent: ref.__loomContent },
124
+ size: bytes.byteLength,
125
+ ...(projected !== undefined && { digest: projected }),
126
+ ...(retain && { retain: true }),
127
+ };
128
+ options.onOffload?.({
129
+ ...(ctx.toolId !== undefined && { toolId: ctx.toolId }),
130
+ stepId: ctx.stepId,
131
+ executionId: ctx.executionId,
132
+ workflowId: ctx.workflowId,
133
+ size: bytes.byteLength,
134
+ contentAddress: ref.__loomContent,
135
+ });
136
+ // ADR 0085 / 0140 - an offloaded result that carried untrusted content (a tainted top level OR a
137
+ // nested marker) must not launder it into a clean-looking envelope + digest: the envelope itself is
138
+ // tainted, so the loop fences it and records the taint (the sweep still finds the inner envelope).
139
+ let origin;
140
+ if (json.includes("__loomTainted")) {
141
+ // Scan the SERIALIZED form (what the log and the prompt hold). A marker that is only text still
142
+ // taints (fail closed).
143
+ try {
144
+ origin = (0, classify_1.nestedTaintOrigin)(JSON.parse(json)) ?? "unknown:taint-marker-in-text";
145
+ }
146
+ catch {
147
+ origin = "unknown:taint-marker-in-text";
148
+ }
149
+ }
150
+ return origin === undefined ? envelope : (0, classify_1.tainted)(envelope, origin);
151
+ };
152
+ }
153
+ /**
154
+ * A ready-made `defaultDigest` (CC-2): the first `maxChars` (default 256) characters of the result's
155
+ * JSON text, so the model sees what an offloaded tool result BEGAN with instead of a bare hash. Pure
156
+ * and deterministic (a function of the result only). It is NOT a summary: it is a head, and it can cut
157
+ * a JSON string anywhere.
158
+ *
159
+ * Untrusted content is never previewed: a result carrying an ADR 0085 taint marker ANYWHERE (a nested
160
+ * `{ __loomTainted }` wrapper, such as an A2A reply's `content`) yields no digest at all, because a
161
+ * digest rides into the model's prompt as ordinary text and would launder the taint. A result JSON cannot
162
+ * encode yields none either.
163
+ */
164
+ function previewDigest(maxChars = 256) {
165
+ return (result) => {
166
+ let json;
167
+ try {
168
+ json = JSON.stringify(result);
169
+ }
170
+ catch {
171
+ return undefined;
172
+ }
173
+ if (json === undefined || json.includes('"__loomTainted"'))
174
+ return undefined;
175
+ let end = Math.min(maxChars, json.length);
176
+ // Never end on a lone high surrogate (it would not round-trip through UTF-8).
177
+ if (end < json.length && end > 0) {
178
+ const last = json.charCodeAt(end - 1);
179
+ if (last >= 0xd800 && last <= 0xdbff)
180
+ end--;
181
+ }
182
+ return { preview: json.slice(0, end), ...(end < json.length && { truncated: true }) };
183
+ };
184
+ }
185
+ /**
186
+ * CC-4 — resolve an envelope back to its payload, for use OUTSIDE the
187
+ * determinism boundary (rendering evidence in a UI, exporting a report).
188
+ * Returns `null` when the bytes were erased/never stored — the store's
189
+ * null-on-absence contract, surfaced as-is so callers decide loudness.
190
+ * Flow control must NOT branch on the resolved payload (CC-5 lint).
191
+ */
192
+ async function resolveClaimCheck(reader, envelope, access) {
193
+ if (envelope.codec !== undefined && envelope.codec !== "json") {
194
+ throw new TypeError(`resolveClaimCheck: envelope codec is "${envelope.codec}", not JSON — use resolveClaimCheckBytes for stream-offloaded content`);
195
+ }
196
+ const bytes = await reader.get(envelope.ref, access);
197
+ if (bytes === null)
198
+ return null;
199
+ return JSON.parse(new TextDecoder().decode(bytes));
200
+ }
201
+ /**
202
+ * CC-4 for stream-offloaded content (ST-2): the raw bytes, `null` on absence.
203
+ * Same boundary rule as {@link resolveClaimCheck}: OUTSIDE the determinism
204
+ * boundary only.
205
+ */
206
+ async function resolveClaimCheckBytes(reader, envelope, access) {
207
+ return reader.get(envelope.ref, access);
208
+ }
209
+ /**
210
+ * TS-10 (ADR 0062) — the batch twin of {@link resolveClaimCheck}, for
211
+ * interactive read paths (frozen-snapshot serving: a completed run's envelopes,
212
+ * one human waiting). One `getMany` round-trip when the reader supports it
213
+ * (coalesced parallel `get`s otherwise), deduped by content address; results
214
+ * positionally aligned with `envelopes`, `null` per erased/absent entry.
215
+ * Same boundary rule: OUTSIDE the determinism boundary only.
216
+ */
217
+ async function resolveClaimChecks(reader, envelopes, access) {
218
+ for (const envelope of envelopes) {
219
+ if (envelope.codec !== undefined && envelope.codec !== "json") {
220
+ throw new TypeError(`resolveClaimChecks: envelope codec is "${envelope.codec}", not JSON — use resolveClaimCheckBytes for stream-offloaded content`);
221
+ }
222
+ }
223
+ const distinct = new Map();
224
+ for (const e of envelopes) {
225
+ if (!distinct.has(e.ref.__loomContent))
226
+ distinct.set(e.ref.__loomContent, e.ref);
227
+ }
228
+ const refs = [...distinct.values()];
229
+ const fetched = reader.getMany !== undefined
230
+ ? await reader.getMany(refs, access)
231
+ : await Promise.all(refs.map((r) => reader.get(r, access)));
232
+ const byAddress = new Map();
233
+ refs.forEach((r, i) => byAddress.set(r.__loomContent, fetched[i] ?? null));
234
+ const decoder = new TextDecoder();
235
+ return envelopes.map((e) => {
236
+ const bytes = byAddress.get(e.ref.__loomContent) ?? null;
237
+ // Decode per-occurrence so callers never alias one parsed object.
238
+ return bytes === null ? null : JSON.parse(decoder.decode(bytes));
239
+ });
240
+ }
241
+ //# sourceMappingURL=claimCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claimCheck.js","sourceRoot":"","sources":["../src/claimCheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export { effectTimingMiddleware } from "./profile";
2
+ export type { EffectProfile, EffectProfiler } from "./profile";
3
+ export { retryMiddleware, type RetryOptions } from "./retry";
4
+ export { claimCheckMiddleware, isClaimCheck, isStreamResult, previewDigest, resolveClaimCheck, resolveClaimCheckBytes, resolveClaimChecks, streamResult, type ClaimCheckEnvelope, type ClaimCheckInfo, type ClaimCheckOptions, type ClaimCheckAccess, type ClaimCheckReader, type ClaimCheckStore, type PreviewDigest, type StreamedResult, } from "./claimCheck";
5
+ export { meteringMiddleware, llmUsageTokens, QuotaExceededError, type Budget, type MeterInfo, type MeteringOptions, type Pricing, type ResourceDelta, } from "./metering";
6
+ export { redactionMiddleware, redactOutputFrom, secretOutputPathsByStep, secretRef, isSecretRef, InMemorySecretResolver, type SecretRef, type SecretResolver, type RedactionOptions, } from "./redaction";
7
+ export { nestedBudgetMiddleware, BudgetLedger, type BudgetScope, type NestedBudgetOptions, type ScopeSpend, } from "./nestedBudget";
8
+ export { safetyMiddleware, SafetyViolationError, denyPatterns, piiValidator, schemaValidator, killSwitch, type SafetyPhase, type SafetyCheckInfo, type SafetyVerdict, type SafetyValidator, type SafetyOptions, type SchemaLike, } from "./safety";
9
+ export { estimateTokensByChars, streamTokenBudget } from "./streamTokenBudget";
10
+ export type { StreamTokenBudgetOptions, TokenEstimator } from "./streamTokenBudget";
11
+ export { rateLimitMiddleware, RateLimitExceededError, type RateLimitOptions, type RateLimitScope, } from "./rateLimit";
12
+ export { killSwitchMiddleware, InMemoryKillSwitch, KillSwitchEngagedError, type KillScope, type KillSwitchRegistry, type KillVerdict, } from "./killSwitchRegistry";
13
+ //# 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,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,YAAY,EACZ,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,aAAa,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,uBAAuB,EACvB,SAAS,EACT,WAAW,EACX,sBAAsB,EACtB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,YAAY,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KillSwitchEngagedError = exports.InMemoryKillSwitch = exports.killSwitchMiddleware = exports.RateLimitExceededError = exports.rateLimitMiddleware = exports.streamTokenBudget = exports.estimateTokensByChars = exports.killSwitch = exports.schemaValidator = exports.piiValidator = exports.denyPatterns = exports.SafetyViolationError = exports.safetyMiddleware = exports.BudgetLedger = exports.nestedBudgetMiddleware = exports.InMemorySecretResolver = exports.isSecretRef = exports.secretRef = exports.secretOutputPathsByStep = exports.redactOutputFrom = exports.redactionMiddleware = exports.QuotaExceededError = exports.llmUsageTokens = exports.meteringMiddleware = exports.streamResult = exports.resolveClaimChecks = exports.resolveClaimCheckBytes = exports.resolveClaimCheck = exports.previewDigest = exports.isStreamResult = exports.isClaimCheck = exports.claimCheckMiddleware = exports.retryMiddleware = exports.effectTimingMiddleware = void 0;
4
+ var profile_1 = require("./profile");
5
+ Object.defineProperty(exports, "effectTimingMiddleware", { enumerable: true, get: function () { return profile_1.effectTimingMiddleware; } });
6
+ var retry_1 = require("./retry");
7
+ Object.defineProperty(exports, "retryMiddleware", { enumerable: true, get: function () { return retry_1.retryMiddleware; } });
8
+ var claimCheck_1 = require("./claimCheck");
9
+ Object.defineProperty(exports, "claimCheckMiddleware", { enumerable: true, get: function () { return claimCheck_1.claimCheckMiddleware; } });
10
+ Object.defineProperty(exports, "isClaimCheck", { enumerable: true, get: function () { return claimCheck_1.isClaimCheck; } });
11
+ Object.defineProperty(exports, "isStreamResult", { enumerable: true, get: function () { return claimCheck_1.isStreamResult; } });
12
+ Object.defineProperty(exports, "previewDigest", { enumerable: true, get: function () { return claimCheck_1.previewDigest; } });
13
+ Object.defineProperty(exports, "resolveClaimCheck", { enumerable: true, get: function () { return claimCheck_1.resolveClaimCheck; } });
14
+ Object.defineProperty(exports, "resolveClaimCheckBytes", { enumerable: true, get: function () { return claimCheck_1.resolveClaimCheckBytes; } });
15
+ Object.defineProperty(exports, "resolveClaimChecks", { enumerable: true, get: function () { return claimCheck_1.resolveClaimChecks; } });
16
+ Object.defineProperty(exports, "streamResult", { enumerable: true, get: function () { return claimCheck_1.streamResult; } });
17
+ var metering_1 = require("./metering");
18
+ Object.defineProperty(exports, "meteringMiddleware", { enumerable: true, get: function () { return metering_1.meteringMiddleware; } });
19
+ Object.defineProperty(exports, "llmUsageTokens", { enumerable: true, get: function () { return metering_1.llmUsageTokens; } });
20
+ Object.defineProperty(exports, "QuotaExceededError", { enumerable: true, get: function () { return metering_1.QuotaExceededError; } });
21
+ var redaction_1 = require("./redaction");
22
+ Object.defineProperty(exports, "redactionMiddleware", { enumerable: true, get: function () { return redaction_1.redactionMiddleware; } });
23
+ Object.defineProperty(exports, "redactOutputFrom", { enumerable: true, get: function () { return redaction_1.redactOutputFrom; } });
24
+ Object.defineProperty(exports, "secretOutputPathsByStep", { enumerable: true, get: function () { return redaction_1.secretOutputPathsByStep; } });
25
+ Object.defineProperty(exports, "secretRef", { enumerable: true, get: function () { return redaction_1.secretRef; } });
26
+ Object.defineProperty(exports, "isSecretRef", { enumerable: true, get: function () { return redaction_1.isSecretRef; } });
27
+ Object.defineProperty(exports, "InMemorySecretResolver", { enumerable: true, get: function () { return redaction_1.InMemorySecretResolver; } });
28
+ var nestedBudget_1 = require("./nestedBudget");
29
+ Object.defineProperty(exports, "nestedBudgetMiddleware", { enumerable: true, get: function () { return nestedBudget_1.nestedBudgetMiddleware; } });
30
+ Object.defineProperty(exports, "BudgetLedger", { enumerable: true, get: function () { return nestedBudget_1.BudgetLedger; } });
31
+ var safety_1 = require("./safety");
32
+ Object.defineProperty(exports, "safetyMiddleware", { enumerable: true, get: function () { return safety_1.safetyMiddleware; } });
33
+ Object.defineProperty(exports, "SafetyViolationError", { enumerable: true, get: function () { return safety_1.SafetyViolationError; } });
34
+ Object.defineProperty(exports, "denyPatterns", { enumerable: true, get: function () { return safety_1.denyPatterns; } });
35
+ Object.defineProperty(exports, "piiValidator", { enumerable: true, get: function () { return safety_1.piiValidator; } });
36
+ Object.defineProperty(exports, "schemaValidator", { enumerable: true, get: function () { return safety_1.schemaValidator; } });
37
+ Object.defineProperty(exports, "killSwitch", { enumerable: true, get: function () { return safety_1.killSwitch; } });
38
+ var streamTokenBudget_1 = require("./streamTokenBudget");
39
+ Object.defineProperty(exports, "estimateTokensByChars", { enumerable: true, get: function () { return streamTokenBudget_1.estimateTokensByChars; } });
40
+ Object.defineProperty(exports, "streamTokenBudget", { enumerable: true, get: function () { return streamTokenBudget_1.streamTokenBudget; } });
41
+ var rateLimit_1 = require("./rateLimit");
42
+ Object.defineProperty(exports, "rateLimitMiddleware", { enumerable: true, get: function () { return rateLimit_1.rateLimitMiddleware; } });
43
+ Object.defineProperty(exports, "RateLimitExceededError", { enumerable: true, get: function () { return rateLimit_1.RateLimitExceededError; } });
44
+ var killSwitchRegistry_1 = require("./killSwitchRegistry");
45
+ Object.defineProperty(exports, "killSwitchMiddleware", { enumerable: true, get: function () { return killSwitchRegistry_1.killSwitchMiddleware; } });
46
+ Object.defineProperty(exports, "InMemoryKillSwitch", { enumerable: true, get: function () { return killSwitchRegistry_1.InMemoryKillSwitch; } });
47
+ Object.defineProperty(exports, "KillSwitchEngagedError", { enumerable: true, get: function () { return killSwitchRegistry_1.KillSwitchEngagedError; } });
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAmD;AAA1C,iHAAA,sBAAsB,OAAA;AAE/B,iCAA6D;AAApD,wGAAA,eAAe,OAAA;AACxB,2CAiBsB;AAhBpB,kHAAA,oBAAoB,OAAA;AACpB,0GAAA,YAAY,OAAA;AACZ,4GAAA,cAAc,OAAA;AACd,2GAAA,aAAa,OAAA;AACb,+GAAA,iBAAiB,OAAA;AACjB,oHAAA,sBAAsB,OAAA;AACtB,gHAAA,kBAAkB,OAAA;AAClB,0GAAA,YAAY,OAAA;AAUd,uCASoB;AARlB,8GAAA,kBAAkB,OAAA;AAClB,0GAAA,cAAc,OAAA;AACd,8GAAA,kBAAkB,OAAA;AAOpB,yCAUqB;AATnB,gHAAA,mBAAmB,OAAA;AACnB,6GAAA,gBAAgB,OAAA;AAChB,oHAAA,uBAAuB,OAAA;AACvB,sGAAA,SAAS,OAAA;AACT,wGAAA,WAAW,OAAA;AACX,mHAAA,sBAAsB,OAAA;AAKxB,+CAMwB;AALtB,sHAAA,sBAAsB,OAAA;AACtB,4GAAA,YAAY,OAAA;AAKd,mCAakB;AAZhB,0GAAA,gBAAgB,OAAA;AAChB,8GAAA,oBAAoB,OAAA;AACpB,sGAAA,YAAY,OAAA;AACZ,sGAAA,YAAY,OAAA;AACZ,yGAAA,eAAe,OAAA;AACf,oGAAA,UAAU,OAAA;AAQZ,yDAA+E;AAAtE,0HAAA,qBAAqB,OAAA;AAAE,sHAAA,iBAAiB,OAAA;AAEjD,yCAKqB;AAJnB,gHAAA,mBAAmB,OAAA;AACnB,mHAAA,sBAAsB,OAAA;AAIxB,2DAO8B;AAN5B,0HAAA,oBAAoB,OAAA;AACpB,wHAAA,kBAAkB,OAAA;AAClB,4HAAA,sBAAsB,OAAA"}
@@ -0,0 +1,74 @@
1
+ import type { EffectContext, EffectMiddleware } from "@loomwork/effect-runtime";
2
+ import { SafetyViolationError } from "./safety";
3
+ export type KillScope = "system" | "tenant" | "workflow";
4
+ /** Why an effect is being refused. */
5
+ export interface KillVerdict {
6
+ scope: KillScope;
7
+ /** The tenant / workflow id (absent for `system`). */
8
+ key?: string;
9
+ reason: string;
10
+ }
11
+ /**
12
+ * Where the stop flags live. Return `undefined` to let the effect run. Must be cheap — it is
13
+ * consulted before EVERY effect — and must fail CLOSED or open as the deployment prefers;
14
+ * a throw is treated as a refusal (fail closed) by {@link killSwitchMiddleware}.
15
+ */
16
+ export interface KillSwitchRegistry {
17
+ /**
18
+ * Where the stop flags live, DECLARED by the registry. Optional and additive (no SPI version
19
+ * bump: an absent field changes nothing for any existing registry).
20
+ *
21
+ * - `"process"` — the flags live in this process's memory ({@link InMemoryKillSwitch}); a stop
22
+ * issued in another process is invisible here.
23
+ * - `"shared"` — the flags live in a store every process reads (a DB row, a feature-flag
24
+ * service), so a stop issued anywhere applies here.
25
+ *
26
+ * Tooling that runs your effects OUTSIDE the long-running app (`loom resume` / `loom start`)
27
+ * reads this and is FAIL-CLOSED: only a registry that affirmatively declares `"shared"` is
28
+ * trusted to carry an operator stop across processes. Absent, or anything else, is treated as
29
+ * process-local. A wrapper or subclass must re-declare it: forwarding is the wrapper's claim.
30
+ */
31
+ readonly scope?: "process" | "shared";
32
+ check(ctx: EffectContext): KillVerdict | undefined | Promise<KillVerdict | undefined>;
33
+ }
34
+ export declare class KillSwitchEngagedError extends SafetyViolationError {
35
+ readonly scope: KillScope;
36
+ readonly key: string | undefined;
37
+ /** A stop is a decision, not a fault: retrying it just repeats the refusal. */
38
+ readonly retryable = false;
39
+ constructor(verdict: KillVerdict);
40
+ }
41
+ /** Single-process registry with the operator-facing admin API. */
42
+ export declare class InMemoryKillSwitch implements KillSwitchRegistry {
43
+ /** Declares itself process-local (see {@link KillSwitchRegistry.scope}). */
44
+ readonly scope: "process";
45
+ private system;
46
+ private readonly tenants;
47
+ private readonly workflows;
48
+ /** Stop every effect in the process. */
49
+ stopAll(reason?: string): void;
50
+ resumeAll(): void;
51
+ /** Stop every effect whose principal chain names `tenant`. */
52
+ stopTenant(tenant: string, reason?: string): void;
53
+ resumeTenant(tenant: string): void;
54
+ /** Stop every effect of one flow (one agent). */
55
+ stopWorkflow(workflowId: string, reason?: string): void;
56
+ resumeWorkflow(workflowId: string): void;
57
+ /** What is currently stopped, for an operator console. */
58
+ status(): {
59
+ system?: string;
60
+ tenants: Record<string, string>;
61
+ workflows: Record<string, string>;
62
+ };
63
+ check(ctx: EffectContext): KillVerdict | undefined;
64
+ }
65
+ /**
66
+ * Refuse every effect the registry stops. Place it OUTERMOST so a stopped effect never
67
+ * resolves a secret or spends budget. The refusal is recorded as a durable `SAFETY_BLOCKED`
68
+ * fact (the same audit list the K6 kill-switch validator writes) and thrown as
69
+ * {@link KillSwitchEngagedError}, a `SafetyViolationError` carrying `retryable = false`
70
+ * (which `retryMiddleware`'s default classifier honours), so it fails the step through the
71
+ * existing path and is not retried.
72
+ */
73
+ export declare function killSwitchMiddleware(registry: KillSwitchRegistry): EffectMiddleware;
74
+ //# sourceMappingURL=killSwitchRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"killSwitchRegistry.d.ts","sourceRoot":"","sources":["../src/killSwitchRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAwBhD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzD,sCAAsC;AACtC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,SAAS,CAAC;IACjB,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACtC,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;CACvF;AAED,qBAAa,sBAAuB,SAAQ,oBAAoB;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,SAAS;gBACf,OAAO,EAAE,WAAW;CAUjC;AAED,kEAAkE;AAClE,qBAAa,kBAAmB,YAAW,kBAAkB;IAC3D,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAG,SAAS,CAAU;IACpC,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IAEvD,wCAAwC;IACxC,OAAO,CAAC,MAAM,SAAgB,GAAG,IAAI;IAGrC,SAAS,IAAI,IAAI;IAGjB,8DAA8D;IAC9D,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAgB,GAAG,IAAI;IAGxD,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAGlC,iDAAiD;IACjD,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAkB,GAAG,IAAI;IAGhE,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIxC,0DAA0D;IAC1D,MAAM,IAAI;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACnC;IAQD,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,GAAG,SAAS;CAWnD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,gBAAgB,CA2BnF"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryKillSwitch = exports.KillSwitchEngagedError = void 0;
4
+ exports.killSwitchMiddleware = killSwitchMiddleware;
5
+ const safety_1 = require("./safety");
6
+ class KillSwitchEngagedError extends safety_1.SafetyViolationError {
7
+ scope;
8
+ key;
9
+ /** A stop is a decision, not a fault: retrying it just repeats the refusal. */
10
+ retryable = false;
11
+ constructor(verdict) {
12
+ super("kill-switch", `${verdict.scope}${verdict.key !== undefined ? ` "${verdict.key}"` : ""} stopped: ${verdict.reason}`, "kill-switch");
13
+ this.name = "KillSwitchEngagedError";
14
+ this.scope = verdict.scope;
15
+ this.key = verdict.key;
16
+ }
17
+ }
18
+ exports.KillSwitchEngagedError = KillSwitchEngagedError;
19
+ /** Single-process registry with the operator-facing admin API. */
20
+ class InMemoryKillSwitch {
21
+ /** Declares itself process-local (see {@link KillSwitchRegistry.scope}). */
22
+ scope = "process";
23
+ system;
24
+ tenants = new Map();
25
+ workflows = new Map();
26
+ /** Stop every effect in the process. */
27
+ stopAll(reason = "system stop") {
28
+ this.system = reason;
29
+ }
30
+ resumeAll() {
31
+ this.system = undefined;
32
+ }
33
+ /** Stop every effect whose principal chain names `tenant`. */
34
+ stopTenant(tenant, reason = "tenant stop") {
35
+ this.tenants.set(tenant, reason);
36
+ }
37
+ resumeTenant(tenant) {
38
+ this.tenants.delete(tenant);
39
+ }
40
+ /** Stop every effect of one flow (one agent). */
41
+ stopWorkflow(workflowId, reason = "workflow stop") {
42
+ this.workflows.set(workflowId, reason);
43
+ }
44
+ resumeWorkflow(workflowId) {
45
+ this.workflows.delete(workflowId);
46
+ }
47
+ /** What is currently stopped, for an operator console. */
48
+ status() {
49
+ return {
50
+ ...(this.system !== undefined && { system: this.system }),
51
+ tenants: Object.fromEntries(this.tenants),
52
+ workflows: Object.fromEntries(this.workflows),
53
+ };
54
+ }
55
+ check(ctx) {
56
+ if (this.system !== undefined)
57
+ return { scope: "system", reason: this.system };
58
+ const tenant = ctx.principal?.tenant;
59
+ if (tenant !== undefined) {
60
+ const reason = this.tenants.get(tenant);
61
+ if (reason !== undefined)
62
+ return { scope: "tenant", key: tenant, reason };
63
+ }
64
+ const wf = this.workflows.get(ctx.workflowId);
65
+ if (wf !== undefined)
66
+ return { scope: "workflow", key: ctx.workflowId, reason: wf };
67
+ return undefined;
68
+ }
69
+ }
70
+ exports.InMemoryKillSwitch = InMemoryKillSwitch;
71
+ /**
72
+ * Refuse every effect the registry stops. Place it OUTERMOST so a stopped effect never
73
+ * resolves a secret or spends budget. The refusal is recorded as a durable `SAFETY_BLOCKED`
74
+ * fact (the same audit list the K6 kill-switch validator writes) and thrown as
75
+ * {@link KillSwitchEngagedError}, a `SafetyViolationError` carrying `retryable = false`
76
+ * (which `retryMiddleware`'s default classifier honours), so it fails the step through the
77
+ * existing path and is not retried.
78
+ */
79
+ function killSwitchMiddleware(registry) {
80
+ return async (ctx, _input, next) => {
81
+ let verdict;
82
+ try {
83
+ verdict = await registry.check(ctx);
84
+ }
85
+ catch (err) {
86
+ // A registry that cannot answer fails CLOSED: a kill switch that errors open is a
87
+ // switch that is off exactly when the store it reads is down.
88
+ verdict = {
89
+ scope: "system",
90
+ reason: `kill-switch registry unavailable: ${err instanceof Error ? err.message : String(err)}`,
91
+ };
92
+ }
93
+ if (verdict !== undefined) {
94
+ ctx.emit("SAFETY_BLOCKED", {
95
+ stepId: ctx.stepId,
96
+ validatorId: "kill-switch",
97
+ phase: "input",
98
+ reason: verdict.reason,
99
+ category: "kill-switch",
100
+ scope: verdict.scope,
101
+ ...(verdict.key !== undefined && { key: verdict.key }),
102
+ });
103
+ throw new KillSwitchEngagedError(verdict);
104
+ }
105
+ return next();
106
+ };
107
+ }
108
+ //# sourceMappingURL=killSwitchRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"killSwitchRegistry.js","sourceRoot":"","sources":["../src/killSwitchRegistry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import type { EffectMiddleware } from "@loomwork/effect-runtime";
2
+ export interface ResourceDelta {
3
+ tokens?: number;
4
+ costUsd?: number;
5
+ ms?: number;
6
+ /** Peak resident memory attributable to the effect, in bytes. */
7
+ memBytes?: number;
8
+ /** Wall-clock time, in ms (distinct from `ms` when the effect runs off-thread). */
9
+ wallMs?: number;
10
+ /** Network bytes transferred by the effect. */
11
+ netBytes?: number;
12
+ /**
13
+ * ADR 0115 — open dimensions (`gpu_seconds`, `credits`), by name. Folded into
14
+ * `_resources.custom`; the kernel assigns no unit and no price, so converting these to money
15
+ * is this pricing function's job. At most 32 names, each matching `VOCABULARY_NAME_PATTERN`
16
+ * (`@loomwork/core`), never a built-in name. A bad name (or value) makes `ctx.emit` throw AFTER the
17
+ * effect ran, like a built-in ceiling breach.
18
+ */
19
+ custom?: Readonly<Record<string, number>>;
20
+ }
21
+ export interface MeterInfo {
22
+ stepId: string;
23
+ input: unknown;
24
+ /** The effect's result — `undefined` when metering an aborted effect (K8). */
25
+ result: unknown;
26
+ /** Measured wall-time of the effect, in ms. */
27
+ ms: number;
28
+ /**
29
+ * K8 — true when the effect was severed mid-flight (cancellation/deadline).
30
+ * The wall-time up to the abort is still metered so cancel-before-completion
31
+ * cannot evade budgets; pricing may add provider-reported partial usage.
32
+ */
33
+ aborted?: boolean;
34
+ }
35
+ /** Compute the resource delta for one effect call — e.g. tokens×rate for an LLM. */
36
+ export type Pricing = (info: MeterInfo) => ResourceDelta;
37
+ export interface Budget {
38
+ maxTokens?: number;
39
+ maxCostUsd?: number;
40
+ maxMemBytes?: number;
41
+ maxWallMs?: number;
42
+ maxNetBytes?: number;
43
+ /**
44
+ * ADR 0115 — ceilings for open dimensions, by name (`{ gpu_seconds: 60 }`): an execution whose
45
+ * `_resources.custom[name]` has reached the ceiling has its next effect denied, like every
46
+ * other dimension. Only enforced where set.
47
+ */
48
+ maxCustom?: Readonly<Record<string, number>>;
49
+ }
50
+ /** True when `name` is a built-in metering dimension (never a custom one). */
51
+ export declare function isBuiltinDimension(name: string): boolean;
52
+ /** True when `name` is a valid custom dimension name (pattern shared with the fold's guard). */
53
+ export declare function isCustomDimensionName(name: string): boolean;
54
+ /**
55
+ * Validate a `Budget.maxCustom` and return a FROZEN shallow copy to enforce against (so a later
56
+ * mutation of the caller's object cannot smuggle in a built-in name or a bad ceiling). Refuses a
57
+ * built-in dimension name (use `maxTokens` etc.: a custom ceiling on `tokens` would read
58
+ * `_resources.custom.tokens`, which nothing meters) and a non-numeric ceiling.
59
+ */
60
+ export declare function assertMaxCustom(maxCustom: Readonly<Record<string, number>> | undefined): Readonly<Record<string, number>> | undefined;
61
+ /** The first custom ceiling the spend has reached, as a reason — own-property reads only. */
62
+ export declare function overCustomBudget(custom: Readonly<Record<string, number>> | undefined, maxCustom: Readonly<Record<string, number>> | undefined): string | null;
63
+ export interface MeteringOptions {
64
+ pricing: Pricing;
65
+ /** When set, an execution over budget has its next effect denied (admission control). */
66
+ budget?: Budget;
67
+ /** Injectable clock (defaults to Date.now); only affects the measured `ms`. */
68
+ clock?: () => number;
69
+ }
70
+ export declare class QuotaExceededError extends Error {
71
+ readonly reason: string;
72
+ /** A budget refusal is a decision; retrying repeats it (`retryMiddleware` honours this). */
73
+ readonly retryable = false;
74
+ constructor(reason: string);
75
+ }
76
+ /** The RESOURCE_METERED payload for a delta — only dimensions the pricing reported. */
77
+ export declare function meteredPayload(delta: ResourceDelta, ms: number): Record<string, number | Readonly<Record<string, number>>>;
78
+ /** Read token usage from an LlmResponse-shaped result (`{ usage: { inputTokens, outputTokens } }`). */
79
+ export declare function llmUsageTokens(result: unknown): number;
80
+ export declare function meteringMiddleware(options: MeteringOptions): EffectMiddleware;
81
+ //# sourceMappingURL=metering.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metering.d.ts","sourceRoot":"","sources":["../src/metering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,gBAAgB,EAAoB,MAAM,0BAA0B,CAAC;AAclG,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IAIZ,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,oFAAoF;AACpF,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,aAAa,CAAC;AAEzD,MAAM,WAAW,MAAM;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC9C;AAED,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,gGAAgG;AAChG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACtD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAa9C;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,EACpD,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACtD,MAAM,GAAG,IAAI,CAQf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,SAAS;gBACf,MAAM,EAAE,MAAM;CAK3B;AAqBD,uFAAuF;AACvF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,MAAM,GACT,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAU3D;AAED,uGAAuG;AACvG,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAKtD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CA8C7E"}