@contractspec/integration.workflow-devkit 0.1.3 → 0.1.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.
@@ -1,180 +1 @@
1
- // src/helpers.ts
2
- import { evaluateExpression } from "@contractspec/lib.contracts-spec/workflow/expression";
3
- function inferWorkflowDevkitBehavior(step) {
4
- return step.runtime?.workflowDevkit?.behavior ?? step.type;
5
- }
6
- function resolveWorkflowDevkitEntryStepId(spec) {
7
- const entryStepId = spec.definition.entryStepId ?? spec.definition.steps[0]?.id;
8
- if (!entryStepId) {
9
- throw new Error(`Workflow ${spec.meta.key}.v${spec.meta.version} does not define an entry step.`);
10
- }
11
- return entryStepId;
12
- }
13
- function resolveWorkflowDevkitRunIdentity(spec, runIdentity) {
14
- if (runIdentity) {
15
- return runIdentity;
16
- }
17
- const strategy = spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version";
18
- const prefix = spec.runtime?.workflowDevkit?.runIdentity?.prefix;
19
- const baseIdentity = strategy === "meta-key-version" ? `${spec.meta.key}.v${spec.meta.version}` : `${spec.meta.key}.v${spec.meta.version}`;
20
- return prefix ? `${prefix}:${baseIdentity}` : baseIdentity;
21
- }
22
- function resolveWorkflowDevkitWaitToken(spec, step, runIdentity) {
23
- const runtime = step.runtime?.workflowDevkit;
24
- if (!runtime) {
25
- return;
26
- }
27
- const explicitToken = runtime.hookWait?.token ?? runtime.webhookWait?.token ?? runtime.approvalWait?.token ?? runtime.streamSession?.followUpToken;
28
- if (explicitToken) {
29
- return explicitToken;
30
- }
31
- const tokenStrategy = spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic";
32
- const prefix = spec.runtime?.workflowDevkit?.hookTokens?.prefix ?? spec.meta.key;
33
- const stableStepId = sanitizeIdentifier(step.id);
34
- if (tokenStrategy === "session-scoped") {
35
- const resolvedRunIdentity = sanitizeIdentifier(resolveWorkflowDevkitRunIdentity(spec, runIdentity));
36
- return `${prefix}:${resolvedRunIdentity}:${stableStepId}`;
37
- }
38
- if (tokenStrategy === "step-scoped") {
39
- return `${prefix}:v${spec.meta.version}:${stableStepId}`;
40
- }
41
- return `${prefix}:${stableStepId}`;
42
- }
43
- function resolveWorkflowDevkitNextStepId(spec, step, data, input, output) {
44
- const transitions = spec.definition.transitions.filter((transition) => transition.from === step.id);
45
- for (const transition of transitions) {
46
- if (evaluateExpression(transition.condition, {
47
- data,
48
- input,
49
- output
50
- })) {
51
- return transition.to;
52
- }
53
- }
54
- return null;
55
- }
56
- function mergeWorkflowDevkitData(current, input, output) {
57
- const next = { ...current };
58
- if (isRecord(input)) {
59
- Object.assign(next, input);
60
- }
61
- if (isRecord(output)) {
62
- Object.assign(next, output);
63
- }
64
- return next;
65
- }
66
- function sanitizeIdentifier(value) {
67
- return value.replace(/[^a-zA-Z0-9_-]+/g, "-");
68
- }
69
- function isRecord(value) {
70
- return value != null && typeof value === "object" && !Array.isArray(value);
71
- }
72
-
73
- // src/runtime.ts
74
- async function runWorkflowSpecWithWorkflowDevkit(options) {
75
- const history = [];
76
- let currentStepId = resolveWorkflowDevkitEntryStepId(options.spec);
77
- let data = { ...options.initialData ?? {} };
78
- let input = options.initialData;
79
- while (currentStepId) {
80
- const step = lookupStep(options.spec, currentStepId);
81
- const runtime = step.runtime?.workflowDevkit;
82
- const context = {
83
- data,
84
- input,
85
- runIdentity: options.runIdentity,
86
- runtime,
87
- spec: options.spec,
88
- step
89
- };
90
- const behavior = inferWorkflowDevkitBehavior(step);
91
- const token = resolveWorkflowDevkitWaitToken(options.spec, step, options.runIdentity);
92
- const output = await executeWorkflowDevkitBehavior(behavior, context, token, options.bridge, options.primitives);
93
- history.push({
94
- behavior,
95
- input,
96
- output,
97
- stepId: step.id,
98
- token
99
- });
100
- data = mergeWorkflowDevkitData(data, input, output);
101
- const nextStepId = resolveWorkflowDevkitNextStepId(options.spec, step, data, input, output);
102
- if (!nextStepId) {
103
- return {
104
- currentStep: null,
105
- data,
106
- history,
107
- status: "completed"
108
- };
109
- }
110
- currentStepId = nextStepId;
111
- input = output;
112
- }
113
- return {
114
- currentStep: null,
115
- data,
116
- history,
117
- status: "completed"
118
- };
119
- }
120
- async function executeWorkflowDevkitBehavior(behavior, context, token, bridge, primitives) {
121
- switch (behavior) {
122
- case "sleep":
123
- if (!context.runtime?.sleep?.duration) {
124
- throw new Error(`Step "${context.step.id}" is missing sleep.duration.`);
125
- }
126
- await primitives.sleep(context.runtime.sleep.duration);
127
- return { sleptFor: context.runtime.sleep.duration };
128
- case "hookWait":
129
- return awaitExternalWait(context, token, bridge?.onExternalWait, primitives.createHook);
130
- case "webhookWait":
131
- return awaitExternalWait(context, token, bridge?.onExternalWait, primitives.createWebhook ?? primitives.createHook, context.runtime?.webhookWait?.path, context.runtime?.webhookWait?.method);
132
- case "approvalWait":
133
- return awaitExternalWait(context, token, bridge?.onApprovalRequested, primitives.createHook);
134
- case "streamSession":
135
- return awaitExternalWait(context, token, bridge?.onStreamSession, primitives.createHook);
136
- case "automation":
137
- if (!bridge?.executeAutomationStep) {
138
- throw new Error("Workflow DevKit bridge requires executeAutomationStep for automation steps.");
139
- }
140
- return bridge.executeAutomationStep(context);
141
- case "human":
142
- if (!bridge?.awaitHumanInput) {
143
- throw new Error("Workflow DevKit bridge requires awaitHumanInput for human steps without explicit wait behavior.");
144
- }
145
- return bridge.awaitHumanInput(context);
146
- case "decision":
147
- return bridge?.executeDecisionStep ? bridge.executeDecisionStep(context) : context.input;
148
- }
149
- }
150
- async function awaitExternalWait(context, token, notifier, factory, path, method) {
151
- if (!token) {
152
- throw new Error(`Step "${context.step.id}" requires a Workflow DevKit wait token.`);
153
- }
154
- const behavior = context.runtime?.behavior;
155
- if (behavior !== "approvalWait" && behavior !== "hookWait" && behavior !== "streamSession" && behavior !== "webhookWait") {
156
- throw new Error(`Step "${context.step.id}" is not configured with an external wait behavior.`);
157
- }
158
- const waitContext = {
159
- ...context,
160
- behavior,
161
- token
162
- };
163
- await notifier?.(waitContext);
164
- const hook = factory({ method, path, token });
165
- try {
166
- return await hook;
167
- } finally {
168
- await hook.dispose?.();
169
- }
170
- }
171
- function lookupStep(spec, stepId) {
172
- const step = spec.definition.steps.find((candidate) => candidate.id === stepId);
173
- if (!step) {
174
- throw new Error(`Step "${stepId}" not found in workflow ${spec.meta.key}.v${spec.meta.version}.`);
175
- }
176
- return step;
177
- }
178
- export {
179
- runWorkflowSpecWithWorkflowDevkit
180
- };
1
+ import{evaluateExpression as C}from"@contractspec/lib.contracts-spec/workflow/expression";function X(j){return j.runtime?.workflowDevkit?.behavior??j.type}function Y(j){let q=j.definition.entryStepId??j.definition.steps[0]?.id;if(!q)throw Error(`Workflow ${j.meta.key}.v${j.meta.version} does not define an entry step.`);return q}function N(j,q){if(q)return q;let F=j.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",A=j.runtime?.workflowDevkit?.runIdentity?.prefix,G=F==="meta-key-version"?`${j.meta.key}.v${j.meta.version}`:`${j.meta.key}.v${j.meta.version}`;return A?`${A}:${G}`:G}function Z(j,q,F){let A=q.runtime?.workflowDevkit;if(!A)return;let G=A.hookWait?.token??A.webhookWait?.token??A.approvalWait?.token??A.streamSession?.followUpToken;if(G)return G;let J=j.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",H=j.runtime?.workflowDevkit?.hookTokens?.prefix??j.meta.key,K=U(q.id);if(J==="session-scoped"){let L=U(N(j,F));return`${H}:${L}:${K}`}if(J==="step-scoped")return`${H}:v${j.meta.version}:${K}`;return`${H}:${K}`}function _(j,q,F,A,G){let J=j.definition.transitions.filter((H)=>H.from===q.id);for(let H of J)if(C(H.condition,{data:F,input:A,output:G}))return H.to;return null}function $(j,q,F){let A={...j};if(V(q))Object.assign(A,q);if(V(F))Object.assign(A,F);return A}function U(j){return j.replace(/[^a-zA-Z0-9_-]+/g,"-")}function V(j){return j!=null&&typeof j==="object"&&!Array.isArray(j)}async function D(j){let q=[],F=Y(j.spec),A={...j.initialData??{}},G=j.initialData;while(F){let J=B(j.spec,F),H=J.runtime?.workflowDevkit,K={data:A,input:G,runIdentity:j.runIdentity,runtime:H,spec:j.spec,step:J},L=X(J),P=Z(j.spec,J,j.runIdentity),M=await z(L,K,P,j.bridge,j.primitives);q.push({behavior:L,input:G,output:M,stepId:J.id,token:P}),A=$(A,G,M);let Q=_(j.spec,J,A,G,M);if(!Q)return{currentStep:null,data:A,history:q,status:"completed"};F=Q,G=M}return{currentStep:null,data:A,history:q,status:"completed"}}async function z(j,q,F,A,G){switch(j){case"sleep":if(!q.runtime?.sleep?.duration)throw Error(`Step "${q.step.id}" is missing sleep.duration.`);return await G.sleep(q.runtime.sleep.duration),{sleptFor:q.runtime.sleep.duration};case"hookWait":return O(q,F,A?.onExternalWait,G.createHook);case"webhookWait":return O(q,F,A?.onExternalWait,G.createWebhook??G.createHook,q.runtime?.webhookWait?.path,q.runtime?.webhookWait?.method);case"approvalWait":return O(q,F,A?.onApprovalRequested,G.createHook);case"streamSession":return O(q,F,A?.onStreamSession,G.createHook);case"automation":if(!A?.executeAutomationStep)throw Error("Workflow DevKit bridge requires executeAutomationStep for automation steps.");return A.executeAutomationStep(q);case"human":if(!A?.awaitHumanInput)throw Error("Workflow DevKit bridge requires awaitHumanInput for human steps without explicit wait behavior.");return A.awaitHumanInput(q);case"decision":return A?.executeDecisionStep?A.executeDecisionStep(q):q.input}}async function O(j,q,F,A,G,J){if(!q)throw Error(`Step "${j.step.id}" requires a Workflow DevKit wait token.`);let H=j.runtime?.behavior;if(H!=="approvalWait"&&H!=="hookWait"&&H!=="streamSession"&&H!=="webhookWait")throw Error(`Step "${j.step.id}" is not configured with an external wait behavior.`);let K={...j,behavior:H,token:q};await F?.(K);let L=A({method:J,path:G,token:q});try{return await L}finally{await L.dispose?.()}}function B(j,q){let F=j.definition.steps.find((A)=>A.id===q);if(!F)throw Error(`Step "${q}" not found in workflow ${j.meta.key}.v${j.meta.version}.`);return F}export{D as runWorkflowSpecWithWorkflowDevkit};
@@ -1,101 +1,2 @@
1
1
  // @bun
