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.
Files changed (262) hide show
  1. package/README.md +88 -13
  2. package/dist/cron/builder/index.cjs +166 -0
  3. package/dist/cron/builder/index.d.cts +28 -0
  4. package/dist/cron/builder/index.d.cts.map +1 -0
  5. package/dist/cron/builder/index.d.mts +28 -0
  6. package/dist/cron/builder/index.d.mts.map +1 -0
  7. package/dist/cron/builder/index.mjs +163 -0
  8. package/dist/cron/builder/index.mjs.map +1 -0
  9. package/dist/cron/builder/types.cjs +27 -0
  10. package/dist/cron/builder/types.d.cts +79 -0
  11. package/dist/cron/builder/types.d.cts.map +1 -0
  12. package/dist/cron/builder/types.d.mts +79 -0
  13. package/dist/cron/builder/types.d.mts.map +1 -0
  14. package/dist/cron/builder/types.mjs +28 -0
  15. package/dist/cron/builder/types.mjs.map +1 -0
  16. package/dist/cron/core/index.cjs +308 -0
  17. package/dist/cron/core/index.d.cts +39 -0
  18. package/dist/cron/core/index.d.cts.map +1 -0
  19. package/dist/cron/core/index.d.mts +39 -0
  20. package/dist/cron/core/index.d.mts.map +1 -0
  21. package/dist/cron/core/index.mjs +310 -0
  22. package/dist/cron/core/index.mjs.map +1 -0
  23. package/dist/cron/{scanner.cjs → core/scanner.cjs} +2 -2
  24. package/dist/cron/{scanner.mjs → core/scanner.mjs} +2 -2
  25. package/dist/cron/core/scanner.mjs.map +1 -0
  26. package/dist/cron/{types.d.cts → core/types.d.cts} +1 -1
  27. package/dist/cron/core/types.d.cts.map +1 -0
  28. package/dist/cron/{types.d.mts → core/types.d.mts} +1 -1
  29. package/dist/cron/core/types.d.mts.map +1 -0
  30. package/dist/errors/types.d.cts +1 -1
  31. package/dist/errors/types.d.mts +1 -1
  32. package/dist/lib/cache/index.d.cts +3 -3
  33. package/dist/lib/cache/index.d.mts +3 -3
  34. package/dist/lib/cron/index.cjs +12 -275
  35. package/dist/lib/cron/index.d.cts +4 -39
  36. package/dist/lib/cron/index.d.mts +4 -39
  37. package/dist/lib/cron/index.mjs +4 -277
  38. package/dist/lib/errors/index.d.cts +2 -2
  39. package/dist/lib/errors/index.d.cts.map +1 -1
  40. package/dist/lib/errors/index.d.mts +2 -2
  41. package/dist/lib/errors/index.d.mts.map +1 -1
  42. package/dist/lib/errors/index.mjs.map +1 -1
  43. package/dist/lib/i18n/index.cjs +6 -1
  44. package/dist/lib/i18n/index.d.cts.map +1 -1
  45. package/dist/lib/i18n/index.d.mts.map +1 -1
  46. package/dist/lib/i18n/index.mjs +6 -1
  47. package/dist/lib/i18n/index.mjs.map +1 -1
  48. package/dist/lib/logging/index.cjs +18 -0
  49. package/dist/lib/logging/index.d.cts +7 -0
  50. package/dist/lib/logging/index.d.mts +7 -0
  51. package/dist/lib/logging/index.mjs +5 -0
  52. package/dist/lib/orm/index.cjs +20 -0
  53. package/dist/lib/orm/index.d.cts +7 -0
  54. package/dist/lib/orm/index.d.mts +7 -0
  55. package/dist/lib/orm/index.mjs +6 -0
  56. package/dist/lib/prompts/index.d.cts +8 -8
  57. package/dist/lib/prompts/index.d.mts +8 -8
  58. package/dist/lib/pubsub/index.cjs +82 -13
  59. package/dist/lib/pubsub/index.d.cts +14 -5
  60. package/dist/lib/pubsub/index.d.cts.map +1 -1
  61. package/dist/lib/pubsub/index.d.mts +14 -5
  62. package/dist/lib/pubsub/index.d.mts.map +1 -1
  63. package/dist/lib/pubsub/index.mjs +82 -13
  64. package/dist/lib/pubsub/index.mjs.map +1 -1
  65. package/dist/lib/queue/index.d.cts +2 -2
  66. package/dist/lib/queue/index.d.mts +2 -2
  67. package/dist/lib/workflow/index.cjs +534 -0
  68. package/dist/lib/workflow/index.d.cts +7 -0
  69. package/dist/lib/workflow/index.d.cts.map +1 -0
  70. package/dist/lib/workflow/index.d.mts +7 -0
  71. package/dist/lib/workflow/index.d.mts.map +1 -0
  72. package/dist/lib/workflow/index.mjs +535 -0
  73. package/dist/lib/workflow/index.mjs.map +1 -0
  74. package/dist/logging/core/index.cjs +99 -0
  75. package/dist/logging/core/index.d.cts +26 -0
  76. package/dist/logging/core/index.d.cts.map +1 -0
  77. package/dist/logging/core/index.d.mts +26 -0
  78. package/dist/logging/core/index.d.mts.map +1 -0
  79. package/dist/logging/core/index.mjs +99 -0
  80. package/dist/logging/core/index.mjs.map +1 -0
  81. package/dist/logging/core/types.cjs +10 -0
  82. package/dist/logging/core/types.d.cts +22 -0
  83. package/dist/logging/core/types.d.cts.map +1 -0
  84. package/dist/logging/core/types.d.mts +22 -0
  85. package/dist/logging/core/types.d.mts.map +1 -0
  86. package/dist/logging/core/types.mjs +12 -0
  87. package/dist/logging/core/types.mjs.map +1 -0
  88. package/dist/logging/formatter/index.cjs +119 -0
  89. package/dist/logging/formatter/index.d.cts +27 -0
  90. package/dist/logging/formatter/index.d.cts.map +1 -0
  91. package/dist/logging/formatter/index.d.mts +27 -0
  92. package/dist/logging/formatter/index.d.mts.map +1 -0
  93. package/dist/logging/formatter/index.mjs +115 -0
  94. package/dist/logging/formatter/index.mjs.map +1 -0
  95. package/dist/logging/formatter/types.d.cts +5 -0
  96. package/dist/logging/formatter/types.d.cts.map +1 -0
  97. package/dist/logging/formatter/types.d.mts +5 -0
  98. package/dist/logging/formatter/types.d.mts.map +1 -0
  99. package/dist/logging/provider/index.cjs +165 -0
  100. package/dist/logging/provider/index.d.cts +28 -0
  101. package/dist/logging/provider/index.d.cts.map +1 -0
  102. package/dist/logging/provider/index.d.mts +28 -0
  103. package/dist/logging/provider/index.d.mts.map +1 -0
  104. package/dist/logging/provider/index.mjs +165 -0
  105. package/dist/logging/provider/index.mjs.map +1 -0
  106. package/dist/logging/provider/types.d.cts +23 -0
  107. package/dist/logging/provider/types.d.cts.map +1 -0
  108. package/dist/logging/provider/types.d.mts +23 -0
  109. package/dist/logging/provider/types.d.mts.map +1 -0
  110. package/dist/orm/column.cjs +137 -0
  111. package/dist/orm/column.d.cts +121 -0
  112. package/dist/orm/column.d.cts.map +1 -0
  113. package/dist/orm/column.d.mts +121 -0
  114. package/dist/orm/column.d.mts.map +1 -0
  115. package/dist/orm/column.mjs +132 -0
  116. package/dist/orm/column.mjs.map +1 -0
  117. package/dist/orm/dialect/index.cjs +14 -0
  118. package/dist/orm/dialect/index.mjs +16 -0
  119. package/dist/orm/dialect/index.mjs.map +1 -0
  120. package/dist/orm/dialect/mysql.cjs +31 -0
  121. package/dist/orm/dialect/mysql.mjs +33 -0
  122. package/dist/orm/dialect/mysql.mjs.map +1 -0
  123. package/dist/orm/dialect/postgres.cjs +23 -0
  124. package/dist/orm/dialect/postgres.mjs +25 -0
  125. package/dist/orm/dialect/postgres.mjs.map +1 -0
  126. package/dist/orm/dialect/sqlite.cjs +31 -0
  127. package/dist/orm/dialect/sqlite.mjs +33 -0
  128. package/dist/orm/dialect/sqlite.mjs.map +1 -0
  129. package/dist/orm/dialect/utils.cjs +8 -0
  130. package/dist/orm/dialect/utils.mjs +10 -0
  131. package/dist/orm/dialect/utils.mjs.map +1 -0
  132. package/dist/orm/internal/table-columns.cjs +31 -0
  133. package/dist/orm/internal/table-columns.mjs +32 -0
  134. package/dist/orm/internal/table-columns.mjs.map +1 -0
  135. package/dist/orm/internal/table-lookup.cjs +35 -0
  136. package/dist/orm/internal/table-lookup.mjs +35 -0
  137. package/dist/orm/internal/table-lookup.mjs.map +1 -0
  138. package/dist/orm/internal/table-relations.cjs +28 -0
  139. package/dist/orm/internal/table-relations.mjs +29 -0
  140. package/dist/orm/internal/table-relations.mjs.map +1 -0
  141. package/dist/orm/migration/config.cjs +7 -0
  142. package/dist/orm/migration/config.d.cts +7 -0
  143. package/dist/orm/migration/config.d.cts.map +1 -0
  144. package/dist/orm/migration/config.d.mts +7 -0
  145. package/dist/orm/migration/config.d.mts.map +1 -0
  146. package/dist/orm/migration/config.mjs +8 -0
  147. package/dist/orm/migration/config.mjs.map +1 -0
  148. package/dist/orm/migration/types.d.cts +20 -0
  149. package/dist/orm/migration/types.d.cts.map +1 -0
  150. package/dist/orm/migration/types.d.mts +20 -0
  151. package/dist/orm/migration/types.d.mts.map +1 -0
  152. package/dist/orm/orm.cjs +41 -0
  153. package/dist/orm/orm.d.cts +18 -0
  154. package/dist/orm/orm.d.cts.map +1 -0
  155. package/dist/orm/orm.d.mts +18 -0
  156. package/dist/orm/orm.d.mts.map +1 -0
  157. package/dist/orm/orm.mjs +43 -0
  158. package/dist/orm/orm.mjs.map +1 -0
  159. package/dist/orm/relation.cjs +18 -0
  160. package/dist/orm/relation.d.cts +8 -0
  161. package/dist/orm/relation.d.cts.map +1 -0
  162. package/dist/orm/relation.d.mts +8 -0
  163. package/dist/orm/relation.d.mts.map +1 -0
  164. package/dist/orm/relation.mjs +19 -0
  165. package/dist/orm/relation.mjs.map +1 -0
  166. package/dist/orm/runtime/builders/mutations.cjs +29 -0
  167. package/dist/orm/runtime/builders/mutations.mjs +28 -0
  168. package/dist/orm/runtime/builders/mutations.mjs.map +1 -0
  169. package/dist/orm/runtime/builders/select.cjs +18 -0
  170. package/dist/orm/runtime/builders/select.mjs +19 -0
  171. package/dist/orm/runtime/builders/select.mjs.map +1 -0
  172. package/dist/orm/runtime/client.cjs +90 -0
  173. package/dist/orm/runtime/client.mjs +92 -0
  174. package/dist/orm/runtime/client.mjs.map +1 -0
  175. package/dist/orm/runtime/context.cjs +49 -0
  176. package/dist/orm/runtime/context.mjs +51 -0
  177. package/dist/orm/runtime/context.mjs.map +1 -0
  178. package/dist/orm/runtime/dialect/index.cjs +11 -0
  179. package/dist/orm/runtime/dialect/index.mjs +13 -0
  180. package/dist/orm/runtime/dialect/index.mjs.map +1 -0
  181. package/dist/orm/runtime/dialect/mysql.cjs +95 -0
  182. package/dist/orm/runtime/dialect/mysql.mjs +97 -0
  183. package/dist/orm/runtime/dialect/mysql.mjs.map +1 -0
  184. package/dist/orm/runtime/dialect/postgres.cjs +51 -0
  185. package/dist/orm/runtime/dialect/postgres.mjs +53 -0
  186. package/dist/orm/runtime/dialect/postgres.mjs.map +1 -0
  187. package/dist/orm/runtime/dialect/sqlite.cjs +4 -0
  188. package/dist/orm/runtime/dialect/sqlite.mjs +7 -0
  189. package/dist/orm/runtime/dialect/sqlite.mjs.map +1 -0
  190. package/dist/orm/runtime/errors.cjs +19 -0
  191. package/dist/orm/runtime/errors.mjs +21 -0
  192. package/dist/orm/runtime/errors.mjs.map +1 -0
  193. package/dist/orm/runtime/hydrate/many.cjs +46 -0
  194. package/dist/orm/runtime/hydrate/many.mjs +48 -0
  195. package/dist/orm/runtime/hydrate/many.mjs.map +1 -0
  196. package/dist/orm/runtime/hydrate/one.cjs +38 -0
  197. package/dist/orm/runtime/hydrate/one.mjs +40 -0
  198. package/dist/orm/runtime/hydrate/one.mjs.map +1 -0
  199. package/dist/orm/runtime/hydrate.cjs +49 -0
  200. package/dist/orm/runtime/hydrate.mjs +51 -0
  201. package/dist/orm/runtime/hydrate.mjs.map +1 -0
  202. package/dist/orm/runtime/rows.cjs +30 -0
  203. package/dist/orm/runtime/rows.mjs +31 -0
  204. package/dist/orm/runtime/rows.mjs.map +1 -0
  205. package/dist/orm/runtime/utils.cjs +27 -0
  206. package/dist/orm/runtime/utils.mjs +27 -0
  207. package/dist/orm/runtime/utils.mjs.map +1 -0
  208. package/dist/orm/sql/parse-array.cjs +64 -0
  209. package/dist/orm/sql/parse-array.mjs +66 -0
  210. package/dist/orm/sql/parse-array.mjs.map +1 -0
  211. package/dist/orm/sql/plan/select.cjs +36 -0
  212. package/dist/orm/sql/plan/select.mjs +38 -0
  213. package/dist/orm/sql/plan/select.mjs.map +1 -0
  214. package/dist/orm/sql/plan/where/operators.cjs +95 -0
  215. package/dist/orm/sql/plan/where/operators.mjs +97 -0
  216. package/dist/orm/sql/plan/where/operators.mjs.map +1 -0
  217. package/dist/orm/sql/plan/where.cjs +59 -0
  218. package/dist/orm/sql/plan/where.mjs +61 -0
  219. package/dist/orm/sql/plan/where.mjs.map +1 -0
  220. package/dist/orm/sql/serialize/clauses.cjs +36 -0
  221. package/dist/orm/sql/serialize/clauses.mjs +37 -0
  222. package/dist/orm/sql/serialize/clauses.mjs.map +1 -0
  223. package/dist/orm/sql/serialize/joins.cjs +31 -0
  224. package/dist/orm/sql/serialize/joins.mjs +33 -0
  225. package/dist/orm/sql/serialize/joins.mjs.map +1 -0
  226. package/dist/orm/sql/serialize/values.cjs +30 -0
  227. package/dist/orm/sql/serialize/values.mjs +32 -0
  228. package/dist/orm/sql/serialize/values.mjs.map +1 -0
  229. package/dist/orm/sql/serialize/where/predicate.cjs +73 -0
  230. package/dist/orm/sql/serialize/where/predicate.mjs +75 -0
  231. package/dist/orm/sql/serialize/where/predicate.mjs.map +1 -0
  232. package/dist/orm/sql/serialize/where/tree.cjs +26 -0
  233. package/dist/orm/sql/serialize/where/tree.mjs +28 -0
  234. package/dist/orm/sql/serialize/where/tree.mjs.map +1 -0
  235. package/dist/orm/sql/serialize/where.cjs +10 -0
  236. package/dist/orm/sql/serialize/where.mjs +12 -0
  237. package/dist/orm/sql/serialize/where.mjs.map +1 -0
  238. package/dist/orm/sql/serialize.cjs +24 -0
  239. package/dist/orm/sql/serialize.mjs +25 -0
  240. package/dist/orm/sql/serialize.mjs.map +1 -0
  241. package/dist/orm/table.cjs +12 -0
  242. package/dist/orm/table.d.cts +12 -0
  243. package/dist/orm/table.d.cts.map +1 -0
  244. package/dist/orm/table.d.mts +12 -0
  245. package/dist/orm/table.d.mts.map +1 -0
  246. package/dist/orm/table.mjs +14 -0
  247. package/dist/orm/table.mjs.map +1 -0
  248. package/dist/orm/types.d.cts +183 -0
  249. package/dist/orm/types.d.cts.map +1 -0
  250. package/dist/orm/types.d.mts +183 -0
  251. package/dist/orm/types.d.mts.map +1 -0
  252. package/dist/workflow/types.d.cts +83 -0
  253. package/dist/workflow/types.d.cts.map +1 -0
  254. package/dist/workflow/types.d.mts +83 -0
  255. package/dist/workflow/types.d.mts.map +1 -0
  256. package/package.json +29 -3
  257. package/dist/cron/scanner.mjs.map +0 -1
  258. package/dist/cron/types.d.cts.map +0 -1
  259. package/dist/cron/types.d.mts.map +0 -1
  260. package/dist/lib/cron/index.d.cts.map +0 -1
  261. package/dist/lib/cron/index.d.mts.map +0 -1
  262. package/dist/lib/cron/index.mjs.map +0 -1
