@a5c-ai/babysitter-sdk 0.0.16
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/dist/cli/main.d.ts +5 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +1343 -0
- package/dist/cli/nodeTaskRunner.d.ts +16 -0
- package/dist/cli/nodeTaskRunner.d.ts.map +1 -0
- package/dist/cli/nodeTaskRunner.js +46 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/runner/env.d.ts +58 -0
- package/dist/runner/env.d.ts.map +1 -0
- package/dist/runner/env.js +113 -0
- package/dist/runner/index.d.ts +3 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +18 -0
- package/dist/runner/nodeRunner.d.ts +60 -0
- package/dist/runner/nodeRunner.d.ts.map +1 -0
- package/dist/runner/nodeRunner.js +354 -0
- package/dist/runtime/commitEffectResult.d.ts +3 -0
- package/dist/runtime/commitEffectResult.d.ts.map +1 -0
- package/dist/runtime/commitEffectResult.js +172 -0
- package/dist/runtime/constants.d.ts +2 -0
- package/dist/runtime/constants.d.ts.map +1 -0
- package/dist/runtime/constants.js +5 -0
- package/dist/runtime/createRun.d.ts +3 -0
- package/dist/runtime/createRun.d.ts.map +1 -0
- package/dist/runtime/createRun.js +81 -0
- package/dist/runtime/errorUtils.d.ts +10 -0
- package/dist/runtime/errorUtils.d.ts.map +1 -0
- package/dist/runtime/errorUtils.js +42 -0
- package/dist/runtime/exceptions.d.ts +45 -0
- package/dist/runtime/exceptions.d.ts.map +1 -0
- package/dist/runtime/exceptions.js +99 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +34 -0
- package/dist/runtime/instrumentation.d.ts +6 -0
- package/dist/runtime/instrumentation.d.ts.map +1 -0
- package/dist/runtime/instrumentation.js +14 -0
- package/dist/runtime/intrinsics/breakpoint.d.ts +4 -0
- package/dist/runtime/intrinsics/breakpoint.d.ts.map +1 -0
- package/dist/runtime/intrinsics/breakpoint.js +42 -0
- package/dist/runtime/intrinsics/index.d.ts +7 -0
- package/dist/runtime/intrinsics/index.d.ts.map +1 -0
- package/dist/runtime/intrinsics/index.js +15 -0
- package/dist/runtime/intrinsics/orchestratorTask.d.ts +4 -0
- package/dist/runtime/intrinsics/orchestratorTask.d.ts.map +1 -0
- package/dist/runtime/intrinsics/orchestratorTask.js +28 -0
- package/dist/runtime/intrinsics/parallel.d.ts +5 -0
- package/dist/runtime/intrinsics/parallel.d.ts.map +1 -0
- package/dist/runtime/intrinsics/parallel.js +45 -0
- package/dist/runtime/intrinsics/sleep.d.ts +4 -0
- package/dist/runtime/intrinsics/sleep.d.ts.map +1 -0
- package/dist/runtime/intrinsics/sleep.js +70 -0
- package/dist/runtime/intrinsics/task.d.ts +20 -0
- package/dist/runtime/intrinsics/task.d.ts.map +1 -0
- package/dist/runtime/intrinsics/task.js +237 -0
- package/dist/runtime/invocation/hashInvocationKey.d.ts +12 -0
- package/dist/runtime/invocation/hashInvocationKey.d.ts.map +1 -0
- package/dist/runtime/invocation/hashInvocationKey.js +12 -0
- package/dist/runtime/invocation/index.d.ts +3 -0
- package/dist/runtime/invocation/index.d.ts.map +1 -0
- package/dist/runtime/invocation/index.js +5 -0
- package/dist/runtime/orchestrateIteration.d.ts +3 -0
- package/dist/runtime/orchestrateIteration.d.ts.map +1 -0
- package/dist/runtime/orchestrateIteration.js +195 -0
- package/dist/runtime/processContext.d.ts +19 -0
- package/dist/runtime/processContext.d.ts.map +1 -0
- package/dist/runtime/processContext.js +55 -0
- package/dist/runtime/replay/createReplayEngine.d.ts +31 -0
- package/dist/runtime/replay/createReplayEngine.d.ts.map +1 -0
- package/dist/runtime/replay/createReplayEngine.js +82 -0
- package/dist/runtime/replay/effectIndex.d.ts +34 -0
- package/dist/runtime/replay/effectIndex.d.ts.map +1 -0
- package/dist/runtime/replay/effectIndex.js +241 -0
- package/dist/runtime/replay/index.d.ts +7 -0
- package/dist/runtime/replay/index.d.ts.map +1 -0
- package/dist/runtime/replay/index.js +19 -0
- package/dist/runtime/replay/replayCursor.d.ts +7 -0
- package/dist/runtime/replay/replayCursor.d.ts.map +1 -0
- package/dist/runtime/replay/replayCursor.js +22 -0
- package/dist/runtime/replay/stateCache.d.ts +48 -0
- package/dist/runtime/replay/stateCache.d.ts.map +1 -0
- package/dist/runtime/replay/stateCache.js +211 -0
- package/dist/runtime/types.d.ts +147 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/storage/atomic.d.ts +2 -0
- package/dist/storage/atomic.d.ts.map +1 -0
- package/dist/storage/atomic.js +54 -0
- package/dist/storage/cleanup.d.ts +4 -0
- package/dist/storage/cleanup.d.ts.map +1 -0
- package/dist/storage/cleanup.js +96 -0
- package/dist/storage/clock.d.ts +6 -0
- package/dist/storage/clock.d.ts.map +1 -0
- package/dist/storage/clock.js +29 -0
- package/dist/storage/createRunDir.d.ts +6 -0
- package/dist/storage/createRunDir.d.ts.map +1 -0
- package/dist/storage/createRunDir.js +59 -0
- package/dist/storage/index.d.ts +9 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +28 -0
- package/dist/storage/journal.d.ts +4 -0
- package/dist/storage/journal.d.ts.map +1 -0
- package/dist/storage/journal.js +103 -0
- package/dist/storage/lock.d.ts +5 -0
- package/dist/storage/lock.d.ts.map +1 -0
- package/dist/storage/lock.js +41 -0
- package/dist/storage/paths.d.ts +19 -0
- package/dist/storage/paths.d.ts.map +1 -0
- package/dist/storage/paths.js +46 -0
- package/dist/storage/runFiles.d.ts +5 -0
- package/dist/storage/runFiles.d.ts.map +1 -0
- package/dist/storage/runFiles.js +39 -0
- package/dist/storage/snapshotState.d.ts +10 -0
- package/dist/storage/snapshotState.d.ts.map +1 -0
- package/dist/storage/snapshotState.js +15 -0
- package/dist/storage/storeTaskArtifacts.d.ts +6 -0
- package/dist/storage/storeTaskArtifacts.d.ts.map +1 -0
- package/dist/storage/storeTaskArtifacts.js +58 -0
- package/dist/storage/tasks.d.ts +17 -0
- package/dist/storage/tasks.d.ts.map +1 -0
- package/dist/storage/tasks.js +82 -0
- package/dist/storage/types.d.ts +112 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage/ulids.d.ts +11 -0
- package/dist/storage/ulids.d.ts.map +1 -0
- package/dist/storage/ulids.js +25 -0
- package/dist/tasks/batching.d.ts +29 -0
- package/dist/tasks/batching.d.ts.map +1 -0
- package/dist/tasks/batching.js +66 -0
- package/dist/tasks/context.d.ts +11 -0
- package/dist/tasks/context.d.ts.map +1 -0
- package/dist/tasks/context.js +181 -0
- package/dist/tasks/defineTask.d.ts +9 -0
- package/dist/tasks/defineTask.d.ts.map +1 -0
- package/dist/tasks/defineTask.js +58 -0
- package/dist/tasks/index.d.ts +8 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +23 -0
- package/dist/tasks/kinds/index.d.ts +7 -0
- package/dist/tasks/kinds/index.d.ts.map +1 -0
- package/dist/tasks/kinds/index.js +333 -0
- package/dist/tasks/registry.d.ts +53 -0
- package/dist/tasks/registry.d.ts.map +1 -0
- package/dist/tasks/registry.js +145 -0
- package/dist/tasks/serializer.d.ts +60 -0
- package/dist/tasks/serializer.d.ts.map +1 -0
- package/dist/tasks/serializer.js +193 -0
- package/dist/tasks/types.d.ts +148 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +2 -0
- package/dist/test-fixtures/kinds/index.d.ts +56 -0
- package/dist/test-fixtures/kinds/index.d.ts.map +1 -0
- package/dist/test-fixtures/kinds/index.js +44 -0
- package/dist/testing/deterministic.d.ts +90 -0
- package/dist/testing/deterministic.d.ts.map +1 -0
- package/dist/testing/deterministic.js +449 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +23 -0
- package/dist/testing/runHarness.d.ts +64 -0
- package/dist/testing/runHarness.d.ts.map +1 -0
- package/dist/testing/runHarness.js +161 -0
- package/dist/testing/snapshots.d.ts +17 -0
- package/dist/testing/snapshots.d.ts.map +1 -0
- package/dist/testing/snapshots.js +24 -0
- package/package.json +35 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runTaskIntrinsic = runTaskIntrinsic;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const journal_1 = require("../../storage/journal");
|
|
10
|
+
const tasks_1 = require("../../storage/tasks");
|
|
11
|
+
const ulids_1 = require("../../storage/ulids");
|
|
12
|
+
const exceptions_1 = require("../exceptions");
|
|
13
|
+
const invocation_1 = require("../invocation");
|
|
14
|
+
const instrumentation_1 = require("../instrumentation");
|
|
15
|
+
const context_1 = require("../../tasks/context");
|
|
16
|
+
const registry_1 = require("../../tasks/registry");
|
|
17
|
+
const serializer_1 = require("../../tasks/serializer");
|
|
18
|
+
async function runTaskIntrinsic(options) {
|
|
19
|
+
const { task } = options;
|
|
20
|
+
if (!task || typeof task.build !== "function" || typeof task.id !== "string" || !task.id) {
|
|
21
|
+
throw new exceptions_1.InvalidTaskDefinitionError("ctx.task requires a DefinedTask created via defineTask()");
|
|
22
|
+
}
|
|
23
|
+
const stepId = options.context.replayCursor.nextStepId();
|
|
24
|
+
const invocation = (0, invocation_1.hashInvocationKey)({
|
|
25
|
+
processId: options.context.processId,
|
|
26
|
+
stepId,
|
|
27
|
+
taskId: task.id,
|
|
28
|
+
});
|
|
29
|
+
const existing = options.context.effectIndex.getByInvocation(invocation.key);
|
|
30
|
+
if (existing) {
|
|
31
|
+
return handleExistingInvocation(existing, options);
|
|
32
|
+
}
|
|
33
|
+
return requestNewEffect(stepId, invocation.key, invocation.digest, options);
|
|
34
|
+
}
|
|
35
|
+
async function handleExistingInvocation(record, options) {
|
|
36
|
+
if (record.status === "requested") {
|
|
37
|
+
const taskDef = await ensureTaskDefinition(options.context.runDir, record);
|
|
38
|
+
throw new exceptions_1.EffectPendingError(buildEffectAction(record, taskDef));
|
|
39
|
+
}
|
|
40
|
+
if (record.status === "resolved_error") {
|
|
41
|
+
const error = record.error ? (0, exceptions_1.rehydrateSerializedError)(record.error) : new Error("Task failed");
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
const stored = await (0, tasks_1.readTaskResult)(options.context.runDir, record.effectId, record.resultRef ? normalizeRef(options.context.runDir, record.resultRef) : undefined);
|
|
45
|
+
if (!stored) {
|
|
46
|
+
throw new exceptions_1.RunFailedError(`Result for effect ${record.effectId} is missing from disk`, {
|
|
47
|
+
effectId: record.effectId,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (stored.status !== "ok") {
|
|
51
|
+
const err = stored.error ? (0, exceptions_1.rehydrateSerializedError)(stored.error) : new Error("Task reported failure");
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
const value = await resolveStoredResultValue(options.context.runDir, stored);
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
async function requestNewEffect(stepId, invocationKey, invocationHash, options) {
|
|
58
|
+
const effectId = (0, ulids_1.nextUlid)();
|
|
59
|
+
const buildCtx = (0, context_1.createTaskBuildContext)({
|
|
60
|
+
effectId,
|
|
61
|
+
runId: options.context.runId,
|
|
62
|
+
runDir: options.context.runDir,
|
|
63
|
+
invocationKey,
|
|
64
|
+
taskId: options.task.id,
|
|
65
|
+
label: options.invokeOptions?.label,
|
|
66
|
+
});
|
|
67
|
+
const taskDef = await Promise.resolve(options.task.build(options.args, buildCtx));
|
|
68
|
+
if (!taskDef || typeof taskDef.kind !== "string") {
|
|
69
|
+
throw new exceptions_1.InvalidTaskDefinitionError(`Task ${options.task.id} did not provide a kind`);
|
|
70
|
+
}
|
|
71
|
+
const { taskRef: taskDefRef, inputsRef } = await (0, serializer_1.serializeAndWriteTaskDefinition)({
|
|
72
|
+
runDir: options.context.runDir,
|
|
73
|
+
effectId,
|
|
74
|
+
taskId: options.task.id,
|
|
75
|
+
invocationKey,
|
|
76
|
+
stepId,
|
|
77
|
+
task: taskDef,
|
|
78
|
+
inputs: options.args,
|
|
79
|
+
});
|
|
80
|
+
const kind = taskDef.kind;
|
|
81
|
+
const normalizedLabels = collectInvocationLabels(buildCtx, taskDef);
|
|
82
|
+
const label = deriveEffectLabel(buildCtx, taskDef, normalizedLabels, options.task.id);
|
|
83
|
+
const labelMetadata = normalizedLabels.length ? normalizedLabels : undefined;
|
|
84
|
+
const eventPayload = {
|
|
85
|
+
effectId,
|
|
86
|
+
invocationKey,
|
|
87
|
+
invocationHash,
|
|
88
|
+
stepId,
|
|
89
|
+
taskId: options.task.id,
|
|
90
|
+
kind,
|
|
91
|
+
label,
|
|
92
|
+
taskDefRef,
|
|
93
|
+
inputsRef,
|
|
94
|
+
labels: labelMetadata,
|
|
95
|
+
};
|
|
96
|
+
const appendResult = await (0, journal_1.appendEvent)({
|
|
97
|
+
runDir: options.context.runDir,
|
|
98
|
+
eventType: "EFFECT_REQUESTED",
|
|
99
|
+
event: eventPayload,
|
|
100
|
+
});
|
|
101
|
+
const syntheticEvent = {
|
|
102
|
+
seq: appendResult.seq,
|
|
103
|
+
ulid: appendResult.ulid,
|
|
104
|
+
filename: appendResult.filename,
|
|
105
|
+
path: appendResult.path,
|
|
106
|
+
type: "EFFECT_REQUESTED",
|
|
107
|
+
recordedAt: appendResult.recordedAt,
|
|
108
|
+
data: eventPayload,
|
|
109
|
+
checksum: appendResult.checksum,
|
|
110
|
+
};
|
|
111
|
+
try {
|
|
112
|
+
options.context.effectIndex.applyEvent(syntheticEvent);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
(0, instrumentation_1.emitRuntimeMetric)(options.context.logger, "invocation.collision", {
|
|
116
|
+
invocationKey,
|
|
117
|
+
effectId,
|
|
118
|
+
});
|
|
119
|
+
throw new exceptions_1.InvocationCollisionError(invocationKey);
|
|
120
|
+
}
|
|
121
|
+
registry_1.globalTaskRegistry.recordEffect({
|
|
122
|
+
effectId,
|
|
123
|
+
invocationKey,
|
|
124
|
+
taskId: options.task.id,
|
|
125
|
+
kind,
|
|
126
|
+
label,
|
|
127
|
+
labels: normalizedLabels,
|
|
128
|
+
status: "pending",
|
|
129
|
+
taskDefRef,
|
|
130
|
+
inputsRef,
|
|
131
|
+
metadata: taskDef.metadata,
|
|
132
|
+
stepId,
|
|
133
|
+
requestedAt: appendResult.recordedAt,
|
|
134
|
+
});
|
|
135
|
+
const actionRecord = {
|
|
136
|
+
effectId,
|
|
137
|
+
invocationKey,
|
|
138
|
+
invocationHash,
|
|
139
|
+
stepId,
|
|
140
|
+
taskId: options.task.id,
|
|
141
|
+
status: "requested",
|
|
142
|
+
kind,
|
|
143
|
+
label,
|
|
144
|
+
labels: labelMetadata,
|
|
145
|
+
taskDefRef,
|
|
146
|
+
inputsRef,
|
|
147
|
+
requestedAt: appendResult.recordedAt,
|
|
148
|
+
};
|
|
149
|
+
const action = buildEffectAction(actionRecord, taskDef);
|
|
150
|
+
throw new exceptions_1.EffectRequestedError(action);
|
|
151
|
+
}
|
|
152
|
+
async function ensureTaskDefinition(runDir, record) {
|
|
153
|
+
const stored = await (0, tasks_1.readTaskDefinition)(runDir, record.effectId);
|
|
154
|
+
if (!stored) {
|
|
155
|
+
throw new exceptions_1.RunFailedError(`Task definition missing for effect ${record.effectId}`, {
|
|
156
|
+
effectId: record.effectId,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return stored;
|
|
160
|
+
}
|
|
161
|
+
function buildEffectAction(record, taskDef) {
|
|
162
|
+
const schedulerHints = deriveSchedulerHints(taskDef);
|
|
163
|
+
return {
|
|
164
|
+
effectId: record.effectId,
|
|
165
|
+
invocationKey: record.invocationKey,
|
|
166
|
+
kind: record.kind ?? taskDef.kind,
|
|
167
|
+
label: record.label ?? record.labels?.[0] ?? taskDef.title,
|
|
168
|
+
labels: record.labels ?? taskDef.labels,
|
|
169
|
+
taskDef,
|
|
170
|
+
taskId: record.taskId,
|
|
171
|
+
stepId: record.stepId,
|
|
172
|
+
taskDefRef: record.taskDefRef,
|
|
173
|
+
inputsRef: record.inputsRef,
|
|
174
|
+
requestedAt: record.requestedAt,
|
|
175
|
+
schedulerHints,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function deriveSchedulerHints(taskDef) {
|
|
179
|
+
const hints = {};
|
|
180
|
+
const sleepHint = extractSleepTarget(taskDef);
|
|
181
|
+
if (typeof sleepHint === "number" && Number.isFinite(sleepHint)) {
|
|
182
|
+
hints.sleepUntilEpochMs = sleepHint;
|
|
183
|
+
}
|
|
184
|
+
return Object.keys(hints).length ? hints : undefined;
|
|
185
|
+
}
|
|
186
|
+
function extractSleepTarget(taskDef) {
|
|
187
|
+
if (typeof taskDef.sleep?.targetEpochMs === "number") {
|
|
188
|
+
return taskDef.sleep.targetEpochMs;
|
|
189
|
+
}
|
|
190
|
+
const metadataTarget = taskDef.metadata?.targetEpochMs;
|
|
191
|
+
return typeof metadataTarget === "number" ? metadataTarget : undefined;
|
|
192
|
+
}
|
|
193
|
+
function normalizeRef(runDir, ref) {
|
|
194
|
+
return path_1.default.isAbsolute(ref) ? ref : path_1.default.join(runDir, ref);
|
|
195
|
+
}
|
|
196
|
+
async function resolveStoredResultValue(runDir, stored) {
|
|
197
|
+
if (stored.result !== undefined) {
|
|
198
|
+
return stored.result;
|
|
199
|
+
}
|
|
200
|
+
if (stored.value !== undefined) {
|
|
201
|
+
return stored.value;
|
|
202
|
+
}
|
|
203
|
+
if (stored.resultRef) {
|
|
204
|
+
const absolute = normalizeRef(runDir, stored.resultRef);
|
|
205
|
+
const raw = await fs_1.promises.readFile(absolute, "utf8");
|
|
206
|
+
return JSON.parse(raw);
|
|
207
|
+
}
|
|
208
|
+
throw new exceptions_1.RunFailedError("Result payload missing data", { effectId: stored.effectId });
|
|
209
|
+
}
|
|
210
|
+
function collectInvocationLabels(ctx, taskDef) {
|
|
211
|
+
const combined = [];
|
|
212
|
+
const addLabels = (values) => {
|
|
213
|
+
if (!Array.isArray(values))
|
|
214
|
+
return;
|
|
215
|
+
combined.push(...values);
|
|
216
|
+
};
|
|
217
|
+
addLabels(ctx.labels);
|
|
218
|
+
addLabels(taskDef.labels);
|
|
219
|
+
return dedupeLabels(combined);
|
|
220
|
+
}
|
|
221
|
+
function dedupeLabels(values) {
|
|
222
|
+
const seen = new Set();
|
|
223
|
+
const normalized = [];
|
|
224
|
+
for (const value of values) {
|
|
225
|
+
if (typeof value !== "string")
|
|
226
|
+
continue;
|
|
227
|
+
const trimmed = value.trim();
|
|
228
|
+
if (!trimmed || seen.has(trimmed))
|
|
229
|
+
continue;
|
|
230
|
+
seen.add(trimmed);
|
|
231
|
+
normalized.push(trimmed);
|
|
232
|
+
}
|
|
233
|
+
return normalized;
|
|
234
|
+
}
|
|
235
|
+
function deriveEffectLabel(ctx, taskDef, labels, fallbackTaskId) {
|
|
236
|
+
return ctx.label ?? labels[0] ?? taskDef.title ?? fallbackTaskId;
|
|
237
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface InvocationKeyComponents {
|
|
2
|
+
processId: string;
|
|
3
|
+
stepId: string;
|
|
4
|
+
taskId: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InvocationKeyInfo {
|
|
7
|
+
key: string;
|
|
8
|
+
digest: string;
|
|
9
|
+
components: InvocationKeyComponents;
|
|
10
|
+
}
|
|
11
|
+
export declare function hashInvocationKey(components: InvocationKeyComponents): InvocationKeyInfo;
|
|
12
|
+
//# sourceMappingURL=hashInvocationKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashInvocationKey.d.ts","sourceRoot":"","sources":["../../../src/runtime/invocation/hashInvocationKey.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,uBAAuB,CAAC;CACrC;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,uBAAuB,GAAG,iBAAiB,CAIxF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hashInvocationKey = hashInvocationKey;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
function hashInvocationKey(components) {
|
|
9
|
+
const key = `${components.processId}:${components.stepId}:${components.taskId}`;
|
|
10
|
+
const digest = crypto_1.default.createHash("sha256").update(key).digest("hex");
|
|
11
|
+
return { key, digest, components };
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/runtime/invocation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashInvocationKey = void 0;
|
|
4
|
+
var hashInvocationKey_1 = require("./hashInvocationKey");
|
|
5
|
+
Object.defineProperty(exports, "hashInvocationKey", { enumerable: true, get: function () { return hashInvocationKey_1.hashInvocationKey; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrateIteration.d.ts","sourceRoot":"","sources":["../../src/runtime/orchestrateIteration.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,eAAe,EACf,kBAAkB,EAGnB,MAAM,SAAS,CAAC;AAWjB,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CA2DhG"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.orchestrateIteration = orchestrateIteration;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const url_1 = require("url");
|
|
9
|
+
const journal_1 = require("../storage/journal");
|
|
10
|
+
const runFiles_1 = require("../storage/runFiles");
|
|
11
|
+
const createReplayEngine_1 = require("./replay/createReplayEngine");
|
|
12
|
+
const processContext_1 = require("./processContext");
|
|
13
|
+
const exceptions_1 = require("./exceptions");
|
|
14
|
+
const errorUtils_1 = require("./errorUtils");
|
|
15
|
+
const instrumentation_1 = require("./instrumentation");
|
|
16
|
+
// Use an indirect dynamic import so TypeScript does not downlevel to require() in CommonJS builds.
|
|
17
|
+
const dynamicImportModule = new Function("specifier", "return import(specifier);");
|
|
18
|
+
async function orchestrateIteration(options) {
|
|
19
|
+
const iterationStartedAt = Date.now();
|
|
20
|
+
const nowFn = resolveNow(options.now);
|
|
21
|
+
const engine = await initializeReplayEngine(options, nowFn, iterationStartedAt);
|
|
22
|
+
const defaultEntrypoint = {
|
|
23
|
+
importPath: engine.metadata.entrypoint?.importPath ?? engine.metadata.processPath,
|
|
24
|
+
exportName: engine.metadata.entrypoint?.exportName,
|
|
25
|
+
};
|
|
26
|
+
const processFn = await loadProcessFunction(options, defaultEntrypoint, options.runDir);
|
|
27
|
+
const inputs = options.inputs ?? engine.inputs;
|
|
28
|
+
let finalStatus = "failed";
|
|
29
|
+
const logger = engine.internalContext.logger ?? options.logger;
|
|
30
|
+
try {
|
|
31
|
+
const output = await (0, processContext_1.withProcessContext)(engine.internalContext, () => processFn(inputs, engine.context, options.context));
|
|
32
|
+
const outputRef = await (0, runFiles_1.writeRunOutput)(options.runDir, output);
|
|
33
|
+
await (0, journal_1.appendEvent)({
|
|
34
|
+
runDir: options.runDir,
|
|
35
|
+
eventType: "RUN_COMPLETED",
|
|
36
|
+
event: {
|
|
37
|
+
outputRef,
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const result = { status: "completed", output, metadata: createIterationMetadata(engine) };
|
|
41
|
+
finalStatus = result.status;
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const waiting = asWaitingResult(error);
|
|
46
|
+
if (waiting) {
|
|
47
|
+
finalStatus = waiting.status;
|
|
48
|
+
return {
|
|
49
|
+
status: "waiting",
|
|
50
|
+
nextActions: annotateWaitingActions(waiting.nextActions),
|
|
51
|
+
metadata: createIterationMetadata(engine),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const failure = (0, errorUtils_1.serializeUnknownError)(error);
|
|
55
|
+
await (0, journal_1.appendEvent)({
|
|
56
|
+
runDir: options.runDir,
|
|
57
|
+
eventType: "RUN_FAILED",
|
|
58
|
+
event: { error: failure },
|
|
59
|
+
});
|
|
60
|
+
const result = {
|
|
61
|
+
status: "failed",
|
|
62
|
+
error: failure,
|
|
63
|
+
metadata: createIterationMetadata(engine),
|
|
64
|
+
};
|
|
65
|
+
finalStatus = result.status;
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
(0, instrumentation_1.emitRuntimeMetric)(logger, "replay.iteration", {
|
|
70
|
+
duration_ms: Date.now() - iterationStartedAt,
|
|
71
|
+
status: finalStatus,
|
|
72
|
+
runId: engine.runId,
|
|
73
|
+
stepCount: engine.replayCursor.value,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function loadProcessFunction(options, defaults, runDir) {
|
|
78
|
+
const importPath = options.process?.importPath ?? defaults.importPath;
|
|
79
|
+
if (!importPath) {
|
|
80
|
+
throw new exceptions_1.RunFailedError("Process import path is missing");
|
|
81
|
+
}
|
|
82
|
+
const exportName = options.process?.exportName ?? defaults.exportName ?? "process";
|
|
83
|
+
const resolvedPath = path_1.default.isAbsolute(importPath) ? importPath : path_1.default.resolve(runDir, importPath);
|
|
84
|
+
const moduleUrl = (0, url_1.pathToFileURL)(resolvedPath).href;
|
|
85
|
+
let mod;
|
|
86
|
+
try {
|
|
87
|
+
mod = await dynamicImportModule(moduleUrl);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new exceptions_1.RunFailedError(`Failed to load process module at ${resolvedPath}`, {
|
|
91
|
+
error: (0, errorUtils_1.serializeUnknownError)(error),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const candidate = (exportName && mod[exportName]) ??
|
|
95
|
+
(!exportName && mod.default) ??
|
|
96
|
+
mod.process ??
|
|
97
|
+
mod.default;
|
|
98
|
+
if (typeof candidate !== "function") {
|
|
99
|
+
throw new exceptions_1.RunFailedError(`Export '${exportName}' was not a function in ${resolvedPath}`);
|
|
100
|
+
}
|
|
101
|
+
return candidate;
|
|
102
|
+
}
|
|
103
|
+
function asWaitingResult(error) {
|
|
104
|
+
if (error instanceof exceptions_1.ParallelPendingError) {
|
|
105
|
+
return { status: "waiting", nextActions: error.batch.actions };
|
|
106
|
+
}
|
|
107
|
+
if (error instanceof exceptions_1.EffectRequestedError || error instanceof exceptions_1.EffectPendingError) {
|
|
108
|
+
return { status: "waiting", nextActions: [error.action] };
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function resolveNow(now) {
|
|
113
|
+
if (!now)
|
|
114
|
+
return () => new Date();
|
|
115
|
+
if (typeof now === "function") {
|
|
116
|
+
return now;
|
|
117
|
+
}
|
|
118
|
+
const fixed = now;
|
|
119
|
+
return () => fixed;
|
|
120
|
+
}
|
|
121
|
+
async function initializeReplayEngine(options, nowFn, iterationStartedAt) {
|
|
122
|
+
try {
|
|
123
|
+
return await (0, createReplayEngine_1.createReplayEngine)({ runDir: options.runDir, now: nowFn, logger: options.logger });
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
(0, instrumentation_1.emitRuntimeMetric)(options.logger, "replay.iteration", {
|
|
127
|
+
duration_ms: Date.now() - iterationStartedAt,
|
|
128
|
+
status: "failed",
|
|
129
|
+
runDir: options.runDir,
|
|
130
|
+
phase: "initialize",
|
|
131
|
+
error: error instanceof Error ? error.message : String(error),
|
|
132
|
+
});
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function annotateWaitingActions(actions) {
|
|
137
|
+
const pendingCount = actions.length;
|
|
138
|
+
return actions.map((action) => {
|
|
139
|
+
const derivedSleep = deriveSleepHint(action);
|
|
140
|
+
const nextHints = mergeSchedulerHints(action.schedulerHints, {
|
|
141
|
+
pendingCount,
|
|
142
|
+
sleepUntilEpochMs: derivedSleep,
|
|
143
|
+
});
|
|
144
|
+
if (nextHints === action.schedulerHints ||
|
|
145
|
+
(nextHints === undefined && action.schedulerHints === undefined)) {
|
|
146
|
+
return action;
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
...action,
|
|
150
|
+
schedulerHints: nextHints,
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function deriveSleepHint(action) {
|
|
155
|
+
if (typeof action.schedulerHints?.sleepUntilEpochMs === "number") {
|
|
156
|
+
return action.schedulerHints.sleepUntilEpochMs;
|
|
157
|
+
}
|
|
158
|
+
const direct = action.taskDef?.sleep?.targetEpochMs;
|
|
159
|
+
if (typeof direct === "number") {
|
|
160
|
+
return direct;
|
|
161
|
+
}
|
|
162
|
+
const metadataTarget = action.taskDef?.metadata?.targetEpochMs;
|
|
163
|
+
return typeof metadataTarget === "number" ? metadataTarget : undefined;
|
|
164
|
+
}
|
|
165
|
+
function mergeSchedulerHints(base, extra) {
|
|
166
|
+
const merged = { ...(base ?? {}) };
|
|
167
|
+
let changed = false;
|
|
168
|
+
if (extra.pendingCount !== undefined && merged.pendingCount !== extra.pendingCount) {
|
|
169
|
+
merged.pendingCount = extra.pendingCount;
|
|
170
|
+
changed = true;
|
|
171
|
+
}
|
|
172
|
+
if (extra.sleepUntilEpochMs !== undefined &&
|
|
173
|
+
merged.sleepUntilEpochMs !== extra.sleepUntilEpochMs) {
|
|
174
|
+
merged.sleepUntilEpochMs = extra.sleepUntilEpochMs;
|
|
175
|
+
changed = true;
|
|
176
|
+
}
|
|
177
|
+
if (extra.parallelGroupId !== undefined &&
|
|
178
|
+
merged.parallelGroupId !== extra.parallelGroupId) {
|
|
179
|
+
merged.parallelGroupId = extra.parallelGroupId;
|
|
180
|
+
changed = true;
|
|
181
|
+
}
|
|
182
|
+
if (!changed) {
|
|
183
|
+
return base;
|
|
184
|
+
}
|
|
185
|
+
return merged;
|
|
186
|
+
}
|
|
187
|
+
function createIterationMetadata(engine) {
|
|
188
|
+
return {
|
|
189
|
+
stateVersion: engine.stateCache?.stateVersion,
|
|
190
|
+
pendingEffectsByKind: engine.stateCache?.pendingEffectsByKind,
|
|
191
|
+
journalHead: engine.stateCache?.journalHead ?? null,
|
|
192
|
+
stateRebuilt: Boolean(engine.stateRebuild),
|
|
193
|
+
stateRebuildReason: engine.stateRebuild?.reason ?? null,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TaskIntrinsicContext } from "./intrinsics/task";
|
|
2
|
+
import { ProcessContext } from "./types";
|
|
3
|
+
export interface ProcessContextInit extends Omit<TaskIntrinsicContext, "now"> {
|
|
4
|
+
processId: string;
|
|
5
|
+
now?: () => Date;
|
|
6
|
+
}
|
|
7
|
+
export interface InternalProcessContext extends TaskIntrinsicContext {
|
|
8
|
+
processId: string;
|
|
9
|
+
now: () => Date;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateProcessContextResult {
|
|
12
|
+
context: ProcessContext;
|
|
13
|
+
internalContext: InternalProcessContext;
|
|
14
|
+
}
|
|
15
|
+
export declare function createProcessContext(init: ProcessContextInit): CreateProcessContextResult;
|
|
16
|
+
export declare function withProcessContext<T>(internal: InternalProcessContext, fn: () => Promise<T> | T): Promise<T>;
|
|
17
|
+
export declare function getActiveProcessContext(): InternalProcessContext | undefined;
|
|
18
|
+
export declare function requireProcessContext(): InternalProcessContext;
|
|
19
|
+
//# sourceMappingURL=processContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processContext.d.ts","sourceRoot":"","sources":["../../src/runtime/processContext.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAK3E,OAAO,EAAE,cAAc,EAAmB,MAAM,SAAS,CAAC;AAG1D,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,KAAK,CAAC;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AAID,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,cAAc,CAAC;IACxB,eAAe,EAAE,sBAAsB,CAAC;CACzC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,GAAG,0BAA0B,CA+BzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAE5G;AAED,wBAAgB,uBAAuB,IAAI,sBAAsB,GAAG,SAAS,CAE5E;AAED,wBAAgB,qBAAqB,IAAI,sBAAsB,CAM9D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createProcessContext = createProcessContext;
|
|
4
|
+
exports.withProcessContext = withProcessContext;
|
|
5
|
+
exports.getActiveProcessContext = getActiveProcessContext;
|
|
6
|
+
exports.requireProcessContext = requireProcessContext;
|
|
7
|
+
const async_hooks_1 = require("async_hooks");
|
|
8
|
+
const task_1 = require("./intrinsics/task");
|
|
9
|
+
const breakpoint_1 = require("./intrinsics/breakpoint");
|
|
10
|
+
const sleep_1 = require("./intrinsics/sleep");
|
|
11
|
+
const orchestratorTask_1 = require("./intrinsics/orchestratorTask");
|
|
12
|
+
const parallel_1 = require("./intrinsics/parallel");
|
|
13
|
+
const exceptions_1 = require("./exceptions");
|
|
14
|
+
const contextStorage = new async_hooks_1.AsyncLocalStorage();
|
|
15
|
+
function createProcessContext(init) {
|
|
16
|
+
const internal = {
|
|
17
|
+
...init,
|
|
18
|
+
now: init.now ?? (() => new Date()),
|
|
19
|
+
};
|
|
20
|
+
const parallelHelpers = {
|
|
21
|
+
all: (thunks) => (0, parallel_1.runParallelAll)(thunks),
|
|
22
|
+
map: (items, fn) => (0, parallel_1.runParallelMap)(items, fn),
|
|
23
|
+
};
|
|
24
|
+
const processContext = {
|
|
25
|
+
now: () => internal.now(),
|
|
26
|
+
task: (task, args, options) => (0, task_1.runTaskIntrinsic)({
|
|
27
|
+
task,
|
|
28
|
+
args,
|
|
29
|
+
invokeOptions: options,
|
|
30
|
+
context: internal,
|
|
31
|
+
}),
|
|
32
|
+
breakpoint: (payload, options) => (0, breakpoint_1.runBreakpointIntrinsic)(payload, internal, options),
|
|
33
|
+
sleepUntil: (target, options) => (0, sleep_1.runSleepIntrinsic)(target, internal, options),
|
|
34
|
+
orchestratorTask: (payload, options) => (0, orchestratorTask_1.runOrchestratorTaskIntrinsic)(payload, internal, options),
|
|
35
|
+
parallel: parallelHelpers,
|
|
36
|
+
log: internal.logger,
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
context: processContext,
|
|
40
|
+
internalContext: internal,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function withProcessContext(internal, fn) {
|
|
44
|
+
return contextStorage.run(internal, () => Promise.resolve().then(fn));
|
|
45
|
+
}
|
|
46
|
+
function getActiveProcessContext() {
|
|
47
|
+
return contextStorage.getStore();
|
|
48
|
+
}
|
|
49
|
+
function requireProcessContext() {
|
|
50
|
+
const ctx = getActiveProcessContext();
|
|
51
|
+
if (!ctx) {
|
|
52
|
+
throw new exceptions_1.MissingProcessContextError();
|
|
53
|
+
}
|
|
54
|
+
return ctx;
|
|
55
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RunMetadata } from "../../storage/types";
|
|
2
|
+
import { EffectIndex } from "./effectIndex";
|
|
3
|
+
import { ReplayCursor } from "./replayCursor";
|
|
4
|
+
import { ProcessContext } from "../types";
|
|
5
|
+
import { InternalProcessContext } from "../processContext";
|
|
6
|
+
import { StateCacheSnapshot } from "./stateCache";
|
|
7
|
+
export interface CreateReplayEngineOptions {
|
|
8
|
+
runDir: string;
|
|
9
|
+
now?: () => Date;
|
|
10
|
+
logger?: (...args: any[]) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface ReplayEngine {
|
|
13
|
+
runId: string;
|
|
14
|
+
runDir: string;
|
|
15
|
+
metadata: RunMetadata;
|
|
16
|
+
inputs?: unknown;
|
|
17
|
+
effectIndex: EffectIndex;
|
|
18
|
+
replayCursor: ReplayCursor;
|
|
19
|
+
context: ProcessContext;
|
|
20
|
+
internalContext: InternalProcessContext;
|
|
21
|
+
stateCache?: StateCacheSnapshot | null;
|
|
22
|
+
stateRebuild?: {
|
|
23
|
+
reason: string;
|
|
24
|
+
previous?: {
|
|
25
|
+
seq: number;
|
|
26
|
+
ulid: string;
|
|
27
|
+
} | null;
|
|
28
|
+
} | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function createReplayEngine(options: CreateReplayEngineOptions): Promise<ReplayEngine>;
|
|
31
|
+
//# sourceMappingURL=createReplayEngine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createReplayEngine.d.ts","sourceRoot":"","sources":["../../../src/runtime/replay/createReplayEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAoB,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAwB,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGjF,OAAO,EAAwD,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAExG,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,EAAE,cAAc,CAAC;IACxB,eAAe,EAAE,sBAAsB,CAAC;IACxC,UAAU,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACvC,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CAC3F;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiClG"}
|