@shipfox/api-workflows 12.1.0 → 12.3.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/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +45 -0
- package/README.md +20 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +56 -0
- package/dist/config.js.map +1 -0
- package/dist/core/entities/job.d.ts +1 -1
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/step.d.ts +2 -2
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/errors.d.ts +18 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +21 -2
- package/dist/core/errors.js.map +1 -1
- package/dist/core/step-config/assemble-run-context.d.ts +15 -5
- package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
- package/dist/core/step-config/assemble-run-context.js +77 -27
- package/dist/core/step-config/assemble-run-context.js.map +1 -1
- package/dist/core/step-config/fields.d.ts +5 -0
- package/dist/core/step-config/fields.d.ts.map +1 -1
- package/dist/core/step-config/fields.js +21 -3
- package/dist/core/step-config/fields.js.map +1 -1
- package/dist/core/step-config/index.d.ts +1 -1
- package/dist/core/step-config/index.d.ts.map +1 -1
- package/dist/core/step-config/index.js +1 -1
- package/dist/core/step-config/index.js.map +1 -1
- package/dist/core/step-config/job-output-limits.d.ts +11 -0
- package/dist/core/step-config/job-output-limits.d.ts.map +1 -0
- package/dist/core/step-config/job-output-limits.js +88 -0
- package/dist/core/step-config/job-output-limits.js.map +1 -0
- package/dist/core/step-config/materialize-workflow-model.d.ts +1 -1
- package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.js +47 -18
- package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
- package/dist/db/db.d.ts +50 -50
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-listeners.d.ts.map +1 -1
- package/dist/db/job-listeners.js +6 -5
- package/dist/db/job-listeners.js.map +1 -1
- package/dist/db/schema/job-executions.d.ts +3 -3
- package/dist/db/schema/job-listener-events.d.ts +1 -1
- package/dist/db/schema/jobs.d.ts +7 -7
- package/dist/db/schema/outbox.d.ts +1 -1
- package/dist/db/schema/step-attempts.d.ts +2 -2
- package/dist/db/schema/steps.d.ts +5 -5
- package/dist/db/schema/workflow-run-attempts.d.ts +3 -3
- package/dist/db/schema/workflow-run-counters.d.ts +1 -1
- package/dist/db/schema/workflow-runs.d.ts +2 -2
- package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
- package/dist/db/workflow-runs/job-executions.js +4 -2
- package/dist/db/workflow-runs/job-executions.js.map +1 -1
- package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
- package/dist/db/workflow-runs/jobs.js +33 -3
- package/dist/db/workflow-runs/jobs.js.map +1 -1
- package/dist/db/workflow-runs/outbox.d.ts +1 -0
- package/dist/db/workflow-runs/outbox.d.ts.map +1 -1
- package/dist/db/workflow-runs/outbox.js +1 -0
- package/dist/db/workflow-runs/outbox.js.map +1 -1
- package/dist/db/workflow-runs/steps.d.ts +28 -0
- package/dist/db/workflow-runs/steps.d.ts.map +1 -1
- package/dist/db/workflow-runs/steps.js +49 -1
- package/dist/db/workflow-runs/steps.js.map +1 -1
- package/dist/db/workflow-runs.d.ts +2 -2
- package/dist/db/workflow-runs.d.ts.map +1 -1
- package/dist/db/workflow-runs.js +1 -1
- package/dist/db/workflow-runs.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +1 -0
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +8 -0
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/dto/evaluation-trace.d.ts +4 -0
- package/dist/presentation/dto/evaluation-trace.d.ts.map +1 -0
- package/dist/presentation/dto/evaluation-trace.js +39 -0
- package/dist/presentation/dto/evaluation-trace.js.map +1 -0
- package/dist/presentation/dto/index.d.ts +2 -1
- package/dist/presentation/dto/index.d.ts.map +1 -1
- package/dist/presentation/dto/index.js +2 -1
- package/dist/presentation/dto/index.js.map +1 -1
- package/dist/presentation/dto/job.d.ts.map +1 -1
- package/dist/presentation/dto/job.js +6 -0
- package/dist/presentation/dto/job.js.map +1 -1
- package/dist/presentation/dto/step.d.ts +2 -1
- package/dist/presentation/dto/step.d.ts.map +1 -1
- package/dist/presentation/dto/step.js +12 -0
- package/dist/presentation/dto/step.js.map +1 -1
- package/dist/presentation/index.d.ts +1 -1
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +1 -1
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/routes/get-step-attempt-detail.d.ts +3 -0
- package/dist/presentation/routes/get-step-attempt-detail.d.ts.map +1 -0
- package/dist/presentation/routes/get-step-attempt-detail.js +38 -0
- package/dist/presentation/routes/get-step-attempt-detail.js.map +1 -0
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +2 -0
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -1
- package/dist/presentation/subscribers/index.d.ts +1 -0
- package/dist/presentation/subscribers/index.d.ts.map +1 -1
- package/dist/presentation/subscribers/index.js +1 -0
- package/dist/presentation/subscribers/index.js.map +1 -1
- package/dist/presentation/subscribers/on-failure-annotations.d.ts +5 -0
- package/dist/presentation/subscribers/on-failure-annotations.d.ts.map +1 -0
- package/dist/presentation/subscribers/on-failure-annotations.js +160 -0
- package/dist/presentation/subscribers/on-failure-annotations.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +1 -1
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
- package/dist/temporal/workflows/test-env.d.ts +2 -2
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +18 -16
- package/src/config.test.ts +85 -0
- package/src/config.ts +71 -0
- package/src/core/errors.ts +44 -2
- package/src/core/job-execution.test.ts +1 -0
- package/src/core/step-config/assemble-run-context.test.ts +232 -20
- package/src/core/step-config/assemble-run-context.ts +126 -28
- package/src/core/step-config/fields.ts +42 -3
- package/src/core/step-config/index.ts +2 -0
- package/src/core/step-config/job-output-limits.ts +130 -0
- package/src/core/step-config/materialize-workflow-model.catalog.test.ts +117 -0
- package/src/core/step-config/materialize-workflow-model.test.ts +306 -1
- package/src/core/step-config/materialize-workflow-model.ts +65 -18
- package/src/db/index.ts +4 -0
- package/src/db/job-listeners.ts +14 -3
- package/src/db/workflow-runs/job-executions.test.ts +207 -1
- package/src/db/workflow-runs/job-executions.ts +15 -2
- package/src/db/workflow-runs/job-status.test.ts +10 -3
- package/src/db/workflow-runs/jobs.test.ts +49 -0
- package/src/db/workflow-runs/jobs.ts +53 -6
- package/src/db/workflow-runs/outbox.ts +7 -1
- package/src/db/workflow-runs/run-create.test.ts +56 -0
- package/src/db/workflow-runs/steps.test.ts +148 -0
- package/src/db/workflow-runs/steps.ts +105 -1
- package/src/db/workflow-runs.ts +4 -0
- package/src/index.ts +9 -0
- package/src/metrics/instance.ts +10 -0
- package/src/presentation/dto/evaluation-trace.ts +27 -0
- package/src/presentation/dto/index.ts +2 -1
- package/src/presentation/dto/job.ts +6 -0
- package/src/presentation/dto/step.test.ts +96 -1
- package/src/presentation/dto/step.ts +17 -0
- package/src/presentation/index.ts +2 -0
- package/src/presentation/routes/get-step-attempt-detail.test.ts +159 -0
- package/src/presentation/routes/get-step-attempt-detail.ts +33 -0
- package/src/presentation/routes/index.ts +2 -0
- package/src/presentation/subscribers/index.ts +4 -0
- package/src/presentation/subscribers/on-failure-annotations.test.ts +510 -0
- package/src/presentation/subscribers/on-failure-annotations.ts +237 -0
- package/test/factories/workflow-model.ts +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { WORKFLOW_DOCUMENT_JOB_OUTPUTS_MAX_ENTRIES, WORKFLOW_DOCUMENT_STEP_OUTPUT_SCHEMA_MAX_DEPTH } from '@shipfox/workflow-document';
|
|
2
|
+
import { JobOutputNotJsonSafeError } from '#core/errors.js';
|
|
3
|
+
export const MAX_JOB_OUTPUT_ENTRIES = WORKFLOW_DOCUMENT_JOB_OUTPUTS_MAX_ENTRIES;
|
|
4
|
+
export const MAX_JOB_OUTPUT_NESTING_DEPTH = WORKFLOW_DOCUMENT_STEP_OUTPUT_SCHEMA_MAX_DEPTH;
|
|
5
|
+
export const MAX_JOB_OUTPUTS_TOTAL_BYTES = 64 * 1024;
|
|
6
|
+
export const MAX_JOB_OUTPUT_VALUE_BYTES = 16 * 1024;
|
|
7
|
+
const textEncoder = new TextEncoder();
|
|
8
|
+
export function normalizeJobOutputValue(value, outputKey) {
|
|
9
|
+
return normalize(value, outputKey, new WeakSet(), 0);
|
|
10
|
+
}
|
|
11
|
+
export function jobOutputValueByteLength(value) {
|
|
12
|
+
if (typeof value === 'string') return textEncoder.encode(value).byteLength;
|
|
13
|
+
return jsonByteLength(value);
|
|
14
|
+
}
|
|
15
|
+
export function jobOutputRecordEntryByteLength(key, value) {
|
|
16
|
+
return textEncoder.encode(JSON.stringify(key)).byteLength + 1 + jsonByteLength(value);
|
|
17
|
+
}
|
|
18
|
+
function jsonByteLength(value) {
|
|
19
|
+
const serialized = JSON.stringify(value);
|
|
20
|
+
return textEncoder.encode(serialized ?? '').byteLength;
|
|
21
|
+
}
|
|
22
|
+
function normalize(value, outputKey, ancestors, depth) {
|
|
23
|
+
if (value === null) return null;
|
|
24
|
+
switch(typeof value){
|
|
25
|
+
case 'string':
|
|
26
|
+
case 'boolean':
|
|
27
|
+
return value;
|
|
28
|
+
case 'number':
|
|
29
|
+
if (!Number.isFinite(value)) {
|
|
30
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'numbers must be finite');
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
case 'bigint':
|
|
34
|
+
{
|
|
35
|
+
const numberValue = Number(value);
|
|
36
|
+
return Number.isSafeInteger(numberValue) ? numberValue : value.toString();
|
|
37
|
+
}
|
|
38
|
+
case 'undefined':
|
|
39
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'undefined is not a JSON value');
|
|
40
|
+
case 'function':
|
|
41
|
+
case 'symbol':
|
|
42
|
+
throw new JobOutputNotJsonSafeError(outputKey, `values of type ${typeof value} are not JSON values`);
|
|
43
|
+
case 'object':
|
|
44
|
+
return normalizeObject(value, outputKey, ancestors, depth);
|
|
45
|
+
}
|
|
46
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'the value has an unsupported type');
|
|
47
|
+
}
|
|
48
|
+
function normalizeObject(value, outputKey, ancestors, depth) {
|
|
49
|
+
if (value instanceof Date) {
|
|
50
|
+
if (Number.isNaN(value.getTime())) {
|
|
51
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'dates must be valid');
|
|
52
|
+
}
|
|
53
|
+
return value.toISOString();
|
|
54
|
+
}
|
|
55
|
+
if (ancestors.has(value)) {
|
|
56
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'the value contains a circular reference');
|
|
57
|
+
}
|
|
58
|
+
if (depth >= MAX_JOB_OUTPUT_NESTING_DEPTH) {
|
|
59
|
+
throw new JobOutputNotJsonSafeError(outputKey, `values cannot be nested deeper than ${MAX_JOB_OUTPUT_NESTING_DEPTH} levels`);
|
|
60
|
+
}
|
|
61
|
+
if (Array.isArray(value)) {
|
|
62
|
+
ancestors.add(value);
|
|
63
|
+
try {
|
|
64
|
+
const normalized = [];
|
|
65
|
+
for (const item of value){
|
|
66
|
+
normalized.push(normalize(item, outputKey, ancestors, depth + 1));
|
|
67
|
+
}
|
|
68
|
+
return normalized;
|
|
69
|
+
} finally{
|
|
70
|
+
ancestors.delete(value);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const prototype = Object.getPrototypeOf(value);
|
|
74
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
75
|
+
throw new JobOutputNotJsonSafeError(outputKey, 'the value has an unsupported object type');
|
|
76
|
+
}
|
|
77
|
+
ancestors.add(value);
|
|
78
|
+
try {
|
|
79
|
+
return Object.fromEntries(Object.keys(value).map((key)=>[
|
|
80
|
+
key,
|
|
81
|
+
normalize(value[key], outputKey, ancestors, depth + 1)
|
|
82
|
+
]));
|
|
83
|
+
} finally{
|
|
84
|
+
ancestors.delete(value);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=job-output-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/step-config/job-output-limits.ts"],"sourcesContent":["import {\n WORKFLOW_DOCUMENT_JOB_OUTPUTS_MAX_ENTRIES,\n WORKFLOW_DOCUMENT_STEP_OUTPUT_SCHEMA_MAX_DEPTH,\n} from '@shipfox/workflow-document';\nimport {JobOutputNotJsonSafeError} from '#core/errors.js';\n\nexport const MAX_JOB_OUTPUT_ENTRIES = WORKFLOW_DOCUMENT_JOB_OUTPUTS_MAX_ENTRIES;\nexport const MAX_JOB_OUTPUT_NESTING_DEPTH = WORKFLOW_DOCUMENT_STEP_OUTPUT_SCHEMA_MAX_DEPTH;\nexport const MAX_JOB_OUTPUTS_TOTAL_BYTES = 64 * 1024;\nexport const MAX_JOB_OUTPUT_VALUE_BYTES = 16 * 1024;\n\nconst textEncoder = new TextEncoder();\n\nexport type JsonSafeJobOutputValue =\n | null\n | string\n | number\n | boolean\n | readonly JsonSafeJobOutputValue[]\n | {[key: string]: JsonSafeJobOutputValue};\n\nexport function normalizeJobOutputValue(value: unknown, outputKey: string): JsonSafeJobOutputValue {\n return normalize(value, outputKey, new WeakSet<object>(), 0);\n}\n\nexport function jobOutputValueByteLength(value: unknown): number {\n if (typeof value === 'string') return textEncoder.encode(value).byteLength;\n\n return jsonByteLength(value);\n}\n\nexport function jobOutputRecordEntryByteLength(key: string, value: JsonSafeJobOutputValue): number {\n return textEncoder.encode(JSON.stringify(key)).byteLength + 1 + jsonByteLength(value);\n}\n\nfunction jsonByteLength(value: unknown): number {\n const serialized = JSON.stringify(value);\n return textEncoder.encode(serialized ?? '').byteLength;\n}\n\nfunction normalize(\n value: unknown,\n outputKey: string,\n ancestors: WeakSet<object>,\n depth: number,\n): JsonSafeJobOutputValue {\n if (value === null) return null;\n\n switch (typeof value) {\n case 'string':\n case 'boolean':\n return value;\n case 'number':\n if (!Number.isFinite(value)) {\n throw new JobOutputNotJsonSafeError(outputKey, 'numbers must be finite');\n }\n return value;\n case 'bigint': {\n const numberValue = Number(value);\n return Number.isSafeInteger(numberValue) ? numberValue : value.toString();\n }\n case 'undefined':\n throw new JobOutputNotJsonSafeError(outputKey, 'undefined is not a JSON value');\n case 'function':\n case 'symbol':\n throw new JobOutputNotJsonSafeError(\n outputKey,\n `values of type ${typeof value} are not JSON values`,\n );\n case 'object':\n return normalizeObject(value, outputKey, ancestors, depth);\n }\n\n throw new JobOutputNotJsonSafeError(outputKey, 'the value has an unsupported type');\n}\n\nfunction normalizeObject(\n value: object,\n outputKey: string,\n ancestors: WeakSet<object>,\n depth: number,\n): JsonSafeJobOutputValue {\n if (value instanceof Date) {\n if (Number.isNaN(value.getTime())) {\n throw new JobOutputNotJsonSafeError(outputKey, 'dates must be valid');\n }\n return value.toISOString();\n }\n\n if (ancestors.has(value)) {\n throw new JobOutputNotJsonSafeError(outputKey, 'the value contains a circular reference');\n }\n\n if (depth >= MAX_JOB_OUTPUT_NESTING_DEPTH) {\n throw new JobOutputNotJsonSafeError(\n outputKey,\n `values cannot be nested deeper than ${MAX_JOB_OUTPUT_NESTING_DEPTH} levels`,\n );\n }\n\n if (Array.isArray(value)) {\n ancestors.add(value);\n try {\n const normalized: JsonSafeJobOutputValue[] = [];\n for (const item of value) {\n normalized.push(normalize(item, outputKey, ancestors, depth + 1));\n }\n return normalized;\n } finally {\n ancestors.delete(value);\n }\n }\n\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) {\n throw new JobOutputNotJsonSafeError(outputKey, 'the value has an unsupported object type');\n }\n\n ancestors.add(value);\n try {\n return Object.fromEntries(\n Object.keys(value).map((key) => [\n key,\n normalize((value as Record<string, unknown>)[key], outputKey, ancestors, depth + 1),\n ]),\n ) as {[key: string]: JsonSafeJobOutputValue};\n } finally {\n ancestors.delete(value);\n }\n}\n"],"names":["WORKFLOW_DOCUMENT_JOB_OUTPUTS_MAX_ENTRIES","WORKFLOW_DOCUMENT_STEP_OUTPUT_SCHEMA_MAX_DEPTH","JobOutputNotJsonSafeError","MAX_JOB_OUTPUT_ENTRIES","MAX_JOB_OUTPUT_NESTING_DEPTH","MAX_JOB_OUTPUTS_TOTAL_BYTES","MAX_JOB_OUTPUT_VALUE_BYTES","textEncoder","TextEncoder","normalizeJobOutputValue","value","outputKey","normalize","WeakSet","jobOutputValueByteLength","encode","byteLength","jsonByteLength","jobOutputRecordEntryByteLength","key","JSON","stringify","serialized","ancestors","depth","Number","isFinite","numberValue","isSafeInteger","toString","normalizeObject","Date","isNaN","getTime","toISOString","has","Array","isArray","add","normalized","item","push","delete","prototype","Object","getPrototypeOf","fromEntries","keys","map"],"mappings":"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"}
|
|
@@ -36,7 +36,7 @@ export declare function materializeJobOutputs(params: {
|
|
|
36
36
|
readonly job: WorkflowModelJob;
|
|
37
37
|
readonly context: WorkflowEvaluationContext;
|
|
38
38
|
readonly definitionId: string;
|
|
39
|
-
}): Record<string,
|
|
39
|
+
}): Record<string, unknown> | null;
|
|
40
40
|
export declare function modelHasAgentStep(model: WorkflowModel): boolean;
|
|
41
41
|
export {};
|
|
42
42
|
//# sourceMappingURL=materialize-workflow-model.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materialize-workflow-model.d.ts","sourceRoot":"","sources":["../../../src/core/step-config/materialize-workflow-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"materialize-workflow-model.d.ts","sourceRoot":"","sources":["../../../src/core/step-config/materialize-workflow-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAGtF,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EACV,+BAA+B,EAC/B,gCAAgC,EACjC,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,kCAAkC,CAAC;AAEhF,KAAK,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AACtD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;IAChE,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC/C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,+BAA+B,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,gCAAgC,GAAG,IAAI,GAAG,SAAS,CAAC;CAClF;AAED,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,SAAS,uBAAuB,EAAE,CAAC,CA2C7C;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,GAAG,SAAS,MAAM,EAAE,CAiBpB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAgDjC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAE/D"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { DEFAULT_JOB_CHECKOUT } from '@shipfox/api-definitions-dto';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { findInvalidLabels, MAX_RUNNER_LABELS, resolveRunnerLabels } from '@shipfox/runner-labels';
|
|
3
|
+
import { runnerCatalog } from '#config.js';
|
|
4
|
+
import { InvalidJobRunnerLabelsError, JobOutputTooLargeError, JobOutputTooManyEntriesError } from '#core/errors.js';
|
|
5
|
+
import { completeStepField, completeStepFieldWithType } from './fields.js';
|
|
6
|
+
import { jobOutputRecordEntryByteLength, jobOutputValueByteLength, MAX_JOB_OUTPUT_ENTRIES, MAX_JOB_OUTPUT_VALUE_BYTES, MAX_JOB_OUTPUTS_TOTAL_BYTES, normalizeJobOutputValue } from './job-output-limits.js';
|
|
5
7
|
import { materializeJobExecutionSteps } from './materialize-job-execution-steps.js';
|
|
6
8
|
export async function materializeWorkflowModel(params) {
|
|
7
9
|
const { model, context = {
|
|
@@ -58,31 +60,58 @@ export function materializeJobRunner(params) {
|
|
|
58
60
|
context: params.context,
|
|
59
61
|
definitionId: params.definitionId
|
|
60
62
|
}));
|
|
61
|
-
const
|
|
63
|
+
const requestedLabels = [
|
|
62
64
|
...params.job.runner,
|
|
63
65
|
...resolvedLabels
|
|
64
|
-
]
|
|
66
|
+
];
|
|
67
|
+
const labels = resolveRunnerLabels(requestedLabels, runnerCatalog);
|
|
65
68
|
const invalidLabels = findInvalidLabels(labels);
|
|
66
69
|
if (labels.length === 0 || labels.length > MAX_RUNNER_LABELS || invalidLabels.length > 0) {
|
|
67
|
-
throw new InvalidJobRunnerLabelsError(labels);
|
|
70
|
+
throw new InvalidJobRunnerLabelsError(labels, requestedLabels);
|
|
68
71
|
}
|
|
69
72
|
return labels;
|
|
70
73
|
}
|
|
71
74
|
export function materializeJobOutputs(params) {
|
|
72
75
|
const outputs = params.job.outputs;
|
|
73
76
|
if (outputs === undefined) return null;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
const outputEntries = Object.entries(outputs);
|
|
78
|
+
if (outputEntries.length > MAX_JOB_OUTPUT_ENTRIES) {
|
|
79
|
+
throw new JobOutputTooManyEntriesError(outputEntries.length, MAX_JOB_OUTPUT_ENTRIES);
|
|
80
|
+
}
|
|
81
|
+
const materialized = {};
|
|
82
|
+
// This is exactly JSON.stringify(materialized): start with "{}", then add each
|
|
83
|
+
// key/value pair and its comma (except for the first entry).
|
|
84
|
+
let recordBytes = 2;
|
|
85
|
+
for (const [index, [key, template]] of outputEntries.entries()){
|
|
86
|
+
const outputTypes = params.job.outputTypes;
|
|
87
|
+
const outputType = outputTypes !== undefined && Object.hasOwn(outputTypes, key) ? outputTypes[key] : undefined;
|
|
88
|
+
const completionParams = {
|
|
89
|
+
field: 'job.outputs',
|
|
90
|
+
errorField: 'job.outputs',
|
|
91
|
+
template: {
|
|
92
|
+
segments: template
|
|
93
|
+
},
|
|
94
|
+
context: params.context,
|
|
95
|
+
definitionId: params.definitionId
|
|
96
|
+
};
|
|
97
|
+
const value = outputType === undefined || outputType === 'string' ? completeStepField(completionParams) : completeStepFieldWithType(completionParams);
|
|
98
|
+
const normalizedValue = normalizeJobOutputValue(value, key);
|
|
99
|
+
const valueBytes = jobOutputValueByteLength(normalizedValue);
|
|
100
|
+
if (valueBytes > MAX_JOB_OUTPUT_VALUE_BYTES) {
|
|
101
|
+
throw new JobOutputTooLargeError(key, MAX_JOB_OUTPUT_VALUE_BYTES, 'value');
|
|
102
|
+
}
|
|
103
|
+
recordBytes += (index === 0 ? 0 : 1) + jobOutputRecordEntryByteLength(key, normalizedValue);
|
|
104
|
+
Object.defineProperty(materialized, key, {
|
|
105
|
+
configurable: true,
|
|
106
|
+
enumerable: true,
|
|
107
|
+
value: normalizedValue,
|
|
108
|
+
writable: true
|
|
109
|
+
});
|
|
110
|
+
if (recordBytes > MAX_JOB_OUTPUTS_TOTAL_BYTES) {
|
|
111
|
+
throw new JobOutputTooLargeError(key, MAX_JOB_OUTPUTS_TOTAL_BYTES, 'total');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return materialized;
|
|
86
115
|
}
|
|
87
116
|
export function modelHasAgentStep(model) {
|
|
88
117
|
return model.jobs.some((job)=>job.steps.some((step)=>step.kind === 'agent'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/step-config/materialize-workflow-model.ts"],"sourcesContent":["import {DEFAULT_JOB_CHECKOUT, type WorkflowModel} from '@shipfox/api-definitions-dto';\nimport {canonicalizeLabels, findInvalidLabels, MAX_RUNNER_LABELS} from '@shipfox/runner-labels';\nimport type {AgentDefaultsResolver} from '#core/agent-defaults.js';\nimport type {\n AgentToolMaterializationContext,\n AgentToolMaterializationSnapshot,\n} from '#core/agent-tools.js';\nimport {InvalidJobRunnerLabelsError} from '#core/errors.js';\nimport {completeStepField} from './fields.js';\nimport {\n type MaterializedWorkflowStep,\n materializeJobExecutionSteps,\n} from './materialize-job-execution-steps.js';\nimport type {WorkflowEvaluationContext} from './workflow-evaluation-context.js';\n\ntype WorkflowModelJob = WorkflowModel['jobs'][number];\nexport interface MaterializedWorkflowJob {\n readonly key: string;\n readonly mode: WorkflowModelJob['mode'];\n readonly success?: string;\n readonly executionTimeoutMs?: number;\n readonly checkout: Exclude<WorkflowModelJob['checkout'], false>;\n readonly listening?: WorkflowModelJob['listening'];\n readonly name?: string;\n readonly outputs?: WorkflowModelJob['outputs'];\n readonly dependencies: readonly string[];\n readonly runner: readonly string[];\n readonly position: number;\n readonly steps: readonly MaterializedWorkflowStep[];\n}\n\nexport interface MaterializeWorkflowModelParams {\n readonly model: WorkflowModel;\n readonly context?: WorkflowEvaluationContext | undefined;\n readonly resolveAgentDefaults?: AgentDefaultsResolver | undefined;\n readonly definitionId?: string | undefined;\n readonly agentToolContext?: AgentToolMaterializationContext | undefined;\n readonly agentToolSnapshot?: AgentToolMaterializationSnapshot | null | undefined;\n}\n\nexport async function materializeWorkflowModel(\n params: MaterializeWorkflowModelParams,\n): Promise<readonly MaterializedWorkflowJob[]> {\n const {\n model,\n context = {site: 'run-creation', values: {}},\n resolveAgentDefaults,\n definitionId = model.name,\n agentToolContext,\n agentToolSnapshot,\n } = params;\n const jobsById = new Map(model.jobs.map((job) => [job.id, job]));\n\n return await Promise.all(\n model.jobs.map(async (job, position) => {\n const name = job.name;\n return {\n key: job.key,\n mode: job.mode,\n ...(job.success === undefined ? {} : {success: job.success}),\n ...(job.executionTimeoutMs === undefined\n ? {}\n : {executionTimeoutMs: job.executionTimeoutMs}),\n checkout: job.checkout === false ? DEFAULT_JOB_CHECKOUT : job.checkout,\n ...(job.listening === undefined ? {} : {listening: job.listening}),\n ...(name === undefined ? {} : {name}),\n ...(job.outputs === undefined ? {} : {outputs: job.outputs}),\n dependencies: dependencySourceNames(job, jobsById),\n runner: job.runner,\n position,\n steps:\n job.mode === 'listening'\n ? []\n : await materializeJobExecutionSteps({\n model,\n job,\n context,\n resolveAgentDefaults,\n definitionId,\n agentToolContext,\n agentToolSnapshot,\n }),\n };\n }),\n );\n}\n\nexport function materializeJobRunner(params: {\n readonly job: WorkflowModelJob;\n readonly context: WorkflowEvaluationContext;\n readonly definitionId: string;\n}): readonly string[] {\n const resolvedLabels = (params.job.runnerTemplates ?? []).map((template) =>\n completeStepField({\n field: 'job.runner',\n errorField: 'job.runner',\n template: {segments: template},\n context: params.context,\n definitionId: params.definitionId,\n }),\n );\n const labels = canonicalizeLabels([...params.job.runner, ...resolvedLabels]);\n const invalidLabels = findInvalidLabels(labels);\n if (labels.length === 0 || labels.length > MAX_RUNNER_LABELS || invalidLabels.length > 0) {\n throw new InvalidJobRunnerLabelsError(labels);\n }\n return labels;\n}\n\nexport function materializeJobOutputs(params: {\n readonly job: WorkflowModelJob;\n readonly context: WorkflowEvaluationContext;\n readonly definitionId: string;\n}): Record<string, string> | null {\n const outputs = params.job.outputs;\n if (outputs === undefined) return null;\n\n return Object.fromEntries(\n Object.entries(outputs).map(([key, template]) => [\n key,\n completeStepField({\n field: 'job.outputs',\n errorField: 'job.outputs',\n template: {segments: template},\n context: params.context,\n definitionId: params.definitionId,\n }),\n ]),\n );\n}\n\nexport function modelHasAgentStep(model: WorkflowModel): boolean {\n return model.jobs.some((job) => job.steps.some((step) => step.kind === 'agent'));\n}\n\nfunction dependencySourceNames(\n job: WorkflowModelJob,\n jobsById: ReadonlyMap<string, WorkflowModelJob>,\n): readonly string[] {\n return job.dependencies.map((dependencyId) => {\n const dependency = jobsById.get(dependencyId);\n if (!dependency) {\n throw new Error(`Unresolved workflow model dependency \"${dependencyId}\" for job \"${job.id}\"`);\n }\n return dependency.key;\n });\n}\n"],"names":["DEFAULT_JOB_CHECKOUT","canonicalizeLabels","findInvalidLabels","MAX_RUNNER_LABELS","InvalidJobRunnerLabelsError","completeStepField","materializeJobExecutionSteps","materializeWorkflowModel","params","model","context","site","values","resolveAgentDefaults","definitionId","name","agentToolContext","agentToolSnapshot","jobsById","Map","jobs","map","job","id","Promise","all","position","key","mode","success","undefined","executionTimeoutMs","checkout","listening","outputs","dependencies","dependencySourceNames","runner","steps","materializeJobRunner","resolvedLabels","runnerTemplates","template","field","errorField","segments","labels","invalidLabels","length","materializeJobOutputs","Object","fromEntries","entries","modelHasAgentStep","some","step","kind","dependencyId","dependency","get","Error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/step-config/materialize-workflow-model.ts"],"sourcesContent":["import {DEFAULT_JOB_CHECKOUT, type WorkflowModel} from '@shipfox/api-definitions-dto';\nimport {findInvalidLabels, MAX_RUNNER_LABELS, resolveRunnerLabels} from '@shipfox/runner-labels';\nimport {runnerCatalog} from '#config.js';\nimport type {AgentDefaultsResolver} from '#core/agent-defaults.js';\nimport type {\n AgentToolMaterializationContext,\n AgentToolMaterializationSnapshot,\n} from '#core/agent-tools.js';\nimport {\n InvalidJobRunnerLabelsError,\n JobOutputTooLargeError,\n JobOutputTooManyEntriesError,\n} from '#core/errors.js';\nimport {completeStepField, completeStepFieldWithType} from './fields.js';\nimport {\n type JsonSafeJobOutputValue,\n jobOutputRecordEntryByteLength,\n jobOutputValueByteLength,\n MAX_JOB_OUTPUT_ENTRIES,\n MAX_JOB_OUTPUT_VALUE_BYTES,\n MAX_JOB_OUTPUTS_TOTAL_BYTES,\n normalizeJobOutputValue,\n} from './job-output-limits.js';\nimport {\n type MaterializedWorkflowStep,\n materializeJobExecutionSteps,\n} from './materialize-job-execution-steps.js';\nimport type {WorkflowEvaluationContext} from './workflow-evaluation-context.js';\n\ntype WorkflowModelJob = WorkflowModel['jobs'][number];\nexport interface MaterializedWorkflowJob {\n readonly key: string;\n readonly mode: WorkflowModelJob['mode'];\n readonly success?: string;\n readonly executionTimeoutMs?: number;\n readonly checkout: Exclude<WorkflowModelJob['checkout'], false>;\n readonly listening?: WorkflowModelJob['listening'];\n readonly name?: string;\n readonly outputs?: WorkflowModelJob['outputs'];\n readonly dependencies: readonly string[];\n readonly runner: readonly string[];\n readonly position: number;\n readonly steps: readonly MaterializedWorkflowStep[];\n}\n\nexport interface MaterializeWorkflowModelParams {\n readonly model: WorkflowModel;\n readonly context?: WorkflowEvaluationContext | undefined;\n readonly resolveAgentDefaults?: AgentDefaultsResolver | undefined;\n readonly definitionId?: string | undefined;\n readonly agentToolContext?: AgentToolMaterializationContext | undefined;\n readonly agentToolSnapshot?: AgentToolMaterializationSnapshot | null | undefined;\n}\n\nexport async function materializeWorkflowModel(\n params: MaterializeWorkflowModelParams,\n): Promise<readonly MaterializedWorkflowJob[]> {\n const {\n model,\n context = {site: 'run-creation', values: {}},\n resolveAgentDefaults,\n definitionId = model.name,\n agentToolContext,\n agentToolSnapshot,\n } = params;\n const jobsById = new Map(model.jobs.map((job) => [job.id, job]));\n\n return await Promise.all(\n model.jobs.map(async (job, position) => {\n const name = job.name;\n return {\n key: job.key,\n mode: job.mode,\n ...(job.success === undefined ? {} : {success: job.success}),\n ...(job.executionTimeoutMs === undefined\n ? {}\n : {executionTimeoutMs: job.executionTimeoutMs}),\n checkout: job.checkout === false ? DEFAULT_JOB_CHECKOUT : job.checkout,\n ...(job.listening === undefined ? {} : {listening: job.listening}),\n ...(name === undefined ? {} : {name}),\n ...(job.outputs === undefined ? {} : {outputs: job.outputs}),\n dependencies: dependencySourceNames(job, jobsById),\n runner: job.runner,\n position,\n steps:\n job.mode === 'listening'\n ? []\n : await materializeJobExecutionSteps({\n model,\n job,\n context,\n resolveAgentDefaults,\n definitionId,\n agentToolContext,\n agentToolSnapshot,\n }),\n };\n }),\n );\n}\n\nexport function materializeJobRunner(params: {\n readonly job: WorkflowModelJob;\n readonly context: WorkflowEvaluationContext;\n readonly definitionId: string;\n}): readonly string[] {\n const resolvedLabels = (params.job.runnerTemplates ?? []).map((template) =>\n completeStepField({\n field: 'job.runner',\n errorField: 'job.runner',\n template: {segments: template},\n context: params.context,\n definitionId: params.definitionId,\n }),\n );\n const requestedLabels = [...params.job.runner, ...resolvedLabels];\n const labels = resolveRunnerLabels(requestedLabels, runnerCatalog);\n const invalidLabels = findInvalidLabels(labels);\n if (labels.length === 0 || labels.length > MAX_RUNNER_LABELS || invalidLabels.length > 0) {\n throw new InvalidJobRunnerLabelsError(labels, requestedLabels);\n }\n return labels;\n}\n\nexport function materializeJobOutputs(params: {\n readonly job: WorkflowModelJob;\n readonly context: WorkflowEvaluationContext;\n readonly definitionId: string;\n}): Record<string, unknown> | null {\n const outputs = params.job.outputs;\n if (outputs === undefined) return null;\n\n const outputEntries = Object.entries(outputs);\n if (outputEntries.length > MAX_JOB_OUTPUT_ENTRIES) {\n throw new JobOutputTooManyEntriesError(outputEntries.length, MAX_JOB_OUTPUT_ENTRIES);\n }\n\n const materialized: Record<string, JsonSafeJobOutputValue> = {};\n // This is exactly JSON.stringify(materialized): start with \"{}\", then add each\n // key/value pair and its comma (except for the first entry).\n let recordBytes = 2;\n\n for (const [index, [key, template]] of outputEntries.entries()) {\n const outputTypes = params.job.outputTypes;\n const outputType =\n outputTypes !== undefined && Object.hasOwn(outputTypes, key) ? outputTypes[key] : undefined;\n const completionParams = {\n field: 'job.outputs' as const,\n errorField: 'job.outputs' as const,\n template: {segments: template},\n context: params.context,\n definitionId: params.definitionId,\n };\n const value =\n outputType === undefined || outputType === 'string'\n ? completeStepField(completionParams)\n : completeStepFieldWithType(completionParams);\n const normalizedValue = normalizeJobOutputValue(value, key);\n const valueBytes = jobOutputValueByteLength(normalizedValue);\n if (valueBytes > MAX_JOB_OUTPUT_VALUE_BYTES) {\n throw new JobOutputTooLargeError(key, MAX_JOB_OUTPUT_VALUE_BYTES, 'value');\n }\n\n recordBytes += (index === 0 ? 0 : 1) + jobOutputRecordEntryByteLength(key, normalizedValue);\n Object.defineProperty(materialized, key, {\n configurable: true,\n enumerable: true,\n value: normalizedValue,\n writable: true,\n });\n if (recordBytes > MAX_JOB_OUTPUTS_TOTAL_BYTES) {\n throw new JobOutputTooLargeError(key, MAX_JOB_OUTPUTS_TOTAL_BYTES, 'total');\n }\n }\n\n return materialized;\n}\n\nexport function modelHasAgentStep(model: WorkflowModel): boolean {\n return model.jobs.some((job) => job.steps.some((step) => step.kind === 'agent'));\n}\n\nfunction dependencySourceNames(\n job: WorkflowModelJob,\n jobsById: ReadonlyMap<string, WorkflowModelJob>,\n): readonly string[] {\n return job.dependencies.map((dependencyId) => {\n const dependency = jobsById.get(dependencyId);\n if (!dependency) {\n throw new Error(`Unresolved workflow model dependency \"${dependencyId}\" for job \"${job.id}\"`);\n }\n return dependency.key;\n });\n}\n"],"names":["DEFAULT_JOB_CHECKOUT","findInvalidLabels","MAX_RUNNER_LABELS","resolveRunnerLabels","runnerCatalog","InvalidJobRunnerLabelsError","JobOutputTooLargeError","JobOutputTooManyEntriesError","completeStepField","completeStepFieldWithType","jobOutputRecordEntryByteLength","jobOutputValueByteLength","MAX_JOB_OUTPUT_ENTRIES","MAX_JOB_OUTPUT_VALUE_BYTES","MAX_JOB_OUTPUTS_TOTAL_BYTES","normalizeJobOutputValue","materializeJobExecutionSteps","materializeWorkflowModel","params","model","context","site","values","resolveAgentDefaults","definitionId","name","agentToolContext","agentToolSnapshot","jobsById","Map","jobs","map","job","id","Promise","all","position","key","mode","success","undefined","executionTimeoutMs","checkout","listening","outputs","dependencies","dependencySourceNames","runner","steps","materializeJobRunner","resolvedLabels","runnerTemplates","template","field","errorField","segments","requestedLabels","labels","invalidLabels","length","materializeJobOutputs","outputEntries","Object","entries","materialized","recordBytes","index","outputTypes","outputType","hasOwn","completionParams","value","normalizedValue","valueBytes","defineProperty","configurable","enumerable","writable","modelHasAgentStep","some","step","kind","dependencyId","dependency","get","Error"],"mappings":"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"}
|