2
- // src/chat-routes.ts
3
- import { createUIMessageStreamResponse } from "ai";
4
- import { getRun, resumeHook, start } from "workflow/api";
5
- var WORKFLOW_RUN_ID_HEADER = "x-workflow-run-id";
6
- var WORKFLOW_STREAM_TAIL_INDEX_HEADER = "x-workflow-stream-tail-index";
7
- function createWorkflowDevkitStartRoute(options) {
8
- const workflowApi = options.workflowApi ?? { start };
9
- return async (request) => {
10
- const body = await request.json();
11
- const args = await options.buildArgs(body, request);
12
- const run = await workflowApi.start(options.workflow, args);
13
- if (options.createResponse) {
14
- return options.createResponse({ body, run });
15
- }
16
- if (!run.readable) {
17
- return new Response(JSON.stringify({ runId: run.runId }), {
18
- headers: {
19
- "Content-Type": "application/json",
20
- [WORKFLOW_RUN_ID_HEADER]: run.runId
21
- }
22
- });
23
- }
24
- return createUIMessageStreamResponse({
25
- headers: {
26
- [WORKFLOW_RUN_ID_HEADER]: run.runId
27
- },
28
- stream: run.readable
29
- });
30
- };
31
- }
32
- function createWorkflowDevkitFollowUpRoute(options) {
33
- const workflowApi = options.workflowApi ?? { resumeHook };
34
- return async (request, context) => {
35
- const runId = context.params.runId ?? context.params.id;
36
- if (!runId) {
37
- return new Response(JSON.stringify({ error: "Missing run id" }), {
38
- status: 400
39
- });
40
- }
41
- const body = await request.json();
42
- const token = options.resolveToken({ body, request, runId });
43
- const payload = options.buildPayload ? await options.buildPayload(body, request) : body;
44
- await workflowApi.resumeHook(token, payload);
45
- return new Response(JSON.stringify({ ok: true }), {
46
- headers: {
47
- "Content-Type": "application/json",
48
- [WORKFLOW_RUN_ID_HEADER]: runId
49
- }
50
- });
51
- };
52
- }
53
- function createWorkflowDevkitStreamRoute(options = {}) {
54
- const workflowApi = options.workflowApi ?? { getRun };
55
- return async (request, context) => {
56
- const runId = context.params.runId ?? context.params.id;
57
- if (!runId) {
58
- return new Response(JSON.stringify({ error: "Missing run id" }), {
59
- status: 400
60
- });
61
- }
62
- const run = workflowApi.getRun(runId);
63
- if (!run) {
64
- return new Response(JSON.stringify({ error: "Workflow run not found" }), {
65
- status: 404
66
- });
67
- }
68
- const startIndex = readStartIndex(request.url);
69
- const readable = run.getReadable ? run.getReadable({ startIndex }) : run.readable;
70
- if (!readable) {
71
- return new Response(JSON.stringify({ error: "Run has no readable stream" }), {
72
- status: 404
73
- });
74
- }
75
- const tailIndex = await readable.getTailIndex?.();
76
- return createUIMessageStreamResponse({
77
- headers: {
78
- ...tailIndex !== undefined ? {
79
- [WORKFLOW_STREAM_TAIL_INDEX_HEADER]: String(tailIndex)
80
- } : {}
81
- },
82
- stream: readable
83
- });
84
- };
85
- }
86
- function readStartIndex(url) {
87
- const parsed = new URL(url);
88
- const rawStartIndex = parsed.searchParams.get("startIndex");
89
- if (!rawStartIndex) {
90
- return;
91
- }
92
- const parsedStartIndex = Number(rawStartIndex);
93
- return Number.isFinite(parsedStartIndex) ? parsedStartIndex : undefined;
94
- }
95
- export {
96
- createWorkflowDevkitStreamRoute,
97
- createWorkflowDevkitStartRoute,
98
- createWorkflowDevkitFollowUpRoute,
99
- WORKFLOW_STREAM_TAIL_INDEX_HEADER,
100
- WORKFLOW_RUN_ID_HEADER
101
- };
2
+ import{createUIMessageStreamResponse as V}from"ai";import{getRun as Y,resumeHook as Z,start as $}from"workflow/api";var P="x-workflow-run-id",F="x-workflow-stream-tail-index";function X(j){let C=j.workflowApi??{start:$};return async(v)=>{let z=await v.json(),B=await j.buildArgs(z,v),h=await C.start(j.workflow,B);if(j.createResponse)return j.createResponse({body:z,run:h});if(!h.readable)return new Response(JSON.stringify({runId:h.runId}),{headers:{"Content-Type":"application/json",[P]:h.runId}});return V({headers:{[P]:h.runId},stream:h.readable})}}function m(j){let C=j.workflowApi??{resumeHook:Z};return async(v,z)=>{let B=z.params.runId??z.params.id;if(!B)return new Response(JSON.stringify({error:"Missing run id"}),{status:400});let h=await v.json(),J=j.resolveToken({body:h,request:v,runId:B}),G=j.buildPayload?await j.buildPayload(h,v):h;return await C.resumeHook(J,G),new Response(JSON.stringify({ok:!0}),{headers:{"Content-Type":"application/json",[P]:B}})}}function D(j={}){let C=j.workflowApi??{getRun:Y};return async(v,z)=>{let B=z.params.runId??z.params.id;if(!B)return new Response(JSON.stringify({error:"Missing run id"}),{status:400});let h=C.getRun(B);if(!h)return new Response(JSON.stringify({error:"Workflow run not found"}),{status:404});let J=H(v.url),G=h.getReadable?h.getReadable({startIndex:J}):h.readable;if(!G)return new Response(JSON.stringify({error:"Run has no readable stream"}),{status:404});let Q=await G.getTailIndex?.();return V({headers:{...Q!==void 0?{[F]:String(Q)}:{}},stream:G})}}function H(j){let v=new URL(j).searchParams.get("startIndex");if(!v)return;let z=Number(v);return Number.isFinite(z)?z:void 0}export{D as createWorkflowDevkitStreamRoute,X as createWorkflowDevkitStartRoute,m as createWorkflowDevkitFollowUpRoute,F as WORKFLOW_STREAM_TAIL_INDEX_HEADER,P as WORKFLOW_RUN_ID_HEADER};
package/dist/compiler.js CHANGED
@@ -1,118 +1,8 @@
1
1
  // @bun
