@toolproof-core/lib 1.0.4 → 1.0.5
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/shared.d.ts +33 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +67 -0
- package/dist/shared.js.map +1 -0
- package/dist/utils/parallelization.d.ts +3 -0
- package/dist/utils/parallelization.d.ts.map +1 -0
- package/dist/utils/parallelization.js +136 -0
- package/dist/utils/parallelization.js.map +1 -0
- package/dist/utils/resourceChain.d.ts +22 -0
- package/dist/utils/resourceChain.d.ts.map +1 -0
- package/dist/utils/resourceChain.js +38 -0
- package/dist/utils/resourceChain.js.map +1 -0
- package/dist/utils/roleResourceBinding.d.ts +5 -0
- package/dist/utils/roleResourceBinding.d.ts.map +1 -0
- package/dist/utils/roleResourceBinding.js +74 -0
- package/dist/utils/roleResourceBinding.js.map +1 -0
- package/dist/utils/runnableStrategyCreation.d.ts +8 -0
- package/dist/utils/runnableStrategyCreation.d.ts.map +1 -0
- package/dist/utils/runnableStrategyCreation.js +24 -0
- package/dist/utils/runnableStrategyCreation.js.map +1 -0
- package/dist/utils/stepCreation.d.ts +10 -0
- package/dist/utils/stepCreation.d.ts.map +1 -0
- package/dist/utils/stepCreation.js +80 -0
- package/dist/utils/stepCreation.js.map +1 -0
- package/package.json +5 -1
- package/src/shared.ts +126 -0
- package/src/utils/parallelization.ts +177 -0
- package/src/utils/resourceChain.ts +66 -0
- package/src/utils/roleResourceBinding.ts +109 -0
- package/src/utils/runnableStrategyCreation.ts +47 -0
- package/src/utils/stepCreation.ts +112 -0
- package/tsconfig.tsbuildinfo +1 -1
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CreationContextJson, JsonDataJson, ResourceIdentityJson, ResourceInputPotentialJson, ResourceJson, ResourceMissingJson, ResourceOutputPotentialJson, ResourceTypeIdentityJson } from '@toolproof-core/schema';
|
|
2
|
+
import { resolveResourceChain } from './utils/resourceChain.js';
|
|
3
|
+
import { bindInputRefInStrategyState, bindInputResInStrategyState, clearInputBindingInStrategyState } from './utils/roleResourceBinding.js';
|
|
4
|
+
import { createRunnableStrategy } from './utils/runnableStrategyCreation.js';
|
|
5
|
+
import { cloneForStep, cloneWhileStep, createBranchStepFromJobPairs, createJobStepFromJob, createLoopStepFromJobs } from './utils/stepCreation.js';
|
|
6
|
+
export declare const RESOURCE_CHAIN: {
|
|
7
|
+
readonly resolveResourceChain: typeof resolveResourceChain;
|
|
8
|
+
};
|
|
9
|
+
export declare const ROLE_RESOURCE_BINDINGS: {
|
|
10
|
+
readonly bindInputResInStrategyState: typeof bindInputResInStrategyState;
|
|
11
|
+
readonly bindInputRefInStrategyState: typeof bindInputRefInStrategyState;
|
|
12
|
+
readonly clearInputBindingInStrategyState: typeof clearInputBindingInStrategyState;
|
|
13
|
+
};
|
|
14
|
+
export declare const RUNNABLE_STRATEGY_CREATION: {
|
|
15
|
+
readonly createRunnableStrategy: typeof createRunnableStrategy;
|
|
16
|
+
};
|
|
17
|
+
export declare const STEP_CREATION: {
|
|
18
|
+
readonly createJobStepFromJob: typeof createJobStepFromJob;
|
|
19
|
+
readonly createLoopStepFromJobs: typeof createLoopStepFromJobs;
|
|
20
|
+
readonly createBranchStepFromJobPairs: typeof createBranchStepFromJobPairs;
|
|
21
|
+
readonly cloneForStep: typeof cloneForStep;
|
|
22
|
+
readonly cloneWhileStep: typeof cloneWhileStep;
|
|
23
|
+
};
|
|
24
|
+
export declare const RESOURCE_CREATION: {
|
|
25
|
+
readonly createMissingResource: (identity: ResourceIdentityJson, resourceTypeHandle: ResourceTypeIdentityJson) => ResourceMissingJson;
|
|
26
|
+
readonly createOutputPotentialResource: (identity: ResourceIdentityJson, resourceTypeHandle: ResourceTypeIdentityJson, creationContext: CreationContextJson) => ResourceOutputPotentialJson;
|
|
27
|
+
readonly createInputPotentialResource: (identity: ResourceIdentityJson, resourceTypeHandle: ResourceTypeIdentityJson, creationContext: CreationContextJson) => ResourceInputPotentialJson;
|
|
28
|
+
readonly createMaterializedResourceFromPotential: (potential: ResourceOutputPotentialJson | ResourceInputPotentialJson, nucleus: JsonDataJson, opts?: {
|
|
29
|
+
path?: string;
|
|
30
|
+
timestamp?: string;
|
|
31
|
+
}) => ResourceJson;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EACpB,0BAA0B,EAC1B,YAAY,EACZ,mBAAmB,EACnB,2BAA2B,EAC3B,wBAAwB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACH,2BAA2B,EAC3B,2BAA2B,EAC3B,gCAAgC,EACnC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACH,YAAY,EACZ,cAAc,EACd,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACzB,MAAM,yBAAyB,CAAC;AAGjC,eAAO,MAAM,cAAc;;CAEjB,CAAC;AAGX,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAC;AAGX,eAAO,MAAM,0BAA0B;;CAE7B,CAAC;AAGX,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAyBX,eAAO,MAAM,iBAAiB;+CACM,oBAAoB,sBAAsB,wBAAwB,KAAG,mBAAmB;uDAS1G,oBAAoB,sBACV,wBAAwB,mBAC3B,mBAAmB,KACrC,2BAA2B;sDAUhB,oBAAoB,sBACV,wBAAwB,mBAC3B,mBAAmB,KACrC,0BAA0B;kEAUd,2BAA2B,GAAG,0BAA0B,WAC1D,YAAY,SACd;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAC7C,YAAY;CAWT,CAAC"}
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { resolveResourceChain } from './utils/resourceChain.js';
|
|
2
|
+
import { bindInputRefInStrategyState, bindInputResInStrategyState, clearInputBindingInStrategyState, } from './utils/roleResourceBinding.js';
|
|
3
|
+
import { createRunnableStrategy } from './utils/runnableStrategyCreation.js';
|
|
4
|
+
import { cloneForStep, cloneWhileStep, createBranchStepFromJobPairs, createJobStepFromJob, createLoopStepFromJobs, } from './utils/stepCreation.js';
|
|
5
|
+
export const RESOURCE_CHAIN = {
|
|
6
|
+
resolveResourceChain,
|
|
7
|
+
};
|
|
8
|
+
export const ROLE_RESOURCE_BINDINGS = {
|
|
9
|
+
bindInputResInStrategyState,
|
|
10
|
+
bindInputRefInStrategyState,
|
|
11
|
+
clearInputBindingInStrategyState,
|
|
12
|
+
};
|
|
13
|
+
export const RUNNABLE_STRATEGY_CREATION = {
|
|
14
|
+
createRunnableStrategy,
|
|
15
|
+
};
|
|
16
|
+
export const STEP_CREATION = {
|
|
17
|
+
createJobStepFromJob,
|
|
18
|
+
createLoopStepFromJobs,
|
|
19
|
+
createBranchStepFromJobPairs,
|
|
20
|
+
cloneForStep,
|
|
21
|
+
cloneWhileStep,
|
|
22
|
+
};
|
|
23
|
+
function asMaterializedResource(base, nucleus, opts) {
|
|
24
|
+
return {
|
|
25
|
+
identity: base.identity,
|
|
26
|
+
resourceTypeHandle: base.resourceTypeHandle,
|
|
27
|
+
creationContext: base.creationContext,
|
|
28
|
+
resourceShellKind: 'materialized',
|
|
29
|
+
version: 1,
|
|
30
|
+
timestamp: opts?.timestamp ?? new Date().toISOString(),
|
|
31
|
+
path: opts?.path ?? '',
|
|
32
|
+
nucleus,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export const RESOURCE_CREATION = {
|
|
36
|
+
createMissingResource(identity, resourceTypeHandle) {
|
|
37
|
+
return {
|
|
38
|
+
identity,
|
|
39
|
+
resourceTypeHandle,
|
|
40
|
+
resourceShellKind: 'missing',
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
createOutputPotentialResource(identity, resourceTypeHandle, creationContext) {
|
|
44
|
+
return {
|
|
45
|
+
identity,
|
|
46
|
+
resourceTypeHandle,
|
|
47
|
+
creationContext,
|
|
48
|
+
resourceShellKind: 'outputPotential',
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
createInputPotentialResource(identity, resourceTypeHandle, creationContext) {
|
|
52
|
+
return {
|
|
53
|
+
identity,
|
|
54
|
+
resourceTypeHandle,
|
|
55
|
+
creationContext,
|
|
56
|
+
resourceShellKind: 'inputPotential',
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
createMaterializedResourceFromPotential(potential, nucleus, opts) {
|
|
60
|
+
return asMaterializedResource({
|
|
61
|
+
identity: potential.identity,
|
|
62
|
+
resourceTypeHandle: potential.resourceTypeHandle,
|
|
63
|
+
creationContext: potential.creationContext,
|
|
64
|
+
}, nucleus, opts);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACH,2BAA2B,EAC3B,2BAA2B,EAC3B,gCAAgC,GACnC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EACH,YAAY,EACZ,cAAc,EACd,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,GACzB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,oBAAoB;CACd,CAAC;AAGX,MAAM,CAAC,MAAM,sBAAsB,GAAG;IAClC,2BAA2B;IAC3B,2BAA2B;IAC3B,gCAAgC;CAC1B,CAAC;AAGX,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACtC,sBAAsB;CAChB,CAAC;AAGX,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,oBAAoB;IACpB,sBAAsB;IACtB,4BAA4B;IAC5B,YAAY;IACZ,cAAc;CACR,CAAC;AAGX,SAAS,sBAAsB,CAC3B,IAIC,EACD,OAAqB,EACrB,IAA4C;IAE5C,OAAO;QACH,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,iBAAiB,EAAE,cAAc;QACjC,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtD,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE;QACtB,OAAO;KACiB,CAAC;AACjC,CAAC;AAGD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC7B,qBAAqB,CAAC,QAA8B,EAAE,kBAA4C;QAC9F,OAAO;YACH,QAAQ;YACR,kBAAkB;YAClB,iBAAiB,EAAE,SAAS;SAC/B,CAAC;IACN,CAAC;IAED,6BAA6B,CACzB,QAA8B,EAC9B,kBAA4C,EAC5C,eAAoC;QAEpC,OAAO;YACH,QAAQ;YACR,kBAAkB;YAClB,eAAe;YACf,iBAAiB,EAAE,iBAAiB;SACvC,CAAC;IACN,CAAC;IAED,4BAA4B,CACxB,QAA8B,EAC9B,kBAA4C,EAC5C,eAAoC;QAEpC,OAAO;YACH,QAAQ;YACR,kBAAkB;YAClB,eAAe;YACf,iBAAiB,EAAE,gBAAgB;SACtC,CAAC;IACN,CAAC;IAED,uCAAuC,CACnC,SAAmE,EACnE,OAAqB,EACrB,IAA4C;QAE5C,OAAO,sBAAsB,CACzB;YACI,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;YAChD,eAAe,EAAE,SAAS,CAAC,eAAe;SAC7C,EACD,OAAO,EACP,IAAI,CACP,CAAC;IACN,CAAC;CACK,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallelization.d.ts","sourceRoot":"","sources":["../../src/utils/parallelization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAMR,QAAQ,EACR,iBAAiB,EAEpB,MAAM,wBAAwB,CAAC;AAGhC,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,aAAa,EAAE,iBAAiB,GAAG,QAAQ,EAAE,EAAE,CAoKvG"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export function getIndependentThreads(steps, strategyState) {
|
|
2
|
+
const getOwnerLabel = (ownerIndex) => {
|
|
3
|
+
const step = steps[ownerIndex];
|
|
4
|
+
return `steps[${ownerIndex}] stepKind=${step?.stepKind ?? 'unknown'}`;
|
|
5
|
+
};
|
|
6
|
+
// Map each jobStep.identity (including macro-nested job steps) to owning top-level step index.
|
|
7
|
+
const jobStepIdToOwner = new Map();
|
|
8
|
+
const ownerToJobStepIds = new Map();
|
|
9
|
+
const jobStepById = new Map();
|
|
10
|
+
const addJobStep = (jobStep, ownerIndex) => {
|
|
11
|
+
if (!jobStep?.identity)
|
|
12
|
+
return;
|
|
13
|
+
const existingOwner = jobStepIdToOwner.get(jobStep.identity);
|
|
14
|
+
if (existingOwner !== undefined) {
|
|
15
|
+
throw new Error(`Duplicate jobStep.identity '${jobStep.identity}' found in ${getOwnerLabel(ownerIndex)} and ${getOwnerLabel(existingOwner)}`);
|
|
16
|
+
}
|
|
17
|
+
jobStepIdToOwner.set(jobStep.identity, ownerIndex);
|
|
18
|
+
jobStepById.set(jobStep.identity, jobStep);
|
|
19
|
+
const bucket = ownerToJobStepIds.get(ownerIndex) ?? [];
|
|
20
|
+
bucket.push(jobStep.identity);
|
|
21
|
+
ownerToJobStepIds.set(ownerIndex, bucket);
|
|
22
|
+
};
|
|
23
|
+
steps.forEach((step, ownerIndex) => {
|
|
24
|
+
if (step.stepKind === 'job') {
|
|
25
|
+
addJobStep(step, ownerIndex);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (step.stepKind === 'for') {
|
|
29
|
+
const loop = step;
|
|
30
|
+
addJobStep(loop.case?.what, ownerIndex);
|
|
31
|
+
addJobStep(loop.case?.when, ownerIndex);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (step.stepKind === 'while') {
|
|
35
|
+
const loop = step;
|
|
36
|
+
addJobStep(loop.case?.what, ownerIndex);
|
|
37
|
+
addJobStep(loop.case?.when, ownerIndex);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (step.stepKind === 'branch') {
|
|
41
|
+
const branch = step;
|
|
42
|
+
for (const caseItem of branch.cases ?? []) {
|
|
43
|
+
addJobStep(caseItem?.what, ownerIndex);
|
|
44
|
+
addJobStep(caseItem?.when, ownerIndex);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
// Undirected adjacency used for connected components (thread groups).
|
|
50
|
+
const ownerAdj = new Map();
|
|
51
|
+
// Directed dependencies used for strict ordering validation: owner -> producers it depends on.
|
|
52
|
+
const ownerDeps = new Map();
|
|
53
|
+
const ensureOwner = (ownerIndex) => {
|
|
54
|
+
if (!ownerAdj.has(ownerIndex))
|
|
55
|
+
ownerAdj.set(ownerIndex, new Set());
|
|
56
|
+
if (!ownerDeps.has(ownerIndex))
|
|
57
|
+
ownerDeps.set(ownerIndex, new Set());
|
|
58
|
+
};
|
|
59
|
+
for (let i = 0; i < steps.length; i++) {
|
|
60
|
+
ensureOwner(i);
|
|
61
|
+
}
|
|
62
|
+
// Discover dependencies from strategyState.
|
|
63
|
+
for (const [jobStepId, ownerIndex] of jobStepIdToOwner) {
|
|
64
|
+
ensureOwner(ownerIndex);
|
|
65
|
+
const jobStep = jobStepById.get(jobStepId);
|
|
66
|
+
const inputBindings = jobStep?.roleBindings?.inputBindings ?? [];
|
|
67
|
+
const bucket = strategyState?.[jobStepId] ?? {};
|
|
68
|
+
for (const inputRoleHandle of inputBindings) {
|
|
69
|
+
const entry = bucket?.[inputRoleHandle];
|
|
70
|
+
if (!entry || entry.resourceShellKind !== 'inputPotential')
|
|
71
|
+
continue;
|
|
72
|
+
const creatorJobStepHandle = entry?.creationContext?.jobStepHandle;
|
|
73
|
+
if (!creatorJobStepHandle) {
|
|
74
|
+
throw new Error(`Unresolvable inputPotential in jobStep '${jobStepId}' (${getOwnerLabel(ownerIndex)}): missing creationContext.jobStepHandle for role '${inputRoleHandle}'`);
|
|
75
|
+
}
|
|
76
|
+
const producerOwner = jobStepIdToOwner.get(creatorJobStepHandle);
|
|
77
|
+
if (producerOwner === undefined) {
|
|
78
|
+
throw new Error(`Unresolvable inputPotential in jobStep '${jobStepId}' (${getOwnerLabel(ownerIndex)}): creator jobStepHandle '${creatorJobStepHandle}' not found in strategy steps`);
|
|
79
|
+
}
|
|
80
|
+
ensureOwner(producerOwner);
|
|
81
|
+
ownerAdj.get(ownerIndex).add(producerOwner);
|
|
82
|
+
ownerAdj.get(producerOwner).add(ownerIndex);
|
|
83
|
+
ownerDeps.get(ownerIndex).add(producerOwner);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Connected components over owners.
|
|
87
|
+
const visited = new Set();
|
|
88
|
+
const components = [];
|
|
89
|
+
for (let ownerIndex = 0; ownerIndex < steps.length; ownerIndex++) {
|
|
90
|
+
if (visited.has(ownerIndex))
|
|
91
|
+
continue;
|
|
92
|
+
const component = [];
|
|
93
|
+
const queue = [ownerIndex];
|
|
94
|
+
visited.add(ownerIndex);
|
|
95
|
+
while (queue.length > 0) {
|
|
96
|
+
const node = queue.shift();
|
|
97
|
+
component.push(node);
|
|
98
|
+
for (const neighbor of ownerAdj.get(node) ?? []) {
|
|
99
|
+
if (!visited.has(neighbor)) {
|
|
100
|
+
visited.add(neighbor);
|
|
101
|
+
queue.push(neighbor);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
components.push(component);
|
|
106
|
+
}
|
|
107
|
+
// Strict validation: within a thread, the linear order must not contain forward refs.
|
|
108
|
+
for (const comp of components) {
|
|
109
|
+
const compSet = new Set(comp);
|
|
110
|
+
const ownersInOrder = steps.map((_, i) => i).filter((i) => compSet.has(i));
|
|
111
|
+
const position = new Map();
|
|
112
|
+
ownersInOrder.forEach((owner, idx) => position.set(owner, idx));
|
|
113
|
+
for (const consumerOwner of ownersInOrder) {
|
|
114
|
+
const deps = ownerDeps.get(consumerOwner);
|
|
115
|
+
if (!deps || deps.size === 0)
|
|
116
|
+
continue;
|
|
117
|
+
const consumerPos = position.get(consumerOwner);
|
|
118
|
+
for (const producerOwner of deps) {
|
|
119
|
+
const producerPos = position.get(producerOwner);
|
|
120
|
+
if (producerPos === undefined) {
|
|
121
|
+
throw new Error(`Internal error: dependency producer ${getOwnerLabel(producerOwner)} missing from computed thread for ${getOwnerLabel(consumerOwner)}`);
|
|
122
|
+
}
|
|
123
|
+
if (producerPos >= consumerPos) {
|
|
124
|
+
throw new Error(`Invalid step order in thread: ${getOwnerLabel(consumerOwner)} depends on ${getOwnerLabel(producerOwner)}, but producer is not scheduled before consumer`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return components
|
|
130
|
+
.map((compOwners) => {
|
|
131
|
+
const ownerSet = new Set(compOwners);
|
|
132
|
+
return steps.filter((_, i) => ownerSet.has(i));
|
|
133
|
+
})
|
|
134
|
+
.filter((group) => group.length > 0);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=parallelization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallelization.js","sourceRoot":"","sources":["../../src/utils/parallelization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CreationContextJson, ResourceJson, ResourceMissingJson, ResourceOutputPotentialJson, StrategyStateJson } from '@toolproof-core/schema';
|
|
2
|
+
export type ResolveResult = {
|
|
3
|
+
status: 'materialized';
|
|
4
|
+
entry: ResourceJson;
|
|
5
|
+
path: CreationContextJson[];
|
|
6
|
+
} | {
|
|
7
|
+
status: 'missing';
|
|
8
|
+
entry: ResourceMissingJson;
|
|
9
|
+
path: CreationContextJson[];
|
|
10
|
+
} | {
|
|
11
|
+
status: 'outputPotential';
|
|
12
|
+
entry: ResourceOutputPotentialJson;
|
|
13
|
+
path: CreationContextJson[];
|
|
14
|
+
} | {
|
|
15
|
+
status: 'unresolved';
|
|
16
|
+
reason: 'not-found' | 'cycle' | 'depth-exceeded';
|
|
17
|
+
path: CreationContextJson[];
|
|
18
|
+
};
|
|
19
|
+
export declare function resolveResourceChain(strategyState: StrategyStateJson, start: CreationContextJson, opts?: {
|
|
20
|
+
maxDepth?: number;
|
|
21
|
+
}): ResolveResult;
|
|
22
|
+
//# sourceMappingURL=resourceChain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceChain.d.ts","sourceRoot":"","sources":["../../src/utils/resourceChain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EAEnB,2BAA2B,EAC3B,iBAAiB,EACpB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,MAAM,aAAa,GACnB;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAC5E;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAC9E;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,2BAA2B,CAAC;IAAC,IAAI,EAAE,mBAAmB,EAAE,CAAA;CAAE,GAC9F;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,OAAO,GAAG,gBAAgB,CAAC;IAAC,IAAI,EAAE,mBAAmB,EAAE,CAAA;CAAE,CAAC;AAE9G,wBAAgB,oBAAoB,CAChC,aAAa,EAAE,iBAAiB,EAChC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,aAAa,CA8Cf"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function resolveResourceChain(strategyState, start, opts) {
|
|
2
|
+
const maxDepth = opts?.maxDepth ?? 50;
|
|
3
|
+
const visited = new Set();
|
|
4
|
+
const path = [];
|
|
5
|
+
let current = start;
|
|
6
|
+
for (let depth = 0; depth <= maxDepth; depth++) {
|
|
7
|
+
path.push(current);
|
|
8
|
+
const visitKey = `${current.jobStepHandle}::${current.resourceRoleHandle}`;
|
|
9
|
+
if (visited.has(visitKey)) {
|
|
10
|
+
return { status: 'unresolved', reason: 'cycle', path };
|
|
11
|
+
}
|
|
12
|
+
visited.add(visitKey);
|
|
13
|
+
const bucket = strategyState[current.jobStepHandle];
|
|
14
|
+
if (!bucket)
|
|
15
|
+
return { status: 'unresolved', reason: 'not-found', path };
|
|
16
|
+
const entry = bucket[current.resourceRoleHandle];
|
|
17
|
+
if (!entry)
|
|
18
|
+
return { status: 'unresolved', reason: 'not-found', path };
|
|
19
|
+
if (entry.resourceShellKind === 'materialized') {
|
|
20
|
+
return { status: 'materialized', entry: entry, path };
|
|
21
|
+
}
|
|
22
|
+
if (entry.resourceShellKind === 'missing') {
|
|
23
|
+
return { status: 'missing', entry: entry, path };
|
|
24
|
+
}
|
|
25
|
+
if (entry.resourceShellKind === 'outputPotential') {
|
|
26
|
+
return { status: 'outputPotential', entry: entry, path };
|
|
27
|
+
}
|
|
28
|
+
// inputPotential: follow ref backwards
|
|
29
|
+
if (entry.resourceShellKind === 'inputPotential') {
|
|
30
|
+
current = entry.creationContext;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Unknown case
|
|
34
|
+
return { status: 'unresolved', reason: 'not-found', path };
|
|
35
|
+
}
|
|
36
|
+
return { status: 'unresolved', reason: 'depth-exceeded', path };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=resourceChain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resourceChain.js","sourceRoot":"","sources":["../../src/utils/resourceChain.ts"],"names":[],"mappings":"AAeA,MAAM,UAAU,oBAAoB,CAChC,aAAgC,EAChC,KAA0B,EAC1B,IAA4B;IAE5B,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,IAAI,GAA0B,EAAE,CAAC;IACvC,IAAI,OAAO,GAAwB,KAAK,CAAC;IAEzC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,aAAa,KAAK,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAC3E,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEtB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACpD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QACxE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAM9C,CAAC;QACF,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QAEvE,IAAI,KAAK,CAAC,iBAAiB,KAAK,cAAc,EAAE,CAAC;YAC7C,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,KAAqB,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,KAA4B,EAAE,IAAI,EAAE,CAAC;QAC5E,CAAC;QACD,IAAI,KAAK,CAAC,iBAAiB,KAAK,iBAAiB,EAAE,CAAC;YAChD,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAoC,EAAE,IAAI,EAAE,CAAC;QAC5F,CAAC;QAED,uCAAuC;QACvC,IAAI,KAAK,CAAC,iBAAiB,KAAK,gBAAgB,EAAE,CAAC;YAC/C,OAAO,GAAI,KAAoC,CAAC,eAAe,CAAC;YAChE,SAAS;QACb,CAAC;QAED,eAAe;QACf,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAC/D,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ResourceJson, CreationContextJson, StrategyStateJson } from '@toolproof-core/schema';
|
|
2
|
+
export declare function bindInputResInStrategyState(strategyState: StrategyStateJson, target: CreationContextJson, resource: ResourceJson): StrategyStateJson;
|
|
3
|
+
export declare function bindInputRefInStrategyState(strategyState: StrategyStateJson, target: CreationContextJson, source: CreationContextJson): StrategyStateJson;
|
|
4
|
+
export declare function clearInputBindingInStrategyState(strategyState: StrategyStateJson, target: CreationContextJson): StrategyStateJson;
|
|
5
|
+
//# sourceMappingURL=roleResourceBinding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roleResourceBinding.d.ts","sourceRoot":"","sources":["../../src/utils/roleResourceBinding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,YAAY,EAIZ,mBAAmB,EACnB,iBAAiB,EACpB,MAAM,wBAAwB,CAAC;AAGhC,wBAAgB,2BAA2B,CACvC,aAAa,EAAE,iBAAiB,EAChC,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,YAAY,GACvB,iBAAiB,CASnB;AAED,wBAAgB,2BAA2B,CACvC,aAAa,EAAE,iBAAiB,EAChC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,mBAAmB,GAC5B,iBAAiB,CA+DnB;AAED,wBAAgB,gCAAgC,CAC5C,aAAa,EAAE,iBAAiB,EAChC,MAAM,EAAE,mBAAmB,GAC5B,iBAAiB,CAWnB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { resolveResourceChain } from './resourceChain.js';
|
|
2
|
+
export function bindInputResInStrategyState(strategyState, target, resource) {
|
|
3
|
+
const bucket = strategyState[target.jobStepHandle] ?? {};
|
|
4
|
+
return {
|
|
5
|
+
...strategyState,
|
|
6
|
+
[target.jobStepHandle]: {
|
|
7
|
+
...bucket,
|
|
8
|
+
[target.resourceRoleHandle]: resource,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export function bindInputRefInStrategyState(strategyState, target, source) {
|
|
13
|
+
const sourceEntry = strategyState?.[source.jobStepHandle]?.[source.resourceRoleHandle];
|
|
14
|
+
if (!sourceEntry) {
|
|
15
|
+
throw new Error(`resourceEntry not found for source (${source.jobStepHandle}, ${source.resourceRoleHandle})`);
|
|
16
|
+
}
|
|
17
|
+
const result = resolveResourceChain(strategyState, source);
|
|
18
|
+
const bucket = strategyState[target.jobStepHandle] ?? {};
|
|
19
|
+
if (result.status === 'materialized') {
|
|
20
|
+
return {
|
|
21
|
+
...strategyState,
|
|
22
|
+
[target.jobStepHandle]: {
|
|
23
|
+
...bucket,
|
|
24
|
+
[target.resourceRoleHandle]: result.entry,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (result.status === 'missing') {
|
|
29
|
+
const missing = result.entry;
|
|
30
|
+
const reusedMissing = {
|
|
31
|
+
identity: missing.identity,
|
|
32
|
+
resourceTypeHandle: missing.resourceTypeHandle,
|
|
33
|
+
resourceShellKind: 'missing',
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
...strategyState,
|
|
37
|
+
[target.jobStepHandle]: {
|
|
38
|
+
...bucket,
|
|
39
|
+
[target.resourceRoleHandle]: reusedMissing,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (result.status === 'outputPotential') {
|
|
44
|
+
const potentialInput = {
|
|
45
|
+
identity: sourceEntry.identity,
|
|
46
|
+
resourceTypeHandle: sourceEntry.resourceTypeHandle,
|
|
47
|
+
creationContext: {
|
|
48
|
+
jobStepHandle: source.jobStepHandle,
|
|
49
|
+
resourceRoleHandle: source.resourceRoleHandle,
|
|
50
|
+
},
|
|
51
|
+
resourceShellKind: 'inputPotential',
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
...strategyState,
|
|
55
|
+
[target.jobStepHandle]: {
|
|
56
|
+
...bucket,
|
|
57
|
+
[target.resourceRoleHandle]: potentialInput,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Failed to resolve resource chain: ${result.reason}`);
|
|
62
|
+
}
|
|
63
|
+
export function clearInputBindingInStrategyState(strategyState, target) {
|
|
64
|
+
const bucket = strategyState?.[target.jobStepHandle];
|
|
65
|
+
if (!bucket?.[target.resourceRoleHandle])
|
|
66
|
+
return strategyState;
|
|
67
|
+
const nextBucket = { ...bucket };
|
|
68
|
+
delete nextBucket[target.resourceRoleHandle];
|
|
69
|
+
return {
|
|
70
|
+
...strategyState,
|
|
71
|
+
[target.jobStepHandle]: nextBucket,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=roleResourceBinding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roleResourceBinding.js","sourceRoot":"","sources":["../../src/utils/roleResourceBinding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RawStrategyJson, RunnableStrategyJson, RunnableStrategyStatusJson } from '@toolproof-core/schema';
|
|
2
|
+
import type { IdentityName } from '../types/types.js';
|
|
3
|
+
export type GetNewIdentity = (identityName: IdentityName) => string | Promise<string>;
|
|
4
|
+
export declare function createRunnableStrategy(rawStrategy: RawStrategyJson, opts: {
|
|
5
|
+
getNewIdentity: GetNewIdentity;
|
|
6
|
+
status?: RunnableStrategyStatusJson;
|
|
7
|
+
}): Promise<RunnableStrategyJson>;
|
|
8
|
+
//# sourceMappingURL=runnableStrategyCreation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runnableStrategyCreation.d.ts","sourceRoot":"","sources":["../../src/utils/runnableStrategyCreation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,eAAe,EAEf,oBAAoB,EACpB,0BAA0B,EAG7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,MAAM,MAAM,cAAc,GAAG,CAAC,YAAY,EAAE,YAAY,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAGtF,wBAAsB,sBAAsB,CACxC,WAAW,EAAE,eAAe,EAC5B,IAAI,EAAE;IACF,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,CAAC,EAAE,0BAA0B,CAAC;CACvC,GACF,OAAO,CAAC,oBAAoB,CAAC,CAyB/B"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getIndependentThreads } from './parallelization.js';
|
|
2
|
+
export async function createRunnableStrategy(rawStrategy, opts) {
|
|
3
|
+
if (!opts?.getNewIdentity) {
|
|
4
|
+
throw new Error('createRunnableStrategy: opts.getNewIdentity is required');
|
|
5
|
+
}
|
|
6
|
+
const runnableStrategyIdentity = (await opts.getNewIdentity('RunnableStrategyIdentity'));
|
|
7
|
+
const steps = (rawStrategy.steps ?? []);
|
|
8
|
+
const strategyState = (rawStrategy.strategyState ?? {});
|
|
9
|
+
const threadStepGroups = getIndependentThreads(steps, strategyState);
|
|
10
|
+
const strategyThreadDict = {};
|
|
11
|
+
for (const group of threadStepGroups) {
|
|
12
|
+
const threadIdentity = (await opts.getNewIdentity('StrategyThreadIdentity'));
|
|
13
|
+
strategyThreadDict[threadIdentity] = group;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
identity: runnableStrategyIdentity,
|
|
17
|
+
runnableStrategyContext: {
|
|
18
|
+
status: opts.status ?? 'running',
|
|
19
|
+
},
|
|
20
|
+
strategyThreadDict,
|
|
21
|
+
strategyState,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=runnableStrategyCreation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runnableStrategyCreation.js","sourceRoot":"","sources":["../../src/utils/runnableStrategyCreation.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAM7D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CACxC,WAA4B,EAC5B,IAGC;IAED,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,wBAAwB,GAAG,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAiC,CAAC;IACzH,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAe,CAAC;IACtD,MAAM,aAAa,GAAG,CAAC,WAAW,CAAC,aAAa,IAAI,EAAE,CAA0C,CAAC;IAEjG,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACrE,MAAM,kBAAkB,GAAmD,EAAS,CAAC;IAErF,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;QACnC,MAAM,cAAc,GAAG,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAA+B,CAAC;QAC3G,kBAAkB,CAAC,cAAc,CAAC,GAAG,KAAK,CAAC;IAC/C,CAAC;IAED,OAAO;QACH,QAAQ,EAAE,wBAAwB;QAClC,uBAAuB,EAAE;YACrB,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,SAAS;SACnC;QACD,kBAAkB;QAClB,aAAa;KACQ,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BranchStepJson, ForStepJson, JobJson, JobStepJson, WhileStepJson } from '@toolproof-core/schema';
|
|
2
|
+
export declare function createJobStepFromJob(job: JobJson): Promise<JobStepJson>;
|
|
3
|
+
export declare function createLoopStepFromJobs(whatJob: JobJson, whenJob: JobJson, stepKind: 'for' | 'while'): Promise<ForStepJson | WhileStepJson>;
|
|
4
|
+
export declare function createBranchStepFromJobPairs(cases: Array<{
|
|
5
|
+
whatJob: JobJson;
|
|
6
|
+
whenJob: JobJson;
|
|
7
|
+
}>): Promise<BranchStepJson>;
|
|
8
|
+
export declare function cloneForStep(forStep: ForStepJson): ForStepJson;
|
|
9
|
+
export declare function cloneWhileStep(whileStep: WhileStepJson): WhileStepJson;
|
|
10
|
+
//# sourceMappingURL=stepCreation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepCreation.d.ts","sourceRoot":"","sources":["../../src/utils/stepCreation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,cAAc,EAEd,WAAW,EACX,OAAO,EACP,WAAW,EAEX,aAAa,EAChB,MAAM,wBAAwB,CAAC;AAShC,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAa7E;AAGD,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,KAAK,GAAG,OAAO,GAC1B,OAAO,CAAC,WAAW,GAAG,aAAa,CAAC,CAiBtC;AAGD,wBAAsB,4BAA4B,CAC9C,KAAK,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,GACrD,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAGD,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,CAe9D;AAGD,wBAAgB,cAAc,CAAC,SAAS,EAAE,aAAa,GAAG,aAAa,CAetE"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getNewStepIdentity } from '../firebase/firebaseAdminHelpers.js';
|
|
2
|
+
function assertNonEmpty(arr, msg) {
|
|
3
|
+
if (arr.length === 0)
|
|
4
|
+
throw new Error(msg);
|
|
5
|
+
}
|
|
6
|
+
export async function createJobStepFromJob(job) {
|
|
7
|
+
const inputBindings = Object.keys(job.roles.inputDict ?? {});
|
|
8
|
+
const outputBindings = Object.keys(job.roles.outputDict ?? {});
|
|
9
|
+
return {
|
|
10
|
+
identity: getNewStepIdentity('job'),
|
|
11
|
+
stepKind: 'job',
|
|
12
|
+
jobHandle: job.identity,
|
|
13
|
+
roleBindings: {
|
|
14
|
+
inputBindings,
|
|
15
|
+
outputBindings,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export async function createLoopStepFromJobs(whatJob, whenJob, stepKind) {
|
|
20
|
+
const what = await createJobStepFromJob(whatJob);
|
|
21
|
+
const when = await createJobStepFromJob(whenJob);
|
|
22
|
+
if (stepKind === 'for') {
|
|
23
|
+
return {
|
|
24
|
+
identity: getNewStepIdentity('for'),
|
|
25
|
+
stepKind: 'for',
|
|
26
|
+
case: { what, when },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
identity: getNewStepIdentity('while'),
|
|
31
|
+
stepKind: 'while',
|
|
32
|
+
case: { what, when },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export async function createBranchStepFromJobPairs(cases) {
|
|
36
|
+
const resolved = await Promise.all(cases.map(async ({ whatJob, whenJob }) => {
|
|
37
|
+
const what = await createJobStepFromJob(whatJob);
|
|
38
|
+
const when = await createJobStepFromJob(whenJob);
|
|
39
|
+
return { what, when };
|
|
40
|
+
}));
|
|
41
|
+
assertNonEmpty(resolved, 'createBranchStepFromJobPairs requires at least one case');
|
|
42
|
+
return {
|
|
43
|
+
identity: getNewStepIdentity('branch'),
|
|
44
|
+
stepKind: 'branch',
|
|
45
|
+
cases: resolved,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function cloneForStep(forStep) {
|
|
49
|
+
return {
|
|
50
|
+
identity: getNewStepIdentity('for'),
|
|
51
|
+
stepKind: 'for',
|
|
52
|
+
case: {
|
|
53
|
+
what: {
|
|
54
|
+
...forStep.case.what,
|
|
55
|
+
identity: getNewStepIdentity('job'),
|
|
56
|
+
},
|
|
57
|
+
when: {
|
|
58
|
+
...forStep.case.when,
|
|
59
|
+
identity: getNewStepIdentity('job'),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function cloneWhileStep(whileStep) {
|
|
65
|
+
return {
|
|
66
|
+
identity: getNewStepIdentity('while'),
|
|
67
|
+
stepKind: 'while',
|
|
68
|
+
case: {
|
|
69
|
+
what: {
|
|
70
|
+
...whileStep.case.what,
|
|
71
|
+
identity: getNewStepIdentity('job'),
|
|
72
|
+
},
|
|
73
|
+
when: {
|
|
74
|
+
...whileStep.case.when,
|
|
75
|
+
identity: getNewStepIdentity('job'),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=stepCreation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stepCreation.js","sourceRoot":"","sources":["../../src/utils/stepCreation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toolproof-core/lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [],
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"./firebase-admin-helpers": {
|
|
35
35
|
"types": "./dist/firebase/firebaseAdminHelpers.d.ts",
|
|
36
36
|
"import": "./dist/firebase/firebaseAdminHelpers.js"
|
|
37
|
+
},
|
|
38
|
+
"./shared": {
|
|
39
|
+
"types": "./dist/shared.d.ts",
|
|
40
|
+
"import": "./dist/shared.js"
|
|
37
41
|
}
|
|
38
42
|
},
|
|
39
43
|
"devDependencies": {
|
package/src/shared.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreationContextJson,
|
|
3
|
+
JsonDataJson,
|
|
4
|
+
ResourceIdentityJson,
|
|
5
|
+
ResourceInputPotentialJson,
|
|
6
|
+
ResourceJson,
|
|
7
|
+
ResourceMissingJson,
|
|
8
|
+
ResourceOutputPotentialJson,
|
|
9
|
+
ResourceTypeIdentityJson,
|
|
10
|
+
} from '@toolproof-core/schema';
|
|
11
|
+
|
|
12
|
+
import { resolveResourceChain } from './utils/resourceChain.js';
|
|
13
|
+
import {
|
|
14
|
+
bindInputRefInStrategyState,
|
|
15
|
+
bindInputResInStrategyState,
|
|
16
|
+
clearInputBindingInStrategyState,
|
|
17
|
+
} from './utils/roleResourceBinding.js';
|
|
18
|
+
import { createRunnableStrategy } from './utils/runnableStrategyCreation.js';
|
|
19
|
+
import {
|
|
20
|
+
cloneForStep,
|
|
21
|
+
cloneWhileStep,
|
|
22
|
+
createBranchStepFromJobPairs,
|
|
23
|
+
createJobStepFromJob,
|
|
24
|
+
createLoopStepFromJobs,
|
|
25
|
+
} from './utils/stepCreation.js';
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export const RESOURCE_CHAIN = {
|
|
29
|
+
resolveResourceChain,
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
export const ROLE_RESOURCE_BINDINGS = {
|
|
34
|
+
bindInputResInStrategyState,
|
|
35
|
+
bindInputRefInStrategyState,
|
|
36
|
+
clearInputBindingInStrategyState,
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
export const RUNNABLE_STRATEGY_CREATION = {
|
|
41
|
+
createRunnableStrategy,
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export const STEP_CREATION = {
|
|
46
|
+
createJobStepFromJob,
|
|
47
|
+
createLoopStepFromJobs,
|
|
48
|
+
createBranchStepFromJobPairs,
|
|
49
|
+
cloneForStep,
|
|
50
|
+
cloneWhileStep,
|
|
51
|
+
} as const;
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
function asMaterializedResource(
|
|
55
|
+
base: {
|
|
56
|
+
identity: ResourceIdentityJson;
|
|
57
|
+
resourceTypeHandle: ResourceTypeIdentityJson;
|
|
58
|
+
creationContext: CreationContextJson;
|
|
59
|
+
},
|
|
60
|
+
nucleus: JsonDataJson,
|
|
61
|
+
opts?: { path?: string; timestamp?: string }
|
|
62
|
+
): ResourceJson {
|
|
63
|
+
return {
|
|
64
|
+
identity: base.identity,
|
|
65
|
+
resourceTypeHandle: base.resourceTypeHandle,
|
|
66
|
+
creationContext: base.creationContext,
|
|
67
|
+
resourceShellKind: 'materialized',
|
|
68
|
+
version: 1,
|
|
69
|
+
timestamp: opts?.timestamp ?? new Date().toISOString(),
|
|
70
|
+
path: opts?.path ?? '',
|
|
71
|
+
nucleus,
|
|
72
|
+
} as unknown as ResourceJson;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
export const RESOURCE_CREATION = {
|
|
77
|
+
createMissingResource(identity: ResourceIdentityJson, resourceTypeHandle: ResourceTypeIdentityJson): ResourceMissingJson {
|
|
78
|
+
return {
|
|
79
|
+
identity,
|
|
80
|
+
resourceTypeHandle,
|
|
81
|
+
resourceShellKind: 'missing',
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
createOutputPotentialResource(
|
|
86
|
+
identity: ResourceIdentityJson,
|
|
87
|
+
resourceTypeHandle: ResourceTypeIdentityJson,
|
|
88
|
+
creationContext: CreationContextJson
|
|
89
|
+
): ResourceOutputPotentialJson {
|
|
90
|
+
return {
|
|
91
|
+
identity,
|
|
92
|
+
resourceTypeHandle,
|
|
93
|
+
creationContext,
|
|
94
|
+
resourceShellKind: 'outputPotential',
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
createInputPotentialResource(
|
|
99
|
+
identity: ResourceIdentityJson,
|
|
100
|
+
resourceTypeHandle: ResourceTypeIdentityJson,
|
|
101
|
+
creationContext: CreationContextJson
|
|
102
|
+
): ResourceInputPotentialJson {
|
|
103
|
+
return {
|
|
104
|
+
identity,
|
|
105
|
+
resourceTypeHandle,
|
|
106
|
+
creationContext,
|
|
107
|
+
resourceShellKind: 'inputPotential',
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
createMaterializedResourceFromPotential(
|
|
112
|
+
potential: ResourceOutputPotentialJson | ResourceInputPotentialJson,
|
|
113
|
+
nucleus: JsonDataJson,
|
|
114
|
+
opts?: { path?: string; timestamp?: string }
|
|
115
|
+
): ResourceJson {
|
|
116
|
+
return asMaterializedResource(
|
|
117
|
+
{
|
|
118
|
+
identity: potential.identity,
|
|
119
|
+
resourceTypeHandle: potential.resourceTypeHandle,
|
|
120
|
+
creationContext: potential.creationContext,
|
|
121
|
+
},
|
|
122
|
+
nucleus,
|
|
123
|
+
opts
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
} as const;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BranchStepJson,
|
|
3
|
+
ForStepJson,
|
|
4
|
+
JobStepIdentityJson,
|
|
5
|
+
JobStepJson,
|
|
6
|
+
ResourceRoleIdentityJson,
|
|
7
|
+
StepJson,
|
|
8
|
+
StrategyStateJson,
|
|
9
|
+
WhileStepJson,
|
|
10
|
+
} from '@toolproof-core/schema';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export function getIndependentThreads(steps: StepJson[], strategyState: StrategyStateJson): StepJson[][] {
|
|
14
|
+
type OwnerIndex = number;
|
|
15
|
+
|
|
16
|
+
const getOwnerLabel = (ownerIndex: OwnerIndex) => {
|
|
17
|
+
const step = steps[ownerIndex];
|
|
18
|
+
return `steps[${ownerIndex}] stepKind=${(step as any)?.stepKind ?? 'unknown'}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Map each jobStep.identity (including macro-nested job steps) to owning top-level step index.
|
|
22
|
+
const jobStepIdToOwner = new Map<JobStepIdentityJson, OwnerIndex>();
|
|
23
|
+
const ownerToJobStepIds = new Map<OwnerIndex, JobStepIdentityJson[]>();
|
|
24
|
+
const jobStepById = new Map<JobStepIdentityJson, JobStepJson>();
|
|
25
|
+
|
|
26
|
+
const addJobStep = (jobStep: JobStepJson | undefined, ownerIndex: OwnerIndex) => {
|
|
27
|
+
if (!jobStep?.identity) return;
|
|
28
|
+
|
|
29
|
+
const existingOwner = jobStepIdToOwner.get(jobStep.identity);
|
|
30
|
+
if (existingOwner !== undefined) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Duplicate jobStep.identity '${jobStep.identity}' found in ${getOwnerLabel(ownerIndex)} and ${getOwnerLabel(existingOwner)}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
jobStepIdToOwner.set(jobStep.identity, ownerIndex);
|
|
37
|
+
jobStepById.set(jobStep.identity, jobStep);
|
|
38
|
+
const bucket = ownerToJobStepIds.get(ownerIndex) ?? [];
|
|
39
|
+
bucket.push(jobStep.identity);
|
|
40
|
+
ownerToJobStepIds.set(ownerIndex, bucket);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
steps.forEach((step, ownerIndex) => {
|
|
44
|
+
if (step.stepKind === 'job') {
|
|
45
|
+
addJobStep(step as JobStepJson, ownerIndex);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (step.stepKind === 'for') {
|
|
50
|
+
const loop = step as ForStepJson;
|
|
51
|
+
addJobStep(loop.case?.what, ownerIndex);
|
|
52
|
+
addJobStep(loop.case?.when, ownerIndex);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (step.stepKind === 'while') {
|
|
57
|
+
const loop = step as WhileStepJson;
|
|
58
|
+
addJobStep(loop.case?.what, ownerIndex);
|
|
59
|
+
addJobStep(loop.case?.when, ownerIndex);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (step.stepKind === 'branch') {
|
|
64
|
+
const branch = step as BranchStepJson;
|
|
65
|
+
for (const caseItem of branch.cases ?? []) {
|
|
66
|
+
addJobStep(caseItem?.what, ownerIndex);
|
|
67
|
+
addJobStep(caseItem?.when, ownerIndex);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Undirected adjacency used for connected components (thread groups).
|
|
74
|
+
const ownerAdj = new Map<OwnerIndex, Set<OwnerIndex>>();
|
|
75
|
+
// Directed dependencies used for strict ordering validation: owner -> producers it depends on.
|
|
76
|
+
const ownerDeps = new Map<OwnerIndex, Set<OwnerIndex>>();
|
|
77
|
+
|
|
78
|
+
const ensureOwner = (ownerIndex: OwnerIndex) => {
|
|
79
|
+
if (!ownerAdj.has(ownerIndex)) ownerAdj.set(ownerIndex, new Set());
|
|
80
|
+
if (!ownerDeps.has(ownerIndex)) ownerDeps.set(ownerIndex, new Set());
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < steps.length; i++) {
|
|
84
|
+
ensureOwner(i);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Discover dependencies from strategyState.
|
|
88
|
+
for (const [jobStepId, ownerIndex] of jobStepIdToOwner) {
|
|
89
|
+
ensureOwner(ownerIndex);
|
|
90
|
+
|
|
91
|
+
const jobStep = jobStepById.get(jobStepId);
|
|
92
|
+
const inputBindings = jobStep?.roleBindings?.inputBindings ?? [];
|
|
93
|
+
const bucket = strategyState?.[jobStepId] ?? ({} as any);
|
|
94
|
+
|
|
95
|
+
for (const inputRoleHandle of inputBindings) {
|
|
96
|
+
const entry = bucket?.[inputRoleHandle as ResourceRoleIdentityJson] as any;
|
|
97
|
+
if (!entry || entry.resourceShellKind !== 'inputPotential') continue;
|
|
98
|
+
|
|
99
|
+
const creatorJobStepHandle = entry?.creationContext?.jobStepHandle as JobStepIdentityJson | undefined;
|
|
100
|
+
if (!creatorJobStepHandle) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Unresolvable inputPotential in jobStep '${jobStepId}' (${getOwnerLabel(ownerIndex)}): missing creationContext.jobStepHandle for role '${inputRoleHandle}'`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const producerOwner = jobStepIdToOwner.get(creatorJobStepHandle);
|
|
107
|
+
if (producerOwner === undefined) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Unresolvable inputPotential in jobStep '${jobStepId}' (${getOwnerLabel(ownerIndex)}): creator jobStepHandle '${creatorJobStepHandle}' not found in strategy steps`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
ensureOwner(producerOwner);
|
|
114
|
+
ownerAdj.get(ownerIndex)!.add(producerOwner);
|
|
115
|
+
ownerAdj.get(producerOwner)!.add(ownerIndex);
|
|
116
|
+
ownerDeps.get(ownerIndex)!.add(producerOwner);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Connected components over owners.
|
|
121
|
+
const visited = new Set<OwnerIndex>();
|
|
122
|
+
const components: OwnerIndex[][] = [];
|
|
123
|
+
|
|
124
|
+
for (let ownerIndex = 0; ownerIndex < steps.length; ownerIndex++) {
|
|
125
|
+
if (visited.has(ownerIndex)) continue;
|
|
126
|
+
const component: OwnerIndex[] = [];
|
|
127
|
+
const queue: OwnerIndex[] = [ownerIndex];
|
|
128
|
+
visited.add(ownerIndex);
|
|
129
|
+
while (queue.length > 0) {
|
|
130
|
+
const node = queue.shift()!;
|
|
131
|
+
component.push(node);
|
|
132
|
+
for (const neighbor of ownerAdj.get(node) ?? []) {
|
|
133
|
+
if (!visited.has(neighbor)) {
|
|
134
|
+
visited.add(neighbor);
|
|
135
|
+
queue.push(neighbor);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
components.push(component);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Strict validation: within a thread, the linear order must not contain forward refs.
|
|
143
|
+
for (const comp of components) {
|
|
144
|
+
const compSet = new Set(comp);
|
|
145
|
+
const ownersInOrder = steps.map((_, i) => i).filter((i) => compSet.has(i));
|
|
146
|
+
|
|
147
|
+
const position = new Map<OwnerIndex, number>();
|
|
148
|
+
ownersInOrder.forEach((owner, idx) => position.set(owner, idx));
|
|
149
|
+
|
|
150
|
+
for (const consumerOwner of ownersInOrder) {
|
|
151
|
+
const deps = ownerDeps.get(consumerOwner);
|
|
152
|
+
if (!deps || deps.size === 0) continue;
|
|
153
|
+
|
|
154
|
+
const consumerPos = position.get(consumerOwner)!;
|
|
155
|
+
for (const producerOwner of deps) {
|
|
156
|
+
const producerPos = position.get(producerOwner);
|
|
157
|
+
if (producerPos === undefined) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Internal error: dependency producer ${getOwnerLabel(producerOwner)} missing from computed thread for ${getOwnerLabel(consumerOwner)}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
if (producerPos >= consumerPos) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Invalid step order in thread: ${getOwnerLabel(consumerOwner)} depends on ${getOwnerLabel(producerOwner)}, but producer is not scheduled before consumer`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return components
|
|
172
|
+
.map((compOwners) => {
|
|
173
|
+
const ownerSet = new Set(compOwners);
|
|
174
|
+
return steps.filter((_, i) => ownerSet.has(i));
|
|
175
|
+
})
|
|
176
|
+
.filter((group) => group.length > 0);
|
|
177
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreationContextJson,
|
|
3
|
+
ResourceJson,
|
|
4
|
+
ResourceMissingJson,
|
|
5
|
+
ResourceInputPotentialJson,
|
|
6
|
+
ResourceOutputPotentialJson,
|
|
7
|
+
StrategyStateJson,
|
|
8
|
+
} from '@toolproof-core/schema';
|
|
9
|
+
|
|
10
|
+
export type ResolveResult =
|
|
11
|
+
| { status: 'materialized'; entry: ResourceJson; path: CreationContextJson[] }
|
|
12
|
+
| { status: 'missing'; entry: ResourceMissingJson; path: CreationContextJson[] }
|
|
13
|
+
| { status: 'outputPotential'; entry: ResourceOutputPotentialJson; path: CreationContextJson[] }
|
|
14
|
+
| { status: 'unresolved'; reason: 'not-found' | 'cycle' | 'depth-exceeded'; path: CreationContextJson[] };
|
|
15
|
+
|
|
16
|
+
export function resolveResourceChain(
|
|
17
|
+
strategyState: StrategyStateJson,
|
|
18
|
+
start: CreationContextJson,
|
|
19
|
+
opts?: { maxDepth?: number }
|
|
20
|
+
): ResolveResult {
|
|
21
|
+
const maxDepth = opts?.maxDepth ?? 50;
|
|
22
|
+
const visited = new Set<string>();
|
|
23
|
+
const path: CreationContextJson[] = [];
|
|
24
|
+
let current: CreationContextJson = start;
|
|
25
|
+
|
|
26
|
+
for (let depth = 0; depth <= maxDepth; depth++) {
|
|
27
|
+
path.push(current);
|
|
28
|
+
const visitKey = `${current.jobStepHandle}::${current.resourceRoleHandle}`;
|
|
29
|
+
if (visited.has(visitKey)) {
|
|
30
|
+
return { status: 'unresolved', reason: 'cycle', path };
|
|
31
|
+
}
|
|
32
|
+
visited.add(visitKey);
|
|
33
|
+
|
|
34
|
+
const bucket = strategyState[current.jobStepHandle];
|
|
35
|
+
if (!bucket) return { status: 'unresolved', reason: 'not-found', path };
|
|
36
|
+
const entry = bucket[current.resourceRoleHandle] as (
|
|
37
|
+
| ResourceJson
|
|
38
|
+
| ResourceMissingJson
|
|
39
|
+
| ResourceInputPotentialJson
|
|
40
|
+
| ResourceOutputPotentialJson
|
|
41
|
+
| undefined
|
|
42
|
+
);
|
|
43
|
+
if (!entry) return { status: 'unresolved', reason: 'not-found', path };
|
|
44
|
+
|
|
45
|
+
if (entry.resourceShellKind === 'materialized') {
|
|
46
|
+
return { status: 'materialized', entry: entry as ResourceJson, path };
|
|
47
|
+
}
|
|
48
|
+
if (entry.resourceShellKind === 'missing') {
|
|
49
|
+
return { status: 'missing', entry: entry as ResourceMissingJson, path };
|
|
50
|
+
}
|
|
51
|
+
if (entry.resourceShellKind === 'outputPotential') {
|
|
52
|
+
return { status: 'outputPotential', entry: entry as ResourceOutputPotentialJson, path };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// inputPotential: follow ref backwards
|
|
56
|
+
if (entry.resourceShellKind === 'inputPotential') {
|
|
57
|
+
current = (entry as ResourceInputPotentialJson).creationContext;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Unknown case
|
|
62
|
+
return { status: 'unresolved', reason: 'not-found', path };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { status: 'unresolved', reason: 'depth-exceeded', path };
|
|
66
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ResourceJson,
|
|
3
|
+
ResourceMissingJson,
|
|
4
|
+
ResourceInputPotentialJson,
|
|
5
|
+
ResourceOutputPotentialJson,
|
|
6
|
+
CreationContextJson,
|
|
7
|
+
StrategyStateJson,
|
|
8
|
+
} from '@toolproof-core/schema';
|
|
9
|
+
import { resolveResourceChain } from './resourceChain.js';
|
|
10
|
+
|
|
11
|
+
export function bindInputResInStrategyState(
|
|
12
|
+
strategyState: StrategyStateJson,
|
|
13
|
+
target: CreationContextJson,
|
|
14
|
+
resource: ResourceJson
|
|
15
|
+
): StrategyStateJson {
|
|
16
|
+
const bucket = strategyState[target.jobStepHandle] ?? {};
|
|
17
|
+
return {
|
|
18
|
+
...strategyState,
|
|
19
|
+
[target.jobStepHandle]: {
|
|
20
|
+
...bucket,
|
|
21
|
+
[target.resourceRoleHandle]: resource,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function bindInputRefInStrategyState(
|
|
27
|
+
strategyState: StrategyStateJson,
|
|
28
|
+
target: CreationContextJson,
|
|
29
|
+
source: CreationContextJson
|
|
30
|
+
): StrategyStateJson {
|
|
31
|
+
const sourceEntry = strategyState?.[source.jobStepHandle]?.[source.resourceRoleHandle] as (
|
|
32
|
+
| ResourceJson
|
|
33
|
+
| ResourceMissingJson
|
|
34
|
+
| ResourceInputPotentialJson
|
|
35
|
+
| ResourceOutputPotentialJson
|
|
36
|
+
| undefined
|
|
37
|
+
);
|
|
38
|
+
if (!sourceEntry) {
|
|
39
|
+
throw new Error(`resourceEntry not found for source (${source.jobStepHandle}, ${source.resourceRoleHandle})`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = resolveResourceChain(strategyState, source);
|
|
43
|
+
const bucket = strategyState[target.jobStepHandle] ?? {};
|
|
44
|
+
|
|
45
|
+
if (result.status === 'materialized') {
|
|
46
|
+
return {
|
|
47
|
+
...strategyState,
|
|
48
|
+
[target.jobStepHandle]: {
|
|
49
|
+
...bucket,
|
|
50
|
+
[target.resourceRoleHandle]: result.entry,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (result.status === 'missing') {
|
|
56
|
+
const missing = result.entry;
|
|
57
|
+
const reusedMissing: ResourceMissingJson = {
|
|
58
|
+
identity: missing.identity,
|
|
59
|
+
resourceTypeHandle: missing.resourceTypeHandle,
|
|
60
|
+
resourceShellKind: 'missing',
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...strategyState,
|
|
65
|
+
[target.jobStepHandle]: {
|
|
66
|
+
...bucket,
|
|
67
|
+
[target.resourceRoleHandle]: reusedMissing,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (result.status === 'outputPotential') {
|
|
73
|
+
const potentialInput: ResourceInputPotentialJson = {
|
|
74
|
+
identity: sourceEntry.identity,
|
|
75
|
+
resourceTypeHandle: sourceEntry.resourceTypeHandle,
|
|
76
|
+
creationContext: {
|
|
77
|
+
jobStepHandle: source.jobStepHandle,
|
|
78
|
+
resourceRoleHandle: source.resourceRoleHandle,
|
|
79
|
+
},
|
|
80
|
+
resourceShellKind: 'inputPotential',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
...strategyState,
|
|
85
|
+
[target.jobStepHandle]: {
|
|
86
|
+
...bucket,
|
|
87
|
+
[target.resourceRoleHandle]: potentialInput,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
throw new Error(`Failed to resolve resource chain: ${result.reason}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function clearInputBindingInStrategyState(
|
|
96
|
+
strategyState: StrategyStateJson,
|
|
97
|
+
target: CreationContextJson
|
|
98
|
+
): StrategyStateJson {
|
|
99
|
+
const bucket = strategyState?.[target.jobStepHandle];
|
|
100
|
+
if (!bucket?.[target.resourceRoleHandle]) return strategyState;
|
|
101
|
+
|
|
102
|
+
const nextBucket = { ...bucket } as Record<string, unknown>;
|
|
103
|
+
delete nextBucket[target.resourceRoleHandle];
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
...strategyState,
|
|
107
|
+
[target.jobStepHandle]: nextBucket as any,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RawStrategyJson,
|
|
3
|
+
RunnableStrategyIdentityJson,
|
|
4
|
+
RunnableStrategyJson,
|
|
5
|
+
RunnableStrategyStatusJson,
|
|
6
|
+
StepJson,
|
|
7
|
+
StrategyThreadIdentityJson,
|
|
8
|
+
} from '@toolproof-core/schema';
|
|
9
|
+
import type { IdentityName } from '../types/types.js';
|
|
10
|
+
import { getIndependentThreads } from './parallelization.js';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export type GetNewIdentity = (identityName: IdentityName) => string | Promise<string>;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export async function createRunnableStrategy(
|
|
17
|
+
rawStrategy: RawStrategyJson,
|
|
18
|
+
opts: {
|
|
19
|
+
getNewIdentity: GetNewIdentity;
|
|
20
|
+
status?: RunnableStrategyStatusJson;
|
|
21
|
+
}
|
|
22
|
+
): Promise<RunnableStrategyJson> {
|
|
23
|
+
if (!opts?.getNewIdentity) {
|
|
24
|
+
throw new Error('createRunnableStrategy: opts.getNewIdentity is required');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const runnableStrategyIdentity = (await opts.getNewIdentity('RunnableStrategyIdentity')) as RunnableStrategyIdentityJson;
|
|
28
|
+
const steps = (rawStrategy.steps ?? []) as StepJson[];
|
|
29
|
+
const strategyState = (rawStrategy.strategyState ?? {}) as RunnableStrategyJson['strategyState'];
|
|
30
|
+
|
|
31
|
+
const threadStepGroups = getIndependentThreads(steps, strategyState);
|
|
32
|
+
const strategyThreadDict: Record<StrategyThreadIdentityJson, StepJson[]> = {} as any;
|
|
33
|
+
|
|
34
|
+
for (const group of threadStepGroups) {
|
|
35
|
+
const threadIdentity = (await opts.getNewIdentity('StrategyThreadIdentity')) as StrategyThreadIdentityJson;
|
|
36
|
+
strategyThreadDict[threadIdentity] = group;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
identity: runnableStrategyIdentity,
|
|
41
|
+
runnableStrategyContext: {
|
|
42
|
+
status: opts.status ?? 'running',
|
|
43
|
+
},
|
|
44
|
+
strategyThreadDict,
|
|
45
|
+
strategyState,
|
|
46
|
+
} as RunnableStrategyJson;
|
|
47
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BranchStepJson,
|
|
3
|
+
ConditionalJson,
|
|
4
|
+
ForStepJson,
|
|
5
|
+
JobJson,
|
|
6
|
+
JobStepJson,
|
|
7
|
+
ResourceRoleIdentityJson,
|
|
8
|
+
WhileStepJson,
|
|
9
|
+
} from '@toolproof-core/schema';
|
|
10
|
+
import { getNewStepIdentity } from '../firebase/firebaseAdminHelpers.js';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
function assertNonEmpty<T>(arr: T[], msg: string): asserts arr is [T, ...T[]] {
|
|
14
|
+
if (arr.length === 0) throw new Error(msg);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
export async function createJobStepFromJob(job: JobJson): Promise<JobStepJson> {
|
|
19
|
+
const inputBindings = Object.keys(job.roles.inputDict ?? {}) as ResourceRoleIdentityJson[];
|
|
20
|
+
const outputBindings = Object.keys(job.roles.outputDict ?? {}) as ResourceRoleIdentityJson[];
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
identity: getNewStepIdentity('job'),
|
|
24
|
+
stepKind: 'job',
|
|
25
|
+
jobHandle: job.identity,
|
|
26
|
+
roleBindings: {
|
|
27
|
+
inputBindings,
|
|
28
|
+
outputBindings,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
export async function createLoopStepFromJobs(
|
|
35
|
+
whatJob: JobJson,
|
|
36
|
+
whenJob: JobJson,
|
|
37
|
+
stepKind: 'for' | 'while'
|
|
38
|
+
): Promise<ForStepJson | WhileStepJson> {
|
|
39
|
+
const what = await createJobStepFromJob(whatJob);
|
|
40
|
+
const when = await createJobStepFromJob(whenJob);
|
|
41
|
+
|
|
42
|
+
if (stepKind === 'for') {
|
|
43
|
+
return {
|
|
44
|
+
identity: getNewStepIdentity('for'),
|
|
45
|
+
stepKind: 'for',
|
|
46
|
+
case: { what, when },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
identity: getNewStepIdentity('while'),
|
|
52
|
+
stepKind: 'while',
|
|
53
|
+
case: { what, when },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
export async function createBranchStepFromJobPairs(
|
|
59
|
+
cases: Array<{ whatJob: JobJson; whenJob: JobJson }>
|
|
60
|
+
): Promise<BranchStepJson> {
|
|
61
|
+
const resolved = await Promise.all(
|
|
62
|
+
cases.map(async ({ whatJob, whenJob }) => {
|
|
63
|
+
const what = await createJobStepFromJob(whatJob);
|
|
64
|
+
const when = await createJobStepFromJob(whenJob);
|
|
65
|
+
return { what, when } satisfies ConditionalJson;
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
assertNonEmpty(resolved, 'createBranchStepFromJobPairs requires at least one case');
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
identity: getNewStepIdentity('branch'),
|
|
73
|
+
stepKind: 'branch',
|
|
74
|
+
cases: resolved,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
export function cloneForStep(forStep: ForStepJson): ForStepJson {
|
|
80
|
+
return {
|
|
81
|
+
identity: getNewStepIdentity('for'),
|
|
82
|
+
stepKind: 'for',
|
|
83
|
+
case: {
|
|
84
|
+
what: {
|
|
85
|
+
...forStep.case.what,
|
|
86
|
+
identity: getNewStepIdentity('job'),
|
|
87
|
+
},
|
|
88
|
+
when: {
|
|
89
|
+
...forStep.case.when,
|
|
90
|
+
identity: getNewStepIdentity('job'),
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
export function cloneWhileStep(whileStep: WhileStepJson): WhileStepJson {
|
|
98
|
+
return {
|
|
99
|
+
identity: getNewStepIdentity('while'),
|
|
100
|
+
stepKind: 'while',
|
|
101
|
+
case: {
|
|
102
|
+
what: {
|
|
103
|
+
...whileStep.case.what,
|
|
104
|
+
identity: getNewStepIdentity('job'),
|
|
105
|
+
},
|
|
106
|
+
when: {
|
|
107
|
+
...whileStep.case.when,
|
|
108
|
+
identity: getNewStepIdentity('job'),
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/_lib/setup/firebaseadmininit.ts","./src/artifacts/artifacts.ts","./src/firebase/firebaseadminhelpers.ts","./src/types/types.ts","./src/utils/extractfrom.ts","./src/utils/extractfromresourcesbyresourcetypehandle.ts","./src/utils/generatefrom.ts"],"version":"5.9.3"}
|
|
1
|
+
{"root":["./src/shared.ts","./src/_lib/setup/firebaseadmininit.ts","./src/artifacts/artifacts.ts","./src/firebase/firebaseadminhelpers.ts","./src/types/types.ts","./src/utils/extractfrom.ts","./src/utils/extractfromresourcesbyresourcetypehandle.ts","./src/utils/generatefrom.ts","./src/utils/parallelization.ts","./src/utils/resourcechain.ts","./src/utils/roleresourcebinding.ts","./src/utils/runnablestrategycreation.ts","./src/utils/stepcreation.ts"],"version":"5.9.3"}
|