semola 0.5.2 → 0.5.3
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/README.md +88 -13
- package/dist/cron/builder/index.cjs +166 -0
- package/dist/cron/builder/index.d.cts +28 -0
- package/dist/cron/builder/index.d.cts.map +1 -0
- package/dist/cron/builder/index.d.mts +28 -0
- package/dist/cron/builder/index.d.mts.map +1 -0
- package/dist/cron/builder/index.mjs +163 -0
- package/dist/cron/builder/index.mjs.map +1 -0
- package/dist/cron/builder/types.cjs +27 -0
- package/dist/cron/builder/types.d.cts +79 -0
- package/dist/cron/builder/types.d.cts.map +1 -0
- package/dist/cron/builder/types.d.mts +79 -0
- package/dist/cron/builder/types.d.mts.map +1 -0
- package/dist/cron/builder/types.mjs +28 -0
- package/dist/cron/builder/types.mjs.map +1 -0
- package/dist/cron/core/index.cjs +308 -0
- package/dist/cron/core/index.d.cts +39 -0
- package/dist/cron/core/index.d.cts.map +1 -0
- package/dist/cron/core/index.d.mts +39 -0
- package/dist/cron/core/index.d.mts.map +1 -0
- package/dist/cron/core/index.mjs +310 -0
- package/dist/cron/core/index.mjs.map +1 -0
- package/dist/cron/{scanner.cjs → core/scanner.cjs} +2 -2
- package/dist/cron/{scanner.mjs → core/scanner.mjs} +2 -2
- package/dist/cron/core/scanner.mjs.map +1 -0
- package/dist/cron/{types.d.cts → core/types.d.cts} +1 -1
- package/dist/cron/core/types.d.cts.map +1 -0
- package/dist/cron/{types.d.mts → core/types.d.mts} +1 -1
- package/dist/cron/core/types.d.mts.map +1 -0
- package/dist/errors/types.d.cts +1 -1
- package/dist/errors/types.d.mts +1 -1
- package/dist/lib/cache/index.d.cts +3 -3
- package/dist/lib/cache/index.d.mts +3 -3
- package/dist/lib/cron/index.cjs +12 -275
- package/dist/lib/cron/index.d.cts +4 -39
- package/dist/lib/cron/index.d.mts +4 -39
- package/dist/lib/cron/index.mjs +4 -277
- package/dist/lib/errors/index.d.cts +2 -2
- package/dist/lib/errors/index.d.cts.map +1 -1
- package/dist/lib/errors/index.d.mts +2 -2
- package/dist/lib/errors/index.d.mts.map +1 -1
- package/dist/lib/errors/index.mjs.map +1 -1
- package/dist/lib/i18n/index.cjs +6 -1
- package/dist/lib/i18n/index.d.cts.map +1 -1
- package/dist/lib/i18n/index.d.mts.map +1 -1
- package/dist/lib/i18n/index.mjs +6 -1
- package/dist/lib/i18n/index.mjs.map +1 -1
- package/dist/lib/logging/index.cjs +18 -0
- package/dist/lib/logging/index.d.cts +7 -0
- package/dist/lib/logging/index.d.mts +7 -0
- package/dist/lib/logging/index.mjs +5 -0
- package/dist/lib/orm/index.cjs +20 -0
- package/dist/lib/orm/index.d.cts +7 -0
- package/dist/lib/orm/index.d.mts +7 -0
- package/dist/lib/orm/index.mjs +6 -0
- package/dist/lib/prompts/index.d.cts +8 -8
- package/dist/lib/prompts/index.d.mts +8 -8
- package/dist/lib/pubsub/index.cjs +82 -13
- package/dist/lib/pubsub/index.d.cts +14 -5
- package/dist/lib/pubsub/index.d.cts.map +1 -1
- package/dist/lib/pubsub/index.d.mts +14 -5
- package/dist/lib/pubsub/index.d.mts.map +1 -1
- package/dist/lib/pubsub/index.mjs +82 -13
- package/dist/lib/pubsub/index.mjs.map +1 -1
- package/dist/lib/queue/index.d.cts +2 -2
- package/dist/lib/queue/index.d.mts +2 -2
- package/dist/lib/workflow/index.cjs +534 -0
- package/dist/lib/workflow/index.d.cts +7 -0
- package/dist/lib/workflow/index.d.cts.map +1 -0
- package/dist/lib/workflow/index.d.mts +7 -0
- package/dist/lib/workflow/index.d.mts.map +1 -0
- package/dist/lib/workflow/index.mjs +535 -0
- package/dist/lib/workflow/index.mjs.map +1 -0
- package/dist/logging/core/index.cjs +99 -0
- package/dist/logging/core/index.d.cts +26 -0
- package/dist/logging/core/index.d.cts.map +1 -0
- package/dist/logging/core/index.d.mts +26 -0
- package/dist/logging/core/index.d.mts.map +1 -0
- package/dist/logging/core/index.mjs +99 -0
- package/dist/logging/core/index.mjs.map +1 -0
- package/dist/logging/core/types.cjs +10 -0
- package/dist/logging/core/types.d.cts +22 -0
- package/dist/logging/core/types.d.cts.map +1 -0
- package/dist/logging/core/types.d.mts +22 -0
- package/dist/logging/core/types.d.mts.map +1 -0
- package/dist/logging/core/types.mjs +12 -0
- package/dist/logging/core/types.mjs.map +1 -0
- package/dist/logging/formatter/index.cjs +119 -0
- package/dist/logging/formatter/index.d.cts +27 -0
- package/dist/logging/formatter/index.d.cts.map +1 -0
- package/dist/logging/formatter/index.d.mts +27 -0
- package/dist/logging/formatter/index.d.mts.map +1 -0
- package/dist/logging/formatter/index.mjs +115 -0
- package/dist/logging/formatter/index.mjs.map +1 -0
- package/dist/logging/formatter/types.d.cts +5 -0
- package/dist/logging/formatter/types.d.cts.map +1 -0
- package/dist/logging/formatter/types.d.mts +5 -0
- package/dist/logging/formatter/types.d.mts.map +1 -0
- package/dist/logging/provider/index.cjs +165 -0
- package/dist/logging/provider/index.d.cts +28 -0
- package/dist/logging/provider/index.d.cts.map +1 -0
- package/dist/logging/provider/index.d.mts +28 -0
- package/dist/logging/provider/index.d.mts.map +1 -0
- package/dist/logging/provider/index.mjs +165 -0
- package/dist/logging/provider/index.mjs.map +1 -0
- package/dist/logging/provider/types.d.cts +23 -0
- package/dist/logging/provider/types.d.cts.map +1 -0
- package/dist/logging/provider/types.d.mts +23 -0
- package/dist/logging/provider/types.d.mts.map +1 -0
- package/dist/orm/column.cjs +137 -0
- package/dist/orm/column.d.cts +121 -0
- package/dist/orm/column.d.cts.map +1 -0
- package/dist/orm/column.d.mts +121 -0
- package/dist/orm/column.d.mts.map +1 -0
- package/dist/orm/column.mjs +132 -0
- package/dist/orm/column.mjs.map +1 -0
- package/dist/orm/dialect/index.cjs +14 -0
- package/dist/orm/dialect/index.mjs +16 -0
- package/dist/orm/dialect/index.mjs.map +1 -0
- package/dist/orm/dialect/mysql.cjs +31 -0
- package/dist/orm/dialect/mysql.mjs +33 -0
- package/dist/orm/dialect/mysql.mjs.map +1 -0
- package/dist/orm/dialect/postgres.cjs +23 -0
- package/dist/orm/dialect/postgres.mjs +25 -0
- package/dist/orm/dialect/postgres.mjs.map +1 -0
- package/dist/orm/dialect/sqlite.cjs +31 -0
- package/dist/orm/dialect/sqlite.mjs +33 -0
- package/dist/orm/dialect/sqlite.mjs.map +1 -0
- package/dist/orm/dialect/utils.cjs +8 -0
- package/dist/orm/dialect/utils.mjs +10 -0
- package/dist/orm/dialect/utils.mjs.map +1 -0
- package/dist/orm/internal/table-columns.cjs +31 -0
- package/dist/orm/internal/table-columns.mjs +32 -0
- package/dist/orm/internal/table-columns.mjs.map +1 -0
- package/dist/orm/internal/table-lookup.cjs +35 -0
- package/dist/orm/internal/table-lookup.mjs +35 -0
- package/dist/orm/internal/table-lookup.mjs.map +1 -0
- package/dist/orm/internal/table-relations.cjs +28 -0
- package/dist/orm/internal/table-relations.mjs +29 -0
- package/dist/orm/internal/table-relations.mjs.map +1 -0
- package/dist/orm/migration/config.cjs +7 -0
- package/dist/orm/migration/config.d.cts +7 -0
- package/dist/orm/migration/config.d.cts.map +1 -0
- package/dist/orm/migration/config.d.mts +7 -0
- package/dist/orm/migration/config.d.mts.map +1 -0
- package/dist/orm/migration/config.mjs +8 -0
- package/dist/orm/migration/config.mjs.map +1 -0
- package/dist/orm/migration/types.d.cts +20 -0
- package/dist/orm/migration/types.d.cts.map +1 -0
- package/dist/orm/migration/types.d.mts +20 -0
- package/dist/orm/migration/types.d.mts.map +1 -0
- package/dist/orm/orm.cjs +41 -0
- package/dist/orm/orm.d.cts +18 -0
- package/dist/orm/orm.d.cts.map +1 -0
- package/dist/orm/orm.d.mts +18 -0
- package/dist/orm/orm.d.mts.map +1 -0
- package/dist/orm/orm.mjs +43 -0
- package/dist/orm/orm.mjs.map +1 -0
- package/dist/orm/relation.cjs +18 -0
- package/dist/orm/relation.d.cts +8 -0
- package/dist/orm/relation.d.cts.map +1 -0
- package/dist/orm/relation.d.mts +8 -0
- package/dist/orm/relation.d.mts.map +1 -0
- package/dist/orm/relation.mjs +19 -0
- package/dist/orm/relation.mjs.map +1 -0
- package/dist/orm/runtime/builders/mutations.cjs +29 -0
- package/dist/orm/runtime/builders/mutations.mjs +28 -0
- package/dist/orm/runtime/builders/mutations.mjs.map +1 -0
- package/dist/orm/runtime/builders/select.cjs +18 -0
- package/dist/orm/runtime/builders/select.mjs +19 -0
- package/dist/orm/runtime/builders/select.mjs.map +1 -0
- package/dist/orm/runtime/client.cjs +90 -0
- package/dist/orm/runtime/client.mjs +92 -0
- package/dist/orm/runtime/client.mjs.map +1 -0
- package/dist/orm/runtime/context.cjs +49 -0
- package/dist/orm/runtime/context.mjs +51 -0
- package/dist/orm/runtime/context.mjs.map +1 -0
- package/dist/orm/runtime/dialect/index.cjs +11 -0
- package/dist/orm/runtime/dialect/index.mjs +13 -0
- package/dist/orm/runtime/dialect/index.mjs.map +1 -0
- package/dist/orm/runtime/dialect/mysql.cjs +95 -0
- package/dist/orm/runtime/dialect/mysql.mjs +97 -0
- package/dist/orm/runtime/dialect/mysql.mjs.map +1 -0
- package/dist/orm/runtime/dialect/postgres.cjs +51 -0
- package/dist/orm/runtime/dialect/postgres.mjs +53 -0
- package/dist/orm/runtime/dialect/postgres.mjs.map +1 -0
- package/dist/orm/runtime/dialect/sqlite.cjs +4 -0
- package/dist/orm/runtime/dialect/sqlite.mjs +7 -0
- package/dist/orm/runtime/dialect/sqlite.mjs.map +1 -0
- package/dist/orm/runtime/errors.cjs +19 -0
- package/dist/orm/runtime/errors.mjs +21 -0
- package/dist/orm/runtime/errors.mjs.map +1 -0
- package/dist/orm/runtime/hydrate/many.cjs +46 -0
- package/dist/orm/runtime/hydrate/many.mjs +48 -0
- package/dist/orm/runtime/hydrate/many.mjs.map +1 -0
- package/dist/orm/runtime/hydrate/one.cjs +38 -0
- package/dist/orm/runtime/hydrate/one.mjs +40 -0
- package/dist/orm/runtime/hydrate/one.mjs.map +1 -0
- package/dist/orm/runtime/hydrate.cjs +49 -0
- package/dist/orm/runtime/hydrate.mjs +51 -0
- package/dist/orm/runtime/hydrate.mjs.map +1 -0
- package/dist/orm/runtime/rows.cjs +30 -0
- package/dist/orm/runtime/rows.mjs +31 -0
- package/dist/orm/runtime/rows.mjs.map +1 -0
- package/dist/orm/runtime/utils.cjs +27 -0
- package/dist/orm/runtime/utils.mjs +27 -0
- package/dist/orm/runtime/utils.mjs.map +1 -0
- package/dist/orm/sql/parse-array.cjs +64 -0
- package/dist/orm/sql/parse-array.mjs +66 -0
- package/dist/orm/sql/parse-array.mjs.map +1 -0
- package/dist/orm/sql/plan/select.cjs +36 -0
- package/dist/orm/sql/plan/select.mjs +38 -0
- package/dist/orm/sql/plan/select.mjs.map +1 -0
- package/dist/orm/sql/plan/where/operators.cjs +95 -0
- package/dist/orm/sql/plan/where/operators.mjs +97 -0
- package/dist/orm/sql/plan/where/operators.mjs.map +1 -0
- package/dist/orm/sql/plan/where.cjs +59 -0
- package/dist/orm/sql/plan/where.mjs +61 -0
- package/dist/orm/sql/plan/where.mjs.map +1 -0
- package/dist/orm/sql/serialize/clauses.cjs +36 -0
- package/dist/orm/sql/serialize/clauses.mjs +37 -0
- package/dist/orm/sql/serialize/clauses.mjs.map +1 -0
- package/dist/orm/sql/serialize/joins.cjs +31 -0
- package/dist/orm/sql/serialize/joins.mjs +33 -0
- package/dist/orm/sql/serialize/joins.mjs.map +1 -0
- package/dist/orm/sql/serialize/values.cjs +30 -0
- package/dist/orm/sql/serialize/values.mjs +32 -0
- package/dist/orm/sql/serialize/values.mjs.map +1 -0
- package/dist/orm/sql/serialize/where/predicate.cjs +73 -0
- package/dist/orm/sql/serialize/where/predicate.mjs +75 -0
- package/dist/orm/sql/serialize/where/predicate.mjs.map +1 -0
- package/dist/orm/sql/serialize/where/tree.cjs +26 -0
- package/dist/orm/sql/serialize/where/tree.mjs +28 -0
- package/dist/orm/sql/serialize/where/tree.mjs.map +1 -0
- package/dist/orm/sql/serialize/where.cjs +10 -0
- package/dist/orm/sql/serialize/where.mjs +12 -0
- package/dist/orm/sql/serialize/where.mjs.map +1 -0
- package/dist/orm/sql/serialize.cjs +24 -0
- package/dist/orm/sql/serialize.mjs +25 -0
- package/dist/orm/sql/serialize.mjs.map +1 -0
- package/dist/orm/table.cjs +12 -0
- package/dist/orm/table.d.cts +12 -0
- package/dist/orm/table.d.cts.map +1 -0
- package/dist/orm/table.d.mts +12 -0
- package/dist/orm/table.d.mts.map +1 -0
- package/dist/orm/table.mjs +14 -0
- package/dist/orm/table.mjs.map +1 -0
- package/dist/orm/types.d.cts +183 -0
- package/dist/orm/types.d.cts.map +1 -0
- package/dist/orm/types.d.mts +183 -0
- package/dist/orm/types.d.mts.map +1 -0
- package/dist/workflow/types.d.cts +83 -0
- package/dist/workflow/types.d.cts.map +1 -0
- package/dist/workflow/types.d.mts +83 -0
- package/dist/workflow/types.d.mts.map +1 -0
- package/package.json +29 -3
- package/dist/cron/scanner.mjs.map +0 -1
- package/dist/cron/types.d.cts.map +0 -1
- package/dist/cron/types.d.mts.map +0 -1
- package/dist/lib/cron/index.d.cts.map +0 -1
- package/dist/lib/cron/index.d.mts.map +0 -1
- package/dist/lib/cron/index.mjs.map +0 -1
|
@@ -10,10 +10,10 @@ declare class Queue<T> {
|
|
|
10
10
|
private concurrency;
|
|
11
11
|
private pollInterval;
|
|
12
12
|
constructor(options: QueueOptions<T>);
|
|
13
|
-
enqueue(data: T): Promise<readonly [
|
|
13
|
+
enqueue(data: T): Promise<readonly [{
|
|
14
14
|
readonly type: "QueueError";
|
|
15
15
|
readonly message: string;
|
|
16
|
-
}, null]>;
|
|
16
|
+
}, null] | readonly [null, string]>;
|
|
17
17
|
stop(): Promise<void>;
|
|
18
18
|
private waitForPollInterval;
|
|
19
19
|
private serializeJob;
|
|
@@ -10,10 +10,10 @@ declare class Queue<T> {
|
|
|
10
10
|
private concurrency;
|
|
11
11
|
private pollInterval;
|
|
12
12
|
constructor(options: QueueOptions<T>);
|
|
13
|
-
enqueue(data: T): Promise<readonly [
|
|
13
|
+
enqueue(data: T): Promise<readonly [{
|
|
14
14
|
readonly type: "QueueError";
|
|
15
15
|
readonly message: string;
|
|
16
|
-
}, null]>;
|
|
16
|
+
}, null] | readonly [null, string]>;
|
|
17
17
|
stop(): Promise<void>;
|
|
18
18
|
private waitForPollInterval;
|
|
19
19
|
private serializeJob;
|
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_lib_errors_index = require("../errors/index.cjs");
|
|
3
|
+
//#region src/lib/workflow/index.ts
|
|
4
|
+
const DEFAULT_LOCK_TTL = 300 * 1e3;
|
|
5
|
+
const now = () => Date.now();
|
|
6
|
+
const toErrorMessage = (error) => {
|
|
7
|
+
if (error instanceof Error) return error.message;
|
|
8
|
+
return String(error);
|
|
9
|
+
};
|
|
10
|
+
const envelopeSerialize = (value) => {
|
|
11
|
+
return JSON.stringify({ value });
|
|
12
|
+
};
|
|
13
|
+
const envelopeDeserialize = (raw) => {
|
|
14
|
+
const [parseError, parsed] = require_lib_errors_index.mightThrowSync(() => JSON.parse(raw));
|
|
15
|
+
if (parseError) throw parseError;
|
|
16
|
+
if (parsed === null) return;
|
|
17
|
+
if (typeof parsed !== "object") return;
|
|
18
|
+
if ("value" in parsed) return parsed.value;
|
|
19
|
+
};
|
|
20
|
+
const knownStatuses = [
|
|
21
|
+
"pending",
|
|
22
|
+
"running",
|
|
23
|
+
"completed",
|
|
24
|
+
"failed",
|
|
25
|
+
"cancelled"
|
|
26
|
+
];
|
|
27
|
+
var WorkflowDefinition = class {
|
|
28
|
+
options;
|
|
29
|
+
lockTTL;
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.options = options;
|
|
32
|
+
this.lockTTL = options.lockTTL ?? DEFAULT_LOCK_TTL;
|
|
33
|
+
}
|
|
34
|
+
async start(input, options) {
|
|
35
|
+
const executionId = options?.executionId ?? crypto.randomUUID();
|
|
36
|
+
const [createError] = await this.createExecution(executionId, input);
|
|
37
|
+
if (createError) return require_lib_errors_index.err(createError.type, createError.message);
|
|
38
|
+
return this.execute(executionId, input);
|
|
39
|
+
}
|
|
40
|
+
async run(input, options) {
|
|
41
|
+
const [startError, startData] = await this.start(input, options);
|
|
42
|
+
if (startError) return require_lib_errors_index.err(startError.type, startError.message);
|
|
43
|
+
if (!startData) return require_lib_errors_index.err("WorkflowError", "Unexpected empty start result");
|
|
44
|
+
if (startData.status === "cancelled") return require_lib_errors_index.err("WorkflowCancelledError", `Workflow execution ${startData.executionId} was cancelled`);
|
|
45
|
+
if (startData.status !== "completed") return require_lib_errors_index.err("WorkflowExecutionError", `Workflow execution ${startData.executionId} did not complete`);
|
|
46
|
+
const [getError, execution] = await this.get(startData.executionId);
|
|
47
|
+
if (getError) return require_lib_errors_index.err(getError.type, getError.message);
|
|
48
|
+
if (!execution) return require_lib_errors_index.err("WorkflowError", "Unexpected empty execution");
|
|
49
|
+
return require_lib_errors_index.ok(execution.result);
|
|
50
|
+
}
|
|
51
|
+
async resume(executionId) {
|
|
52
|
+
const [getError, execution] = await this.get(executionId);
|
|
53
|
+
if (getError) return require_lib_errors_index.err(getError.type, getError.message);
|
|
54
|
+
if (!execution) return require_lib_errors_index.err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
|
|
55
|
+
if (execution.status === "completed") return require_lib_errors_index.ok({
|
|
56
|
+
executionId,
|
|
57
|
+
status: execution.status
|
|
58
|
+
});
|
|
59
|
+
if (execution.status === "cancelled") return require_lib_errors_index.ok({
|
|
60
|
+
executionId,
|
|
61
|
+
status: execution.status
|
|
62
|
+
});
|
|
63
|
+
return this.execute(executionId, execution.input);
|
|
64
|
+
}
|
|
65
|
+
async get(executionId) {
|
|
66
|
+
const [statusError, status] = await this.getMeta(executionId, "status");
|
|
67
|
+
if (statusError) return require_lib_errors_index.err(statusError.type, statusError.message);
|
|
68
|
+
if (!status) return require_lib_errors_index.err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
|
|
69
|
+
const normalizedStatus = this.normalizeStatus(status);
|
|
70
|
+
if (!normalizedStatus) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} has invalid status ${status}`);
|
|
71
|
+
const [inputError, input] = await this.readInput(executionId);
|
|
72
|
+
if (inputError) return require_lib_errors_index.err(inputError.type, inputError.message);
|
|
73
|
+
if (input === null) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} has invalid input`);
|
|
74
|
+
const [resultError, result] = await this.readResult(executionId);
|
|
75
|
+
if (resultError) return require_lib_errors_index.err(resultError.type, resultError.message);
|
|
76
|
+
const [stepsError, steps] = await this.readStepSnapshots(executionId);
|
|
77
|
+
if (stepsError) return require_lib_errors_index.err(stepsError.type, stepsError.message);
|
|
78
|
+
const [createdAtError, createdAt] = await this.readNumberMeta(executionId, "createdAt");
|
|
79
|
+
if (createdAtError) return require_lib_errors_index.err(createdAtError.type, createdAtError.message);
|
|
80
|
+
if (createdAt === null) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} is missing createdAt`);
|
|
81
|
+
const [updatedAtError, updatedAt] = await this.readNumberMeta(executionId, "updatedAt");
|
|
82
|
+
if (updatedAtError) return require_lib_errors_index.err(updatedAtError.type, updatedAtError.message);
|
|
83
|
+
if (updatedAt === null) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} is missing updatedAt`);
|
|
84
|
+
const [metaError, errorMessage] = await this.getMeta(executionId, "error");
|
|
85
|
+
if (metaError) return require_lib_errors_index.err(metaError.type, metaError.message);
|
|
86
|
+
const [completedAtError, completedAt] = await this.readNumberMeta(executionId, "completedAt");
|
|
87
|
+
if (completedAtError) return require_lib_errors_index.err(completedAtError.type, completedAtError.message);
|
|
88
|
+
const [failedAtError, failedAt] = await this.readNumberMeta(executionId, "failedAt");
|
|
89
|
+
if (failedAtError) return require_lib_errors_index.err(failedAtError.type, failedAtError.message);
|
|
90
|
+
const [cancelledAtError, cancelledAt] = await this.readNumberMeta(executionId, "cancelledAt");
|
|
91
|
+
if (cancelledAtError) return require_lib_errors_index.err(cancelledAtError.type, cancelledAtError.message);
|
|
92
|
+
return require_lib_errors_index.ok({
|
|
93
|
+
id: executionId,
|
|
94
|
+
name: this.options.name,
|
|
95
|
+
status: normalizedStatus,
|
|
96
|
+
input,
|
|
97
|
+
result,
|
|
98
|
+
error: errorMessage,
|
|
99
|
+
createdAt,
|
|
100
|
+
updatedAt,
|
|
101
|
+
completedAt,
|
|
102
|
+
failedAt,
|
|
103
|
+
cancelledAt,
|
|
104
|
+
steps
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
async cancel(executionId) {
|
|
108
|
+
const [getError, execution] = await this.get(executionId);
|
|
109
|
+
if (getError) return require_lib_errors_index.err(getError.type, getError.message);
|
|
110
|
+
if (!execution) return require_lib_errors_index.err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
|
|
111
|
+
if (execution.status === "completed") return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} is already completed`);
|
|
112
|
+
const timestamp = now();
|
|
113
|
+
const [statusError] = await this.setMeta(executionId, "status", "cancelled");
|
|
114
|
+
if (statusError) return require_lib_errors_index.err(statusError.type, statusError.message);
|
|
115
|
+
const [updatedAtError] = await this.setMeta(executionId, "updatedAt", String(timestamp));
|
|
116
|
+
if (updatedAtError) return require_lib_errors_index.err(updatedAtError.type, updatedAtError.message);
|
|
117
|
+
const [cancelledAtError] = await this.setMeta(executionId, "cancelledAt", String(timestamp));
|
|
118
|
+
if (cancelledAtError) return require_lib_errors_index.err(cancelledAtError.type, cancelledAtError.message);
|
|
119
|
+
const [clearErrorError] = await this.setMeta(executionId, "error", "");
|
|
120
|
+
if (clearErrorError) return require_lib_errors_index.err(clearErrorError.type, clearErrorError.message);
|
|
121
|
+
const [clearFailedAtError] = await this.setMeta(executionId, "failedAt", "");
|
|
122
|
+
if (clearFailedAtError) return require_lib_errors_index.err(clearFailedAtError.type, clearFailedAtError.message);
|
|
123
|
+
return require_lib_errors_index.ok({
|
|
124
|
+
executionId,
|
|
125
|
+
createdAt: execution.createdAt,
|
|
126
|
+
cancelledAt: timestamp,
|
|
127
|
+
updatedAt: timestamp,
|
|
128
|
+
status: "cancelled"
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
executionKey(executionId) {
|
|
132
|
+
return `workflow:${this.options.name}:execution:${executionId}`;
|
|
133
|
+
}
|
|
134
|
+
metaKey(executionId) {
|
|
135
|
+
return `${this.executionKey(executionId)}:meta`;
|
|
136
|
+
}
|
|
137
|
+
stepsKey(executionId) {
|
|
138
|
+
return `${this.executionKey(executionId)}:steps`;
|
|
139
|
+
}
|
|
140
|
+
lockKey(executionId) {
|
|
141
|
+
return `${this.executionKey(executionId)}:lock`;
|
|
142
|
+
}
|
|
143
|
+
async createExecution(executionId, input) {
|
|
144
|
+
const [serializeError, serializedInput] = this.serializeInput(input);
|
|
145
|
+
if (serializeError) return require_lib_errors_index.err("WorkflowSerializationError", `Unable to serialize workflow input for ${executionId}`);
|
|
146
|
+
const timestamp = now();
|
|
147
|
+
const [statusReadError, existingStatus] = await this.getMeta(executionId, "status");
|
|
148
|
+
if (statusReadError) return require_lib_errors_index.err(statusReadError.type, statusReadError.message);
|
|
149
|
+
if (existingStatus) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} already exists`);
|
|
150
|
+
const metadata = {
|
|
151
|
+
status: "pending",
|
|
152
|
+
input: serializedInput,
|
|
153
|
+
result: "",
|
|
154
|
+
error: "",
|
|
155
|
+
createdAt: String(timestamp),
|
|
156
|
+
updatedAt: String(timestamp),
|
|
157
|
+
completedAt: "",
|
|
158
|
+
failedAt: "",
|
|
159
|
+
cancelledAt: "",
|
|
160
|
+
steps: "[]"
|
|
161
|
+
};
|
|
162
|
+
const [writeError] = await require_lib_errors_index.mightThrow(this.options.redis.hset(this.metaKey(executionId), metadata));
|
|
163
|
+
if (writeError) return require_lib_errors_index.err("WorkflowError", `Unable to persist metadata for execution ${executionId}`);
|
|
164
|
+
return require_lib_errors_index.ok(null);
|
|
165
|
+
}
|
|
166
|
+
async execute(executionId, input) {
|
|
167
|
+
const token = crypto.randomUUID();
|
|
168
|
+
const [lockError] = await this.acquireLock(executionId, token);
|
|
169
|
+
if (lockError) return require_lib_errors_index.err(lockError.type, lockError.message);
|
|
170
|
+
const [statusCheckError, currentStatus] = await this.getMeta(executionId, "status");
|
|
171
|
+
if (statusCheckError) {
|
|
172
|
+
await this.releaseLock(executionId, token);
|
|
173
|
+
return require_lib_errors_index.err(statusCheckError.type, statusCheckError.message);
|
|
174
|
+
}
|
|
175
|
+
if (currentStatus === "cancelled") {
|
|
176
|
+
await this.releaseLock(executionId, token);
|
|
177
|
+
return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} was cancelled`);
|
|
178
|
+
}
|
|
179
|
+
const timestamp = now();
|
|
180
|
+
const [runningStatusError] = await this.setMeta(executionId, "status", "running");
|
|
181
|
+
if (runningStatusError) {
|
|
182
|
+
await this.releaseLock(executionId, token);
|
|
183
|
+
return require_lib_errors_index.err(runningStatusError.type, runningStatusError.message);
|
|
184
|
+
}
|
|
185
|
+
const [runningUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(timestamp));
|
|
186
|
+
if (runningUpdatedAtError) {
|
|
187
|
+
await this.releaseLock(executionId, token);
|
|
188
|
+
return require_lib_errors_index.err(runningUpdatedAtError.type, runningUpdatedAtError.message);
|
|
189
|
+
}
|
|
190
|
+
const controller = new AbortController();
|
|
191
|
+
const renewInterval = Math.floor(this.lockTTL / 3);
|
|
192
|
+
let lockLost = false;
|
|
193
|
+
const renewTimer = setInterval(async () => {
|
|
194
|
+
const [renewError] = await this.extendLock(executionId, token);
|
|
195
|
+
if (renewError) {
|
|
196
|
+
lockLost = true;
|
|
197
|
+
controller.abort();
|
|
198
|
+
clearInterval(renewTimer);
|
|
199
|
+
}
|
|
200
|
+
}, renewInterval);
|
|
201
|
+
const step = async (name, handler) => {
|
|
202
|
+
const [cancelledError, cancelled] = await this.isCancelled(executionId);
|
|
203
|
+
if (cancelledError) return Promise.reject(new Error(cancelledError.message));
|
|
204
|
+
if (cancelled) {
|
|
205
|
+
controller.abort();
|
|
206
|
+
return Promise.reject(/* @__PURE__ */ new Error("Workflow cancelled"));
|
|
207
|
+
}
|
|
208
|
+
const [readError, cachedStep] = await this.readStepOutput(executionId, name);
|
|
209
|
+
if (readError) return Promise.reject(new Error(readError.message));
|
|
210
|
+
if (cachedStep.found) return cachedStep.value;
|
|
211
|
+
const [stepError, output] = await require_lib_errors_index.mightThrow(Promise.resolve(handler(input, controller.signal)));
|
|
212
|
+
if (stepError) return Promise.reject(stepError);
|
|
213
|
+
const [writeError] = await this.writeStepOutput(executionId, name, output);
|
|
214
|
+
if (writeError) return Promise.reject(new Error(writeError.message));
|
|
215
|
+
return output;
|
|
216
|
+
};
|
|
217
|
+
const [handlerError, result] = await require_lib_errors_index.mightThrow(Promise.resolve(this.options.handler({
|
|
218
|
+
input,
|
|
219
|
+
executionId,
|
|
220
|
+
signal: controller.signal,
|
|
221
|
+
step
|
|
222
|
+
})));
|
|
223
|
+
clearInterval(renewTimer);
|
|
224
|
+
if (lockLost) {
|
|
225
|
+
await this.releaseLock(executionId, token);
|
|
226
|
+
return require_lib_errors_index.err("WorkflowLockError", `Lock expired during execution ${executionId}`);
|
|
227
|
+
}
|
|
228
|
+
const [cancelledError, cancelled] = await this.isCancelled(executionId);
|
|
229
|
+
if (cancelledError) {
|
|
230
|
+
await this.releaseLock(executionId, token);
|
|
231
|
+
return require_lib_errors_index.err(cancelledError.type, cancelledError.message);
|
|
232
|
+
}
|
|
233
|
+
if (cancelled) {
|
|
234
|
+
const cancelledAt = now();
|
|
235
|
+
const [cancelledStatusError] = await this.setMeta(executionId, "status", "cancelled");
|
|
236
|
+
if (cancelledStatusError) {
|
|
237
|
+
await this.releaseLock(executionId, token);
|
|
238
|
+
return require_lib_errors_index.err(cancelledStatusError.type, cancelledStatusError.message);
|
|
239
|
+
}
|
|
240
|
+
const [cancelledUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(cancelledAt));
|
|
241
|
+
if (cancelledUpdatedAtError) {
|
|
242
|
+
await this.releaseLock(executionId, token);
|
|
243
|
+
return require_lib_errors_index.err(cancelledUpdatedAtError.type, cancelledUpdatedAtError.message);
|
|
244
|
+
}
|
|
245
|
+
const [cancelledAtError] = await this.setMeta(executionId, "cancelledAt", String(cancelledAt));
|
|
246
|
+
if (cancelledAtError) {
|
|
247
|
+
await this.releaseLock(executionId, token);
|
|
248
|
+
return require_lib_errors_index.err(cancelledAtError.type, cancelledAtError.message);
|
|
249
|
+
}
|
|
250
|
+
await this.releaseLock(executionId, token);
|
|
251
|
+
return require_lib_errors_index.ok({
|
|
252
|
+
executionId,
|
|
253
|
+
status: "cancelled"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (handlerError) {
|
|
257
|
+
const failedAt = now();
|
|
258
|
+
const [failedStatusError] = await this.setMeta(executionId, "status", "failed");
|
|
259
|
+
if (failedStatusError) {
|
|
260
|
+
await this.releaseLock(executionId, token);
|
|
261
|
+
return require_lib_errors_index.err(failedStatusError.type, failedStatusError.message);
|
|
262
|
+
}
|
|
263
|
+
const [failedMessageError] = await this.setMeta(executionId, "error", toErrorMessage(handlerError));
|
|
264
|
+
if (failedMessageError) {
|
|
265
|
+
await this.releaseLock(executionId, token);
|
|
266
|
+
return require_lib_errors_index.err(failedMessageError.type, failedMessageError.message);
|
|
267
|
+
}
|
|
268
|
+
const [failedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(failedAt));
|
|
269
|
+
if (failedUpdatedAtError) {
|
|
270
|
+
await this.releaseLock(executionId, token);
|
|
271
|
+
return require_lib_errors_index.err(failedUpdatedAtError.type, failedUpdatedAtError.message);
|
|
272
|
+
}
|
|
273
|
+
const [failedAtError] = await this.setMeta(executionId, "failedAt", String(failedAt));
|
|
274
|
+
if (failedAtError) {
|
|
275
|
+
await this.releaseLock(executionId, token);
|
|
276
|
+
return require_lib_errors_index.err(failedAtError.type, failedAtError.message);
|
|
277
|
+
}
|
|
278
|
+
await this.releaseLock(executionId, token);
|
|
279
|
+
return require_lib_errors_index.err("WorkflowExecutionError", `Workflow execution ${executionId} failed: ${toErrorMessage(handlerError)}`);
|
|
280
|
+
}
|
|
281
|
+
const [serializeResultError, serializedResult] = this.serializeResult(result);
|
|
282
|
+
if (serializeResultError) {
|
|
283
|
+
const failedAt = now();
|
|
284
|
+
const [failedStatusError] = await this.setMeta(executionId, "status", "failed");
|
|
285
|
+
if (failedStatusError) {
|
|
286
|
+
await this.releaseLock(executionId, token);
|
|
287
|
+
return require_lib_errors_index.err(failedStatusError.type, failedStatusError.message);
|
|
288
|
+
}
|
|
289
|
+
const [failedMessageError] = await this.setMeta(executionId, "error", serializeResultError.message);
|
|
290
|
+
if (failedMessageError) {
|
|
291
|
+
await this.releaseLock(executionId, token);
|
|
292
|
+
return require_lib_errors_index.err(failedMessageError.type, failedMessageError.message);
|
|
293
|
+
}
|
|
294
|
+
const [failedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(failedAt));
|
|
295
|
+
if (failedUpdatedAtError) {
|
|
296
|
+
await this.releaseLock(executionId, token);
|
|
297
|
+
return require_lib_errors_index.err(failedUpdatedAtError.type, failedUpdatedAtError.message);
|
|
298
|
+
}
|
|
299
|
+
const [failedAtError] = await this.setMeta(executionId, "failedAt", String(failedAt));
|
|
300
|
+
if (failedAtError) {
|
|
301
|
+
await this.releaseLock(executionId, token);
|
|
302
|
+
return require_lib_errors_index.err(failedAtError.type, failedAtError.message);
|
|
303
|
+
}
|
|
304
|
+
await this.releaseLock(executionId, token);
|
|
305
|
+
return require_lib_errors_index.err("WorkflowSerializationError", `Unable to serialize workflow result for ${executionId}`);
|
|
306
|
+
}
|
|
307
|
+
const completedAt = now();
|
|
308
|
+
const [completedResultError] = await this.setMeta(executionId, "result", serializedResult);
|
|
309
|
+
if (completedResultError) {
|
|
310
|
+
await this.releaseLock(executionId, token);
|
|
311
|
+
return require_lib_errors_index.err(completedResultError.type, completedResultError.message);
|
|
312
|
+
}
|
|
313
|
+
const [completedStatusError] = await this.setMeta(executionId, "status", "completed");
|
|
314
|
+
if (completedStatusError) {
|
|
315
|
+
await this.releaseLock(executionId, token);
|
|
316
|
+
return require_lib_errors_index.err(completedStatusError.type, completedStatusError.message);
|
|
317
|
+
}
|
|
318
|
+
const [completedClearErrorError] = await this.setMeta(executionId, "error", "");
|
|
319
|
+
if (completedClearErrorError) {
|
|
320
|
+
await this.releaseLock(executionId, token);
|
|
321
|
+
return require_lib_errors_index.err(completedClearErrorError.type, completedClearErrorError.message);
|
|
322
|
+
}
|
|
323
|
+
const [completedClearFailedAtError] = await this.setMeta(executionId, "failedAt", "");
|
|
324
|
+
if (completedClearFailedAtError) {
|
|
325
|
+
await this.releaseLock(executionId, token);
|
|
326
|
+
return require_lib_errors_index.err(completedClearFailedAtError.type, completedClearFailedAtError.message);
|
|
327
|
+
}
|
|
328
|
+
const [completedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(completedAt));
|
|
329
|
+
if (completedUpdatedAtError) {
|
|
330
|
+
await this.releaseLock(executionId, token);
|
|
331
|
+
return require_lib_errors_index.err(completedUpdatedAtError.type, completedUpdatedAtError.message);
|
|
332
|
+
}
|
|
333
|
+
const [completedAtError] = await this.setMeta(executionId, "completedAt", String(completedAt));
|
|
334
|
+
if (completedAtError) {
|
|
335
|
+
await this.releaseLock(executionId, token);
|
|
336
|
+
return require_lib_errors_index.err(completedAtError.type, completedAtError.message);
|
|
337
|
+
}
|
|
338
|
+
await this.releaseLock(executionId, token);
|
|
339
|
+
return require_lib_errors_index.ok({
|
|
340
|
+
executionId,
|
|
341
|
+
status: "completed"
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async acquireLock(executionId, token) {
|
|
345
|
+
const [lockError, lockResult] = await require_lib_errors_index.mightThrow(this.options.redis.set(this.lockKey(executionId), token, "PX", String(this.lockTTL), "NX"));
|
|
346
|
+
if (lockError) return require_lib_errors_index.err("WorkflowLockError", `Unable to acquire lock for execution ${executionId}`);
|
|
347
|
+
if (lockResult !== "OK") return require_lib_errors_index.err("WorkflowLockError", `Workflow execution ${executionId} is already running`);
|
|
348
|
+
return require_lib_errors_index.ok(null);
|
|
349
|
+
}
|
|
350
|
+
async releaseLock(executionId, token) {
|
|
351
|
+
const [evalError] = await require_lib_errors_index.mightThrow(this.options.redis.send("EVAL", [
|
|
352
|
+
"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end",
|
|
353
|
+
"1",
|
|
354
|
+
this.lockKey(executionId),
|
|
355
|
+
token
|
|
356
|
+
]));
|
|
357
|
+
if (evalError) return require_lib_errors_index.err("WorkflowLockError", `Unable to release lock for execution ${executionId}`);
|
|
358
|
+
return require_lib_errors_index.ok(null);
|
|
359
|
+
}
|
|
360
|
+
async extendLock(executionId, token) {
|
|
361
|
+
const [evalError, result] = await require_lib_errors_index.mightThrow(this.options.redis.send("EVAL", [
|
|
362
|
+
"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end",
|
|
363
|
+
"1",
|
|
364
|
+
this.lockKey(executionId),
|
|
365
|
+
token,
|
|
366
|
+
String(this.lockTTL)
|
|
367
|
+
]));
|
|
368
|
+
if (evalError) return require_lib_errors_index.err("WorkflowLockError", `Unable to extend lock for execution ${executionId}`);
|
|
369
|
+
if (result === 0) return require_lib_errors_index.err("WorkflowLockError", `Lock ownership lost for execution ${executionId}`);
|
|
370
|
+
return require_lib_errors_index.ok(null);
|
|
371
|
+
}
|
|
372
|
+
async isCancelled(executionId) {
|
|
373
|
+
const [statusError, status] = await this.getMeta(executionId, "status");
|
|
374
|
+
if (statusError) return require_lib_errors_index.err(statusError.type, statusError.message);
|
|
375
|
+
return require_lib_errors_index.ok(status === "cancelled");
|
|
376
|
+
}
|
|
377
|
+
async setMeta(executionId, field, value) {
|
|
378
|
+
const [writeError] = await require_lib_errors_index.mightThrow(this.options.redis.hset(this.metaKey(executionId), field, value));
|
|
379
|
+
if (writeError) return require_lib_errors_index.err("WorkflowError", `Unable to persist ${field} for execution ${executionId}`);
|
|
380
|
+
return require_lib_errors_index.ok(null);
|
|
381
|
+
}
|
|
382
|
+
async getMeta(executionId, field) {
|
|
383
|
+
const [readError, value] = await require_lib_errors_index.mightThrow(this.options.redis.hget(this.metaKey(executionId), field));
|
|
384
|
+
if (readError) return require_lib_errors_index.err("WorkflowError", `Unable to read ${field} for execution ${executionId}`);
|
|
385
|
+
if (value === null || value === void 0) return require_lib_errors_index.ok(null);
|
|
386
|
+
if (typeof value !== "string") return require_lib_errors_index.err("WorkflowStateError", `Invalid ${field} value for execution ${executionId}`);
|
|
387
|
+
if (value.length === 0) return require_lib_errors_index.ok(null);
|
|
388
|
+
return require_lib_errors_index.ok(value);
|
|
389
|
+
}
|
|
390
|
+
async readNumberMeta(executionId, field) {
|
|
391
|
+
const [readError, value] = await this.getMeta(executionId, field);
|
|
392
|
+
if (readError) return require_lib_errors_index.err(readError.type, readError.message);
|
|
393
|
+
if (!value) return require_lib_errors_index.ok(null);
|
|
394
|
+
const parsed = Number(value);
|
|
395
|
+
if (!Number.isFinite(parsed)) return require_lib_errors_index.err("WorkflowStateError", `Invalid ${field} value for execution ${executionId}`);
|
|
396
|
+
return require_lib_errors_index.ok(parsed);
|
|
397
|
+
}
|
|
398
|
+
runSerializer(value, serializer, label) {
|
|
399
|
+
const [serializeError, serialized] = require_lib_errors_index.mightThrowSync(() => serializer(value));
|
|
400
|
+
if (serializeError) return require_lib_errors_index.err("WorkflowSerializationError", `Unable to serialize ${label}: ${toErrorMessage(serializeError)}`);
|
|
401
|
+
if (typeof serialized !== "string") return require_lib_errors_index.err("WorkflowSerializationError", `${label} serializer must return a string`);
|
|
402
|
+
return require_lib_errors_index.ok(serialized);
|
|
403
|
+
}
|
|
404
|
+
runDeserializer(raw, deserializer, label) {
|
|
405
|
+
const [deserializeError, value] = require_lib_errors_index.mightThrowSync(() => deserializer(raw));
|
|
406
|
+
if (deserializeError) return require_lib_errors_index.err("WorkflowSerializationError", `Unable to deserialize ${label}: ${toErrorMessage(deserializeError)}`);
|
|
407
|
+
return require_lib_errors_index.ok(value);
|
|
408
|
+
}
|
|
409
|
+
serializeInput(input) {
|
|
410
|
+
return this.runSerializer(input, this.options.serializeInput ?? envelopeSerialize, "workflow input");
|
|
411
|
+
}
|
|
412
|
+
deserializeInput(raw) {
|
|
413
|
+
const deserializer = this.options.deserializeInput ?? ((value) => envelopeDeserialize(value));
|
|
414
|
+
return this.runDeserializer(raw, deserializer, "workflow input");
|
|
415
|
+
}
|
|
416
|
+
serializeResult(result) {
|
|
417
|
+
if (result === null) return require_lib_errors_index.ok(envelopeSerialize(null));
|
|
418
|
+
return this.runSerializer(result, this.options.serializeResult ?? envelopeSerialize, "workflow result");
|
|
419
|
+
}
|
|
420
|
+
deserializeResult(raw) {
|
|
421
|
+
const deserializer = this.options.deserializeResult ?? ((value) => envelopeDeserialize(value));
|
|
422
|
+
return this.runDeserializer(raw, deserializer, "workflow result");
|
|
423
|
+
}
|
|
424
|
+
serializeStepOutput(output) {
|
|
425
|
+
return this.runSerializer(output, this.options.serializeStepOutput ?? envelopeSerialize, "step output");
|
|
426
|
+
}
|
|
427
|
+
deserializeStepOutput(raw) {
|
|
428
|
+
const deserializer = this.options.deserializeStepOutput ?? ((value) => envelopeDeserialize(value));
|
|
429
|
+
return this.runDeserializer(raw, deserializer, "step output");
|
|
430
|
+
}
|
|
431
|
+
async readInput(executionId) {
|
|
432
|
+
const [readError, raw] = await this.getMeta(executionId, "input");
|
|
433
|
+
if (readError) return require_lib_errors_index.err(readError.type, readError.message);
|
|
434
|
+
if (!raw) return require_lib_errors_index.err("WorkflowStateError", `Workflow execution ${executionId} input not found`);
|
|
435
|
+
return this.deserializeInput(raw);
|
|
436
|
+
}
|
|
437
|
+
async readResult(executionId) {
|
|
438
|
+
const [readError, raw] = await this.getMeta(executionId, "result");
|
|
439
|
+
if (readError) return require_lib_errors_index.err(readError.type, readError.message);
|
|
440
|
+
if (!raw) return require_lib_errors_index.ok(null);
|
|
441
|
+
const [deserializeError, result] = this.deserializeResult(raw);
|
|
442
|
+
if (deserializeError) return require_lib_errors_index.err(deserializeError.type, deserializeError.message);
|
|
443
|
+
return require_lib_errors_index.ok(result);
|
|
444
|
+
}
|
|
445
|
+
async writeStepOutput(executionId, stepName, output) {
|
|
446
|
+
const [serializeError, serializedOutput] = this.serializeStepOutput(output);
|
|
447
|
+
if (serializeError) return require_lib_errors_index.err("WorkflowSerializationError", `Unable to serialize step ${stepName} output`);
|
|
448
|
+
const payload = {
|
|
449
|
+
output: serializedOutput,
|
|
450
|
+
completedAt: now()
|
|
451
|
+
};
|
|
452
|
+
const [payloadError, payloadRaw] = require_lib_errors_index.mightThrowSync(() => JSON.stringify(payload));
|
|
453
|
+
if (payloadError || typeof payloadRaw !== "string") return require_lib_errors_index.err("WorkflowSerializationError", `Unable to persist step ${stepName} output`);
|
|
454
|
+
const [writeError] = await require_lib_errors_index.mightThrow(this.options.redis.hset(this.stepsKey(executionId), stepName, payloadRaw));
|
|
455
|
+
if (writeError) return require_lib_errors_index.err("WorkflowError", `Unable to persist step ${stepName} for execution ${executionId}`);
|
|
456
|
+
const [stepNamesError, stepNames] = await this.readStepNames(executionId);
|
|
457
|
+
if (stepNamesError) return require_lib_errors_index.err(stepNamesError.type, stepNamesError.message);
|
|
458
|
+
if (!stepNames.includes(stepName)) {
|
|
459
|
+
const nextStepNames = [...stepNames, stepName];
|
|
460
|
+
const [serializeStepsError, serializedSteps] = require_lib_errors_index.mightThrowSync(() => JSON.stringify(nextStepNames));
|
|
461
|
+
if (serializeStepsError || typeof serializedSteps !== "string") return require_lib_errors_index.err("WorkflowSerializationError", `Unable to persist step history for execution ${executionId}`);
|
|
462
|
+
const [updateStepsError] = await this.setMeta(executionId, "steps", serializedSteps);
|
|
463
|
+
if (updateStepsError) return require_lib_errors_index.err(updateStepsError.type, updateStepsError.message);
|
|
464
|
+
}
|
|
465
|
+
const [updatedError] = await this.setMeta(executionId, "updatedAt", String(now()));
|
|
466
|
+
if (updatedError) return require_lib_errors_index.err(updatedError.type, updatedError.message);
|
|
467
|
+
return require_lib_errors_index.ok(null);
|
|
468
|
+
}
|
|
469
|
+
async readStepOutput(executionId, stepName) {
|
|
470
|
+
const [readError, payloadRaw] = await require_lib_errors_index.mightThrow(this.options.redis.hget(this.stepsKey(executionId), stepName));
|
|
471
|
+
if (readError) return require_lib_errors_index.err("WorkflowError", `Unable to read step ${stepName} for execution ${executionId}`);
|
|
472
|
+
if (!payloadRaw) return require_lib_errors_index.ok({
|
|
473
|
+
found: false,
|
|
474
|
+
value: null
|
|
475
|
+
});
|
|
476
|
+
if (typeof payloadRaw !== "string") return require_lib_errors_index.err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
|
|
477
|
+
const [parseError, parsed] = require_lib_errors_index.mightThrowSync(() => JSON.parse(payloadRaw));
|
|
478
|
+
if (parseError || parsed === null || typeof parsed !== "object") return require_lib_errors_index.err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
|
|
479
|
+
if (typeof parsed.output !== "string") return require_lib_errors_index.err("WorkflowStateError", `Invalid step output for ${stepName} in execution ${executionId}`);
|
|
480
|
+
const outputRaw = parsed.output;
|
|
481
|
+
const [deserializeError, value] = this.deserializeStepOutput(outputRaw);
|
|
482
|
+
if (deserializeError) return require_lib_errors_index.err(deserializeError.type, deserializeError.message);
|
|
483
|
+
return require_lib_errors_index.ok({
|
|
484
|
+
found: true,
|
|
485
|
+
value
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
async readStepNames(executionId) {
|
|
489
|
+
const [readError, stepsRaw] = await this.getMeta(executionId, "steps");
|
|
490
|
+
if (readError) return [readError, []];
|
|
491
|
+
if (!stepsRaw) return require_lib_errors_index.ok([]);
|
|
492
|
+
const [parseError, values] = require_lib_errors_index.mightThrowSync(() => JSON.parse(stepsRaw));
|
|
493
|
+
if (parseError || !Array.isArray(values)) return require_lib_errors_index.err("WorkflowStateError", `Invalid step index for execution ${executionId}`);
|
|
494
|
+
const stepNames = [];
|
|
495
|
+
for (const value of values) if (typeof value === "string") stepNames.push(value);
|
|
496
|
+
return require_lib_errors_index.ok(stepNames);
|
|
497
|
+
}
|
|
498
|
+
async readStepSnapshots(executionId) {
|
|
499
|
+
const [stepNamesError, stepNames] = await this.readStepNames(executionId);
|
|
500
|
+
if (stepNamesError) return [stepNamesError, []];
|
|
501
|
+
const steps = [];
|
|
502
|
+
for (const stepName of stepNames) {
|
|
503
|
+
const [readError, payloadRaw] = await require_lib_errors_index.mightThrow(this.options.redis.hget(this.stepsKey(executionId), stepName));
|
|
504
|
+
if (readError) return require_lib_errors_index.err("WorkflowError", `Unable to read step ${stepName} for execution ${executionId}`);
|
|
505
|
+
if (!payloadRaw) continue;
|
|
506
|
+
if (typeof payloadRaw !== "string") return require_lib_errors_index.err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
|
|
507
|
+
const [parseError, parsed] = require_lib_errors_index.mightThrowSync(() => JSON.parse(payloadRaw));
|
|
508
|
+
if (parseError || parsed === null || typeof parsed !== "object") return require_lib_errors_index.err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
|
|
509
|
+
if (typeof parsed.completedAt !== "number") return require_lib_errors_index.err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
|
|
510
|
+
const completedAt = parsed.completedAt;
|
|
511
|
+
steps.push({
|
|
512
|
+
name: stepName,
|
|
513
|
+
completedAt
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return require_lib_errors_index.ok(steps);
|
|
517
|
+
}
|
|
518
|
+
normalizeStatus(value) {
|
|
519
|
+
for (const status of knownStatuses) if (status === value) return status;
|
|
520
|
+
return null;
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
const defineWorkflow = (options) => {
|
|
524
|
+
const workflow = new WorkflowDefinition(options);
|
|
525
|
+
return {
|
|
526
|
+
start: (input, startOptions) => workflow.start(input, startOptions),
|
|
527
|
+
run: (input, startOptions) => workflow.run(input, startOptions),
|
|
528
|
+
resume: (executionId) => workflow.resume(executionId),
|
|
529
|
+
get: (executionId) => workflow.get(executionId),
|
|
530
|
+
cancel: (executionId) => workflow.cancel(executionId)
|
|
531
|
+
};
|
|
532
|
+
};
|
|
533
|
+
//#endregion
|
|
534
|
+
exports.defineWorkflow = defineWorkflow;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { StepHandler, Workflow, WorkflowError, WorkflowExecution, WorkflowHandlerContext, WorkflowMeta, WorkflowMetaField, WorkflowOptions, WorkflowStartOptions, WorkflowStartResult, WorkflowStatus } from "../../workflow/types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/workflow/index.d.ts
|
|
4
|
+
declare const defineWorkflow: <TInput, TResult = void>(options: WorkflowOptions<TInput, TResult>) => Workflow<TInput, TResult>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { type StepHandler, type Workflow, type WorkflowError, type WorkflowExecution, type WorkflowHandlerContext, type WorkflowMeta, type WorkflowMetaField, type WorkflowOptions, type WorkflowStartOptions, type WorkflowStartResult, type WorkflowStatus, defineWorkflow };
|
|
7
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../src/lib/workflow/index.ts"],"mappings":";;;cAq0Ca,cAAA,2BACX,OAAA,EAAS,eAAA,CAAgB,MAAA,EAAQ,OAAA,MAChC,QAAA,CAAS,MAAA,EAAQ,OAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { StepHandler, Workflow, WorkflowError, WorkflowExecution, WorkflowHandlerContext, WorkflowMeta, WorkflowMetaField, WorkflowOptions, WorkflowStartOptions, WorkflowStartResult, WorkflowStatus } from "../../workflow/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/lib/workflow/index.d.ts
|
|
4
|
+
declare const defineWorkflow: <TInput, TResult = void>(options: WorkflowOptions<TInput, TResult>) => Workflow<TInput, TResult>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { type StepHandler, type Workflow, type WorkflowError, type WorkflowExecution, type WorkflowHandlerContext, type WorkflowMeta, type WorkflowMetaField, type WorkflowOptions, type WorkflowStartOptions, type WorkflowStartResult, type WorkflowStatus, defineWorkflow };
|
|
7
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../src/lib/workflow/index.ts"],"mappings":";;;cAq0Ca,cAAA,2BACX,OAAA,EAAS,eAAA,CAAgB,MAAA,EAAQ,OAAA,MAChC,QAAA,CAAS,MAAA,EAAQ,OAAA"}
|