2
- // src/helpers.ts
3
- import { evaluateExpression } from "@contractspec/lib.contracts-spec/workflow/expression";
4
- function inferWorkflowDevkitBehavior(step) {
5
- return step.runtime?.workflowDevkit?.behavior ?? step.type;
6
- }
7
- function resolveWorkflowDevkitEntryStepId(spec) {
8
- const entryStepId = spec.definition.entryStepId ?? spec.definition.steps[0]?.id;
9
- if (!entryStepId) {
10
- throw new Error(`Workflow ${spec.meta.key}.v${spec.meta.version} does not define an entry step.`);
11
- }
12
- return entryStepId;
13
- }
14
- function resolveWorkflowDevkitRunIdentity(spec, runIdentity) {
15
- if (runIdentity) {
16
- return runIdentity;
17
- }
18
- const strategy = spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version";
19
- const prefix = spec.runtime?.workflowDevkit?.runIdentity?.prefix;
20
- const baseIdentity = strategy === "meta-key-version" ? `${spec.meta.key}.v${spec.meta.version}` : `${spec.meta.key}.v${spec.meta.version}`;
21
- return prefix ? `${prefix}:${baseIdentity}` : baseIdentity;
22
- }
23
- function resolveWorkflowDevkitWaitToken(spec, step, runIdentity) {
24
- const runtime = step.runtime?.workflowDevkit;
25
- if (!runtime) {
26
- return;
27
- }
28
- const explicitToken = runtime.hookWait?.token ?? runtime.webhookWait?.token ?? runtime.approvalWait?.token ?? runtime.streamSession?.followUpToken;
29
- if (explicitToken) {
30
- return explicitToken;
31
- }
32
- const tokenStrategy = spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic";
33
- const prefix = spec.runtime?.workflowDevkit?.hookTokens?.prefix ?? spec.meta.key;
34
- const stableStepId = sanitizeIdentifier(step.id);
35
- if (tokenStrategy === "session-scoped") {
36
- const resolvedRunIdentity = sanitizeIdentifier(resolveWorkflowDevkitRunIdentity(spec, runIdentity));
37
- return `${prefix}:${resolvedRunIdentity}:${stableStepId}`;
38
- }
39
- if (tokenStrategy === "step-scoped") {
40
- return `${prefix}:v${spec.meta.version}:${stableStepId}`;
41
- }
42
- return `${prefix}:${stableStepId}`;
43
- }
44
- function resolveWorkflowDevkitNextStepId(spec, step, data, input, output) {
45
- const transitions = spec.definition.transitions.filter((transition) => transition.from === step.id);
46
- for (const transition of transitions) {
47
- if (evaluateExpression(transition.condition, {
48
- data,
49
- input,
50
- output
51
- })) {
52
- return transition.to;
53
- }
54
- }
55
- return null;
56
- }
57
- function mergeWorkflowDevkitData(current, input, output) {
58
- const next = { ...current };
59
- if (isRecord(input)) {
60
- Object.assign(next, input);
61
- }
62
- if (isRecord(output)) {
63
- Object.assign(next, output);
64
- }
65
- return next;
66
- }
67
- function sanitizeIdentifier(value) {
68
- return value.replace(/[^a-zA-Z0-9_-]+/g, "-");
69
- }
70
- function isRecord(value) {
71
- return value != null && typeof value === "object" && !Array.isArray(value);
72
- }
2
+ import{evaluateExpression as Y}from"@contractspec/lib.contracts-spec/workflow/expression";function Q(j){return j.runtime?.workflowDevkit?.behavior??j.type}function U(j){let q=j.definition.entryStepId??j.definition.steps[0]?.id;if(!q)throw Error(`Workflow ${j.meta.key}.v${j.meta.version} does not define an entry step.`);return q}function Z(j,q){if(q)return q;let C=j.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",A=j.runtime?.workflowDevkit?.runIdentity?.prefix,J=C==="meta-key-version"?`${j.meta.key}.v${j.meta.version}`:`${j.meta.key}.v${j.meta.version}`;return A?`${A}:${J}`:J}function V(j,q,C){let A=q.runtime?.workflowDevkit;if(!A)return;let J=A.hookWait?.token??A.webhookWait?.token??A.approvalWait?.token??A.streamSession?.followUpToken;if(J)return J;let L=j.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",H=j.runtime?.workflowDevkit?.hookTokens?.prefix??j.meta.key,M=K(q.id);if(L==="session-scoped"){let X=K(Z(j,C));return`${H}:${X}:${M}`}if(L==="step-scoped")return`${H}:v${j.meta.version}:${M}`;return`${H}:${M}`}function h(j,q,C,A,J){let L=j.definition.transitions.filter((H)=>H.from===q.id);for(let H of L)if(Y(H.condition,{data:C,input:A,output:J}))return H.to;return null}function D(j,q,C){let A={...j};if(O(q))Object.assign(A,q);if(O(C))Object.assign(A,C);return A}function K(j){return j.replace(/[^a-zA-Z0-9_-]+/g,"-")}function O(j){return j!=null&&typeof j==="object"&&!Array.isArray(j)}function _(j){return{entryStepId:U(j),hostTarget:j.runtime?.workflowDevkit?.hostTarget??"generic",hookTokenStrategy:j.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",integrationMode:j.runtime?.workflowDevkit?.integrationMode??"manual",runIdentityStrategy:j.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",specKey:j.meta.key,specVersion:j.meta.version,steps:j.definition.steps.map((q)=>({behavior:Q(q),id:q.id,label:q.label,operationRef:q.action?.operation?`${q.action.operation.key}.v${q.action.operation.version}`:void 0,runtime:q.runtime?.workflowDevkit,transitions:j.definition.transitions.filter((C)=>C.from===q.id).map((C)=>({condition:C.condition,to:C.to})),type:q.type,waitToken:V(j,q)}))}}function z(j,q){let C=_(j),A=q.workflowFunctionName??`${K(q.exportName)}WorkflowDevkit`;return{genericBootstrap:$(q.exportName,A),manifest:JSON.stringify(C,null,2),nextFollowUpRoute:G(A),nextStartRoute:E(A),nextStreamRoute:B(),workflowModule:P(q.exportName,q.specImportPath,A)}}function $(j,q){return`import { ${q} } from "./${K(j)}.workflow-devkit";
73
3
 
74
- // src/compiler.ts
75
- function compileWorkflowSpecToWorkflowDevkit(spec) {
76
- return {
77
- entryStepId: resolveWorkflowDevkitEntryStepId(spec),
78
- hostTarget: spec.runtime?.workflowDevkit?.hostTarget ?? "generic",
79
- hookTokenStrategy: spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic",
80
- integrationMode: spec.runtime?.workflowDevkit?.integrationMode ?? "manual",
81
- runIdentityStrategy: spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version",
82
- specKey: spec.meta.key,
83
- specVersion: spec.meta.version,
84
- steps: spec.definition.steps.map((step) => ({
85
- behavior: inferWorkflowDevkitBehavior(step),
86
- id: step.id,
87
- label: step.label,
88
- operationRef: step.action?.operation ? `${step.action.operation.key}.v${step.action.operation.version}` : undefined,
89
- runtime: step.runtime?.workflowDevkit,
90
- transitions: spec.definition.transitions.filter((transition) => transition.from === step.id).map((transition) => ({
91
- condition: transition.condition,
92
- to: transition.to
93
- })),
94
- type: step.type,
95
- waitToken: resolveWorkflowDevkitWaitToken(spec, step)
96
- }))
97
- };
98
- }
99
- function generateWorkflowDevkitArtifacts(spec, options) {
100
- const compilation = compileWorkflowSpecToWorkflowDevkit(spec);
101
- const workflowFunctionName = options.workflowFunctionName ?? `${sanitizeIdentifier(options.exportName)}WorkflowDevkit`;
102
- return {
103
- genericBootstrap: createGenericBootstrapTemplate(options.exportName, workflowFunctionName),
104
- manifest: JSON.stringify(compilation, null, 2),
105
- nextFollowUpRoute: createFollowUpRouteTemplate(workflowFunctionName),
106
- nextStartRoute: createStartRouteTemplate(workflowFunctionName),
107
- nextStreamRoute: createStreamRouteTemplate(),
108
- workflowModule: createWorkflowModuleTemplate(options.exportName, options.specImportPath, workflowFunctionName)
109
- };
110
- }
111
- function createGenericBootstrapTemplate(exportName, workflowFunctionName) {
112
- return `import { ${workflowFunctionName} } from "./${sanitizeIdentifier(exportName)}.workflow-devkit";
113
-
114
- export const ${sanitizeIdentifier(exportName)}WorkflowDevkitBootstrap = {
115
- workflow: ${workflowFunctionName},
4
+ export const ${K(j)}WorkflowDevkitBootstrap = {
5
+ workflow: ${q},
116
6
  createBridge() {
117
7
  return {
118
8
  executeAutomationStep: async () => {
@@ -121,49 +11,37 @@ export const ${sanitizeIdentifier(exportName)}WorkflowDevkitBootstrap = {
121
11
  };
122
12
  },
123
13
  };
124
- `;
125
- }
126
- function createStartRouteTemplate(workflowFunctionName) {
127
- return `import { createWorkflowDevkitStartRoute } from "@contractspec/integration.workflow-devkit";
128
- import { ${workflowFunctionName} } from "./workflow";
14
+ `}function E(j){return`import { createWorkflowDevkitStartRoute } from "@contractspec/integration.workflow-devkit";
15
+ import { ${j} } from "./workflow";
129
16
 
130
17
  export const POST = createWorkflowDevkitStartRoute({
131
- workflow: ${workflowFunctionName},
18
+ workflow: ${j},
132
19
  async buildArgs(body) {
133
20
  return [body];
134
21
  },
135
22
  });
136
- `;
137
- }
138
- function createFollowUpRouteTemplate(workflowFunctionName) {
139
- return `import { createWorkflowDevkitFollowUpRoute } from "@contractspec/integration.workflow-devkit";
23
+ `}function G(j){return`import { createWorkflowDevkitFollowUpRoute } from "@contractspec/integration.workflow-devkit";
140
24
 
141
25
  export const POST = createWorkflowDevkitFollowUpRoute({
142
26
  resolveToken({ runId }) {
143
- return \`${workflowFunctionName}:\${runId}\`;
27
+ return \`${j}:\${runId}\`;
144
28
  },
145
29
  });
146
- `;
147
- }
148
- function createStreamRouteTemplate() {
149
- return `import { createWorkflowDevkitStreamRoute } from "@contractspec/integration.workflow-devkit";
30
+ `}function B(){return`import { createWorkflowDevkitStreamRoute } from "@contractspec/integration.workflow-devkit";
150
31
 
151
32
  export const GET = createWorkflowDevkitStreamRoute();
152
- `;
153
- }
154
- function createWorkflowModuleTemplate(exportName, specImportPath, workflowFunctionName) {
155
- return `import { createHook, createWebhook, sleep } from "workflow";
33
+ `}function P(j,q,C){return`import { createHook, createWebhook, sleep } from "workflow";
156
34
  import { runWorkflowSpecWithWorkflowDevkit } from "@contractspec/integration.workflow-devkit";
157
- import { ${exportName} } from "${specImportPath}";
35
+ import { ${j} } from "${q}";
158
36
 
159
- export async function ${workflowFunctionName}(input = {}, bridge = {}) {
37
+ export async function ${C}(input = {}, bridge = {}) {
160
38
  "use workflow";
161
39
 
162
40
  // Keep the workflow function deterministic.
163
41
  // Any Node.js or side-effectful logic should live in "use step" helpers that
164
42
  // your bridge calls, not in this orchestrator itself.
165
43
  return runWorkflowSpecWithWorkflowDevkit({
166
- spec: ${exportName},
44
+ spec: ${j},
167
45
  initialData: input,
168
46
  bridge,
169
47
  primitives: {
@@ -173,9 +51,4 @@ export async function ${workflowFunctionName}(input = {}, bridge = {}) {
173
51
  },
174
52
  });
175
53
  }
176
- `;
177
- }
178
- export {
179
- generateWorkflowDevkitArtifacts,
180
- compileWorkflowSpecToWorkflowDevkit
181
- };
54
+ `}export{z as generateWorkflowDevkitArtifacts,_ as compileWorkflowSpecToWorkflowDevkit};
package/dist/helpers.js CHANGED
@@ -1,81 +1,2 @@
1
1
  // @bun
2
- // src/helpers.ts
3
- import { evaluateExpression } from "@contractspec/lib.contracts-spec/workflow/expression";
4
- function inferWorkflowDevkitBehavior(step) {
5
- return step.runtime?.workflowDevkit?.behavior ?? step.type;
6
- }
7
- function resolveWorkflowDevkitEntryStepId(spec) {
8
- const entryStepId = spec.definition.entryStepId ?? spec.definition.steps[0]?.id;
9
- if (!entryStepId) {
10
- throw new Error(`Workflow ${spec.meta.key}.v${spec.meta.version} does not define an entry step.`);
11
- }
12
- return entryStepId;
13
- }
14
- function resolveWorkflowDevkitRunIdentity(spec, runIdentity) {
15
- if (runIdentity) {
16
- return runIdentity;
17
- }
18
- const strategy = spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version";
19
- const prefix = spec.runtime?.workflowDevkit?.runIdentity?.prefix;
20
- const baseIdentity = strategy === "meta-key-version" ? `${spec.meta.key}.v${spec.meta.version}` : `${spec.meta.key}.v${spec.meta.version}`;
21
- return prefix ? `${prefix}:${baseIdentity}` : baseIdentity;
22
- }
23
- function resolveWorkflowDevkitWaitToken(spec, step, runIdentity) {
24
- const runtime = step.runtime?.workflowDevkit;
25
- if (!runtime) {
26
- return;
27
- }
28
- const explicitToken = runtime.hookWait?.token ?? runtime.webhookWait?.token ?? runtime.approvalWait?.token ?? runtime.streamSession?.followUpToken;
29
- if (explicitToken) {
30
- return explicitToken;
31
- }
32
- const tokenStrategy = spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic";
33
- const prefix = spec.runtime?.workflowDevkit?.hookTokens?.prefix ?? spec.meta.key;
34
- const stableStepId = sanitizeIdentifier(step.id);
35
- if (tokenStrategy === "session-scoped") {
36
- const resolvedRunIdentity = sanitizeIdentifier(resolveWorkflowDevkitRunIdentity(spec, runIdentity));
37
- return `${prefix}:${resolvedRunIdentity}:${stableStepId}`;
38
- }
39
- if (tokenStrategy === "step-scoped") {
40
- return `${prefix}:v${spec.meta.version}:${stableStepId}`;
41
- }
42
- return `${prefix}:${stableStepId}`;
43
- }
44
- function resolveWorkflowDevkitNextStepId(spec, step, data, input, output) {
45
- const transitions = spec.definition.transitions.filter((transition) => transition.from === step.id);
46
- for (const transition of transitions) {
47
- if (evaluateExpression(transition.condition, {
48
- data,
49
- input,
50
- output
51
- })) {
52
- return transition.to;
53
- }
54
- }
55
- return null;
56
- }
57
- function mergeWorkflowDevkitData(current, input, output) {
58
- const next = { ...current };
59
- if (isRecord(input)) {
60
- Object.assign(next, input);
61
- }
62
- if (isRecord(output)) {
63
- Object.assign(next, output);
64
- }
65
- return next;
66
- }
67
- function sanitizeIdentifier(value) {
68
- return value.replace(/[^a-zA-Z0-9_-]+/g, "-");
69
- }
70
- function isRecord(value) {
71
- return value != null && typeof value === "object" && !Array.isArray(value);
72
- }
73
- export {
74
- sanitizeIdentifier,
75
- resolveWorkflowDevkitWaitToken,
76
- resolveWorkflowDevkitRunIdentity,
77
- resolveWorkflowDevkitNextStepId,
78
- resolveWorkflowDevkitEntryStepId,
79
- mergeWorkflowDevkitData,
80
- inferWorkflowDevkitBehavior
81
- };
2
+ import{evaluateExpression as L}from"@contractspec/lib.contracts-spec/workflow/expression";function O(h){return h.runtime?.workflowDevkit?.behavior??h.type}function P(h){let q=h.definition.entryStepId??h.definition.steps[0]?.id;if(!q)throw Error(`Workflow ${h.meta.key}.v${h.meta.version} does not define an entry step.`);return q}function M(h,q){if(q)return q;let A=h.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",j=h.runtime?.workflowDevkit?.runIdentity?.prefix,C=A==="meta-key-version"?`${h.meta.key}.v${h.meta.version}`:`${h.meta.key}.v${h.meta.version}`;return j?`${j}:${C}`:C}function Q(h,q,A){let j=q.runtime?.workflowDevkit;if(!j)return;let C=j.hookWait?.token??j.webhookWait?.token??j.approvalWait?.token??j.streamSession?.followUpToken;if(C)return C;let F=h.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",B=h.runtime?.workflowDevkit?.hookTokens?.prefix??h.meta.key,G=H(q.id);if(F==="session-scoped"){let K=H(M(h,A));return`${B}:${K}:${G}`}if(F==="step-scoped")return`${B}:v${h.meta.version}:${G}`;return`${B}:${G}`}function U(h,q,A,j,C){let F=h.definition.transitions.filter((B)=>B.from===q.id);for(let B of F)if(L(B.condition,{data:A,input:j,output:C}))return B.to;return null}function V(h,q,A){let j={...h};if(J(q))Object.assign(j,q);if(J(A))Object.assign(j,A);return j}function H(h){return h.replace(/[^a-zA-Z0-9_-]+/g,"-")}function J(h){return h!=null&&typeof h==="object"&&!Array.isArray(h)}export{H as sanitizeIdentifier,Q as resolveWorkflowDevkitWaitToken,M as resolveWorkflowDevkitRunIdentity,U as resolveWorkflowDevkitNextStepId,P as resolveWorkflowDevkitEntryStepId,V as mergeWorkflowDevkitData,O as inferWorkflowDevkitBehavior};