@lunora/workflow 1.0.0-alpha.4 → 1.0.0-alpha.41
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/LICENSE.md +6 -0
- package/README.md +25 -2
- package/dist/do/index.d.mts +16 -16
- package/dist/do/index.d.ts +16 -16
- package/dist/do/index.mjs +1 -44
- package/dist/index.d.mts +170 -123
- package/dist/index.d.ts +170 -123
- package/dist/index.mjs +1 -9
- package/dist/packem_shared/MAX_BRANCHES-C05O5LY9.mjs +1 -0
- package/dist/packem_shared/NonRetryableError-9ZqDUzwT.mjs +1 -0
- package/dist/packem_shared/WorkflowsRestError-HhBsn3PQ.mjs +1 -0
- package/dist/packem_shared/branch-marker-CCpWfS5k.mjs +1 -0
- package/dist/packem_shared/createRunStep-DB1SaYfF.mjs +1 -0
- package/dist/packem_shared/createWaitForEvent-DjWsI895.mjs +1 -0
- package/dist/packem_shared/createWorkflowContext-zQR_9N-v.mjs +1 -0
- package/dist/packem_shared/createWorkflowRunContext-C83Yp2Qp.mjs +1 -0
- package/dist/packem_shared/createWorkflows-LvAyUyKq.mjs +1 -0
- package/dist/packem_shared/defineStep-D1-9eOnA.mjs +1 -0
- package/dist/packem_shared/defineWorkflow-tKaIifbZ.mjs +1 -0
- package/dist/packem_shared/defineWorkflowEvent-suERPEEV.mjs +1 -0
- package/dist/packem_shared/run-step-D7XRYstF.mjs +1 -0
- package/dist/packem_shared/types.d-C7jti0tm.d.mts +522 -0
- package/dist/packem_shared/types.d-C7jti0tm.d.ts +522 -0
- package/package.json +3 -2
- package/dist/packem_shared/MAX_BRANCHES-C9MJIFii.mjs +0 -108
- package/dist/packem_shared/NonRetryableError-Dn2dTyBS.mjs +0 -27
- package/dist/packem_shared/WorkflowsRestError-b06i7K5j.mjs +0 -118
- package/dist/packem_shared/createRunStep-8jOXxP2o.mjs +0 -54
- package/dist/packem_shared/createWorkflowContext-D6thzmlF.mjs +0 -14
- package/dist/packem_shared/createWorkflowRunContext-BsMyGuMR.mjs +0 -110
- package/dist/packem_shared/createWorkflows-BoSYVIXg.mjs +0 -23
- package/dist/packem_shared/defineStep-DJQtLw7g.mjs +0 -28
- package/dist/packem_shared/defineWorkflow-DbUC-oCN.mjs +0 -15
- package/dist/packem_shared/types.d-Fdeu2P2C.d.mts +0 -394
- package/dist/packem_shared/types.d-Fdeu2P2C.d.ts +0 -394
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
const API_BASE = "https://api.cloudflare.com/client/v4/accounts";
|
|
2
|
-
const KNOWN_STATUSES = {
|
|
3
|
-
complete: true,
|
|
4
|
-
errored: true,
|
|
5
|
-
paused: true,
|
|
6
|
-
queued: true,
|
|
7
|
-
running: true,
|
|
8
|
-
terminated: true,
|
|
9
|
-
unknown: true,
|
|
10
|
-
waiting: true,
|
|
11
|
-
waitingForPause: true
|
|
12
|
-
};
|
|
13
|
-
const toStatus = (value) => typeof value === "string" && Object.hasOwn(KNOWN_STATUSES, value) ? value : "unknown";
|
|
14
|
-
const asString = (value) => typeof value === "string" && value !== "" ? value : void 0;
|
|
15
|
-
const stringOr = (value, fallback) => typeof value === "string" ? value : fallback;
|
|
16
|
-
const asBoolean = (value) => typeof value === "boolean" ? value : void 0;
|
|
17
|
-
const countAttempts = (value) => {
|
|
18
|
-
if (Array.isArray(value)) {
|
|
19
|
-
return value.length;
|
|
20
|
-
}
|
|
21
|
-
return typeof value === "number" ? value : void 0;
|
|
22
|
-
};
|
|
23
|
-
const toSummary = (raw) => {
|
|
24
|
-
return {
|
|
25
|
-
createdOn: asString(raw["created_on"]),
|
|
26
|
-
endedOn: asString(raw["ended_on"]),
|
|
27
|
-
id: stringOr(raw["id"], ""),
|
|
28
|
-
startedOn: asString(raw["started_on"]),
|
|
29
|
-
status: toStatus(raw["status"])
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
const toStep = (raw) => {
|
|
33
|
-
return {
|
|
34
|
-
attempts: countAttempts(raw["attempts"]),
|
|
35
|
-
end: asString(raw["end"]),
|
|
36
|
-
error: raw["error"],
|
|
37
|
-
name: stringOr(raw["name"], ""),
|
|
38
|
-
output: raw["output"],
|
|
39
|
-
start: asString(raw["start"]),
|
|
40
|
-
success: asBoolean(raw["success"]),
|
|
41
|
-
type: asString(raw["type"])
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
class WorkflowsRestError extends Error {
|
|
45
|
-
status;
|
|
46
|
-
constructor(status, body) {
|
|
47
|
-
super(`Cloudflare Workflows REST API returned ${String(status)}: ${body}`);
|
|
48
|
-
this.name = "WorkflowsRestError";
|
|
49
|
-
this.status = status;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
const createWorkflowsRestClient = (config) => {
|
|
53
|
-
const fetchImpl = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
54
|
-
const base = `${API_BASE}/${config.accountId}/workflows`;
|
|
55
|
-
const request = async (path, init) => {
|
|
56
|
-
const response = await fetchImpl(`${base}${path}`, {
|
|
57
|
-
...init,
|
|
58
|
-
headers: { Authorization: `Bearer ${config.apiToken}`, "Content-Type": "application/json" }
|
|
59
|
-
});
|
|
60
|
-
const text = await response.text();
|
|
61
|
-
let body;
|
|
62
|
-
try {
|
|
63
|
-
body = JSON.parse(text);
|
|
64
|
-
} catch {
|
|
65
|
-
throw new WorkflowsRestError(response.status, text);
|
|
66
|
-
}
|
|
67
|
-
if (!response.ok || body["success"] === false) {
|
|
68
|
-
throw new WorkflowsRestError(response.status, text);
|
|
69
|
-
}
|
|
70
|
-
return body;
|
|
71
|
-
};
|
|
72
|
-
return {
|
|
73
|
-
getInstance: async ({ instanceId, workflowName }) => {
|
|
74
|
-
const body = await request(`/${encodeURIComponent(workflowName)}/instances/${encodeURIComponent(instanceId)}`);
|
|
75
|
-
const result = body["result"] ?? {};
|
|
76
|
-
const steps = Array.isArray(result["steps"]) ? result["steps"] : [];
|
|
77
|
-
return {
|
|
78
|
-
...toSummary(result),
|
|
79
|
-
error: result["error"],
|
|
80
|
-
output: result["output"],
|
|
81
|
-
params: result["params"],
|
|
82
|
-
steps: steps.map((step) => toStep(step))
|
|
83
|
-
};
|
|
84
|
-
},
|
|
85
|
-
listInstances: async ({ page, perPage, status, workflowName }) => {
|
|
86
|
-
const query = new URLSearchParams();
|
|
87
|
-
if (status !== void 0) {
|
|
88
|
-
query.set("status", status);
|
|
89
|
-
}
|
|
90
|
-
if (page !== void 0) {
|
|
91
|
-
query.set("page", String(page));
|
|
92
|
-
}
|
|
93
|
-
if (perPage !== void 0) {
|
|
94
|
-
query.set("per_page", String(perPage));
|
|
95
|
-
}
|
|
96
|
-
const suffix = query.toString() === "" ? "" : `?${query.toString()}`;
|
|
97
|
-
const body = await request(`/${encodeURIComponent(workflowName)}/instances${suffix}`);
|
|
98
|
-
const result = Array.isArray(body["result"]) ? body["result"] : [];
|
|
99
|
-
const info = body["result_info"] ?? {};
|
|
100
|
-
return {
|
|
101
|
-
instances: result.map((instance) => toSummary(instance)),
|
|
102
|
-
page: typeof info["page"] === "number" ? info["page"] : page ?? 1,
|
|
103
|
-
perPage: typeof info["per_page"] === "number" ? info["per_page"] : perPage ?? result.length,
|
|
104
|
-
totalCount: typeof info["total_count"] === "number" ? info["total_count"] : void 0
|
|
105
|
-
};
|
|
106
|
-
},
|
|
107
|
-
setInstanceStatus: async ({ action, instanceId, workflowName }) => {
|
|
108
|
-
const body = await request(`/${encodeURIComponent(workflowName)}/instances/${encodeURIComponent(instanceId)}`, {
|
|
109
|
-
body: JSON.stringify({ status: action }),
|
|
110
|
-
method: "PATCH"
|
|
111
|
-
});
|
|
112
|
-
const result = body["result"] ?? {};
|
|
113
|
-
return { status: toStatus(result["status"]) };
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export { WorkflowsRestError, createWorkflowsRestClient };
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { parseValidatorMap } from '@lunora/values';
|
|
2
|
-
import { convertNonRetryableError, NonRetryableError } from './NonRetryableError-Dn2dTyBS.mjs';
|
|
3
|
-
|
|
4
|
-
const validateStepArgs = (validators, source) => parseValidatorMap(validators, source, "step args");
|
|
5
|
-
const createRunStep = (deps) => async (step, args, options) => {
|
|
6
|
-
const config = options?.config ?? step.config;
|
|
7
|
-
const validatedArgs = validateStepArgs(step.args, args);
|
|
8
|
-
const callback = async (nativeContext) => {
|
|
9
|
-
const stepContext = {
|
|
10
|
-
attempt: nativeContext.attempt,
|
|
11
|
-
config: nativeContext.config,
|
|
12
|
-
env: deps.env,
|
|
13
|
-
log: deps.log,
|
|
14
|
-
run: deps.run,
|
|
15
|
-
step: nativeContext.step
|
|
16
|
-
};
|
|
17
|
-
let result;
|
|
18
|
-
try {
|
|
19
|
-
result = await step.handler(stepContext, validatedArgs);
|
|
20
|
-
} catch (error) {
|
|
21
|
-
return convertNonRetryableError(error, deps.nonRetryableErrorClass);
|
|
22
|
-
}
|
|
23
|
-
if (!step.returns) {
|
|
24
|
-
return result;
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
return step.returns.parse(result);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
-
const nonRetryable = new NonRetryableError(`step "${step.name}" returns validation failed: ${message}`);
|
|
31
|
-
if (error !== void 0) {
|
|
32
|
-
nonRetryable.cause = error;
|
|
33
|
-
}
|
|
34
|
-
return convertNonRetryableError(nonRetryable, deps.nonRetryableErrorClass);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
const rollbackHandler = step.rollback;
|
|
38
|
-
const rollbackOptions = rollbackHandler ? {
|
|
39
|
-
rollback: async (rollbackContext) => {
|
|
40
|
-
await rollbackHandler({
|
|
41
|
-
args: validatedArgs,
|
|
42
|
-
env: deps.env,
|
|
43
|
-
error: rollbackContext.error,
|
|
44
|
-
log: deps.log,
|
|
45
|
-
output: rollbackContext.output,
|
|
46
|
-
run: deps.run
|
|
47
|
-
});
|
|
48
|
-
},
|
|
49
|
-
rollbackConfig: step.rollbackConfig
|
|
50
|
-
} : void 0;
|
|
51
|
-
return config === void 0 ? deps.step.do(step.name, callback, rollbackOptions) : deps.step.do(step.name, config, callback, rollbackOptions);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export { createRunStep, validateStepArgs };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import createWorkflows from './createWorkflows-BoSYVIXg.mjs';
|
|
2
|
-
|
|
3
|
-
const createWorkflowContext = (env, specs) => {
|
|
4
|
-
const bindings = {};
|
|
5
|
-
for (const spec of specs) {
|
|
6
|
-
const binding = env[spec.binding];
|
|
7
|
-
if (binding && typeof binding.create === "function" && typeof binding.createBatch === "function" && typeof binding.get === "function") {
|
|
8
|
-
bindings[spec.exportName] = binding;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
return createWorkflows({ bindings });
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export { createWorkflowContext };
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { workflowBindingName } from './defineWorkflow-DbUC-oCN.mjs';
|
|
2
|
-
import { createSpawn, createParallel } from './MAX_BRANCHES-C9MJIFii.mjs';
|
|
3
|
-
import { createRunStep } from './createRunStep-8jOXxP2o.mjs';
|
|
4
|
-
|
|
5
|
-
const createDispatchLogger = (prefix) => {
|
|
6
|
-
return {
|
|
7
|
-
debug: (message, ...rest) => {
|
|
8
|
-
console.debug(prefix, message, ...rest);
|
|
9
|
-
},
|
|
10
|
-
error: (message, ...rest) => {
|
|
11
|
-
console.error(prefix, message, ...rest);
|
|
12
|
-
},
|
|
13
|
-
info: (message, ...rest) => {
|
|
14
|
-
console.info(prefix, message, ...rest);
|
|
15
|
-
},
|
|
16
|
-
warn: (message, ...rest) => {
|
|
17
|
-
console.warn(prefix, message, ...rest);
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const SCHEDULER_DISPATCH_PATH = "/_lunora/scheduler/dispatch";
|
|
23
|
-
const trimTrailingSlashes = (value) => {
|
|
24
|
-
let end = value.length;
|
|
25
|
-
while (end > 0 && value[end - 1] === "/") {
|
|
26
|
-
end -= 1;
|
|
27
|
-
}
|
|
28
|
-
return value.slice(0, end);
|
|
29
|
-
};
|
|
30
|
-
const createDispatchRunner = (options) => {
|
|
31
|
-
const { label } = options;
|
|
32
|
-
const globalFetch = globalThis.fetch;
|
|
33
|
-
const fetchImpl = options.fetchImpl ?? (typeof globalFetch === "function" ? globalFetch.bind(globalThis) : void 0);
|
|
34
|
-
return async (function_, args, runOptions = {}) => {
|
|
35
|
-
if (typeof fetchImpl !== "function") {
|
|
36
|
-
throw new TypeError(`${label}: no fetch implementation available — pass fetchImpl or run on a platform with global fetch`);
|
|
37
|
-
}
|
|
38
|
-
const origin = options.env.LUNORA_ORIGIN_URL;
|
|
39
|
-
if (typeof origin !== "string" || origin.length === 0) {
|
|
40
|
-
throw new Error(`${label}: \`LUNORA_ORIGIN_URL\` must be set on the Worker env so a handler can call back into Lunora functions`);
|
|
41
|
-
}
|
|
42
|
-
const token = options.env.LUNORA_ADMIN_TOKEN;
|
|
43
|
-
if (typeof token !== "string" || token.length === 0) {
|
|
44
|
-
throw new Error(`${label}: \`LUNORA_ADMIN_TOKEN\` must be set on the Worker env to authenticate function dispatch`);
|
|
45
|
-
}
|
|
46
|
-
const url = `${trimTrailingSlashes(origin)}${SCHEDULER_DISPATCH_PATH}`;
|
|
47
|
-
const response = await fetchImpl(url, {
|
|
48
|
-
body: JSON.stringify({ args: args ?? {}, functionPath: function_.__lunoraRef, shardKey: runOptions.shardKey }),
|
|
49
|
-
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
|
|
50
|
-
method: "POST"
|
|
51
|
-
});
|
|
52
|
-
if (!response.ok) {
|
|
53
|
-
throw new Error(`${label}: function dispatch failed (${String(response.status)}): ${await response.text()}`);
|
|
54
|
-
}
|
|
55
|
-
const text = await response.text();
|
|
56
|
-
if (text.length === 0) {
|
|
57
|
-
return void 0;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
return JSON.parse(text);
|
|
61
|
-
} catch {
|
|
62
|
-
return text;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const createWorkflowRunContext = (options) => {
|
|
68
|
-
const log = createDispatchLogger(`[workflow:${options.exportName}]`);
|
|
69
|
-
const run = createDispatchRunner({ env: options.env, fetchImpl: options.fetchImpl, label: "@lunora/workflow" });
|
|
70
|
-
const resolveBinding = (workflow) => {
|
|
71
|
-
const bindingName = workflowBindingName(workflow);
|
|
72
|
-
const binding = options.env[bindingName];
|
|
73
|
-
if (!binding || typeof binding.create !== "function" || typeof binding.get !== "function") {
|
|
74
|
-
throw new Error(
|
|
75
|
-
`@lunora/workflow: cannot spawn child workflow "${workflow}" — no Workflow binding "${bindingName}" on env (is it declared in lunora/workflows.ts?)`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
return binding;
|
|
79
|
-
};
|
|
80
|
-
let childCounter = 0;
|
|
81
|
-
const nextChildId = (explicit) => {
|
|
82
|
-
if (explicit !== void 0) {
|
|
83
|
-
return explicit;
|
|
84
|
-
}
|
|
85
|
-
const id = `${options.event.instanceId}-c${String(childCounter)}`;
|
|
86
|
-
childCounter += 1;
|
|
87
|
-
return id;
|
|
88
|
-
};
|
|
89
|
-
const fanOutDeps = {
|
|
90
|
-
env: options.env,
|
|
91
|
-
instanceId: options.event.instanceId,
|
|
92
|
-
nextChildId,
|
|
93
|
-
parentBinding: workflowBindingName(options.exportName),
|
|
94
|
-
resolveBinding,
|
|
95
|
-
step: options.step
|
|
96
|
-
};
|
|
97
|
-
return {
|
|
98
|
-
env: options.env,
|
|
99
|
-
event: options.event,
|
|
100
|
-
log,
|
|
101
|
-
parallel: createParallel(fanOutDeps),
|
|
102
|
-
params: options.event.payload,
|
|
103
|
-
run,
|
|
104
|
-
runStep: createRunStep({ env: options.env, log, nonRetryableErrorClass: options.nonRetryableErrorClass, run, step: options.step }),
|
|
105
|
-
spawn: createSpawn(fanOutDeps),
|
|
106
|
-
step: options.step
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export { createWorkflowRunContext };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const handleFor = (binding) => {
|
|
2
|
-
return {
|
|
3
|
-
create: async (options) => binding.create(options),
|
|
4
|
-
createBatch: async (batch) => binding.createBatch(batch),
|
|
5
|
-
get: async (id) => binding.get(id)
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
const createWorkflows = (options) => {
|
|
9
|
-
const bindings = options.bindings ?? {};
|
|
10
|
-
return {
|
|
11
|
-
get: (name) => {
|
|
12
|
-
const binding = bindings[name];
|
|
13
|
-
if (binding === void 0) {
|
|
14
|
-
const known = Object.keys(bindings);
|
|
15
|
-
const suffix = known.length === 0 ? "no workflows are declared" : `known workflows: ${known.join(", ")}`;
|
|
16
|
-
throw new Error(`@lunora/workflow: no workflow named "${name}" (${suffix})`);
|
|
17
|
-
}
|
|
18
|
-
return handleFor(binding);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export { createWorkflows as default };
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const defineStep = (name, config) => {
|
|
2
|
-
if (typeof name !== "string" || name.length === 0) {
|
|
3
|
-
throw new TypeError("defineStep: `name` must be a non-empty string (the durable step label)");
|
|
4
|
-
}
|
|
5
|
-
const declaredArgs = config.args;
|
|
6
|
-
if (typeof declaredArgs !== "object" || declaredArgs === null) {
|
|
7
|
-
throw new TypeError("defineStep: `args` must be a validator map (e.g. `{ id: v.string() }`)");
|
|
8
|
-
}
|
|
9
|
-
if (typeof config.handler !== "function") {
|
|
10
|
-
throw new TypeError("defineStep: `handler` must be a function (the step body)");
|
|
11
|
-
}
|
|
12
|
-
if (config.rollback !== void 0 && typeof config.rollback !== "function") {
|
|
13
|
-
throw new TypeError("defineStep: `rollback` must be a function when provided");
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
args: config.args,
|
|
17
|
-
config: config.config,
|
|
18
|
-
handler: config.handler,
|
|
19
|
-
isLunoraStep: true,
|
|
20
|
-
name,
|
|
21
|
-
returns: config.returns,
|
|
22
|
-
rollback: config.rollback,
|
|
23
|
-
rollbackConfig: config.rollbackConfig
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
const isStepDefinition = (value) => typeof value === "object" && value !== null && value.isLunoraStep === true;
|
|
27
|
-
|
|
28
|
-
export { defineStep, isStepDefinition };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const workflowClassName = (exportName) => `${exportName.charAt(0).toUpperCase()}${exportName.slice(1)}Workflow`;
|
|
2
|
-
const workflowBindingName = (exportName) => `WORKFLOW_${exportName.replaceAll(/(?<=[a-z0-9])(?=[A-Z])/g, "_").toUpperCase()}`;
|
|
3
|
-
const workflowDefaultName = (exportName) => exportName.replaceAll(/(?<=[a-z0-9])(?=[A-Z])/g, "-").toLowerCase();
|
|
4
|
-
const defineWorkflow = (config) => {
|
|
5
|
-
if (typeof config.handler !== "function") {
|
|
6
|
-
throw new TypeError("defineWorkflow: `handler` must be a function (the workflow body)");
|
|
7
|
-
}
|
|
8
|
-
if (config.name !== void 0 && (typeof config.name !== "string" || config.name.length === 0)) {
|
|
9
|
-
throw new TypeError("defineWorkflow: `name` must be a non-empty string when provided");
|
|
10
|
-
}
|
|
11
|
-
return { ...config, isLunoraWorkflow: true };
|
|
12
|
-
};
|
|
13
|
-
const isWorkflowDefinition = (value) => typeof value === "object" && value !== null && value.isLunoraWorkflow === true;
|
|
14
|
-
|
|
15
|
-
export { defineWorkflow, isWorkflowDefinition, workflowBindingName, workflowClassName, workflowDefaultName };
|