@@ -0,0 +1,535 @@
1
+ import { err, mightThrow, mightThrowSync, ok } from "../errors/index.mjs";
2
+ //#region src/lib/workflow/index.ts
3
+ const DEFAULT_LOCK_TTL = 300 * 1e3;
4
+ const now = () => Date.now();
5
+ const toErrorMessage = (error) => {
6
+ if (error instanceof Error) return error.message;
7
+ return String(error);
8
+ };
9
+ const envelopeSerialize = (value) => {
10
+ return JSON.stringify({ value });
11
+ };
12
+ const envelopeDeserialize = (raw) => {
13
+ const [parseError, parsed] = mightThrowSync(() => JSON.parse(raw));
14
+ if (parseError) throw parseError;
15
+ if (parsed === null) return;
16
+ if (typeof parsed !== "object") return;
17
+ if ("value" in parsed) return parsed.value;
18
+ };
19
+ const knownStatuses = [
20
+ "pending",
21
+ "running",
22
+ "completed",
23
+ "failed",
24
+ "cancelled"
25
+ ];
26
+ var WorkflowDefinition = class {
27
+ options;
28
+ lockTTL;
29
+ constructor(options) {
30
+ this.options = options;
31
+ this.lockTTL = options.lockTTL ?? DEFAULT_LOCK_TTL;
32
+ }
33
+ async start(input, options) {
34
+ const executionId = options?.executionId ?? crypto.randomUUID();
35
+ const [createError] = await this.createExecution(executionId, input);
36
+ if (createError) return err(createError.type, createError.message);
37
+ return this.execute(executionId, input);
38
+ }
39
+ async run(input, options) {
40
+ const [startError, startData] = await this.start(input, options);
41
+ if (startError) return err(startError.type, startError.message);
42
+ if (!startData) return err("WorkflowError", "Unexpected empty start result");
43
+ if (startData.status === "cancelled") return err("WorkflowCancelledError", `Workflow execution ${startData.executionId} was cancelled`);
44
+ if (startData.status !== "completed") return err("WorkflowExecutionError", `Workflow execution ${startData.executionId} did not complete`);
45
+ const [getError, execution] = await this.get(startData.executionId);
46
+ if (getError) return err(getError.type, getError.message);
47
+ if (!execution) return err("WorkflowError", "Unexpected empty execution");
48
+ return ok(execution.result);
49
+ }
50
+ async resume(executionId) {
51
+ const [getError, execution] = await this.get(executionId);
52
+ if (getError) return err(getError.type, getError.message);
53
+ if (!execution) return err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
54
+ if (execution.status === "completed") return ok({
55
+ executionId,
56
+ status: execution.status
57
+ });
58
+ if (execution.status === "cancelled") return ok({
59
+ executionId,
60
+ status: execution.status
61
+ });
62
+ return this.execute(executionId, execution.input);
63
+ }
64
+ async get(executionId) {
65
+ const [statusError, status] = await this.getMeta(executionId, "status");
66
+ if (statusError) return err(statusError.type, statusError.message);
67
+ if (!status) return err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
68
+ const normalizedStatus = this.normalizeStatus(status);
69
+ if (!normalizedStatus) return err("WorkflowStateError", `Workflow execution ${executionId} has invalid status ${status}`);
70
+ const [inputError, input] = await this.readInput(executionId);
71
+ if (inputError) return err(inputError.type, inputError.message);
72
+ if (input === null) return err("WorkflowStateError", `Workflow execution ${executionId} has invalid input`);
73
+ const [resultError, result] = await this.readResult(executionId);
74
+ if (resultError) return err(resultError.type, resultError.message);
75
+ const [stepsError, steps] = await this.readStepSnapshots(executionId);
76
+ if (stepsError) return err(stepsError.type, stepsError.message);
77
+ const [createdAtError, createdAt] = await this.readNumberMeta(executionId, "createdAt");
78
+ if (createdAtError) return err(createdAtError.type, createdAtError.message);
79
+ if (createdAt === null) return err("WorkflowStateError", `Workflow execution ${executionId} is missing createdAt`);
80
+ const [updatedAtError, updatedAt] = await this.readNumberMeta(executionId, "updatedAt");
81
+ if (updatedAtError) return err(updatedAtError.type, updatedAtError.message);
82
+ if (updatedAt === null) return err("WorkflowStateError", `Workflow execution ${executionId} is missing updatedAt`);
83
+ const [metaError, errorMessage] = await this.getMeta(executionId, "error");
84
+ if (metaError) return err(metaError.type, metaError.message);
85
+ const [completedAtError, completedAt] = await this.readNumberMeta(executionId, "completedAt");
86
+ if (completedAtError) return err(completedAtError.type, completedAtError.message);
87
+ const [failedAtError, failedAt] = await this.readNumberMeta(executionId, "failedAt");
88
+ if (failedAtError) return err(failedAtError.type, failedAtError.message);
89
+ const [cancelledAtError, cancelledAt] = await this.readNumberMeta(executionId, "cancelledAt");
90
+ if (cancelledAtError) return err(cancelledAtError.type, cancelledAtError.message);
91
+ return ok({
92
+ id: executionId,
93
+ name: this.options.name,
94
+ status: normalizedStatus,
95
+ input,
96
+ result,
97
+ error: errorMessage,
98
+ createdAt,
99
+ updatedAt,
100
+ completedAt,
101
+ failedAt,
102
+ cancelledAt,
103
+ steps
104
+ });
105
+ }
106
+ async cancel(executionId) {
107
+ const [getError, execution] = await this.get(executionId);
108
+ if (getError) return err(getError.type, getError.message);
109
+ if (!execution) return err("WorkflowNotFoundError", `Workflow execution ${executionId} not found`);
110
+ if (execution.status === "completed") return err("WorkflowStateError", `Workflow execution ${executionId} is already completed`);
111
+ const timestamp = now();
112
+ const [statusError] = await this.setMeta(executionId, "status", "cancelled");
113
+ if (statusError) return err(statusError.type, statusError.message);
114
+ const [updatedAtError] = await this.setMeta(executionId, "updatedAt", String(timestamp));
115
+ if (updatedAtError) return err(updatedAtError.type, updatedAtError.message);
116
+ const [cancelledAtError] = await this.setMeta(executionId, "cancelledAt", String(timestamp));
117
+ if (cancelledAtError) return err(cancelledAtError.type, cancelledAtError.message);
118
+ const [clearErrorError] = await this.setMeta(executionId, "error", "");
119
+ if (clearErrorError) return err(clearErrorError.type, clearErrorError.message);
120
+ const [clearFailedAtError] = await this.setMeta(executionId, "failedAt", "");
121
+ if (clearFailedAtError) return err(clearFailedAtError.type, clearFailedAtError.message);
122
+ return ok({
123
+ executionId,
124
+ createdAt: execution.createdAt,
125
+ cancelledAt: timestamp,
126
+ updatedAt: timestamp,
127
+ status: "cancelled"
128
+ });
129
+ }
130
+ executionKey(executionId) {
131
+ return `workflow:${this.options.name}:execution:${executionId}`;
132
+ }
133
+ metaKey(executionId) {
134
+ return `${this.executionKey(executionId)}:meta`;
135
+ }
136
+ stepsKey(executionId) {
137
+ return `${this.executionKey(executionId)}:steps`;
138
+ }
139
+ lockKey(executionId) {
140
+ return `${this.executionKey(executionId)}:lock`;
141
+ }
142
+ async createExecution(executionId, input) {
143
+ const [serializeError, serializedInput] = this.serializeInput(input);
144
+ if (serializeError) return err("WorkflowSerializationError", `Unable to serialize workflow input for ${executionId}`);
145
+ const timestamp = now();
146
+ const [statusReadError, existingStatus] = await this.getMeta(executionId, "status");
147
+ if (statusReadError) return err(statusReadError.type, statusReadError.message);
148
+ if (existingStatus) return err("WorkflowStateError", `Workflow execution ${executionId} already exists`);
149
+ const metadata = {
150
+ status: "pending",
151
+ input: serializedInput,
152
+ result: "",
153
+ error: "",
154
+ createdAt: String(timestamp),
155
+ updatedAt: String(timestamp),
156
+ completedAt: "",
157
+ failedAt: "",
158
+ cancelledAt: "",
159
+ steps: "[]"
160
+ };
161
+ const [writeError] = await mightThrow(this.options.redis.hset(this.metaKey(executionId), metadata));
162
+ if (writeError) return err("WorkflowError", `Unable to persist metadata for execution ${executionId}`);
163
+ return ok(null);
164
+ }
165
+ async execute(executionId, input) {
166
+ const token = crypto.randomUUID();
167
+ const [lockError] = await this.acquireLock(executionId, token);
168
+ if (lockError) return err(lockError.type, lockError.message);
169
+ const [statusCheckError, currentStatus] = await this.getMeta(executionId, "status");
170
+ if (statusCheckError) {
171
+ await this.releaseLock(executionId, token);
172
+ return err(statusCheckError.type, statusCheckError.message);
173
+ }
174
+ if (currentStatus === "cancelled") {
175
+ await this.releaseLock(executionId, token);
176
+ return err("WorkflowStateError", `Workflow execution ${executionId} was cancelled`);
177
+ }
178
+ const timestamp = now();
179
+ const [runningStatusError] = await this.setMeta(executionId, "status", "running");
180
+ if (runningStatusError) {
181
+ await this.releaseLock(executionId, token);
182
+ return err(runningStatusError.type, runningStatusError.message);
183
+ }
184
+ const [runningUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(timestamp));
185
+ if (runningUpdatedAtError) {
186
+ await this.releaseLock(executionId, token);
187
+ return err(runningUpdatedAtError.type, runningUpdatedAtError.message);
188
+ }
189
+ const controller = new AbortController();
190
+ const renewInterval = Math.floor(this.lockTTL / 3);
191
+ let lockLost = false;
192
+ const renewTimer = setInterval(async () => {
193
+ const [renewError] = await this.extendLock(executionId, token);
194
+ if (renewError) {
195
+ lockLost = true;
196
+ controller.abort();
197
+ clearInterval(renewTimer);
198
+ }
199
+ }, renewInterval);
200
+ const step = async (name, handler) => {
201
+ const [cancelledError, cancelled] = await this.isCancelled(executionId);
202
+ if (cancelledError) return Promise.reject(new Error(cancelledError.message));
203
+ if (cancelled) {
204
+ controller.abort();
205
+ return Promise.reject(/* @__PURE__ */ new Error("Workflow cancelled"));
206
+ }
207
+ const [readError, cachedStep] = await this.readStepOutput(executionId, name);
208
+ if (readError) return Promise.reject(new Error(readError.message));
209
+ if (cachedStep.found) return cachedStep.value;
210
+ const [stepError, output] = await mightThrow(Promise.resolve(handler(input, controller.signal)));
211
+ if (stepError) return Promise.reject(stepError);
212
+ const [writeError] = await this.writeStepOutput(executionId, name, output);
213
+ if (writeError) return Promise.reject(new Error(writeError.message));
214
+ return output;
215
+ };
216
+ const [handlerError, result] = await mightThrow(Promise.resolve(this.options.handler({
217
+ input,
218
+ executionId,
219
+ signal: controller.signal,
220
+ step
221
+ })));
222
+ clearInterval(renewTimer);
223
+ if (lockLost) {
224
+ await this.releaseLock(executionId, token);
225
+ return err("WorkflowLockError", `Lock expired during execution ${executionId}`);
226
+ }
227
+ const [cancelledError, cancelled] = await this.isCancelled(executionId);
228
+ if (cancelledError) {
229
+ await this.releaseLock(executionId, token);
230
+ return err(cancelledError.type, cancelledError.message);
231
+ }
232
+ if (cancelled) {
233
+ const cancelledAt = now();
234
+ const [cancelledStatusError] = await this.setMeta(executionId, "status", "cancelled");
235
+ if (cancelledStatusError) {
236
+ await this.releaseLock(executionId, token);
237
+ return err(cancelledStatusError.type, cancelledStatusError.message);
238
+ }
239
+ const [cancelledUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(cancelledAt));
240
+ if (cancelledUpdatedAtError) {
241
+ await this.releaseLock(executionId, token);
242
+ return err(cancelledUpdatedAtError.type, cancelledUpdatedAtError.message);
243
+ }
244
+ const [cancelledAtError] = await this.setMeta(executionId, "cancelledAt", String(cancelledAt));
245
+ if (cancelledAtError) {
246
+ await this.releaseLock(executionId, token);
247
+ return err(cancelledAtError.type, cancelledAtError.message);
248
+ }
249
+ await this.releaseLock(executionId, token);
250
+ return ok({
251
+ executionId,
252
+ status: "cancelled"
253
+ });
254
+ }
255
+ if (handlerError) {
256
+ const failedAt = now();
257
+ const [failedStatusError] = await this.setMeta(executionId, "status", "failed");
258
+ if (failedStatusError) {
259
+ await this.releaseLock(executionId, token);
260
+ return err(failedStatusError.type, failedStatusError.message);
261
+ }
262
+ const [failedMessageError] = await this.setMeta(executionId, "error", toErrorMessage(handlerError));
263
+ if (failedMessageError) {
264
+ await this.releaseLock(executionId, token);
265
+ return err(failedMessageError.type, failedMessageError.message);
266
+ }
267
+ const [failedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(failedAt));
268
+ if (failedUpdatedAtError) {
269
+ await this.releaseLock(executionId, token);
270
+ return err(failedUpdatedAtError.type, failedUpdatedAtError.message);
271
+ }
272
+ const [failedAtError] = await this.setMeta(executionId, "failedAt", String(failedAt));
273
+ if (failedAtError) {
274
+ await this.releaseLock(executionId, token);
275
+ return err(failedAtError.type, failedAtError.message);
276
+ }
277
+ await this.releaseLock(executionId, token);
278
+ return err("WorkflowExecutionError", `Workflow execution ${executionId} failed: ${toErrorMessage(handlerError)}`);
279
+ }
280
+ const [serializeResultError, serializedResult] = this.serializeResult(result);
281
+ if (serializeResultError) {
282
+ const failedAt = now();
283
+ const [failedStatusError] = await this.setMeta(executionId, "status", "failed");
284
+ if (failedStatusError) {
285
+ await this.releaseLock(executionId, token);
286
+ return err(failedStatusError.type, failedStatusError.message);
287
+ }
288
+ const [failedMessageError] = await this.setMeta(executionId, "error", serializeResultError.message);
289
+ if (failedMessageError) {
290
+ await this.releaseLock(executionId, token);
291
+ return err(failedMessageError.type, failedMessageError.message);
292
+ }
293
+ const [failedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(failedAt));
294
+ if (failedUpdatedAtError) {
295
+ await this.releaseLock(executionId, token);
296
+ return err(failedUpdatedAtError.type, failedUpdatedAtError.message);
297
+ }
298
+ const [failedAtError] = await this.setMeta(executionId, "failedAt", String(failedAt));
299
+ if (failedAtError) {
300
+ await this.releaseLock(executionId, token);
301
+ return err(failedAtError.type, failedAtError.message);
302
+ }
303
+ await this.releaseLock(executionId, token);
304
+ return err("WorkflowSerializationError", `Unable to serialize workflow result for ${executionId}`);
305
+ }
306
+ const completedAt = now();
307
+ const [completedResultError] = await this.setMeta(executionId, "result", serializedResult);
308
+ if (completedResultError) {
309
+ await this.releaseLock(executionId, token);
310
+ return err(completedResultError.type, completedResultError.message);
311
+ }
312
+ const [completedStatusError] = await this.setMeta(executionId, "status", "completed");
313
+ if (completedStatusError) {
314
+ await this.releaseLock(executionId, token);
315
+ return err(completedStatusError.type, completedStatusError.message);
316
+ }
317
+ const [completedClearErrorError] = await this.setMeta(executionId, "error", "");
318
+ if (completedClearErrorError) {
319
+ await this.releaseLock(executionId, token);
320
+ return err(completedClearErrorError.type, completedClearErrorError.message);
321
+ }
322
+ const [completedClearFailedAtError] = await this.setMeta(executionId, "failedAt", "");
323
+ if (completedClearFailedAtError) {
324
+ await this.releaseLock(executionId, token);
325
+ return err(completedClearFailedAtError.type, completedClearFailedAtError.message);
326
+ }
327
+ const [completedUpdatedAtError] = await this.setMeta(executionId, "updatedAt", String(completedAt));
328
+ if (completedUpdatedAtError) {
329
+ await this.releaseLock(executionId, token);
330
+ return err(completedUpdatedAtError.type, completedUpdatedAtError.message);
331
+ }
332
+ const [completedAtError] = await this.setMeta(executionId, "completedAt", String(completedAt));
333
+ if (completedAtError) {
334
+ await this.releaseLock(executionId, token);
335
+ return err(completedAtError.type, completedAtError.message);
336
+ }
337
+ await this.releaseLock(executionId, token);
338
+ return ok({
339
+ executionId,
340
+ status: "completed"
341
+ });
342
+ }
343
+ async acquireLock(executionId, token) {
344
+ const [lockError, lockResult] = await mightThrow(this.options.redis.set(this.lockKey(executionId), token, "PX", String(this.lockTTL), "NX"));
345
+ if (lockError) return err("WorkflowLockError", `Unable to acquire lock for execution ${executionId}`);
346
+ if (lockResult !== "OK") return err("WorkflowLockError", `Workflow execution ${executionId} is already running`);
347
+ return ok(null);
348
+ }
349
+ async releaseLock(executionId, token) {
350
+ const [evalError] = await mightThrow(this.options.redis.send("EVAL", [
351
+ "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end",
352
+ "1",
353
+ this.lockKey(executionId),
354
+ token
355
+ ]));
356
+ if (evalError) return err("WorkflowLockError", `Unable to release lock for execution ${executionId}`);
357
+ return ok(null);
358
+ }
359
+ async extendLock(executionId, token) {
360
+ const [evalError, result] = await mightThrow(this.options.redis.send("EVAL", [
361
+ "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end",
362
+ "1",
363
+ this.lockKey(executionId),
364
+ token,
365
+ String(this.lockTTL)
366
+ ]));
367
+ if (evalError) return err("WorkflowLockError", `Unable to extend lock for execution ${executionId}`);
368
+ if (result === 0) return err("WorkflowLockError", `Lock ownership lost for execution ${executionId}`);
369
+ return ok(null);
370
+ }
371
+ async isCancelled(executionId) {
372
+ const [statusError, status] = await this.getMeta(executionId, "status");
373
+ if (statusError) return err(statusError.type, statusError.message);
374
+ return ok(status === "cancelled");
375
+ }
376
+ async setMeta(executionId, field, value) {
377
+ const [writeError] = await mightThrow(this.options.redis.hset(this.metaKey(executionId), field, value));
378
+ if (writeError) return err("WorkflowError", `Unable to persist ${field} for execution ${executionId}`);
379
+ return ok(null);
380
+ }
381
+ async getMeta(executionId, field) {
382
+ const [readError, value] = await mightThrow(this.options.redis.hget(this.metaKey(executionId), field));
383
+ if (readError) return err("WorkflowError", `Unable to read ${field} for execution ${executionId}`);
384
+ if (value === null || value === void 0) return ok(null);
385
+ if (typeof value !== "string") return err("WorkflowStateError", `Invalid ${field} value for execution ${executionId}`);
386
+ if (value.length === 0) return ok(null);
387
+ return ok(value);
388
+ }
389
+ async readNumberMeta(executionId, field) {
390
+ const [readError, value] = await this.getMeta(executionId, field);
391
+ if (readError) return err(readError.type, readError.message);
392
+ if (!value) return ok(null);
393
+ const parsed = Number(value);
394
+ if (!Number.isFinite(parsed)) return err("WorkflowStateError", `Invalid ${field} value for execution ${executionId}`);
395
+ return ok(parsed);
396
+ }
397
+ runSerializer(value, serializer, label) {
398
+ const [serializeError, serialized] = mightThrowSync(() => serializer(value));
399
+ if (serializeError) return err("WorkflowSerializationError", `Unable to serialize ${label}: ${toErrorMessage(serializeError)}`);
400
+ if (typeof serialized !== "string") return err("WorkflowSerializationError", `${label} serializer must return a string`);
401
+ return ok(serialized);
402
+ }
403
+ runDeserializer(raw, deserializer, label) {
404
+ const [deserializeError, value] = mightThrowSync(() => deserializer(raw));
405
+ if (deserializeError) return err("WorkflowSerializationError", `Unable to deserialize ${label}: ${toErrorMessage(deserializeError)}`);
406
+ return ok(value);
407
+ }
408
+ serializeInput(input) {
409
+ return this.runSerializer(input, this.options.serializeInput ?? envelopeSerialize, "workflow input");
410
+ }
411
+ deserializeInput(raw) {
412
+ const deserializer = this.options.deserializeInput ?? ((value) => envelopeDeserialize(value));
413
+ return this.runDeserializer(raw, deserializer, "workflow input");
414
+ }
415
+ serializeResult(result) {
416
+ if (result === null) return ok(envelopeSerialize(null));
417
+ return this.runSerializer(result, this.options.serializeResult ?? envelopeSerialize, "workflow result");
418
+ }
419
+ deserializeResult(raw) {
420
+ const deserializer = this.options.deserializeResult ?? ((value) => envelopeDeserialize(value));
421
+ return this.runDeserializer(raw, deserializer, "workflow result");
422
+ }
423
+ serializeStepOutput(output) {
424
+ return this.runSerializer(output, this.options.serializeStepOutput ?? envelopeSerialize, "step output");
425
+ }
426
+ deserializeStepOutput(raw) {
427
+ const deserializer = this.options.deserializeStepOutput ?? ((value) => envelopeDeserialize(value));
428
+ return this.runDeserializer(raw, deserializer, "step output");
429
+ }
430
+ async readInput(executionId) {
431
+ const [readError, raw] = await this.getMeta(executionId, "input");
432
+ if (readError) return err(readError.type, readError.message);
433
+ if (!raw) return err("WorkflowStateError", `Workflow execution ${executionId} input not found`);
434
+ return this.deserializeInput(raw);
435
+ }
436
+ async readResult(executionId) {
437
+ const [readError, raw] = await this.getMeta(executionId, "result");
438
+ if (readError) return err(readError.type, readError.message);
439
+ if (!raw) return ok(null);
440
+ const [deserializeError, result] = this.deserializeResult(raw);
441
+ if (deserializeError) return err(deserializeError.type, deserializeError.message);
442
+ return ok(result);
443
+ }
444
+ async writeStepOutput(executionId, stepName, output) {
445
+ const [serializeError, serializedOutput] = this.serializeStepOutput(output);
446
+ if (serializeError) return err("WorkflowSerializationError", `Unable to serialize step ${stepName} output`);
447
+ const payload = {
448
+ output: serializedOutput,
449
+ completedAt: now()
450
+ };
451
+ const [payloadError, payloadRaw] = mightThrowSync(() => JSON.stringify(payload));
452
+ if (payloadError || typeof payloadRaw !== "string") return err("WorkflowSerializationError", `Unable to persist step ${stepName} output`);
453
+ const [writeError] = await mightThrow(this.options.redis.hset(this.stepsKey(executionId), stepName, payloadRaw));
454
+ if (writeError) return err("WorkflowError", `Unable to persist step ${stepName} for execution ${executionId}`);
455
+ const [stepNamesError, stepNames] = await this.readStepNames(executionId);
456
+ if (stepNamesError) return err(stepNamesError.type, stepNamesError.message);
457
+ if (!stepNames.includes(stepName)) {
458
+ const nextStepNames = [...stepNames, stepName];
459
+ const [serializeStepsError, serializedSteps] = mightThrowSync(() => JSON.stringify(nextStepNames));
460
+ if (serializeStepsError || typeof serializedSteps !== "string") return err("WorkflowSerializationError", `Unable to persist step history for execution ${executionId}`);
461
+ const [updateStepsError] = await this.setMeta(executionId, "steps", serializedSteps);
462
+ if (updateStepsError) return err(updateStepsError.type, updateStepsError.message);
463
+ }
464
+ const [updatedError] = await this.setMeta(executionId, "updatedAt", String(now()));
465
+ if (updatedError) return err(updatedError.type, updatedError.message);
466
+ return ok(null);
467
+ }
468
+ async readStepOutput(executionId, stepName) {
469
+ const [readError, payloadRaw] = await mightThrow(this.options.redis.hget(this.stepsKey(executionId), stepName));
470
+ if (readError) return err("WorkflowError", `Unable to read step ${stepName} for execution ${executionId}`);
471
+ if (!payloadRaw) return ok({
472
+ found: false,
473
+ value: null
474
+ });
475
+ if (typeof payloadRaw !== "string") return err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
476
+ const [parseError, parsed] = mightThrowSync(() => JSON.parse(payloadRaw));
477
+ if (parseError || parsed === null || typeof parsed !== "object") return err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
478
+ if (typeof parsed.output !== "string") return err("WorkflowStateError", `Invalid step output for ${stepName} in execution ${executionId}`);
479
+ const outputRaw = parsed.output;
480
+ const [deserializeError, value] = this.deserializeStepOutput(outputRaw);
481
+ if (deserializeError) return err(deserializeError.type, deserializeError.message);
482
+ return ok({
483
+ found: true,
484
+ value
485
+ });
486
+ }
487
+ async readStepNames(executionId) {
488
+ const [readError, stepsRaw] = await this.getMeta(executionId, "steps");
489
+ if (readError) return [readError, []];
490
+ if (!stepsRaw) return ok([]);
491
+ const [parseError, values] = mightThrowSync(() => JSON.parse(stepsRaw));
492
+ if (parseError || !Array.isArray(values)) return err("WorkflowStateError", `Invalid step index for execution ${executionId}`);
493
+ const stepNames = [];
494
+ for (const value of values) if (typeof value === "string") stepNames.push(value);
495
+ return ok(stepNames);
496
+ }
497
+ async readStepSnapshots(executionId) {
498
+ const [stepNamesError, stepNames] = await this.readStepNames(executionId);
499
+ if (stepNamesError) return [stepNamesError, []];
500
+ const steps = [];
501
+ for (const stepName of stepNames) {
502
+ const [readError, payloadRaw] = await mightThrow(this.options.redis.hget(this.stepsKey(executionId), stepName));
503
+ if (readError) return err("WorkflowError", `Unable to read step ${stepName} for execution ${executionId}`);
504
+ if (!payloadRaw) continue;
505
+ if (typeof payloadRaw !== "string") return err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
506
+ const [parseError, parsed] = mightThrowSync(() => JSON.parse(payloadRaw));
507
+ if (parseError || parsed === null || typeof parsed !== "object") return err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
508
+ if (typeof parsed.completedAt !== "number") return err("WorkflowStateError", `Invalid step payload for ${stepName} in execution ${executionId}`);
509
+ const completedAt = parsed.completedAt;
510
+ steps.push({
511
+ name: stepName,
512
+ completedAt
513
+ });
514
+ }
515
+ return ok(steps);
516
+ }
517
+ normalizeStatus(value) {
518
+ for (const status of knownStatuses) if (status === value) return status;
519
+ return null;
520
+ }
521
+ };
522
+ const defineWorkflow = (options) => {
523
+ const workflow = new WorkflowDefinition(options);
524
+ return {
525
+ start: (input, startOptions) => workflow.start(input, startOptions),
526
+ run: (input, startOptions) => workflow.run(input, startOptions),
527
+ resume: (executionId) => workflow.resume(executionId),
528
+ get: (executionId) => workflow.get(executionId),
529
+ cancel: (executionId) => workflow.cancel(executionId)
530
+ };
531
+ };
532
+ //#endregion
533
+ export { defineWorkflow };
534
+
535
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/lib/workflow/index.ts"],"sourcesContent":["import { err, mightThrow, mightThrowSync, ok } from \"../errors/index.js\";\nimport type {\n StepSnapshot,\n Workflow,\n WorkflowCancelResult,\n WorkflowExecution,\n WorkflowMeta,\n WorkflowMetaField,\n WorkflowOptions,\n WorkflowStartOptions,\n WorkflowStartResult,\n WorkflowStatus,\n} from \"./types.js\";\n\nconst DEFAULT_LOCK_TTL = 5 * 60 * 1000;\n\nconst now = () => Date.now();\n\nconst toErrorMessage = (error: unknown) => {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n};\n\nconst envelopeSerialize = (value: unknown) => {\n return JSON.stringify({ value });\n};\n\nconst envelopeDeserialize = (raw: string) => {\n const [parseError, parsed] = mightThrowSync(() => JSON.parse(raw));\n\n if (parseError) {\n throw parseError;\n }\n\n if (parsed === null) {\n return undefined;\n }\n\n if (typeof parsed !== \"object\") {\n return undefined;\n }\n\n if (\"value\" in parsed) {\n return parsed.value;\n }\n\n return undefined;\n};\n\nconst knownStatuses: WorkflowStatus[] = [\n \"pending\",\n \"running\",\n \"completed\",\n \"failed\",\n \"cancelled\",\n];\n\nclass WorkflowDefinition<TInput, TResult> {\n private options: WorkflowOptions<TInput, TResult>;\n private lockTTL: number;\n\n public constructor(options: WorkflowOptions<TInput, TResult>) {\n this.options = options;\n this.lockTTL = options.lockTTL ?? DEFAULT_LOCK_TTL;\n }\n\n public async start(input: TInput, options?: WorkflowStartOptions) {\n const executionId = options?.executionId ?? crypto.randomUUID();\n\n const [createError] = await this.createExecution(executionId, input);\n\n if (createError) {\n return err(createError.type, createError.message);\n }\n\n return this.execute(executionId, input);\n }\n\n public async run(input: TInput, options?: WorkflowStartOptions) {\n const [startError, startData] = await this.start(input, options);\n\n if (startError) {\n return err(startError.type, startError.message);\n }\n\n if (!startData) {\n return err(\"WorkflowError\", \"Unexpected empty start result\");\n }\n\n if (startData.status === \"cancelled\") {\n return err(\n \"WorkflowCancelledError\",\n `Workflow execution ${startData.executionId} was cancelled`,\n );\n }\n\n if (startData.status !== \"completed\") {\n return err(\n \"WorkflowExecutionError\",\n `Workflow execution ${startData.executionId} did not complete`,\n );\n }\n\n const [getError, execution] = await this.get(startData.executionId);\n\n if (getError) {\n return err(getError.type, getError.message);\n }\n\n if (!execution) {\n return err(\"WorkflowError\", \"Unexpected empty execution\");\n }\n\n return ok(execution.result);\n }\n\n public async resume(executionId: string) {\n const [getError, execution] = await this.get(executionId);\n\n if (getError) {\n return err(getError.type, getError.message);\n }\n\n if (!execution) {\n return err(\n \"WorkflowNotFoundError\",\n `Workflow execution ${executionId} not found`,\n );\n }\n\n if (execution.status === \"completed\") {\n return ok({ executionId, status: execution.status });\n }\n\n if (execution.status === \"cancelled\") {\n return ok({ executionId, status: execution.status });\n }\n\n return this.execute(executionId, execution.input);\n }\n\n public async get(executionId: string) {\n const [statusError, status] = await this.getMeta(executionId, \"status\");\n\n if (statusError) {\n return err(statusError.type, statusError.message);\n }\n\n if (!status) {\n return err(\n \"WorkflowNotFoundError\",\n `Workflow execution ${executionId} not found`,\n );\n }\n\n const normalizedStatus = this.normalizeStatus(status);\n\n if (!normalizedStatus) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} has invalid status ${status}`,\n );\n }\n\n const [inputError, input] = await this.readInput(executionId);\n\n if (inputError) {\n return err(inputError.type, inputError.message);\n }\n\n if (input === null) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} has invalid input`,\n );\n }\n\n const [resultError, result] = await this.readResult(executionId);\n\n if (resultError) {\n return err(resultError.type, resultError.message);\n }\n\n const [stepsError, steps] = await this.readStepSnapshots(executionId);\n\n if (stepsError) {\n return err(stepsError.type, stepsError.message);\n }\n\n const [createdAtError, createdAt] = await this.readNumberMeta(\n executionId,\n \"createdAt\",\n );\n\n if (createdAtError) {\n return err(createdAtError.type, createdAtError.message);\n }\n\n if (createdAt === null) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} is missing createdAt`,\n );\n }\n\n const [updatedAtError, updatedAt] = await this.readNumberMeta(\n executionId,\n \"updatedAt\",\n );\n\n if (updatedAtError) {\n return err(updatedAtError.type, updatedAtError.message);\n }\n\n if (updatedAt === null) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} is missing updatedAt`,\n );\n }\n\n const [metaError, errorMessage] = await this.getMeta(executionId, \"error\");\n\n if (metaError) {\n return err(metaError.type, metaError.message);\n }\n\n const [completedAtError, completedAt] = await this.readNumberMeta(\n executionId,\n \"completedAt\",\n );\n\n if (completedAtError) {\n return err(completedAtError.type, completedAtError.message);\n }\n\n const [failedAtError, failedAt] = await this.readNumberMeta(\n executionId,\n \"failedAt\",\n );\n\n if (failedAtError) {\n return err(failedAtError.type, failedAtError.message);\n }\n\n const [cancelledAtError, cancelledAt] = await this.readNumberMeta(\n executionId,\n \"cancelledAt\",\n );\n\n if (cancelledAtError) {\n return err(cancelledAtError.type, cancelledAtError.message);\n }\n\n const data: WorkflowExecution<TInput, TResult> = {\n id: executionId,\n name: this.options.name,\n status: normalizedStatus,\n input,\n result,\n error: errorMessage,\n createdAt,\n updatedAt,\n completedAt,\n failedAt,\n cancelledAt,\n steps,\n };\n\n return ok(data);\n }\n\n public async cancel(executionId: string) {\n const [getError, execution] = await this.get(executionId);\n\n if (getError) {\n return err(getError.type, getError.message);\n }\n\n if (!execution) {\n return err(\n \"WorkflowNotFoundError\",\n `Workflow execution ${executionId} not found`,\n );\n }\n\n if (execution.status === \"completed\") {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} is already completed`,\n );\n }\n\n const timestamp = now();\n\n const [statusError] = await this.setMeta(\n executionId,\n \"status\",\n \"cancelled\",\n );\n if (statusError) {\n return err(statusError.type, statusError.message);\n }\n\n const [updatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(timestamp),\n );\n if (updatedAtError) {\n return err(updatedAtError.type, updatedAtError.message);\n }\n\n const [cancelledAtError] = await this.setMeta(\n executionId,\n \"cancelledAt\",\n String(timestamp),\n );\n if (cancelledAtError) {\n return err(cancelledAtError.type, cancelledAtError.message);\n }\n\n const [clearErrorError] = await this.setMeta(executionId, \"error\", \"\");\n\n if (clearErrorError) {\n return err(clearErrorError.type, clearErrorError.message);\n }\n\n const [clearFailedAtError] = await this.setMeta(\n executionId,\n \"failedAt\",\n \"\",\n );\n\n if (clearFailedAtError) {\n return err(clearFailedAtError.type, clearFailedAtError.message);\n }\n\n const response: WorkflowCancelResult = {\n executionId,\n createdAt: execution.createdAt,\n cancelledAt: timestamp,\n updatedAt: timestamp,\n status: \"cancelled\",\n };\n\n return ok(response);\n }\n\n private executionKey(executionId: string) {\n return `workflow:${this.options.name}:execution:${executionId}`;\n }\n\n private metaKey(executionId: string) {\n return `${this.executionKey(executionId)}:meta`;\n }\n\n private stepsKey(executionId: string) {\n return `${this.executionKey(executionId)}:steps`;\n }\n\n private lockKey(executionId: string) {\n return `${this.executionKey(executionId)}:lock`;\n }\n\n private async createExecution(executionId: string, input: TInput) {\n const [serializeError, serializedInput] = this.serializeInput(input);\n\n if (serializeError) {\n return err(\n \"WorkflowSerializationError\",\n `Unable to serialize workflow input for ${executionId}`,\n );\n }\n\n const timestamp = now();\n\n const [statusReadError, existingStatus] = await this.getMeta(\n executionId,\n \"status\",\n );\n\n if (statusReadError) {\n return err(statusReadError.type, statusReadError.message);\n }\n\n if (existingStatus) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} already exists`,\n );\n }\n\n const metadata: WorkflowMeta = {\n status: \"pending\",\n input: serializedInput,\n result: \"\",\n error: \"\",\n createdAt: String(timestamp),\n updatedAt: String(timestamp),\n completedAt: \"\",\n failedAt: \"\",\n cancelledAt: \"\",\n steps: \"[]\",\n };\n\n const [writeError] = await mightThrow(\n this.options.redis.hset(this.metaKey(executionId), metadata),\n );\n\n if (writeError) {\n return err(\n \"WorkflowError\",\n `Unable to persist metadata for execution ${executionId}`,\n );\n }\n\n return ok(null);\n }\n\n private async execute(executionId: string, input: TInput) {\n const token = crypto.randomUUID();\n\n const [lockError] = await this.acquireLock(executionId, token);\n\n if (lockError) {\n return err(lockError.type, lockError.message);\n }\n\n const [statusCheckError, currentStatus] = await this.getMeta(\n executionId,\n \"status\",\n );\n\n if (statusCheckError) {\n await this.releaseLock(executionId, token);\n return err(statusCheckError.type, statusCheckError.message);\n }\n\n if (currentStatus === \"cancelled\") {\n await this.releaseLock(executionId, token);\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} was cancelled`,\n );\n }\n\n const timestamp = now();\n\n const [runningStatusError] = await this.setMeta(\n executionId,\n \"status\",\n \"running\",\n );\n\n if (runningStatusError) {\n await this.releaseLock(executionId, token);\n return err(runningStatusError.type, runningStatusError.message);\n }\n\n const [runningUpdatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(timestamp),\n );\n\n if (runningUpdatedAtError) {\n await this.releaseLock(executionId, token);\n return err(runningUpdatedAtError.type, runningUpdatedAtError.message);\n }\n\n const controller = new AbortController();\n\n const renewInterval = Math.floor(this.lockTTL / 3);\n\n let lockLost = false;\n\n const renewTimer = setInterval(async () => {\n const [renewError] = await this.extendLock(executionId, token);\n\n if (renewError) {\n lockLost = true;\n controller.abort();\n clearInterval(renewTimer);\n }\n }, renewInterval);\n\n const step = async <TStep>(\n name: string,\n handler: (\n inputValue: TInput,\n signal: AbortSignal,\n ) => TStep | Promise<TStep>,\n ) => {\n const [cancelledError, cancelled] = await this.isCancelled(executionId);\n\n if (cancelledError) {\n return Promise.reject(new Error(cancelledError.message));\n }\n\n if (cancelled) {\n controller.abort();\n return Promise.reject(new Error(\"Workflow cancelled\"));\n }\n\n const [readError, cachedStep] = await this.readStepOutput<TStep>(\n executionId,\n name,\n );\n\n if (readError) {\n return Promise.reject(new Error(readError.message));\n }\n\n if (cachedStep.found) {\n return cachedStep.value as TStep;\n }\n\n const [stepError, output] = await mightThrow(\n Promise.resolve(handler(input, controller.signal)),\n );\n\n if (stepError) {\n return Promise.reject(stepError);\n }\n\n const [writeError] = await this.writeStepOutput(\n executionId,\n name,\n output,\n );\n\n if (writeError) {\n return Promise.reject(new Error(writeError.message));\n }\n\n return output as TStep;\n };\n\n const [handlerError, result] = await mightThrow(\n Promise.resolve(\n this.options.handler({\n input,\n executionId,\n signal: controller.signal,\n step,\n }),\n ),\n );\n\n clearInterval(renewTimer);\n\n if (lockLost) {\n await this.releaseLock(executionId, token);\n\n return err(\n \"WorkflowLockError\",\n `Lock expired during execution ${executionId}`,\n );\n }\n\n const [cancelledError, cancelled] = await this.isCancelled(executionId);\n\n if (cancelledError) {\n await this.releaseLock(executionId, token);\n return err(cancelledError.type, cancelledError.message);\n }\n\n if (cancelled) {\n const cancelledAt = now();\n\n const [cancelledStatusError] = await this.setMeta(\n executionId,\n \"status\",\n \"cancelled\",\n );\n\n if (cancelledStatusError) {\n await this.releaseLock(executionId, token);\n return err(cancelledStatusError.type, cancelledStatusError.message);\n }\n\n const [cancelledUpdatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(cancelledAt),\n );\n\n if (cancelledUpdatedAtError) {\n await this.releaseLock(executionId, token);\n return err(\n cancelledUpdatedAtError.type,\n cancelledUpdatedAtError.message,\n );\n }\n\n const [cancelledAtError] = await this.setMeta(\n executionId,\n \"cancelledAt\",\n String(cancelledAt),\n );\n\n if (cancelledAtError) {\n await this.releaseLock(executionId, token);\n return err(cancelledAtError.type, cancelledAtError.message);\n }\n\n await this.releaseLock(executionId, token);\n\n const response: WorkflowStartResult = {\n executionId,\n status: \"cancelled\",\n };\n\n return ok(response);\n }\n\n if (handlerError) {\n const failedAt = now();\n\n const [failedStatusError] = await this.setMeta(\n executionId,\n \"status\",\n \"failed\",\n );\n\n if (failedStatusError) {\n await this.releaseLock(executionId, token);\n return err(failedStatusError.type, failedStatusError.message);\n }\n\n const [failedMessageError] = await this.setMeta(\n executionId,\n \"error\",\n toErrorMessage(handlerError),\n );\n\n if (failedMessageError) {\n await this.releaseLock(executionId, token);\n return err(failedMessageError.type, failedMessageError.message);\n }\n\n const [failedUpdatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(failedAt),\n );\n\n if (failedUpdatedAtError) {\n await this.releaseLock(executionId, token);\n return err(failedUpdatedAtError.type, failedUpdatedAtError.message);\n }\n\n const [failedAtError] = await this.setMeta(\n executionId,\n \"failedAt\",\n String(failedAt),\n );\n\n if (failedAtError) {\n await this.releaseLock(executionId, token);\n return err(failedAtError.type, failedAtError.message);\n }\n\n await this.releaseLock(executionId, token);\n\n return err(\n \"WorkflowExecutionError\",\n `Workflow execution ${executionId} failed: ${toErrorMessage(handlerError)}`,\n );\n }\n\n const [serializeResultError, serializedResult] =\n this.serializeResult(result);\n\n if (serializeResultError) {\n const failedAt = now();\n\n const [failedStatusError] = await this.setMeta(\n executionId,\n \"status\",\n \"failed\",\n );\n\n if (failedStatusError) {\n await this.releaseLock(executionId, token);\n return err(failedStatusError.type, failedStatusError.message);\n }\n\n const [failedMessageError] = await this.setMeta(\n executionId,\n \"error\",\n serializeResultError.message,\n );\n\n if (failedMessageError) {\n await this.releaseLock(executionId, token);\n return err(failedMessageError.type, failedMessageError.message);\n }\n\n const [failedUpdatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(failedAt),\n );\n\n if (failedUpdatedAtError) {\n await this.releaseLock(executionId, token);\n return err(failedUpdatedAtError.type, failedUpdatedAtError.message);\n }\n\n const [failedAtError] = await this.setMeta(\n executionId,\n \"failedAt\",\n String(failedAt),\n );\n\n if (failedAtError) {\n await this.releaseLock(executionId, token);\n return err(failedAtError.type, failedAtError.message);\n }\n\n await this.releaseLock(executionId, token);\n\n return err(\n \"WorkflowSerializationError\",\n `Unable to serialize workflow result for ${executionId}`,\n );\n }\n\n const completedAt = now();\n\n const [completedResultError] = await this.setMeta(\n executionId,\n \"result\",\n serializedResult,\n );\n\n if (completedResultError) {\n await this.releaseLock(executionId, token);\n return err(completedResultError.type, completedResultError.message);\n }\n\n const [completedStatusError] = await this.setMeta(\n executionId,\n \"status\",\n \"completed\",\n );\n\n if (completedStatusError) {\n await this.releaseLock(executionId, token);\n return err(completedStatusError.type, completedStatusError.message);\n }\n\n const [completedClearErrorError] = await this.setMeta(\n executionId,\n \"error\",\n \"\",\n );\n\n if (completedClearErrorError) {\n await this.releaseLock(executionId, token);\n return err(\n completedClearErrorError.type,\n completedClearErrorError.message,\n );\n }\n\n const [completedClearFailedAtError] = await this.setMeta(\n executionId,\n \"failedAt\",\n \"\",\n );\n\n if (completedClearFailedAtError) {\n await this.releaseLock(executionId, token);\n return err(\n completedClearFailedAtError.type,\n completedClearFailedAtError.message,\n );\n }\n\n const [completedUpdatedAtError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(completedAt),\n );\n\n if (completedUpdatedAtError) {\n await this.releaseLock(executionId, token);\n return err(completedUpdatedAtError.type, completedUpdatedAtError.message);\n }\n\n const [completedAtError] = await this.setMeta(\n executionId,\n \"completedAt\",\n String(completedAt),\n );\n\n if (completedAtError) {\n await this.releaseLock(executionId, token);\n return err(completedAtError.type, completedAtError.message);\n }\n\n await this.releaseLock(executionId, token);\n\n const response: WorkflowStartResult = {\n executionId,\n status: \"completed\",\n };\n\n return ok(response);\n }\n\n private async acquireLock(executionId: string, token: string) {\n const [lockError, lockResult] = await mightThrow(\n this.options.redis.set(\n this.lockKey(executionId),\n token,\n \"PX\",\n String(this.lockTTL),\n \"NX\",\n ),\n );\n\n if (lockError) {\n return err(\n \"WorkflowLockError\",\n `Unable to acquire lock for execution ${executionId}`,\n );\n }\n\n if (lockResult !== \"OK\") {\n return err(\n \"WorkflowLockError\",\n `Workflow execution ${executionId} is already running`,\n );\n }\n\n return ok(null);\n }\n\n private async releaseLock(executionId: string, token: string) {\n const script =\n \"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end\";\n\n const [evalError] = await mightThrow(\n this.options.redis.send(\"EVAL\", [\n script,\n \"1\",\n this.lockKey(executionId),\n token,\n ]),\n );\n\n if (evalError) {\n return err(\n \"WorkflowLockError\",\n `Unable to release lock for execution ${executionId}`,\n );\n }\n\n return ok(null);\n }\n\n private async extendLock(executionId: string, token: string) {\n const script =\n \"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('PEXPIRE', KEYS[1], ARGV[2]) else return 0 end\";\n\n const [evalError, result] = await mightThrow(\n this.options.redis.send(\"EVAL\", [\n script,\n \"1\",\n this.lockKey(executionId),\n token,\n String(this.lockTTL),\n ]),\n );\n\n if (evalError) {\n return err(\n \"WorkflowLockError\",\n `Unable to extend lock for execution ${executionId}`,\n );\n }\n\n if (result === 0) {\n return err(\n \"WorkflowLockError\",\n `Lock ownership lost for execution ${executionId}`,\n );\n }\n\n return ok(null);\n }\n\n private async isCancelled(executionId: string) {\n const [statusError, status] = await this.getMeta(executionId, \"status\");\n\n if (statusError) {\n return err(statusError.type, statusError.message);\n }\n\n return ok(status === \"cancelled\");\n }\n\n private async setMeta(\n executionId: string,\n field: WorkflowMetaField,\n value: string,\n ) {\n const [writeError] = await mightThrow(\n this.options.redis.hset(this.metaKey(executionId), field, value),\n );\n\n if (writeError) {\n return err(\n \"WorkflowError\",\n `Unable to persist ${field} for execution ${executionId}`,\n );\n }\n\n return ok(null);\n }\n\n private async getMeta(executionId: string, field: WorkflowMetaField) {\n const [readError, value] = await mightThrow(\n this.options.redis.hget(this.metaKey(executionId), field),\n );\n\n if (readError) {\n return err(\n \"WorkflowError\",\n `Unable to read ${field} for execution ${executionId}`,\n );\n }\n\n if (value === null || value === undefined) {\n return ok(null);\n }\n\n if (typeof value !== \"string\") {\n return err(\n \"WorkflowStateError\",\n `Invalid ${field} value for execution ${executionId}`,\n );\n }\n\n if (value.length === 0) {\n return ok(null);\n }\n\n return ok(value);\n }\n\n private async readNumberMeta(executionId: string, field: WorkflowMetaField) {\n const [readError, value] = await this.getMeta(executionId, field);\n\n if (readError) {\n return err(readError.type, readError.message);\n }\n\n if (!value) {\n return ok(null);\n }\n\n const parsed = Number(value);\n\n if (!Number.isFinite(parsed)) {\n return err(\n \"WorkflowStateError\",\n `Invalid ${field} value for execution ${executionId}`,\n );\n }\n\n return ok(parsed);\n }\n\n private runSerializer<T>(\n value: T,\n serializer: (v: T) => string,\n label: string,\n ) {\n const [serializeError, serialized] = mightThrowSync(() =>\n serializer(value),\n );\n\n if (serializeError) {\n return err(\n \"WorkflowSerializationError\",\n `Unable to serialize ${label}: ${toErrorMessage(serializeError)}`,\n );\n }\n\n if (typeof serialized !== \"string\") {\n return err(\n \"WorkflowSerializationError\",\n `${label} serializer must return a string`,\n );\n }\n\n return ok(serialized);\n }\n\n private runDeserializer<T>(\n raw: string,\n deserializer: (v: string) => T,\n label: string,\n ) {\n const [deserializeError, value] = mightThrowSync(() => deserializer(raw));\n\n if (deserializeError) {\n return err(\n \"WorkflowSerializationError\",\n `Unable to deserialize ${label}: ${toErrorMessage(deserializeError)}`,\n );\n }\n\n return ok(value);\n }\n\n private serializeInput(input: TInput) {\n return this.runSerializer(\n input,\n this.options.serializeInput ?? envelopeSerialize,\n \"workflow input\",\n );\n }\n\n private deserializeInput(raw: string) {\n const deserializer =\n this.options.deserializeInput ??\n ((value: string) => envelopeDeserialize(value) as TInput);\n\n return this.runDeserializer(raw, deserializer, \"workflow input\");\n }\n\n private serializeResult(result: TResult | null) {\n if (result === null) {\n return ok(envelopeSerialize(null));\n }\n\n return this.runSerializer(\n result,\n this.options.serializeResult ?? envelopeSerialize,\n \"workflow result\",\n );\n }\n\n private deserializeResult(raw: string) {\n const deserializer =\n this.options.deserializeResult ??\n ((value: string) => envelopeDeserialize(value) as TResult);\n\n return this.runDeserializer(raw, deserializer, \"workflow result\");\n }\n\n private serializeStepOutput(output: unknown) {\n return this.runSerializer(\n output,\n this.options.serializeStepOutput ?? envelopeSerialize,\n \"step output\",\n );\n }\n\n private deserializeStepOutput(raw: string) {\n const deserializer =\n this.options.deserializeStepOutput ??\n ((value: string) => envelopeDeserialize(value));\n\n return this.runDeserializer(raw, deserializer, \"step output\");\n }\n\n private async readInput(executionId: string) {\n const [readError, raw] = await this.getMeta(executionId, \"input\");\n\n if (readError) {\n return err(readError.type, readError.message);\n }\n\n if (!raw) {\n return err(\n \"WorkflowStateError\",\n `Workflow execution ${executionId} input not found`,\n );\n }\n\n return this.deserializeInput(raw);\n }\n\n private async readResult(executionId: string) {\n const [readError, raw] = await this.getMeta(executionId, \"result\");\n\n if (readError) {\n return err(readError.type, readError.message);\n }\n\n if (!raw) {\n return ok(null);\n }\n\n const [deserializeError, result] = this.deserializeResult(raw);\n\n if (deserializeError) {\n return err(deserializeError.type, deserializeError.message);\n }\n\n return ok(result);\n }\n\n private async writeStepOutput(\n executionId: string,\n stepName: string,\n output: unknown,\n ) {\n const [serializeError, serializedOutput] = this.serializeStepOutput(output);\n\n if (serializeError) {\n return err(\n \"WorkflowSerializationError\",\n `Unable to serialize step ${stepName} output`,\n );\n }\n\n const payload = {\n output: serializedOutput,\n completedAt: now(),\n };\n\n const [payloadError, payloadRaw] = mightThrowSync(() =>\n JSON.stringify(payload),\n );\n\n if (payloadError || typeof payloadRaw !== \"string\") {\n return err(\n \"WorkflowSerializationError\",\n `Unable to persist step ${stepName} output`,\n );\n }\n\n const [writeError] = await mightThrow(\n this.options.redis.hset(this.stepsKey(executionId), stepName, payloadRaw),\n );\n\n if (writeError) {\n return err(\n \"WorkflowError\",\n `Unable to persist step ${stepName} for execution ${executionId}`,\n );\n }\n\n const [stepNamesError, stepNames] = await this.readStepNames(executionId);\n\n if (stepNamesError) {\n return err(stepNamesError.type, stepNamesError.message);\n }\n\n if (!stepNames.includes(stepName)) {\n const nextStepNames = [...stepNames, stepName];\n\n const [serializeStepsError, serializedSteps] = mightThrowSync(() =>\n JSON.stringify(nextStepNames),\n );\n\n if (serializeStepsError || typeof serializedSteps !== \"string\") {\n return err(\n \"WorkflowSerializationError\",\n `Unable to persist step history for execution ${executionId}`,\n );\n }\n\n const [updateStepsError] = await this.setMeta(\n executionId,\n \"steps\",\n serializedSteps,\n );\n\n if (updateStepsError) {\n return err(updateStepsError.type, updateStepsError.message);\n }\n }\n\n const [updatedError] = await this.setMeta(\n executionId,\n \"updatedAt\",\n String(now()),\n );\n\n if (updatedError) {\n return err(updatedError.type, updatedError.message);\n }\n\n return ok(null);\n }\n\n private async readStepOutput<TStep>(executionId: string, stepName: string) {\n const [readError, payloadRaw] = await mightThrow(\n this.options.redis.hget(this.stepsKey(executionId), stepName),\n );\n\n if (readError) {\n return err(\n \"WorkflowError\",\n `Unable to read step ${stepName} for execution ${executionId}`,\n );\n }\n\n if (!payloadRaw) {\n return ok({ found: false, value: null });\n }\n\n if (typeof payloadRaw !== \"string\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step payload for ${stepName} in execution ${executionId}`,\n );\n }\n\n const [parseError, parsed] = mightThrowSync(() => JSON.parse(payloadRaw));\n\n if (parseError || parsed === null || typeof parsed !== \"object\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step payload for ${stepName} in execution ${executionId}`,\n );\n }\n\n if (typeof parsed.output !== \"string\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step output for ${stepName} in execution ${executionId}`,\n );\n }\n\n const outputRaw = parsed.output;\n\n const [deserializeError, value] = this.deserializeStepOutput(outputRaw);\n\n if (deserializeError) {\n return err(deserializeError.type, deserializeError.message);\n }\n\n return ok({ found: true, value: value as TStep });\n }\n\n private async readStepNames(executionId: string) {\n const [readError, stepsRaw] = await this.getMeta(executionId, \"steps\");\n\n if (readError) {\n return [readError, []] as const;\n }\n\n if (!stepsRaw) {\n return ok([] as string[]);\n }\n\n const [parseError, values] = mightThrowSync(() => JSON.parse(stepsRaw));\n\n if (parseError || !Array.isArray(values)) {\n return err(\n \"WorkflowStateError\",\n `Invalid step index for execution ${executionId}`,\n );\n }\n\n const stepNames: string[] = [];\n\n for (const value of values) {\n if (typeof value === \"string\") {\n stepNames.push(value);\n }\n }\n\n return ok(stepNames);\n }\n\n private async readStepSnapshots(executionId: string) {\n const [stepNamesError, stepNames] = await this.readStepNames(executionId);\n\n if (stepNamesError) {\n return [stepNamesError, []] as const;\n }\n\n const steps: StepSnapshot[] = [];\n\n for (const stepName of stepNames) {\n const [readError, payloadRaw] = await mightThrow(\n this.options.redis.hget(this.stepsKey(executionId), stepName),\n );\n\n if (readError) {\n return err(\n \"WorkflowError\",\n `Unable to read step ${stepName} for execution ${executionId}`,\n );\n }\n\n if (!payloadRaw) {\n continue;\n }\n\n if (typeof payloadRaw !== \"string\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step payload for ${stepName} in execution ${executionId}`,\n );\n }\n\n const [parseError, parsed] = mightThrowSync(() => JSON.parse(payloadRaw));\n\n if (parseError || parsed === null || typeof parsed !== \"object\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step payload for ${stepName} in execution ${executionId}`,\n );\n }\n\n if (typeof parsed.completedAt !== \"number\") {\n return err(\n \"WorkflowStateError\",\n `Invalid step payload for ${stepName} in execution ${executionId}`,\n );\n }\n\n const completedAt = parsed.completedAt;\n\n steps.push({\n name: stepName,\n completedAt,\n });\n }\n\n return ok(steps);\n }\n\n private normalizeStatus(value: string) {\n for (const status of knownStatuses) {\n if (status === value) {\n return status;\n }\n }\n\n return null;\n }\n}\n\nexport const defineWorkflow = <TInput, TResult = void>(\n options: WorkflowOptions<TInput, TResult>,\n): Workflow<TInput, TResult> => {\n const workflow = new WorkflowDefinition(options);\n\n return {\n start: (input, startOptions) => workflow.start(input, startOptions),\n run: (input, startOptions) => workflow.run(input, startOptions),\n resume: (executionId) => workflow.resume(executionId),\n get: (executionId) => workflow.get(executionId),\n cancel: (executionId) => workflow.cancel(executionId),\n };\n};\n\nexport type {\n StepHandler,\n Workflow,\n WorkflowError,\n WorkflowExecution,\n WorkflowHandlerContext,\n WorkflowMeta,\n WorkflowMetaField,\n WorkflowOptions,\n WorkflowStartOptions,\n WorkflowStartResult,\n WorkflowStatus,\n} from \"./types.js\";\n"],"mappings":";;AAcA,MAAM,mBAAmB,MAAS;AAElC,MAAM,YAAY,KAAK,KAAK;AAE5B,MAAM,kBAAkB,UAAmB;AACzC,KAAI,iBAAiB,MACnB,QAAO,MAAM;AAGf,QAAO,OAAO,MAAM;;AAGtB,MAAM,qBAAqB,UAAmB;AAC5C,QAAO,KAAK,UAAU,EAAE,OAAO,CAAC;;AAGlC,MAAM,uBAAuB,QAAgB;CAC3C,MAAM,CAAC,YAAY,UAAU,qBAAqB,KAAK,MAAM,IAAI,CAAC;AAElE,KAAI,WACF,OAAM;AAGR,KAAI,WAAW,KACb;AAGF,KAAI,OAAO,WAAW,SACpB;AAGF,KAAI,WAAW,OACb,QAAO,OAAO;;AAMlB,MAAM,gBAAkC;CACtC;CACA;CACA;CACA;CACA;CACD;AAED,IAAM,qBAAN,MAA0C;CACxC;CACA;CAEA,YAAmB,SAA2C;AAC5D,OAAK,UAAU;AACf,OAAK,UAAU,QAAQ,WAAW;;CAGpC,MAAa,MAAM,OAAe,SAAgC;EAChE,MAAM,cAAc,SAAS,eAAe,OAAO,YAAY;EAE/D,MAAM,CAAC,eAAe,MAAM,KAAK,gBAAgB,aAAa,MAAM;AAEpE,MAAI,YACF,QAAO,IAAI,YAAY,MAAM,YAAY,QAAQ;AAGnD,SAAO,KAAK,QAAQ,aAAa,MAAM;;CAGzC,MAAa,IAAI,OAAe,SAAgC;EAC9D,MAAM,CAAC,YAAY,aAAa,MAAM,KAAK,MAAM,OAAO,QAAQ;AAEhE,MAAI,WACF,QAAO,IAAI,WAAW,MAAM,WAAW,QAAQ;AAGjD,MAAI,CAAC,UACH,QAAO,IAAI,iBAAiB,gCAAgC;AAG9D,MAAI,UAAU,WAAW,YACvB,QAAO,IACL,0BACA,sBAAsB,UAAU,YAAY,gBAC7C;AAGH,MAAI,UAAU,WAAW,YACvB,QAAO,IACL,0BACA,sBAAsB,UAAU,YAAY,mBAC7C;EAGH,MAAM,CAAC,UAAU,aAAa,MAAM,KAAK,IAAI,UAAU,YAAY;AAEnE,MAAI,SACF,QAAO,IAAI,SAAS,MAAM,SAAS,QAAQ;AAG7C,MAAI,CAAC,UACH,QAAO,IAAI,iBAAiB,6BAA6B;AAG3D,SAAO,GAAG,UAAU,OAAO;;CAG7B,MAAa,OAAO,aAAqB;EACvC,MAAM,CAAC,UAAU,aAAa,MAAM,KAAK,IAAI,YAAY;AAEzD,MAAI,SACF,QAAO,IAAI,SAAS,MAAM,SAAS,QAAQ;AAG7C,MAAI,CAAC,UACH,QAAO,IACL,yBACA,sBAAsB,YAAY,YACnC;AAGH,MAAI,UAAU,WAAW,YACvB,QAAO,GAAG;GAAE;GAAa,QAAQ,UAAU;GAAQ,CAAC;AAGtD,MAAI,UAAU,WAAW,YACvB,QAAO,GAAG;GAAE;GAAa,QAAQ,UAAU;GAAQ,CAAC;AAGtD,SAAO,KAAK,QAAQ,aAAa,UAAU,MAAM;;CAGnD,MAAa,IAAI,aAAqB;EACpC,MAAM,CAAC,aAAa,UAAU,MAAM,KAAK,QAAQ,aAAa,SAAS;AAEvE,MAAI,YACF,QAAO,IAAI,YAAY,MAAM,YAAY,QAAQ;AAGnD,MAAI,CAAC,OACH,QAAO,IACL,yBACA,sBAAsB,YAAY,YACnC;EAGH,MAAM,mBAAmB,KAAK,gBAAgB,OAAO;AAErD,MAAI,CAAC,iBACH,QAAO,IACL,sBACA,sBAAsB,YAAY,sBAAsB,SACzD;EAGH,MAAM,CAAC,YAAY,SAAS,MAAM,KAAK,UAAU,YAAY;AAE7D,MAAI,WACF,QAAO,IAAI,WAAW,MAAM,WAAW,QAAQ;AAGjD,MAAI,UAAU,KACZ,QAAO,IACL,sBACA,sBAAsB,YAAY,oBACnC;EAGH,MAAM,CAAC,aAAa,UAAU,MAAM,KAAK,WAAW,YAAY;AAEhE,MAAI,YACF,QAAO,IAAI,YAAY,MAAM,YAAY,QAAQ;EAGnD,MAAM,CAAC,YAAY,SAAS,MAAM,KAAK,kBAAkB,YAAY;AAErE,MAAI,WACF,QAAO,IAAI,WAAW,MAAM,WAAW,QAAQ;EAGjD,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,eAC7C,aACA,YACD;AAED,MAAI,eACF,QAAO,IAAI,eAAe,MAAM,eAAe,QAAQ;AAGzD,MAAI,cAAc,KAChB,QAAO,IACL,sBACA,sBAAsB,YAAY,uBACnC;EAGH,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,eAC7C,aACA,YACD;AAED,MAAI,eACF,QAAO,IAAI,eAAe,MAAM,eAAe,QAAQ;AAGzD,MAAI,cAAc,KAChB,QAAO,IACL,sBACA,sBAAsB,YAAY,uBACnC;EAGH,MAAM,CAAC,WAAW,gBAAgB,MAAM,KAAK,QAAQ,aAAa,QAAQ;AAE1E,MAAI,UACF,QAAO,IAAI,UAAU,MAAM,UAAU,QAAQ;EAG/C,MAAM,CAAC,kBAAkB,eAAe,MAAM,KAAK,eACjD,aACA,cACD;AAED,MAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;EAG7D,MAAM,CAAC,eAAe,YAAY,MAAM,KAAK,eAC3C,aACA,WACD;AAED,MAAI,cACF,QAAO,IAAI,cAAc,MAAM,cAAc,QAAQ;EAGvD,MAAM,CAAC,kBAAkB,eAAe,MAAM,KAAK,eACjD,aACA,cACD;AAED,MAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;AAkB7D,SAAO,GAf0C;GAC/C,IAAI;GACJ,MAAM,KAAK,QAAQ;GACnB,QAAQ;GACR;GACA;GACA,OAAO;GACP;GACA;GACA;GACA;GACA;GACA;GACD,CAEc;;CAGjB,MAAa,OAAO,aAAqB;EACvC,MAAM,CAAC,UAAU,aAAa,MAAM,KAAK,IAAI,YAAY;AAEzD,MAAI,SACF,QAAO,IAAI,SAAS,MAAM,SAAS,QAAQ;AAG7C,MAAI,CAAC,UACH,QAAO,IACL,yBACA,sBAAsB,YAAY,YACnC;AAGH,MAAI,UAAU,WAAW,YACvB,QAAO,IACL,sBACA,sBAAsB,YAAY,uBACnC;EAGH,MAAM,YAAY,KAAK;EAEvB,MAAM,CAAC,eAAe,MAAM,KAAK,QAC/B,aACA,UACA,YACD;AACD,MAAI,YACF,QAAO,IAAI,YAAY,MAAM,YAAY,QAAQ;EAGnD,MAAM,CAAC,kBAAkB,MAAM,KAAK,QAClC,aACA,aACA,OAAO,UAAU,CAClB;AACD,MAAI,eACF,QAAO,IAAI,eAAe,MAAM,eAAe,QAAQ;EAGzD,MAAM,CAAC,oBAAoB,MAAM,KAAK,QACpC,aACA,eACA,OAAO,UAAU,CAClB;AACD,MAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;EAG7D,MAAM,CAAC,mBAAmB,MAAM,KAAK,QAAQ,aAAa,SAAS,GAAG;AAEtE,MAAI,gBACF,QAAO,IAAI,gBAAgB,MAAM,gBAAgB,QAAQ;EAG3D,MAAM,CAAC,sBAAsB,MAAM,KAAK,QACtC,aACA,YACA,GACD;AAED,MAAI,mBACF,QAAO,IAAI,mBAAmB,MAAM,mBAAmB,QAAQ;AAWjE,SAAO,GARgC;GACrC;GACA,WAAW,UAAU;GACrB,aAAa;GACb,WAAW;GACX,QAAQ;GACT,CAEkB;;CAGrB,aAAqB,aAAqB;AACxC,SAAO,YAAY,KAAK,QAAQ,KAAK,aAAa;;CAGpD,QAAgB,aAAqB;AACnC,SAAO,GAAG,KAAK,aAAa,YAAY,CAAC;;CAG3C,SAAiB,aAAqB;AACpC,SAAO,GAAG,KAAK,aAAa,YAAY,CAAC;;CAG3C,QAAgB,aAAqB;AACnC,SAAO,GAAG,KAAK,aAAa,YAAY,CAAC;;CAG3C,MAAc,gBAAgB,aAAqB,OAAe;EAChE,MAAM,CAAC,gBAAgB,mBAAmB,KAAK,eAAe,MAAM;AAEpE,MAAI,eACF,QAAO,IACL,8BACA,0CAA0C,cAC3C;EAGH,MAAM,YAAY,KAAK;EAEvB,MAAM,CAAC,iBAAiB,kBAAkB,MAAM,KAAK,QACnD,aACA,SACD;AAED,MAAI,gBACF,QAAO,IAAI,gBAAgB,MAAM,gBAAgB,QAAQ;AAG3D,MAAI,eACF,QAAO,IACL,sBACA,sBAAsB,YAAY,iBACnC;EAGH,MAAM,WAAyB;GAC7B,QAAQ;GACR,OAAO;GACP,QAAQ;GACR,OAAO;GACP,WAAW,OAAO,UAAU;GAC5B,WAAW,OAAO,UAAU;GAC5B,aAAa;GACb,UAAU;GACV,aAAa;GACb,OAAO;GACR;EAED,MAAM,CAAC,cAAc,MAAM,WACzB,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,SAAS,CAC7D;AAED,MAAI,WACF,QAAO,IACL,iBACA,4CAA4C,cAC7C;AAGH,SAAO,GAAG,KAAK;;CAGjB,MAAc,QAAQ,aAAqB,OAAe;EACxD,MAAM,QAAQ,OAAO,YAAY;EAEjC,MAAM,CAAC,aAAa,MAAM,KAAK,YAAY,aAAa,MAAM;AAE9D,MAAI,UACF,QAAO,IAAI,UAAU,MAAM,UAAU,QAAQ;EAG/C,MAAM,CAAC,kBAAkB,iBAAiB,MAAM,KAAK,QACnD,aACA,SACD;AAED,MAAI,kBAAkB;AACpB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;;AAG7D,MAAI,kBAAkB,aAAa;AACjC,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IACL,sBACA,sBAAsB,YAAY,gBACnC;;EAGH,MAAM,YAAY,KAAK;EAEvB,MAAM,CAAC,sBAAsB,MAAM,KAAK,QACtC,aACA,UACA,UACD;AAED,MAAI,oBAAoB;AACtB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,mBAAmB,MAAM,mBAAmB,QAAQ;;EAGjE,MAAM,CAAC,yBAAyB,MAAM,KAAK,QACzC,aACA,aACA,OAAO,UAAU,CAClB;AAED,MAAI,uBAAuB;AACzB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,sBAAsB,MAAM,sBAAsB,QAAQ;;EAGvE,MAAM,aAAa,IAAI,iBAAiB;EAExC,MAAM,gBAAgB,KAAK,MAAM,KAAK,UAAU,EAAE;EAElD,IAAI,WAAW;EAEf,MAAM,aAAa,YAAY,YAAY;GACzC,MAAM,CAAC,cAAc,MAAM,KAAK,WAAW,aAAa,MAAM;AAE9D,OAAI,YAAY;AACd,eAAW;AACX,eAAW,OAAO;AAClB,kBAAc,WAAW;;KAE1B,cAAc;EAEjB,MAAM,OAAO,OACX,MACA,YAIG;GACH,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,YAAY,YAAY;AAEvE,OAAI,eACF,QAAO,QAAQ,OAAO,IAAI,MAAM,eAAe,QAAQ,CAAC;AAG1D,OAAI,WAAW;AACb,eAAW,OAAO;AAClB,WAAO,QAAQ,uBAAO,IAAI,MAAM,qBAAqB,CAAC;;GAGxD,MAAM,CAAC,WAAW,cAAc,MAAM,KAAK,eACzC,aACA,KACD;AAED,OAAI,UACF,QAAO,QAAQ,OAAO,IAAI,MAAM,UAAU,QAAQ,CAAC;AAGrD,OAAI,WAAW,MACb,QAAO,WAAW;GAGpB,MAAM,CAAC,WAAW,UAAU,MAAM,WAChC,QAAQ,QAAQ,QAAQ,OAAO,WAAW,OAAO,CAAC,CACnD;AAED,OAAI,UACF,QAAO,QAAQ,OAAO,UAAU;GAGlC,MAAM,CAAC,cAAc,MAAM,KAAK,gBAC9B,aACA,MACA,OACD;AAED,OAAI,WACF,QAAO,QAAQ,OAAO,IAAI,MAAM,WAAW,QAAQ,CAAC;AAGtD,UAAO;;EAGT,MAAM,CAAC,cAAc,UAAU,MAAM,WACnC,QAAQ,QACN,KAAK,QAAQ,QAAQ;GACnB;GACA;GACA,QAAQ,WAAW;GACnB;GACD,CAAC,CACH,CACF;AAED,gBAAc,WAAW;AAEzB,MAAI,UAAU;AACZ,SAAM,KAAK,YAAY,aAAa,MAAM;AAE1C,UAAO,IACL,qBACA,iCAAiC,cAClC;;EAGH,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,YAAY,YAAY;AAEvE,MAAI,gBAAgB;AAClB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,eAAe,MAAM,eAAe,QAAQ;;AAGzD,MAAI,WAAW;GACb,MAAM,cAAc,KAAK;GAEzB,MAAM,CAAC,wBAAwB,MAAM,KAAK,QACxC,aACA,UACA,YACD;AAED,OAAI,sBAAsB;AACxB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,qBAAqB,MAAM,qBAAqB,QAAQ;;GAGrE,MAAM,CAAC,2BAA2B,MAAM,KAAK,QAC3C,aACA,aACA,OAAO,YAAY,CACpB;AAED,OAAI,yBAAyB;AAC3B,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IACL,wBAAwB,MACxB,wBAAwB,QACzB;;GAGH,MAAM,CAAC,oBAAoB,MAAM,KAAK,QACpC,aACA,eACA,OAAO,YAAY,CACpB;AAED,OAAI,kBAAkB;AACpB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;;AAG7D,SAAM,KAAK,YAAY,aAAa,MAAM;AAO1C,UAAO,GAL+B;IACpC;IACA,QAAQ;IACT,CAEkB;;AAGrB,MAAI,cAAc;GAChB,MAAM,WAAW,KAAK;GAEtB,MAAM,CAAC,qBAAqB,MAAM,KAAK,QACrC,aACA,UACA,SACD;AAED,OAAI,mBAAmB;AACrB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,kBAAkB,MAAM,kBAAkB,QAAQ;;GAG/D,MAAM,CAAC,sBAAsB,MAAM,KAAK,QACtC,aACA,SACA,eAAe,aAAa,CAC7B;AAED,OAAI,oBAAoB;AACtB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,mBAAmB,MAAM,mBAAmB,QAAQ;;GAGjE,MAAM,CAAC,wBAAwB,MAAM,KAAK,QACxC,aACA,aACA,OAAO,SAAS,CACjB;AAED,OAAI,sBAAsB;AACxB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,qBAAqB,MAAM,qBAAqB,QAAQ;;GAGrE,MAAM,CAAC,iBAAiB,MAAM,KAAK,QACjC,aACA,YACA,OAAO,SAAS,CACjB;AAED,OAAI,eAAe;AACjB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,cAAc,MAAM,cAAc,QAAQ;;AAGvD,SAAM,KAAK,YAAY,aAAa,MAAM;AAE1C,UAAO,IACL,0BACA,sBAAsB,YAAY,WAAW,eAAe,aAAa,GAC1E;;EAGH,MAAM,CAAC,sBAAsB,oBAC3B,KAAK,gBAAgB,OAAO;AAE9B,MAAI,sBAAsB;GACxB,MAAM,WAAW,KAAK;GAEtB,MAAM,CAAC,qBAAqB,MAAM,KAAK,QACrC,aACA,UACA,SACD;AAED,OAAI,mBAAmB;AACrB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,kBAAkB,MAAM,kBAAkB,QAAQ;;GAG/D,MAAM,CAAC,sBAAsB,MAAM,KAAK,QACtC,aACA,SACA,qBAAqB,QACtB;AAED,OAAI,oBAAoB;AACtB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,mBAAmB,MAAM,mBAAmB,QAAQ;;GAGjE,MAAM,CAAC,wBAAwB,MAAM,KAAK,QACxC,aACA,aACA,OAAO,SAAS,CACjB;AAED,OAAI,sBAAsB;AACxB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,qBAAqB,MAAM,qBAAqB,QAAQ;;GAGrE,MAAM,CAAC,iBAAiB,MAAM,KAAK,QACjC,aACA,YACA,OAAO,SAAS,CACjB;AAED,OAAI,eAAe;AACjB,UAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,WAAO,IAAI,cAAc,MAAM,cAAc,QAAQ;;AAGvD,SAAM,KAAK,YAAY,aAAa,MAAM;AAE1C,UAAO,IACL,8BACA,2CAA2C,cAC5C;;EAGH,MAAM,cAAc,KAAK;EAEzB,MAAM,CAAC,wBAAwB,MAAM,KAAK,QACxC,aACA,UACA,iBACD;AAED,MAAI,sBAAsB;AACxB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,qBAAqB,MAAM,qBAAqB,QAAQ;;EAGrE,MAAM,CAAC,wBAAwB,MAAM,KAAK,QACxC,aACA,UACA,YACD;AAED,MAAI,sBAAsB;AACxB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,qBAAqB,MAAM,qBAAqB,QAAQ;;EAGrE,MAAM,CAAC,4BAA4B,MAAM,KAAK,QAC5C,aACA,SACA,GACD;AAED,MAAI,0BAA0B;AAC5B,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IACL,yBAAyB,MACzB,yBAAyB,QAC1B;;EAGH,MAAM,CAAC,+BAA+B,MAAM,KAAK,QAC/C,aACA,YACA,GACD;AAED,MAAI,6BAA6B;AAC/B,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IACL,4BAA4B,MAC5B,4BAA4B,QAC7B;;EAGH,MAAM,CAAC,2BAA2B,MAAM,KAAK,QAC3C,aACA,aACA,OAAO,YAAY,CACpB;AAED,MAAI,yBAAyB;AAC3B,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,wBAAwB,MAAM,wBAAwB,QAAQ;;EAG3E,MAAM,CAAC,oBAAoB,MAAM,KAAK,QACpC,aACA,eACA,OAAO,YAAY,CACpB;AAED,MAAI,kBAAkB;AACpB,SAAM,KAAK,YAAY,aAAa,MAAM;AAC1C,UAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;;AAG7D,QAAM,KAAK,YAAY,aAAa,MAAM;AAO1C,SAAO,GAL+B;GACpC;GACA,QAAQ;GACT,CAEkB;;CAGrB,MAAc,YAAY,aAAqB,OAAe;EAC5D,MAAM,CAAC,WAAW,cAAc,MAAM,WACpC,KAAK,QAAQ,MAAM,IACjB,KAAK,QAAQ,YAAY,EACzB,OACA,MACA,OAAO,KAAK,QAAQ,EACpB,KACD,CACF;AAED,MAAI,UACF,QAAO,IACL,qBACA,wCAAwC,cACzC;AAGH,MAAI,eAAe,KACjB,QAAO,IACL,qBACA,sBAAsB,YAAY,qBACnC;AAGH,SAAO,GAAG,KAAK;;CAGjB,MAAc,YAAY,aAAqB,OAAe;EAI5D,MAAM,CAAC,aAAa,MAAM,WACxB,KAAK,QAAQ,MAAM,KAAK,QAAQ;GAHhC;GAKE;GACA,KAAK,QAAQ,YAAY;GACzB;GACD,CAAC,CACH;AAED,MAAI,UACF,QAAO,IACL,qBACA,wCAAwC,cACzC;AAGH,SAAO,GAAG,KAAK;;CAGjB,MAAc,WAAW,aAAqB,OAAe;EAI3D,MAAM,CAAC,WAAW,UAAU,MAAM,WAChC,KAAK,QAAQ,MAAM,KAAK,QAAQ;GAHhC;GAKE;GACA,KAAK,QAAQ,YAAY;GACzB;GACA,OAAO,KAAK,QAAQ;GACrB,CAAC,CACH;AAED,MAAI,UACF,QAAO,IACL,qBACA,uCAAuC,cACxC;AAGH,MAAI,WAAW,EACb,QAAO,IACL,qBACA,qCAAqC,cACtC;AAGH,SAAO,GAAG,KAAK;;CAGjB,MAAc,YAAY,aAAqB;EAC7C,MAAM,CAAC,aAAa,UAAU,MAAM,KAAK,QAAQ,aAAa,SAAS;AAEvE,MAAI,YACF,QAAO,IAAI,YAAY,MAAM,YAAY,QAAQ;AAGnD,SAAO,GAAG,WAAW,YAAY;;CAGnC,MAAc,QACZ,aACA,OACA,OACA;EACA,MAAM,CAAC,cAAc,MAAM,WACzB,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,OAAO,MAAM,CACjE;AAED,MAAI,WACF,QAAO,IACL,iBACA,qBAAqB,MAAM,iBAAiB,cAC7C;AAGH,SAAO,GAAG,KAAK;;CAGjB,MAAc,QAAQ,aAAqB,OAA0B;EACnE,MAAM,CAAC,WAAW,SAAS,MAAM,WAC/B,KAAK,QAAQ,MAAM,KAAK,KAAK,QAAQ,YAAY,EAAE,MAAM,CAC1D;AAED,MAAI,UACF,QAAO,IACL,iBACA,kBAAkB,MAAM,iBAAiB,cAC1C;AAGH,MAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B,QAAO,GAAG,KAAK;AAGjB,MAAI,OAAO,UAAU,SACnB,QAAO,IACL,sBACA,WAAW,MAAM,uBAAuB,cACzC;AAGH,MAAI,MAAM,WAAW,EACnB,QAAO,GAAG,KAAK;AAGjB,SAAO,GAAG,MAAM;;CAGlB,MAAc,eAAe,aAAqB,OAA0B;EAC1E,MAAM,CAAC,WAAW,SAAS,MAAM,KAAK,QAAQ,aAAa,MAAM;AAEjE,MAAI,UACF,QAAO,IAAI,UAAU,MAAM,UAAU,QAAQ;AAG/C,MAAI,CAAC,MACH,QAAO,GAAG,KAAK;EAGjB,MAAM,SAAS,OAAO,MAAM;AAE5B,MAAI,CAAC,OAAO,SAAS,OAAO,CAC1B,QAAO,IACL,sBACA,WAAW,MAAM,uBAAuB,cACzC;AAGH,SAAO,GAAG,OAAO;;CAGnB,cACE,OACA,YACA,OACA;EACA,MAAM,CAAC,gBAAgB,cAAc,qBACnC,WAAW,MAAM,CAClB;AAED,MAAI,eACF,QAAO,IACL,8BACA,uBAAuB,MAAM,IAAI,eAAe,eAAe,GAChE;AAGH,MAAI,OAAO,eAAe,SACxB,QAAO,IACL,8BACA,GAAG,MAAM,kCACV;AAGH,SAAO,GAAG,WAAW;;CAGvB,gBACE,KACA,cACA,OACA;EACA,MAAM,CAAC,kBAAkB,SAAS,qBAAqB,aAAa,IAAI,CAAC;AAEzE,MAAI,iBACF,QAAO,IACL,8BACA,yBAAyB,MAAM,IAAI,eAAe,iBAAiB,GACpE;AAGH,SAAO,GAAG,MAAM;;CAGlB,eAAuB,OAAe;AACpC,SAAO,KAAK,cACV,OACA,KAAK,QAAQ,kBAAkB,mBAC/B,iBACD;;CAGH,iBAAyB,KAAa;EACpC,MAAM,eACJ,KAAK,QAAQ,sBACX,UAAkB,oBAAoB,MAAM;AAEhD,SAAO,KAAK,gBAAgB,KAAK,cAAc,iBAAiB;;CAGlE,gBAAwB,QAAwB;AAC9C,MAAI,WAAW,KACb,QAAO,GAAG,kBAAkB,KAAK,CAAC;AAGpC,SAAO,KAAK,cACV,QACA,KAAK,QAAQ,mBAAmB,mBAChC,kBACD;;CAGH,kBAA0B,KAAa;EACrC,MAAM,eACJ,KAAK,QAAQ,uBACX,UAAkB,oBAAoB,MAAM;AAEhD,SAAO,KAAK,gBAAgB,KAAK,cAAc,kBAAkB;;CAGnE,oBAA4B,QAAiB;AAC3C,SAAO,KAAK,cACV,QACA,KAAK,QAAQ,uBAAuB,mBACpC,cACD;;CAGH,sBAA8B,KAAa;EACzC,MAAM,eACJ,KAAK,QAAQ,2BACX,UAAkB,oBAAoB,MAAM;AAEhD,SAAO,KAAK,gBAAgB,KAAK,cAAc,cAAc;;CAG/D,MAAc,UAAU,aAAqB;EAC3C,MAAM,CAAC,WAAW,OAAO,MAAM,KAAK,QAAQ,aAAa,QAAQ;AAEjE,MAAI,UACF,QAAO,IAAI,UAAU,MAAM,UAAU,QAAQ;AAG/C,MAAI,CAAC,IACH,QAAO,IACL,sBACA,sBAAsB,YAAY,kBACnC;AAGH,SAAO,KAAK,iBAAiB,IAAI;;CAGnC,MAAc,WAAW,aAAqB;EAC5C,MAAM,CAAC,WAAW,OAAO,MAAM,KAAK,QAAQ,aAAa,SAAS;AAElE,MAAI,UACF,QAAO,IAAI,UAAU,MAAM,UAAU,QAAQ;AAG/C,MAAI,CAAC,IACH,QAAO,GAAG,KAAK;EAGjB,MAAM,CAAC,kBAAkB,UAAU,KAAK,kBAAkB,IAAI;AAE9D,MAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;AAG7D,SAAO,GAAG,OAAO;;CAGnB,MAAc,gBACZ,aACA,UACA,QACA;EACA,MAAM,CAAC,gBAAgB,oBAAoB,KAAK,oBAAoB,OAAO;AAE3E,MAAI,eACF,QAAO,IACL,8BACA,4BAA4B,SAAS,SACtC;EAGH,MAAM,UAAU;GACd,QAAQ;GACR,aAAa,KAAK;GACnB;EAED,MAAM,CAAC,cAAc,cAAc,qBACjC,KAAK,UAAU,QAAQ,CACxB;AAED,MAAI,gBAAgB,OAAO,eAAe,SACxC,QAAO,IACL,8BACA,0BAA0B,SAAS,SACpC;EAGH,MAAM,CAAC,cAAc,MAAM,WACzB,KAAK,QAAQ,MAAM,KAAK,KAAK,SAAS,YAAY,EAAE,UAAU,WAAW,CAC1E;AAED,MAAI,WACF,QAAO,IACL,iBACA,0BAA0B,SAAS,iBAAiB,cACrD;EAGH,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,cAAc,YAAY;AAEzE,MAAI,eACF,QAAO,IAAI,eAAe,MAAM,eAAe,QAAQ;AAGzD,MAAI,CAAC,UAAU,SAAS,SAAS,EAAE;GACjC,MAAM,gBAAgB,CAAC,GAAG,WAAW,SAAS;GAE9C,MAAM,CAAC,qBAAqB,mBAAmB,qBAC7C,KAAK,UAAU,cAAc,CAC9B;AAED,OAAI,uBAAuB,OAAO,oBAAoB,SACpD,QAAO,IACL,8BACA,gDAAgD,cACjD;GAGH,MAAM,CAAC,oBAAoB,MAAM,KAAK,QACpC,aACA,SACA,gBACD;AAED,OAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;;EAI/D,MAAM,CAAC,gBAAgB,MAAM,KAAK,QAChC,aACA,aACA,OAAO,KAAK,CAAC,CACd;AAED,MAAI,aACF,QAAO,IAAI,aAAa,MAAM,aAAa,QAAQ;AAGrD,SAAO,GAAG,KAAK;;CAGjB,MAAc,eAAsB,aAAqB,UAAkB;EACzE,MAAM,CAAC,WAAW,cAAc,MAAM,WACpC,KAAK,QAAQ,MAAM,KAAK,KAAK,SAAS,YAAY,EAAE,SAAS,CAC9D;AAED,MAAI,UACF,QAAO,IACL,iBACA,uBAAuB,SAAS,iBAAiB,cAClD;AAGH,MAAI,CAAC,WACH,QAAO,GAAG;GAAE,OAAO;GAAO,OAAO;GAAM,CAAC;AAG1C,MAAI,OAAO,eAAe,SACxB,QAAO,IACL,sBACA,4BAA4B,SAAS,gBAAgB,cACtD;EAGH,MAAM,CAAC,YAAY,UAAU,qBAAqB,KAAK,MAAM,WAAW,CAAC;AAEzE,MAAI,cAAc,WAAW,QAAQ,OAAO,WAAW,SACrD,QAAO,IACL,sBACA,4BAA4B,SAAS,gBAAgB,cACtD;AAGH,MAAI,OAAO,OAAO,WAAW,SAC3B,QAAO,IACL,sBACA,2BAA2B,SAAS,gBAAgB,cACrD;EAGH,MAAM,YAAY,OAAO;EAEzB,MAAM,CAAC,kBAAkB,SAAS,KAAK,sBAAsB,UAAU;AAEvE,MAAI,iBACF,QAAO,IAAI,iBAAiB,MAAM,iBAAiB,QAAQ;AAG7D,SAAO,GAAG;GAAE,OAAO;GAAa;GAAgB,CAAC;;CAGnD,MAAc,cAAc,aAAqB;EAC/C,MAAM,CAAC,WAAW,YAAY,MAAM,KAAK,QAAQ,aAAa,QAAQ;AAEtE,MAAI,UACF,QAAO,CAAC,WAAW,EAAE,CAAC;AAGxB,MAAI,CAAC,SACH,QAAO,GAAG,EAAE,CAAa;EAG3B,MAAM,CAAC,YAAY,UAAU,qBAAqB,KAAK,MAAM,SAAS,CAAC;AAEvE,MAAI,cAAc,CAAC,MAAM,QAAQ,OAAO,CACtC,QAAO,IACL,sBACA,oCAAoC,cACrC;EAGH,MAAM,YAAsB,EAAE;AAE9B,OAAK,MAAM,SAAS,OAClB,KAAI,OAAO,UAAU,SACnB,WAAU,KAAK,MAAM;AAIzB,SAAO,GAAG,UAAU;;CAGtB,MAAc,kBAAkB,aAAqB;EACnD,MAAM,CAAC,gBAAgB,aAAa,MAAM,KAAK,cAAc,YAAY;AAEzE,MAAI,eACF,QAAO,CAAC,gBAAgB,EAAE,CAAC;EAG7B,MAAM,QAAwB,EAAE;AAEhC,OAAK,MAAM,YAAY,WAAW;GAChC,MAAM,CAAC,WAAW,cAAc,MAAM,WACpC,KAAK,QAAQ,MAAM,KAAK,KAAK,SAAS,YAAY,EAAE,SAAS,CAC9D;AAED,OAAI,UACF,QAAO,IACL,iBACA,uBAAuB,SAAS,iBAAiB,cAClD;AAGH,OAAI,CAAC,WACH;AAGF,OAAI,OAAO,eAAe,SACxB,QAAO,IACL,sBACA,4BAA4B,SAAS,gBAAgB,cACtD;GAGH,MAAM,CAAC,YAAY,UAAU,qBAAqB,KAAK,MAAM,WAAW,CAAC;AAEzE,OAAI,cAAc,WAAW,QAAQ,OAAO,WAAW,SACrD,QAAO,IACL,sBACA,4BAA4B,SAAS,gBAAgB,cACtD;AAGH,OAAI,OAAO,OAAO,gBAAgB,SAChC,QAAO,IACL,sBACA,4BAA4B,SAAS,gBAAgB,cACtD;GAGH,MAAM,cAAc,OAAO;AAE3B,SAAM,KAAK;IACT,MAAM;IACN;IACD,CAAC;;AAGJ,SAAO,GAAG,MAAM;;CAGlB,gBAAwB,OAAe;AACrC,OAAK,MAAM,UAAU,cACnB,KAAI,WAAW,MACb,QAAO;AAIX,SAAO;;;AAIX,MAAa,kBACX,YAC8B;CAC9B,MAAM,WAAW,IAAI,mBAAmB,QAAQ;AAEhD,QAAO;EACL,QAAQ,OAAO,iBAAiB,SAAS,MAAM,OAAO,aAAa;EACnE,MAAM,OAAO,iBAAiB,SAAS,IAAI,OAAO,aAAa;EAC/D,SAAS,gBAAgB,SAAS,OAAO,YAAY;EACrD,MAAM,gBAAgB,SAAS,IAAI,YAAY;EAC/C,SAAS,gBAAgB,SAAS,OAAO,YAAY;EACtD"}