@nifrajs/coding-agent 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EXTENSIONS.md +25 -0
- package/PERFORMANCE.md +19 -0
- package/README.md +69 -0
- package/REGISTRY.md +15 -0
- package/SECURITY.md +32 -0
- package/dist/approvals.d.ts +70 -0
- package/dist/approvals.d.ts.map +1 -0
- package/dist/approvals.js +174 -0
- package/dist/approvals.js.map +1 -0
- package/dist/capabilities.d.ts +20 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +49 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +380 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +17 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +66 -0
- package/dist/context.js.map +1 -0
- package/dist/deployment-adapters.d.ts +40 -0
- package/dist/deployment-adapters.d.ts.map +1 -0
- package/dist/deployment-adapters.js +147 -0
- package/dist/deployment-adapters.js.map +1 -0
- package/dist/diff.d.ts +17 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +61 -0
- package/dist/diff.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +35 -0
- package/dist/errors.js.map +1 -0
- package/dist/extensions.d.ts +104 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +284 -0
- package/dist/extensions.js.map +1 -0
- package/dist/handoffs.d.ts +97 -0
- package/dist/handoffs.d.ts.map +1 -0
- package/dist/handoffs.js +199 -0
- package/dist/handoffs.js.map +1 -0
- package/dist/healing.d.ts +56 -0
- package/dist/healing.d.ts.map +1 -0
- package/dist/healing.js +54 -0
- package/dist/healing.js.map +1 -0
- package/dist/host.d.ts +61 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +369 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/isolated-worker.d.ts +2 -0
- package/dist/isolated-worker.d.ts.map +1 -0
- package/dist/isolated-worker.js +155 -0
- package/dist/isolated-worker.js.map +1 -0
- package/dist/isolated.d.ts +52 -0
- package/dist/isolated.d.ts.map +1 -0
- package/dist/isolated.js +293 -0
- package/dist/isolated.js.map +1 -0
- package/dist/native.d.ts +92 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +339 -0
- package/dist/native.js.map +1 -0
- package/dist/orchestration/artifact-port.d.ts +30 -0
- package/dist/orchestration/artifact-port.d.ts.map +1 -0
- package/dist/orchestration/artifact-port.js +59 -0
- package/dist/orchestration/artifact-port.js.map +1 -0
- package/dist/orchestration/catalog.d.ts +71 -0
- package/dist/orchestration/catalog.d.ts.map +1 -0
- package/dist/orchestration/catalog.js +46 -0
- package/dist/orchestration/catalog.js.map +1 -0
- package/dist/orchestration/compile.d.ts +59 -0
- package/dist/orchestration/compile.d.ts.map +1 -0
- package/dist/orchestration/compile.js +268 -0
- package/dist/orchestration/compile.js.map +1 -0
- package/dist/orchestration/dispatch.d.ts +115 -0
- package/dist/orchestration/dispatch.d.ts.map +1 -0
- package/dist/orchestration/dispatch.js +220 -0
- package/dist/orchestration/dispatch.js.map +1 -0
- package/dist/orchestration/durable-jobs.d.ts +35 -0
- package/dist/orchestration/durable-jobs.d.ts.map +1 -0
- package/dist/orchestration/durable-jobs.js +273 -0
- package/dist/orchestration/durable-jobs.js.map +1 -0
- package/dist/orchestration/effect-key.d.ts +23 -0
- package/dist/orchestration/effect-key.d.ts.map +1 -0
- package/dist/orchestration/effect-key.js +24 -0
- package/dist/orchestration/effect-key.js.map +1 -0
- package/dist/orchestration/evidence-store.d.ts +75 -0
- package/dist/orchestration/evidence-store.d.ts.map +1 -0
- package/dist/orchestration/evidence-store.js +183 -0
- package/dist/orchestration/evidence-store.js.map +1 -0
- package/dist/orchestration/hash.d.ts +12 -0
- package/dist/orchestration/hash.d.ts.map +1 -0
- package/dist/orchestration/hash.js +43 -0
- package/dist/orchestration/hash.js.map +1 -0
- package/dist/orchestration/host.d.ts +121 -0
- package/dist/orchestration/host.d.ts.map +1 -0
- package/dist/orchestration/host.js +334 -0
- package/dist/orchestration/host.js.map +1 -0
- package/dist/orchestration/index.d.ts +20 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +19 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/policy.d.ts +63 -0
- package/dist/orchestration/policy.d.ts.map +1 -0
- package/dist/orchestration/policy.js +80 -0
- package/dist/orchestration/policy.js.map +1 -0
- package/dist/orchestration/recovery.d.ts +87 -0
- package/dist/orchestration/recovery.d.ts.map +1 -0
- package/dist/orchestration/recovery.js +197 -0
- package/dist/orchestration/recovery.js.map +1 -0
- package/dist/orchestration/tracer.d.ts +31 -0
- package/dist/orchestration/tracer.d.ts.map +1 -0
- package/dist/orchestration/tracer.js +141 -0
- package/dist/orchestration/tracer.js.map +1 -0
- package/dist/plans.d.ts +35 -0
- package/dist/plans.d.ts.map +1 -0
- package/dist/plans.js +63 -0
- package/dist/plans.js.map +1 -0
- package/dist/presets.d.ts +10 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +70 -0
- package/dist/presets.js.map +1 -0
- package/dist/process.d.ts +6 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +42 -0
- package/dist/process.js.map +1 -0
- package/dist/registry.d.ts +37 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +51 -0
- package/dist/registry.js.map +1 -0
- package/dist/replay.d.ts +24 -0
- package/dist/replay.d.ts.map +1 -0
- package/dist/replay.js +154 -0
- package/dist/replay.js.map +1 -0
- package/dist/rpc.d.ts +51 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +412 -0
- package/dist/rpc.js.map +1 -0
- package/dist/session-migration.d.ts +59 -0
- package/dist/session-migration.d.ts.map +1 -0
- package/dist/session-migration.js +315 -0
- package/dist/session-migration.js.map +1 -0
- package/dist/sessions.d.ts +74 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +222 -0
- package/dist/sessions.js.map +1 -0
- package/dist/subagents.d.ts +51 -0
- package/dist/subagents.d.ts.map +1 -0
- package/dist/subagents.js +141 -0
- package/dist/subagents.js.map +1 -0
- package/dist/tools.d.ts +13 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +37 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui.d.ts +42 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +93 -0
- package/dist/ui.js.map +1 -0
- package/dist/verification.d.ts +34 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +91 -0
- package/dist/verification.js.map +1 -0
- package/dist/workflows.d.ts +98 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +174 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +84 -0
- package/src/approvals.ts +249 -0
- package/src/capabilities.ts +74 -0
- package/src/cli.ts +405 -0
- package/src/context.ts +81 -0
- package/src/deployment-adapters.ts +181 -0
- package/src/diff.ts +80 -0
- package/src/errors.ts +46 -0
- package/src/extensions.ts +402 -0
- package/src/handoffs.ts +299 -0
- package/src/healing.ts +93 -0
- package/src/host.ts +465 -0
- package/src/index.ts +165 -0
- package/src/isolated-worker.ts +177 -0
- package/src/isolated.ts +344 -0
- package/src/native.ts +478 -0
- package/src/orchestration/artifact-port.ts +75 -0
- package/src/orchestration/catalog.ts +102 -0
- package/src/orchestration/compile.ts +373 -0
- package/src/orchestration/dispatch.ts +383 -0
- package/src/orchestration/durable-jobs.ts +374 -0
- package/src/orchestration/effect-key.ts +35 -0
- package/src/orchestration/evidence-store.ts +233 -0
- package/src/orchestration/hash.ts +43 -0
- package/src/orchestration/host.ts +445 -0
- package/src/orchestration/index.ts +131 -0
- package/src/orchestration/policy.ts +116 -0
- package/src/orchestration/recovery.ts +271 -0
- package/src/orchestration/tracer.ts +177 -0
- package/src/plans.ts +105 -0
- package/src/presets.ts +90 -0
- package/src/process.ts +47 -0
- package/src/registry.ts +80 -0
- package/src/replay.ts +190 -0
- package/src/rpc.ts +598 -0
- package/src/session-migration.ts +401 -0
- package/src/sessions.ts +303 -0
- package/src/subagents.ts +210 -0
- package/src/tools.ts +52 -0
- package/src/ui.ts +137 -0
- package/src/verification.ts +133 -0
- package/src/workflows.ts +279 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evidence-only dispatch contracts for at-least-once run execution.
|
|
3
|
+
*
|
|
4
|
+
* These values deliberately contain no job payload, tenant state, credentials, retention policy,
|
|
5
|
+
* error message, or tool/model data. A durable operated adapter may implement the ports, but the
|
|
6
|
+
* public reference adapters are disposable and keep only identifiers, digests, counters, and
|
|
7
|
+
* lifecycle evidence. Delivery is at-least-once; callers make effects idempotent with the key
|
|
8
|
+
* derived below and prove completion before a recovered worker skips the effect.
|
|
9
|
+
*/
|
|
10
|
+
import { sha256HexOf } from "./hash.js";
|
|
11
|
+
export const RUN_DISPATCH_VERSION = 1;
|
|
12
|
+
export const DISPATCH_JOB_NAME = "nifra.agent.run-node";
|
|
13
|
+
export const MAX_DISPATCH_STRING = 256;
|
|
14
|
+
export const MAX_DISPATCH_ATTEMPTS = 16;
|
|
15
|
+
export const systemClock = Object.freeze({ now: () => Date.now() });
|
|
16
|
+
const DIGEST = /^[0-9a-f]{64}$/;
|
|
17
|
+
const TOKEN = /^[A-Za-z0-9._:-]{1,256}$/;
|
|
18
|
+
const FORBIDDEN = new Set([
|
|
19
|
+
"prompt",
|
|
20
|
+
"message",
|
|
21
|
+
"text",
|
|
22
|
+
"input",
|
|
23
|
+
"output",
|
|
24
|
+
"arguments",
|
|
25
|
+
"body",
|
|
26
|
+
"response",
|
|
27
|
+
"secret",
|
|
28
|
+
"credential",
|
|
29
|
+
"diagnostic",
|
|
30
|
+
"stack",
|
|
31
|
+
"content",
|
|
32
|
+
"transcript",
|
|
33
|
+
"artifact",
|
|
34
|
+
]);
|
|
35
|
+
function record(value, where) {
|
|
36
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
37
|
+
throw new TypeError(`${where} must be an object`);
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function rejectKeys(value, allowed, where) {
|
|
41
|
+
for (const key of Object.keys(value)) {
|
|
42
|
+
if (FORBIDDEN.has(key.toLowerCase()))
|
|
43
|
+
throw new TypeError(`${where} contains forbidden field '${key}'`);
|
|
44
|
+
if (!allowed.has(key))
|
|
45
|
+
throw new TypeError(`${where} contains unknown field '${key}'`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function boundedString(value, name) {
|
|
49
|
+
if (typeof value !== "string" || value.length === 0 || value.length > MAX_DISPATCH_STRING)
|
|
50
|
+
throw new TypeError(`${name} must be a non-empty bounded string`);
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
function digest(value, name) {
|
|
54
|
+
const text = boundedString(value, name);
|
|
55
|
+
if (!DIGEST.test(text))
|
|
56
|
+
throw new TypeError(`${name} must be a lowercase sha256 digest`);
|
|
57
|
+
return text;
|
|
58
|
+
}
|
|
59
|
+
function token(value, name) {
|
|
60
|
+
const text = boundedString(value, name);
|
|
61
|
+
if (!TOKEN.test(text))
|
|
62
|
+
throw new TypeError(`${name} must be an opaque schedule token`);
|
|
63
|
+
return text;
|
|
64
|
+
}
|
|
65
|
+
function nonNegative(value, name) {
|
|
66
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
67
|
+
throw new TypeError(`${name} must be a non-negative safe integer`);
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
function attempts(value) {
|
|
71
|
+
const result = nonNegative(value, "maxAttempts");
|
|
72
|
+
if (result < 1 || result > MAX_DISPATCH_ATTEMPTS)
|
|
73
|
+
throw new RangeError(`maxAttempts must be between 1 and ${MAX_DISPATCH_ATTEMPTS}`);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
const DISPATCH_KEYS = new Set([
|
|
77
|
+
"version",
|
|
78
|
+
"dispatchId",
|
|
79
|
+
"runId",
|
|
80
|
+
"planDigest",
|
|
81
|
+
"nodeId",
|
|
82
|
+
"maxAttempts",
|
|
83
|
+
"notBefore",
|
|
84
|
+
]);
|
|
85
|
+
/** Parse a dispatch identity and reject content or undeclared fields. */
|
|
86
|
+
export function parseRunDispatch(value) {
|
|
87
|
+
const input = record(value, "run dispatch");
|
|
88
|
+
rejectKeys(input, DISPATCH_KEYS, "run dispatch");
|
|
89
|
+
if (input.version !== RUN_DISPATCH_VERSION)
|
|
90
|
+
throw new TypeError("run dispatch.version is unsupported");
|
|
91
|
+
return Object.freeze({
|
|
92
|
+
version: RUN_DISPATCH_VERSION,
|
|
93
|
+
dispatchId: token(input.dispatchId, "dispatchId"),
|
|
94
|
+
runId: token(input.runId, "runId"),
|
|
95
|
+
planDigest: digest(input.planDigest, "planDigest"),
|
|
96
|
+
nodeId: token(input.nodeId, "nodeId"),
|
|
97
|
+
maxAttempts: attempts(input.maxAttempts),
|
|
98
|
+
notBefore: nonNegative(input.notBefore, "notBefore"),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const LEASE_KEYS = new Set([
|
|
102
|
+
"version",
|
|
103
|
+
"leaseId",
|
|
104
|
+
"dispatch",
|
|
105
|
+
"attempt",
|
|
106
|
+
"generation",
|
|
107
|
+
"leasedAt",
|
|
108
|
+
"leaseUntil",
|
|
109
|
+
"scheduleToken",
|
|
110
|
+
"idempotencyKey",
|
|
111
|
+
]);
|
|
112
|
+
export function parseRunLease(value) {
|
|
113
|
+
const input = record(value, "run lease");
|
|
114
|
+
rejectKeys(input, LEASE_KEYS, "run lease");
|
|
115
|
+
if (input.version !== RUN_DISPATCH_VERSION)
|
|
116
|
+
throw new TypeError("run lease.version is unsupported");
|
|
117
|
+
const attempt = attempts(input.attempt);
|
|
118
|
+
const generation = nonNegative(input.generation, "generation");
|
|
119
|
+
return Object.freeze({
|
|
120
|
+
version: RUN_DISPATCH_VERSION,
|
|
121
|
+
leaseId: token(input.leaseId, "leaseId"),
|
|
122
|
+
dispatch: parseRunDispatch(input.dispatch),
|
|
123
|
+
attempt,
|
|
124
|
+
generation,
|
|
125
|
+
leasedAt: nonNegative(input.leasedAt, "leasedAt"),
|
|
126
|
+
leaseUntil: nonNegative(input.leaseUntil, "leaseUntil"),
|
|
127
|
+
scheduleToken: token(input.scheduleToken, "scheduleToken"),
|
|
128
|
+
idempotencyKey: token(input.idempotencyKey, "idempotencyKey"),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const CHECKPOINT_KEYS = new Set([
|
|
132
|
+
"version",
|
|
133
|
+
"dispatchId",
|
|
134
|
+
"runId",
|
|
135
|
+
"nodeId",
|
|
136
|
+
"attempt",
|
|
137
|
+
"generation",
|
|
138
|
+
"boundary",
|
|
139
|
+
"idempotencyKey",
|
|
140
|
+
"at",
|
|
141
|
+
"scheduleToken",
|
|
142
|
+
]);
|
|
143
|
+
export function parseRunCheckpoint(value) {
|
|
144
|
+
const input = record(value, "run checkpoint");
|
|
145
|
+
rejectKeys(input, CHECKPOINT_KEYS, "run checkpoint");
|
|
146
|
+
if (input.version !== RUN_DISPATCH_VERSION)
|
|
147
|
+
throw new TypeError("run checkpoint.version is unsupported");
|
|
148
|
+
const boundary = input.boundary;
|
|
149
|
+
if (boundary !== "before-effect" && boundary !== "after-effect")
|
|
150
|
+
throw new TypeError("run checkpoint.boundary is invalid");
|
|
151
|
+
return Object.freeze({
|
|
152
|
+
version: RUN_DISPATCH_VERSION,
|
|
153
|
+
dispatchId: token(input.dispatchId, "dispatchId"),
|
|
154
|
+
runId: token(input.runId, "runId"),
|
|
155
|
+
nodeId: token(input.nodeId, "nodeId"),
|
|
156
|
+
attempt: attempts(input.attempt),
|
|
157
|
+
generation: nonNegative(input.generation, "generation"),
|
|
158
|
+
boundary,
|
|
159
|
+
idempotencyKey: token(input.idempotencyKey, "idempotencyKey"),
|
|
160
|
+
at: nonNegative(input.at, "at"),
|
|
161
|
+
scheduleToken: token(input.scheduleToken, "scheduleToken"),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const EVIDENCE_KEYS = new Set([
|
|
165
|
+
"version",
|
|
166
|
+
"dispatchId",
|
|
167
|
+
"runId",
|
|
168
|
+
"nodeId",
|
|
169
|
+
"state",
|
|
170
|
+
"attempt",
|
|
171
|
+
"generation",
|
|
172
|
+
"at",
|
|
173
|
+
"scheduleToken",
|
|
174
|
+
"idempotencyKey",
|
|
175
|
+
"code",
|
|
176
|
+
]);
|
|
177
|
+
const STATES = new Set([
|
|
178
|
+
"queued",
|
|
179
|
+
"leased",
|
|
180
|
+
"checkpointed",
|
|
181
|
+
"retrying",
|
|
182
|
+
"succeeded",
|
|
183
|
+
"failed",
|
|
184
|
+
"cancelled",
|
|
185
|
+
"dead-lettered",
|
|
186
|
+
]);
|
|
187
|
+
export function parseRunDispatchEvidence(value) {
|
|
188
|
+
const input = record(value, "run dispatch evidence");
|
|
189
|
+
rejectKeys(input, EVIDENCE_KEYS, "run dispatch evidence");
|
|
190
|
+
if (input.version !== RUN_DISPATCH_VERSION)
|
|
191
|
+
throw new TypeError("run dispatch evidence.version is unsupported");
|
|
192
|
+
if (typeof input.state !== "string" || !STATES.has(input.state))
|
|
193
|
+
throw new TypeError("run dispatch evidence.state is invalid");
|
|
194
|
+
return Object.freeze({
|
|
195
|
+
version: RUN_DISPATCH_VERSION,
|
|
196
|
+
dispatchId: token(input.dispatchId, "dispatchId"),
|
|
197
|
+
runId: token(input.runId, "runId"),
|
|
198
|
+
nodeId: token(input.nodeId, "nodeId"),
|
|
199
|
+
state: input.state,
|
|
200
|
+
attempt: attempts(input.attempt),
|
|
201
|
+
generation: nonNegative(input.generation, "generation"),
|
|
202
|
+
at: nonNegative(input.at, "at"),
|
|
203
|
+
scheduleToken: token(input.scheduleToken, "scheduleToken"),
|
|
204
|
+
idempotencyKey: token(input.idempotencyKey, "idempotencyKey"),
|
|
205
|
+
...(input.code === undefined ? {} : { code: token(input.code, "code") }),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/** Stable key for one logical node attempt. Duplicate delivery uses the same boundary number. */
|
|
209
|
+
export function deriveRunIdempotencyKey(planDigest, runId, nodeId, logicalAttemptBoundary) {
|
|
210
|
+
const plan = digest(planDigest, "planDigest");
|
|
211
|
+
const run = token(runId, "runId");
|
|
212
|
+
const node = token(nodeId, "nodeId");
|
|
213
|
+
const attempt = attempts(logicalAttemptBoundary);
|
|
214
|
+
return sha256HexOf(`${plan}\u0000${run}\u0000${node}\u0000${attempt}`);
|
|
215
|
+
}
|
|
216
|
+
/** Create a parsed dispatch identity before handing it to any adapter. */
|
|
217
|
+
export function createRunDispatch(input) {
|
|
218
|
+
return parseRunDispatch({ version: RUN_DISPATCH_VERSION, ...input });
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/orchestration/dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter from the dependency-free jobs lease contract to run-node dispatch.
|
|
3
|
+
*
|
|
4
|
+
* The supplied JobStore should be dedicated to this adapter (JobStore has no claim-by-name
|
|
5
|
+
* operation). Its persisted payload is the parsed, content-free RunDispatch identity. The adapter
|
|
6
|
+
* adds lease generations and rejects stale completions in-process; a durable operated implementation
|
|
7
|
+
* must enforce the same compare-and-commit rule in its data layer.
|
|
8
|
+
*/
|
|
9
|
+
import type { JobStore } from "@nifrajs/jobs";
|
|
10
|
+
import { type RunDispatchEvidence, type RunDispatchStore } from "./dispatch.js";
|
|
11
|
+
export interface DurableJobsStoreOptions {
|
|
12
|
+
/** A dedicated at-least-once JobStore. Defaults to disposable in-memory storage. */
|
|
13
|
+
readonly store?: JobStore;
|
|
14
|
+
/** Injected time source used for lease and cancellation decisions. */
|
|
15
|
+
readonly now?: () => number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create an at-least-once run dispatch store over an existing JobStore.
|
|
19
|
+
*
|
|
20
|
+
* JobStore's `attempt` increments only when a caller explicitly retries; an expired lease is
|
|
21
|
+
* redelivered at the same logical attempt, which is what makes the idempotency key stable across a
|
|
22
|
+
* duplicate delivery. A retry intentionally advances the logical attempt and gets a new key.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createDurableJobsStore(options?: DurableJobsStoreOptions): RunDispatchStore & {
|
|
25
|
+
readonly jobs: JobStore;
|
|
26
|
+
deadLetters(): readonly RunDispatchEvidence[];
|
|
27
|
+
};
|
|
28
|
+
/** Disposable local reference adapter; it makes no durability or exactly-once guarantee. */
|
|
29
|
+
export declare function createMemoryRunDispatchStore(options?: {
|
|
30
|
+
readonly now?: () => number;
|
|
31
|
+
}): RunDispatchStore & {
|
|
32
|
+
readonly jobs: JobStore;
|
|
33
|
+
deadLetters(): readonly RunDispatchEvidence[];
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=durable-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durable-jobs.d.ts","sourceRoot":"","sources":["../../src/orchestration/durable-jobs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,eAAe,CAAA;AAExD,OAAO,EAcL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,uBAAuB;IACtC,oFAAoF;IACpF,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;IACzB,sEAAsE;IACtE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC5B;AA+ED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,GAAG;IAChG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,WAAW,IAAI,SAAS,mBAAmB,EAAE,CAAA;CAC9C,CA+OA;AAED,4FAA4F;AAC5F,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GAC5C,gBAAgB,GAAG;IACpB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,WAAW,IAAI,SAAS,mBAAmB,EAAE,CAAA;CAC9C,CAEA"}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter from the dependency-free jobs lease contract to run-node dispatch.
|
|
3
|
+
*
|
|
4
|
+
* The supplied JobStore should be dedicated to this adapter (JobStore has no claim-by-name
|
|
5
|
+
* operation). Its persisted payload is the parsed, content-free RunDispatch identity. The adapter
|
|
6
|
+
* adds lease generations and rejects stale completions in-process; a durable operated implementation
|
|
7
|
+
* must enforce the same compare-and-commit rule in its data layer.
|
|
8
|
+
*/
|
|
9
|
+
import { MemoryJobStore } from "@nifrajs/jobs";
|
|
10
|
+
import { DISPATCH_JOB_NAME, deriveRunIdempotencyKey, parseRunCheckpoint, parseRunDispatch, parseRunDispatchEvidence, parseRunLease, RUN_DISPATCH_VERSION, } from "./dispatch.js";
|
|
11
|
+
function code(value) {
|
|
12
|
+
if (!/^[A-Za-z0-9_.:-]{1,256}$/.test(value))
|
|
13
|
+
throw new TypeError("dispatch code must be a stable token");
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function result(codeValue) {
|
|
17
|
+
return { ok: codeValue === "accepted", code: codeValue };
|
|
18
|
+
}
|
|
19
|
+
function leaseMatches(entry, lease) {
|
|
20
|
+
return (entry !== undefined &&
|
|
21
|
+
entry.leaseId === lease.leaseId &&
|
|
22
|
+
entry.generation === lease.generation &&
|
|
23
|
+
entry.attempt === lease.attempt &&
|
|
24
|
+
entry.dispatch.dispatchId === lease.dispatch.dispatchId &&
|
|
25
|
+
entry.dispatch.planDigest === lease.dispatch.planDigest &&
|
|
26
|
+
entry.dispatch.nodeId === lease.dispatch.nodeId &&
|
|
27
|
+
entry.lease?.idempotencyKey === lease.idempotencyKey);
|
|
28
|
+
}
|
|
29
|
+
function isTerminal(state) {
|
|
30
|
+
return (state === "succeeded" ||
|
|
31
|
+
state === "failed" ||
|
|
32
|
+
state === "cancelled" ||
|
|
33
|
+
state === "dead-lettered");
|
|
34
|
+
}
|
|
35
|
+
function evidenceFor(entry, state, at, scheduleToken, idempotencyKey, codeValue) {
|
|
36
|
+
return parseRunDispatchEvidence({
|
|
37
|
+
version: RUN_DISPATCH_VERSION,
|
|
38
|
+
dispatchId: entry.dispatch.dispatchId,
|
|
39
|
+
runId: entry.dispatch.runId,
|
|
40
|
+
nodeId: entry.dispatch.nodeId,
|
|
41
|
+
state,
|
|
42
|
+
attempt: entry.attempt,
|
|
43
|
+
generation: entry.generation,
|
|
44
|
+
at,
|
|
45
|
+
scheduleToken,
|
|
46
|
+
idempotencyKey,
|
|
47
|
+
...(codeValue === undefined ? {} : { code: code(codeValue) }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function appendEvidence(entry, item) {
|
|
51
|
+
entry.evidence.push(parseRunDispatchEvidence(item));
|
|
52
|
+
}
|
|
53
|
+
function dispatchFromJob(job) {
|
|
54
|
+
if (job.name !== DISPATCH_JOB_NAME)
|
|
55
|
+
throw new TypeError("jobs adapter received an unrelated job");
|
|
56
|
+
return parseRunDispatch(job.payload);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create an at-least-once run dispatch store over an existing JobStore.
|
|
60
|
+
*
|
|
61
|
+
* JobStore's `attempt` increments only when a caller explicitly retries; an expired lease is
|
|
62
|
+
* redelivered at the same logical attempt, which is what makes the idempotency key stable across a
|
|
63
|
+
* duplicate delivery. A retry intentionally advances the logical attempt and gets a new key.
|
|
64
|
+
*/
|
|
65
|
+
export function createDurableJobsStore(options = {}) {
|
|
66
|
+
const jobs = options.store ?? new MemoryJobStore();
|
|
67
|
+
const now = options.now ?? (() => Date.now());
|
|
68
|
+
const byJobId = new Map();
|
|
69
|
+
const byDispatchId = new Map();
|
|
70
|
+
let generation = 0;
|
|
71
|
+
const dead = [];
|
|
72
|
+
async function enqueue(source) {
|
|
73
|
+
const dispatch = parseRunDispatch(source);
|
|
74
|
+
if (byDispatchId.has(dispatch.dispatchId))
|
|
75
|
+
throw new Error("duplicate dispatch id");
|
|
76
|
+
const jobId = await jobs.enqueue({
|
|
77
|
+
name: DISPATCH_JOB_NAME,
|
|
78
|
+
payload: dispatch,
|
|
79
|
+
runAt: dispatch.notBefore,
|
|
80
|
+
maxAttempts: dispatch.maxAttempts,
|
|
81
|
+
});
|
|
82
|
+
const entry = {
|
|
83
|
+
dispatch,
|
|
84
|
+
jobId,
|
|
85
|
+
state: "queued",
|
|
86
|
+
attempt: 1,
|
|
87
|
+
generation: 0,
|
|
88
|
+
leaseId: undefined,
|
|
89
|
+
leaseUntil: 0,
|
|
90
|
+
lease: undefined,
|
|
91
|
+
checkpoint: undefined,
|
|
92
|
+
evidence: [],
|
|
93
|
+
};
|
|
94
|
+
byJobId.set(jobId, entry);
|
|
95
|
+
byDispatchId.set(dispatch.dispatchId, entry);
|
|
96
|
+
}
|
|
97
|
+
async function lease(at, limit, leaseMs) {
|
|
98
|
+
if (!Number.isSafeInteger(at) || at < 0)
|
|
99
|
+
throw new RangeError("dispatch lease time is invalid");
|
|
100
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
101
|
+
throw new RangeError("dispatch lease limit is invalid");
|
|
102
|
+
if (!Number.isFinite(leaseMs) || leaseMs <= 0)
|
|
103
|
+
throw new RangeError("dispatch lease duration is invalid");
|
|
104
|
+
const jobsLeased = await jobs.lease(at, limit, leaseMs);
|
|
105
|
+
const resultLeases = [];
|
|
106
|
+
for (const job of jobsLeased) {
|
|
107
|
+
const dispatch = dispatchFromJob(job);
|
|
108
|
+
const entry = byJobId.get(job.id) ?? byDispatchId.get(dispatch.dispatchId);
|
|
109
|
+
if (entry === undefined)
|
|
110
|
+
throw new Error("jobs adapter lost dispatch identity");
|
|
111
|
+
if (isTerminal(entry.state))
|
|
112
|
+
continue;
|
|
113
|
+
entry.state = "leased";
|
|
114
|
+
entry.attempt = job.attempt + 1;
|
|
115
|
+
entry.generation = ++generation;
|
|
116
|
+
entry.leaseUntil = at + leaseMs;
|
|
117
|
+
entry.leaseId = `${job.id}:${entry.generation}`;
|
|
118
|
+
const idempotencyKey = await deriveRunIdempotencyKey(dispatch.planDigest, dispatch.runId, dispatch.nodeId, entry.attempt);
|
|
119
|
+
const value = parseRunLease({
|
|
120
|
+
version: RUN_DISPATCH_VERSION,
|
|
121
|
+
leaseId: entry.leaseId,
|
|
122
|
+
dispatch,
|
|
123
|
+
attempt: entry.attempt,
|
|
124
|
+
generation: entry.generation,
|
|
125
|
+
leasedAt: at,
|
|
126
|
+
leaseUntil: entry.leaseUntil,
|
|
127
|
+
scheduleToken: `${job.id}:${entry.generation}`,
|
|
128
|
+
idempotencyKey,
|
|
129
|
+
});
|
|
130
|
+
entry.lease = value;
|
|
131
|
+
appendEvidence(entry, evidenceFor(entry, "leased", at, value.scheduleToken, value.idempotencyKey));
|
|
132
|
+
resultLeases.push(value);
|
|
133
|
+
}
|
|
134
|
+
return resultLeases;
|
|
135
|
+
}
|
|
136
|
+
function current(lease) {
|
|
137
|
+
return byDispatchId.get(lease.dispatch.dispatchId);
|
|
138
|
+
}
|
|
139
|
+
async function checkpoint(lease, source) {
|
|
140
|
+
const value = parseRunCheckpoint(source);
|
|
141
|
+
const entry = current(lease);
|
|
142
|
+
if (!leaseMatches(entry, lease))
|
|
143
|
+
return result("stale_lease");
|
|
144
|
+
if (entry.state === "cancelled")
|
|
145
|
+
return result("cancelled");
|
|
146
|
+
if (isTerminal(entry.state))
|
|
147
|
+
return result("terminal");
|
|
148
|
+
if (now() >= entry.leaseUntil)
|
|
149
|
+
return result("stale_lease");
|
|
150
|
+
if (value.dispatchId !== lease.dispatch.dispatchId ||
|
|
151
|
+
value.runId !== lease.dispatch.runId ||
|
|
152
|
+
value.nodeId !== lease.dispatch.nodeId ||
|
|
153
|
+
value.attempt !== lease.attempt ||
|
|
154
|
+
value.generation !== lease.generation ||
|
|
155
|
+
value.idempotencyKey !== lease.idempotencyKey)
|
|
156
|
+
return result("invalid_checkpoint");
|
|
157
|
+
entry.checkpoint = value;
|
|
158
|
+
entry.state = "checkpointed";
|
|
159
|
+
appendEvidence(entry, evidenceFor(entry, "checkpointed", value.at, value.scheduleToken, value.idempotencyKey));
|
|
160
|
+
return result("accepted");
|
|
161
|
+
}
|
|
162
|
+
async function complete(lease, source) {
|
|
163
|
+
const entry = current(lease);
|
|
164
|
+
if (!leaseMatches(entry, lease))
|
|
165
|
+
return result("stale_lease");
|
|
166
|
+
if (entry.state === "cancelled")
|
|
167
|
+
return result("cancelled");
|
|
168
|
+
if (isTerminal(entry.state))
|
|
169
|
+
return result("terminal");
|
|
170
|
+
if (now() >= entry.leaseUntil)
|
|
171
|
+
return result("stale_lease");
|
|
172
|
+
if (source !== undefined) {
|
|
173
|
+
const evidence = parseRunDispatchEvidence(source);
|
|
174
|
+
if (evidence.dispatchId !== lease.dispatch.dispatchId ||
|
|
175
|
+
evidence.attempt !== lease.attempt ||
|
|
176
|
+
evidence.generation !== lease.generation ||
|
|
177
|
+
evidence.idempotencyKey !== lease.idempotencyKey)
|
|
178
|
+
return result("invalid_checkpoint");
|
|
179
|
+
}
|
|
180
|
+
await jobs.complete(entry.jobId);
|
|
181
|
+
entry.state = "succeeded";
|
|
182
|
+
appendEvidence(entry, source ?? evidenceFor(entry, "succeeded", now(), lease.scheduleToken, lease.idempotencyKey));
|
|
183
|
+
entry.lease = undefined;
|
|
184
|
+
return result("accepted");
|
|
185
|
+
}
|
|
186
|
+
async function retry(lease, runAt, failureCode) {
|
|
187
|
+
const entry = current(lease);
|
|
188
|
+
if (!leaseMatches(entry, lease))
|
|
189
|
+
return result("stale_lease");
|
|
190
|
+
if (entry.state === "cancelled")
|
|
191
|
+
return result("cancelled");
|
|
192
|
+
if (isTerminal(entry.state))
|
|
193
|
+
return result("terminal");
|
|
194
|
+
if (now() >= entry.leaseUntil)
|
|
195
|
+
return result("stale_lease");
|
|
196
|
+
if (!Number.isSafeInteger(runAt) || runAt < 0)
|
|
197
|
+
throw new RangeError("dispatch retry time is invalid");
|
|
198
|
+
await jobs.retry(entry.jobId, runAt);
|
|
199
|
+
entry.state = "retrying";
|
|
200
|
+
entry.checkpoint = undefined;
|
|
201
|
+
appendEvidence(entry, evidenceFor(entry, "retrying", now(), lease.scheduleToken, lease.idempotencyKey, failureCode));
|
|
202
|
+
entry.lease = undefined;
|
|
203
|
+
return result("accepted");
|
|
204
|
+
}
|
|
205
|
+
async function deadLetter(lease, failureCode) {
|
|
206
|
+
const entry = current(lease);
|
|
207
|
+
if (!leaseMatches(entry, lease))
|
|
208
|
+
return result("stale_lease");
|
|
209
|
+
if (entry.state === "cancelled")
|
|
210
|
+
return result("cancelled");
|
|
211
|
+
if (isTerminal(entry.state))
|
|
212
|
+
return result("terminal");
|
|
213
|
+
if (now() >= entry.leaseUntil)
|
|
214
|
+
return result("stale_lease");
|
|
215
|
+
const stableCode = code(failureCode);
|
|
216
|
+
await jobs.deadLetter(entry.jobId, stableCode);
|
|
217
|
+
entry.state = "dead-lettered";
|
|
218
|
+
const evidence = evidenceFor(entry, "dead-lettered", now(), lease.scheduleToken, lease.idempotencyKey, stableCode);
|
|
219
|
+
appendEvidence(entry, evidence);
|
|
220
|
+
dead.push(evidence);
|
|
221
|
+
entry.lease = undefined;
|
|
222
|
+
return result("accepted");
|
|
223
|
+
}
|
|
224
|
+
async function cancel(runId, cancellationCode = "cancelled") {
|
|
225
|
+
const stableCode = code(cancellationCode);
|
|
226
|
+
let changed = 0;
|
|
227
|
+
for (const entry of byDispatchId.values()) {
|
|
228
|
+
if (entry.dispatch.runId !== runId || isTerminal(entry.state))
|
|
229
|
+
continue;
|
|
230
|
+
entry.state = "cancelled";
|
|
231
|
+
changed++;
|
|
232
|
+
const lease = entry.lease;
|
|
233
|
+
appendEvidence(entry, evidenceFor(entry, "cancelled", now(), lease?.scheduleToken ?? `${entry.jobId}:cancel`, lease?.idempotencyKey ??
|
|
234
|
+
(await deriveRunIdempotencyKey(entry.dispatch.planDigest, entry.dispatch.runId, entry.dispatch.nodeId, entry.attempt)), stableCode));
|
|
235
|
+
if (lease !== undefined)
|
|
236
|
+
await jobs.deadLetter(entry.jobId, stableCode);
|
|
237
|
+
else
|
|
238
|
+
await jobs.deadLetter(entry.jobId, stableCode);
|
|
239
|
+
entry.lease = undefined;
|
|
240
|
+
}
|
|
241
|
+
return changed;
|
|
242
|
+
}
|
|
243
|
+
function inspect(dispatchId) {
|
|
244
|
+
const entry = byDispatchId.get(dispatchId);
|
|
245
|
+
if (entry === undefined)
|
|
246
|
+
return undefined;
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
dispatch: entry.dispatch,
|
|
249
|
+
state: entry.state,
|
|
250
|
+
attempt: entry.attempt,
|
|
251
|
+
generation: entry.generation,
|
|
252
|
+
...(entry.checkpoint === undefined ? {} : { checkpoint: entry.checkpoint }),
|
|
253
|
+
evidence: Object.freeze([...entry.evidence]),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
jobs,
|
|
258
|
+
enqueue,
|
|
259
|
+
lease,
|
|
260
|
+
checkpoint,
|
|
261
|
+
complete,
|
|
262
|
+
retry,
|
|
263
|
+
deadLetter,
|
|
264
|
+
cancel,
|
|
265
|
+
inspect,
|
|
266
|
+
deadLetters: () => Object.freeze([...dead]),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/** Disposable local reference adapter; it makes no durability or exactly-once guarantee. */
|
|
270
|
+
export function createMemoryRunDispatchStore(options = {}) {
|
|
271
|
+
return createDurableJobsStore({ store: new MemoryJobStore(), ...options });
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=durable-jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"durable-jobs.js","sourceRoot":"","sources":["../../src/orchestration/durable-jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-free idempotency identity for one side-effecting node attempt-boundary.
|
|
3
|
+
*
|
|
4
|
+
* The step author projects only the identity-bearing subset of its input into a byte `selector`
|
|
5
|
+
* (via `CatalogStep.selectEffect`). {@link deriveNodeEffectKey} frames that selector with the
|
|
6
|
+
* non-secret plan/node coordinates and hashes the whole to a digest. The digest is what crosses a
|
|
7
|
+
* boundary or lands in evidence; the selector bytes never leave this function. This mirrors
|
|
8
|
+
* `@nifrajs/core`'s `computeIdempotencyFingerprint`: the hash is the key, the material is consumed.
|
|
9
|
+
*/
|
|
10
|
+
import type { NodeEffectKey } from "@nifrajs/agent-protocol";
|
|
11
|
+
/** Inputs to the effect-key derivation. `selector` is the step's content-free identity projection. */
|
|
12
|
+
export interface EffectKeyMaterial {
|
|
13
|
+
readonly planDigest: string;
|
|
14
|
+
readonly nodeId: string;
|
|
15
|
+
/** Identity-bearing bytes chosen by the step. Consumed into the hash, never retained. */
|
|
16
|
+
readonly selector: Uint8Array;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Derive the stable, content-free key for a node attempt. The returned digest is safe to log and to
|
|
20
|
+
* cross a boundary; two attempts with the same identity converge, distinct identities diverge.
|
|
21
|
+
*/
|
|
22
|
+
export declare function deriveNodeEffectKey(material: EffectKeyMaterial): Promise<NodeEffectKey>;
|
|
23
|
+
//# sourceMappingURL=effect-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-key.d.ts","sourceRoot":"","sources":["../../src/orchestration/effect-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAK5D,sGAAsG;AACtG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAA;CAC9B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAO7F"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-free idempotency identity for one side-effecting node attempt-boundary.
|
|
3
|
+
*
|
|
4
|
+
* The step author projects only the identity-bearing subset of its input into a byte `selector`
|
|
5
|
+
* (via `CatalogStep.selectEffect`). {@link deriveNodeEffectKey} frames that selector with the
|
|
6
|
+
* non-secret plan/node coordinates and hashes the whole to a digest. The digest is what crosses a
|
|
7
|
+
* boundary or lands in evidence; the selector bytes never leave this function. This mirrors
|
|
8
|
+
* `@nifrajs/core`'s `computeIdempotencyFingerprint`: the hash is the key, the material is consumed.
|
|
9
|
+
*/
|
|
10
|
+
import { sha256Hex } from "./hash.js";
|
|
11
|
+
const encoder = new TextEncoder();
|
|
12
|
+
/**
|
|
13
|
+
* Derive the stable, content-free key for a node attempt. The returned digest is safe to log and to
|
|
14
|
+
* cross a boundary; two attempts with the same identity converge, distinct identities diverge.
|
|
15
|
+
*/
|
|
16
|
+
export async function deriveNodeEffectKey(material) {
|
|
17
|
+
const header = encoder.encode(`${material.planDigest}\n${material.nodeId}\n`);
|
|
18
|
+
const framed = new Uint8Array(header.length + material.selector.length);
|
|
19
|
+
framed.set(header, 0);
|
|
20
|
+
framed.set(material.selector, header.length);
|
|
21
|
+
const digest = await sha256Hex(framed);
|
|
22
|
+
return { digest, planDigest: material.planDigest, nodeId: material.nodeId };
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=effect-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-key.js","sourceRoot":"","sources":["../../src/orchestration/effect-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;AAUjC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAA2B;IACnE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAA;IAC7E,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACvE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACrB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAC5C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAA;IACtC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;AAC7E,CAAC"}
|