@zhivex-ai/core 1.18.0 → 1.19.1

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 (255) hide show
  1. package/README.md +4 -0
  2. package/dist/agent/approvals.d.ts +7 -0
  3. package/dist/agent/approvals.d.ts.map +1 -0
  4. package/dist/agent/approvals.js +97 -0
  5. package/dist/agent/approvals.js.map +1 -0
  6. package/dist/agent/cancellation.d.ts +4 -0
  7. package/dist/agent/cancellation.d.ts.map +1 -0
  8. package/dist/agent/cancellation.js +69 -0
  9. package/dist/agent/cancellation.js.map +1 -0
  10. package/dist/agent/common.d.ts +20 -0
  11. package/dist/agent/common.d.ts.map +1 -0
  12. package/dist/agent/common.js +150 -0
  13. package/dist/agent/common.js.map +1 -0
  14. package/dist/agent/compaction.d.ts +6 -0
  15. package/dist/agent/compaction.d.ts.map +1 -0
  16. package/dist/agent/compaction.js +156 -0
  17. package/dist/agent/compaction.js.map +1 -0
  18. package/dist/agent/context.d.ts +58 -0
  19. package/dist/agent/context.d.ts.map +1 -0
  20. package/dist/agent/context.js +267 -0
  21. package/dist/agent/context.js.map +1 -0
  22. package/dist/agent/definition.d.ts +4 -0
  23. package/dist/agent/definition.d.ts.map +1 -0
  24. package/dist/agent/definition.js +35 -0
  25. package/dist/agent/definition.js.map +1 -0
  26. package/dist/agent/execution.d.ts +14 -0
  27. package/dist/agent/execution.d.ts.map +1 -0
  28. package/dist/agent/execution.js +1062 -0
  29. package/dist/agent/execution.js.map +1 -0
  30. package/dist/agent/groups.d.ts +3 -0
  31. package/dist/agent/groups.d.ts.map +1 -0
  32. package/dist/agent/groups.js +130 -0
  33. package/dist/agent/groups.js.map +1 -0
  34. package/dist/agent/guardrails.d.ts +4 -0
  35. package/dist/agent/guardrails.d.ts.map +1 -0
  36. package/dist/agent/guardrails.js +29 -0
  37. package/dist/agent/guardrails.js.map +1 -0
  38. package/dist/agent/instance.d.ts +42 -0
  39. package/dist/agent/instance.d.ts.map +1 -0
  40. package/dist/agent/instance.js +82 -0
  41. package/dist/agent/instance.js.map +1 -0
  42. package/dist/agent/lifecycle.d.ts +31 -0
  43. package/dist/agent/lifecycle.d.ts.map +1 -0
  44. package/dist/agent/lifecycle.js +184 -0
  45. package/dist/agent/lifecycle.js.map +1 -0
  46. package/dist/agent/state.d.ts +6 -0
  47. package/dist/agent/state.d.ts.map +1 -0
  48. package/dist/agent/state.js +119 -0
  49. package/dist/agent/state.js.map +1 -0
  50. package/dist/agent/telemetry.d.ts +12 -0
  51. package/dist/agent/telemetry.d.ts.map +1 -0
  52. package/dist/agent/telemetry.js +176 -0
  53. package/dist/agent/telemetry.js.map +1 -0
  54. package/dist/agent/tool-execution.d.ts +6 -0
  55. package/dist/agent/tool-execution.d.ts.map +1 -0
  56. package/dist/agent/tool-execution.js +176 -0
  57. package/dist/agent/tool-execution.js.map +1 -0
  58. package/dist/agent-run-view.d.ts +9 -0
  59. package/dist/agent-run-view.d.ts.map +1 -0
  60. package/dist/agent-run-view.js +42 -0
  61. package/dist/agent-run-view.js.map +1 -0
  62. package/dist/agent-store/file.d.ts +11 -0
  63. package/dist/agent-store/file.d.ts.map +1 -0
  64. package/dist/agent-store/file.js +534 -0
  65. package/dist/agent-store/file.js.map +1 -0
  66. package/dist/agent-store/memory.d.ts +9 -0
  67. package/dist/agent-store/memory.d.ts.map +1 -0
  68. package/dist/agent-store/memory.js +198 -0
  69. package/dist/agent-store/memory.js.map +1 -0
  70. package/dist/agent-store/postgres.d.ts +4 -0
  71. package/dist/agent-store/postgres.d.ts.map +1 -0
  72. package/dist/agent-store/postgres.js +374 -0
  73. package/dist/agent-store/postgres.js.map +1 -0
  74. package/dist/agent-store/shared.d.ts +19 -0
  75. package/dist/agent-store/shared.d.ts.map +1 -0
  76. package/dist/agent-store/shared.js +137 -0
  77. package/dist/agent-store/shared.js.map +1 -0
  78. package/dist/agent-store/sqlite.d.ts +4 -0
  79. package/dist/agent-store/sqlite.d.ts.map +1 -0
  80. package/dist/agent-store/sqlite.js +362 -0
  81. package/dist/agent-store/sqlite.js.map +1 -0
  82. package/dist/agent-store.d.ts +5 -21
  83. package/dist/agent-store.d.ts.map +1 -1
  84. package/dist/agent-store.js +5 -1588
  85. package/dist/agent-store.js.map +1 -1
  86. package/dist/agent.d.ts +6 -57
  87. package/dist/agent.d.ts.map +1 -1
  88. package/dist/agent.js +6 -2631
  89. package/dist/agent.js.map +1 -1
  90. package/dist/agents-entry.d.ts +19 -0
  91. package/dist/agents-entry.d.ts.map +1 -0
  92. package/dist/agents-entry.js +14 -0
  93. package/dist/agents-entry.js.map +1 -0
  94. package/dist/artifact/file.d.ts +6 -0
  95. package/dist/artifact/file.d.ts.map +1 -0
  96. package/dist/artifact/file.js +380 -0
  97. package/dist/artifact/file.js.map +1 -0
  98. package/dist/artifact/memory.d.ts +3 -0
  99. package/dist/artifact/memory.d.ts.map +1 -0
  100. package/dist/artifact/memory.js +80 -0
  101. package/dist/artifact/memory.js.map +1 -0
  102. package/dist/artifact/postgres.d.ts +3 -0
  103. package/dist/artifact/postgres.d.ts.map +1 -0
  104. package/dist/artifact/postgres.js +283 -0
  105. package/dist/artifact/postgres.js.map +1 -0
  106. package/dist/artifact/shared.d.ts +208 -0
  107. package/dist/artifact/shared.d.ts.map +1 -0
  108. package/dist/artifact/shared.js +523 -0
  109. package/dist/artifact/shared.js.map +1 -0
  110. package/dist/artifact/sqlite.d.ts +3 -0
  111. package/dist/artifact/sqlite.d.ts.map +1 -0
  112. package/dist/artifact/sqlite.js +283 -0
  113. package/dist/artifact/sqlite.js.map +1 -0
  114. package/dist/artifact.d.ts +6 -186
  115. package/dist/artifact.d.ts.map +1 -1
  116. package/dist/artifact.js +6 -1536
  117. package/dist/artifact.js.map +1 -1
  118. package/dist/catalog-contracts.d.ts +52 -0
  119. package/dist/catalog-contracts.d.ts.map +1 -0
  120. package/dist/catalog-contracts.js +250 -0
  121. package/dist/catalog-contracts.js.map +1 -0
  122. package/dist/catalog.d.ts +3 -52
  123. package/dist/catalog.d.ts.map +1 -1
  124. package/dist/catalog.js +3 -249
  125. package/dist/catalog.js.map +1 -1
  126. package/dist/generate-cache-file.d.ts +11 -0
  127. package/dist/generate-cache-file.d.ts.map +1 -0
  128. package/dist/generate-cache-file.js +124 -0
  129. package/dist/generate-cache-file.js.map +1 -0
  130. package/dist/generate-text.d.ts +2 -5
  131. package/dist/generate-text.d.ts.map +1 -1
  132. package/dist/generate-text.js +3 -18
  133. package/dist/generate-text.js.map +1 -1
  134. package/dist/generation-entry.d.ts +6 -0
  135. package/dist/generation-entry.d.ts.map +1 -0
  136. package/dist/generation-entry.js +6 -0
  137. package/dist/generation-entry.js.map +1 -0
  138. package/dist/middleware-runtime.d.ts +35 -0
  139. package/dist/middleware-runtime.d.ts.map +1 -0
  140. package/dist/middleware-runtime.js +532 -0
  141. package/dist/middleware-runtime.js.map +1 -0
  142. package/dist/middleware.d.ts +3 -43
  143. package/dist/middleware.d.ts.map +1 -1
  144. package/dist/middleware.js +3 -653
  145. package/dist/middleware.js.map +1 -1
  146. package/dist/normalize-messages.d.ts +3 -0
  147. package/dist/normalize-messages.d.ts.map +1 -0
  148. package/dist/normalize-messages.js +16 -0
  149. package/dist/normalize-messages.js.map +1 -0
  150. package/dist/provider-entry.d.ts +17 -0
  151. package/dist/provider-entry.d.ts.map +1 -0
  152. package/dist/provider-entry.js +13 -0
  153. package/dist/provider-entry.js.map +1 -0
  154. package/dist/realtime.d.ts +2 -0
  155. package/dist/realtime.d.ts.map +1 -1
  156. package/dist/realtime.js +6 -0
  157. package/dist/realtime.js.map +1 -1
  158. package/dist/store-key.d.ts +3 -0
  159. package/dist/store-key.d.ts.map +1 -0
  160. package/dist/store-key.js +5 -0
  161. package/dist/store-key.js.map +1 -0
  162. package/dist/store-security.d.ts +1 -2
  163. package/dist/store-security.d.ts.map +1 -1
  164. package/dist/store-security.js +2 -4
  165. package/dist/store-security.js.map +1 -1
  166. package/dist/types/agent-state.d.ts +236 -0
  167. package/dist/types/agent-state.d.ts.map +1 -0
  168. package/dist/types/agent-state.js +2 -0
  169. package/dist/types/agent-state.js.map +1 -0
  170. package/dist/types/agents.d.ts +429 -0
  171. package/dist/types/agents.d.ts.map +1 -0
  172. package/dist/types/agents.js +2 -0
  173. package/dist/types/agents.js.map +1 -0
  174. package/dist/types/common.d.ts +179 -0
  175. package/dist/types/common.d.ts.map +1 -0
  176. package/dist/types/common.js +2 -0
  177. package/dist/types/common.js.map +1 -0
  178. package/dist/types/generation.d.ts +109 -0
  179. package/dist/types/generation.d.ts.map +1 -0
  180. package/dist/types/generation.js +2 -0
  181. package/dist/types/generation.js.map +1 -0
  182. package/dist/types/media-data.d.ts +65 -0
  183. package/dist/types/media-data.d.ts.map +1 -0
  184. package/dist/types/media-data.js +2 -0
  185. package/dist/types/media-data.js.map +1 -0
  186. package/dist/types/media.d.ts +141 -0
  187. package/dist/types/media.d.ts.map +1 -0
  188. package/dist/types/media.js +2 -0
  189. package/dist/types/media.js.map +1 -0
  190. package/dist/types/messages.d.ts +82 -0
  191. package/dist/types/messages.d.ts.map +1 -0
  192. package/dist/types/messages.js +2 -0
  193. package/dist/types/messages.js.map +1 -0
  194. package/dist/types/middleware.d.ts +130 -0
  195. package/dist/types/middleware.d.ts.map +1 -0
  196. package/dist/types/middleware.js +2 -0
  197. package/dist/types/middleware.js.map +1 -0
  198. package/dist/types/model-tools.d.ts +409 -0
  199. package/dist/types/model-tools.d.ts.map +1 -0
  200. package/dist/types/model-tools.js +2 -0
  201. package/dist/types/model-tools.js.map +1 -0
  202. package/dist/types/persistence.d.ts +168 -0
  203. package/dist/types/persistence.d.ts.map +1 -0
  204. package/dist/types/persistence.js +2 -0
  205. package/dist/types/persistence.js.map +1 -0
  206. package/dist/types/provider-resources.d.ts +336 -0
  207. package/dist/types/provider-resources.d.ts.map +1 -0
  208. package/dist/types/provider-resources.js +2 -0
  209. package/dist/types/provider-resources.js.map +1 -0
  210. package/dist/types/provider.d.ts +23 -0
  211. package/dist/types/provider.d.ts.map +1 -0
  212. package/dist/types/provider.js +2 -0
  213. package/dist/types/provider.js.map +1 -0
  214. package/dist/types/resource-options.d.ts +88 -0
  215. package/dist/types/resource-options.d.ts.map +1 -0
  216. package/dist/types/resource-options.js +2 -0
  217. package/dist/types/resource-options.js.map +1 -0
  218. package/dist/types/stream.d.ts +70 -0
  219. package/dist/types/stream.d.ts.map +1 -0
  220. package/dist/types/stream.js +2 -0
  221. package/dist/types/stream.js.map +1 -0
  222. package/dist/types/ui.d.ts +110 -0
  223. package/dist/types/ui.d.ts.map +1 -0
  224. package/dist/types/ui.js +2 -0
  225. package/dist/types/ui.js.map +1 -0
  226. package/dist/types.d.ts +16 -2480
  227. package/dist/types.d.ts.map +1 -1
  228. package/dist/ui.d.ts.map +1 -1
  229. package/dist/ui.js +2 -0
  230. package/dist/ui.js.map +1 -1
  231. package/dist/workflow-state-service/file.d.ts +5 -0
  232. package/dist/workflow-state-service/file.d.ts.map +1 -0
  233. package/dist/workflow-state-service/file.js +142 -0
  234. package/dist/workflow-state-service/file.js.map +1 -0
  235. package/dist/workflow-state-service/memory.d.ts +3 -0
  236. package/dist/workflow-state-service/memory.d.ts.map +1 -0
  237. package/dist/workflow-state-service/memory.js +27 -0
  238. package/dist/workflow-state-service/memory.js.map +1 -0
  239. package/dist/workflow-state-service/postgres.d.ts +4 -0
  240. package/dist/workflow-state-service/postgres.d.ts.map +1 -0
  241. package/dist/workflow-state-service/postgres.js +179 -0
  242. package/dist/workflow-state-service/postgres.js.map +1 -0
  243. package/dist/workflow-state-service/shared.d.ts +43 -0
  244. package/dist/workflow-state-service/shared.d.ts.map +1 -0
  245. package/dist/workflow-state-service/shared.js +107 -0
  246. package/dist/workflow-state-service/shared.js.map +1 -0
  247. package/dist/workflow-state-service/sqlite.d.ts +4 -0
  248. package/dist/workflow-state-service/sqlite.d.ts.map +1 -0
  249. package/dist/workflow-state-service/sqlite.js +183 -0
  250. package/dist/workflow-state-service/sqlite.js.map +1 -0
  251. package/dist/workflow-state-service.d.ts +6 -33
  252. package/dist/workflow-state-service.d.ts.map +1 -1
  253. package/dist/workflow-state-service.js +6 -626
  254. package/dist/workflow-state-service.js.map +1 -1
  255. package/package.json +17 -1
@@ -1,628 +1,8 @@
1
- import { promises as fs } from "node:fs";
2
- import path from "node:path";
3
- import { ConflictError, ValidationError } from "./errors.js";
4
- import { assertPostgresClient } from "./postgres-client.js";
5
- import { canonicalStoreFileStem, canonicalStoreKey, ensurePrivateDirectory, writePrivateFile } from "./store-security.js";
6
- import { normalizeWorkflowRunState, WORKFLOW_RUN_STATE_SCHEMA_VERSION, WORKFLOW_STATE_RECORD_SCHEMA_VERSION } from "./workflow-state-contracts.js";
1
+ /** Compatibility facade. Backend implementations live in dedicated internal modules. */
7
2
  export { WORKFLOW_STATE_RECORD_SCHEMA_VERSION } from "./workflow-state-contracts.js";
8
- const cloneJson = (value) => JSON.parse(JSON.stringify(value));
9
- const identifierPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
10
- const workflowStateParts = (input) => [input.appName, input.userId, input.sessionId, input.workflowKey];
11
- const workflowStateKey = (input) => canonicalStoreKey("workflow-state", workflowStateParts(input));
12
- const legacyWorkflowStateKey = (input) => `${input.appName}:${input.userId}:${input.sessionId}:${input.workflowKey}`;
13
- const matchesWorkflowStateLookup = (record, input) => record.appName === input.appName &&
14
- record.userId === input.userId &&
15
- record.sessionId === input.sessionId &&
16
- record.workflowKey === input.workflowKey;
17
- const fileNameForWorkflowState = (input) => `${canonicalStoreFileStem("workflow-state", workflowStateParts(input))}.json`;
18
- const legacyFileNameForWorkflowState = (input) => workflowStateParts(input).map((part) => encodeURIComponent(part)).join("__") + ".json";
19
- export const normalizeWorkflowStateRecord = (value) => {
20
- if (!value || typeof value !== "object" || Array.isArray(value)) {
21
- throw new ValidationError("WorkflowStateRecord must be an object.");
22
- }
23
- const record = value;
24
- if (record.schemaVersion !== undefined && record.schemaVersion > WORKFLOW_STATE_RECORD_SCHEMA_VERSION) {
25
- throw new ValidationError(`Unsupported WorkflowStateRecord schemaVersion ${record.schemaVersion}.`);
26
- }
27
- if (typeof record.appName !== "string" ||
28
- typeof record.userId !== "string" ||
29
- typeof record.sessionId !== "string" ||
30
- typeof record.workflowKey !== "string" ||
31
- typeof record.runId !== "string" ||
32
- typeof record.status !== "string" ||
33
- typeof record.createdAt !== "number" ||
34
- typeof record.updatedAt !== "number" ||
35
- !record.state) {
36
- throw new ValidationError("WorkflowStateRecord is missing required fields.");
37
- }
38
- return {
39
- schemaVersion: WORKFLOW_STATE_RECORD_SCHEMA_VERSION,
40
- revision: typeof record.revision === "number" ? record.revision : 1,
41
- appName: record.appName,
42
- userId: record.userId,
43
- sessionId: record.sessionId,
44
- workflowKey: record.workflowKey,
45
- state: normalizeWorkflowRunState(record.state),
46
- status: record.status,
47
- runId: record.runId,
48
- createdAt: record.createdAt,
49
- updatedAt: record.updatedAt
50
- };
51
- };
52
- export const migrateWorkflowStateRecord = (value, targetVersion = WORKFLOW_STATE_RECORD_SCHEMA_VERSION) => {
53
- if (targetVersion !== WORKFLOW_STATE_RECORD_SCHEMA_VERSION) {
54
- throw new ValidationError(`Unsupported WorkflowStateRecord migration target ${targetVersion}.`);
55
- }
56
- return normalizeWorkflowStateRecord(value);
57
- };
58
- const assertExpectedRevision = (current, expectedRevision) => {
59
- if (expectedRevision !== undefined && (current?.revision ?? 0) !== expectedRevision) {
60
- throw new ConflictError("WorkflowStateRecord revision conflict.");
61
- }
62
- };
63
- const sqliteMutationCount = (result) => {
64
- if (!result || typeof result !== "object") {
65
- return undefined;
66
- }
67
- const record = result;
68
- const value = record.changes ?? record.changeset ?? record.rowCount;
69
- return typeof value === "number" ? value : undefined;
70
- };
71
- const cloneRecord = (record) => cloneJson(normalizeWorkflowStateRecord(record));
72
- const createRecord = (input, existing) => {
73
- const now = Date.now();
74
- const state = normalizeWorkflowRunState(input.state);
75
- return {
76
- schemaVersion: WORKFLOW_STATE_RECORD_SCHEMA_VERSION,
77
- revision: existing ? existing.revision + 1 : 1,
78
- appName: input.appName,
79
- userId: input.userId,
80
- sessionId: input.sessionId,
81
- workflowKey: input.workflowKey,
82
- state: cloneJson({ ...state, schemaVersion: WORKFLOW_RUN_STATE_SCHEMA_VERSION }),
83
- status: state.status,
84
- runId: state.runId,
85
- createdAt: existing?.createdAt ?? now,
86
- updatedAt: now
87
- };
88
- };
89
- const matchesListInput = (record, input) => record.appName === input.appName &&
90
- record.userId === input.userId &&
91
- (input.sessionId === undefined || record.sessionId === input.sessionId) &&
92
- (input.workflowKey === undefined || record.workflowKey === input.workflowKey) &&
93
- (input.status === undefined || record.status === input.status);
94
- const validateIdentifier = (value, fieldName) => {
95
- if (!identifierPattern.test(value)) {
96
- throw new ValidationError(`The "${fieldName}" option must match the SQL identifier pattern [A-Za-z_][A-Za-z0-9_]*.`);
97
- }
98
- return value;
99
- };
100
- const getRecordField = (value, candidates) => {
101
- if (!value || typeof value !== "object") {
102
- return undefined;
103
- }
104
- const record = value;
105
- for (const candidate of candidates) {
106
- if (candidate in record) {
107
- return record[candidate];
108
- }
109
- }
110
- return undefined;
111
- };
112
- const parseWorkflowStateJson = (value) => {
113
- if (!value) {
114
- return undefined;
115
- }
116
- if (typeof value === "string") {
117
- return normalizeWorkflowStateRecord(JSON.parse(value));
118
- }
119
- return normalizeWorkflowStateRecord(value);
120
- };
121
- const prepareSqliteStatement = (db, sql) => {
122
- if (typeof db.prepare === "function") {
123
- return db.prepare(sql);
124
- }
125
- if (typeof db.query === "function") {
126
- return db.query(sql);
127
- }
128
- throw new ValidationError('The "db" option must expose either a "prepare()" or "query()" method.');
129
- };
130
- const ensurePostgresTable = (() => {
131
- const initializedTables = new WeakMap();
132
- return async (client, tableName, createSql) => {
133
- let tables = initializedTables.get(client);
134
- if (!tables) {
135
- tables = new Map();
136
- initializedTables.set(client, tables);
137
- }
138
- let initialization = tables.get(tableName);
139
- if (!initialization) {
140
- initialization = Promise.resolve(client.query(createSql, [])).then(() => undefined);
141
- tables.set(tableName, initialization);
142
- }
143
- await initialization;
144
- };
145
- })();
146
- export const createInMemoryWorkflowStateService = () => {
147
- const states = new Map();
148
- return {
149
- saveWorkflowState(input) {
150
- const existing = states.get(workflowStateKey(input));
151
- assertExpectedRevision(existing, input.expectedRevision);
152
- const record = createRecord(input, existing);
153
- states.set(workflowStateKey(input), cloneRecord(record));
154
- return cloneRecord(record);
155
- },
156
- loadWorkflowState(input) {
157
- const record = states.get(workflowStateKey(input));
158
- return record ? cloneRecord(record) : undefined;
159
- },
160
- listWorkflowStates(input) {
161
- return [...states.values()]
162
- .filter((record) => matchesListInput(record, input))
163
- .sort((left, right) => left.updatedAt - right.updatedAt || left.workflowKey.localeCompare(right.workflowKey))
164
- .map(cloneRecord);
165
- },
166
- deleteWorkflowState(input) {
167
- states.delete(workflowStateKey(input));
168
- }
169
- };
170
- };
171
- export const createFileWorkflowStateService = (options) => {
172
- const filePath = (input) => path.join(options.directory, fileNameForWorkflowState(input));
173
- const legacyFilePath = (input) => path.join(options.directory, legacyFileNameForWorkflowState(input));
174
- const load = async (input) => {
175
- for (const candidate of [filePath(input), legacyFilePath(input)]) {
176
- try {
177
- const record = normalizeWorkflowStateRecord(JSON.parse(await fs.readFile(candidate, "utf8")));
178
- if (matchesWorkflowStateLookup(record, input)) {
179
- return record;
180
- }
181
- }
182
- catch (error) {
183
- if (error.code !== "ENOENT") {
184
- throw error;
185
- }
186
- }
187
- }
188
- return undefined;
189
- };
190
- return {
191
- async saveWorkflowState(input) {
192
- const existing = await load(input);
193
- assertExpectedRevision(existing, input.expectedRevision);
194
- const record = createRecord(input, existing);
195
- await ensurePrivateDirectory(options.directory);
196
- await writePrivateFile(filePath(input), JSON.stringify(record, null, 2));
197
- try {
198
- const legacy = normalizeWorkflowStateRecord(JSON.parse(await fs.readFile(legacyFilePath(input), "utf8")));
199
- if (matchesWorkflowStateLookup(legacy, input)) {
200
- await fs.unlink(legacyFilePath(input));
201
- }
202
- }
203
- catch (error) {
204
- if (error.code !== "ENOENT") {
205
- throw error;
206
- }
207
- }
208
- return cloneRecord(record);
209
- },
210
- loadWorkflowState(input) {
211
- return load(input);
212
- },
213
- async listWorkflowStates(input) {
214
- let entries;
215
- try {
216
- entries = await fs.readdir(options.directory);
217
- }
218
- catch (error) {
219
- if (error.code === "ENOENT") {
220
- return [];
221
- }
222
- throw error;
223
- }
224
- const records = new Map();
225
- for (const entry of entries) {
226
- if (!entry.endsWith(".json")) {
227
- continue;
228
- }
229
- const record = normalizeWorkflowStateRecord(JSON.parse(await fs.readFile(path.join(options.directory, entry), "utf8")));
230
- if (matchesListInput(record, input)) {
231
- const key = workflowStateKey(record);
232
- if (!records.has(key) || entry === fileNameForWorkflowState(record)) {
233
- records.set(key, cloneRecord(record));
234
- }
235
- }
236
- }
237
- return [...records.values()].sort((left, right) => left.updatedAt - right.updatedAt || left.workflowKey.localeCompare(right.workflowKey));
238
- },
239
- async deleteWorkflowState(input) {
240
- await fs.unlink(filePath(input)).catch((error) => {
241
- if (error.code !== "ENOENT") {
242
- throw error;
243
- }
244
- });
245
- try {
246
- const legacy = normalizeWorkflowStateRecord(JSON.parse(await fs.readFile(legacyFilePath(input), "utf8")));
247
- if (matchesWorkflowStateLookup(legacy, input)) {
248
- await fs.unlink(legacyFilePath(input));
249
- }
250
- }
251
- catch (error) {
252
- if (error.code !== "ENOENT") {
253
- throw error;
254
- }
255
- }
256
- }
257
- };
258
- };
259
- export const pruneFileWorkflowStateStore = async (options) => {
260
- const now = options.now ?? Date.now();
261
- const dryRun = options.dryRun ?? true;
262
- let entries;
263
- try {
264
- entries = await fs.readdir(options.directory);
265
- }
266
- catch (error) {
267
- if (error.code === "ENOENT") {
268
- return { directory: options.directory, dryRun, deletedWorkflowStateKeys: [], keptWorkflowStateKeys: [] };
269
- }
270
- throw error;
271
- }
272
- const records = new Map();
273
- for (const entry of entries) {
274
- if (!entry.endsWith(".json")) {
275
- continue;
276
- }
277
- const filePath = path.join(options.directory, entry);
278
- const record = normalizeWorkflowStateRecord(JSON.parse(await fs.readFile(filePath, "utf8")));
279
- const key = workflowStateKey(record);
280
- const existing = records.get(key);
281
- records.set(key, {
282
- filePaths: [...(existing?.filePaths ?? []), filePath],
283
- key,
284
- updatedAt: entry === fileNameForWorkflowState(record) || !existing ? record.updatedAt : existing.updatedAt
285
- });
286
- }
287
- const sorted = [...records.values()].sort((left, right) => right.updatedAt - left.updatedAt || left.key.localeCompare(right.key));
288
- const keepByCount = new Set(options.keepLast === undefined ? [] : sorted.slice(0, Math.max(0, options.keepLast)).map((record) => record.key));
289
- const shouldDelete = (record) => !keepByCount.has(record.key) &&
290
- (options.olderThanMs !== undefined ? now - record.updatedAt > options.olderThanMs : options.keepLast !== undefined);
291
- const deleted = sorted.filter(shouldDelete);
292
- if (!dryRun) {
293
- for (const record of deleted) {
294
- for (const filePath of record.filePaths) {
295
- await fs.unlink(filePath);
296
- }
297
- }
298
- }
299
- return {
300
- directory: options.directory,
301
- dryRun,
302
- deletedWorkflowStateKeys: deleted.map((record) => record.key),
303
- keptWorkflowStateKeys: sorted.filter((record) => !shouldDelete(record)).map((record) => record.key)
304
- };
305
- };
306
- export const createSqliteWorkflowStateService = (options) => {
307
- const tableName = validateIdentifier(options.tableName ?? "zhivex_workflow_states", "tableName");
308
- options.db.exec(`
309
- CREATE TABLE IF NOT EXISTS ${tableName} (
310
- workflow_state_key TEXT PRIMARY KEY,
311
- app_name TEXT NOT NULL,
312
- user_id TEXT NOT NULL,
313
- session_id TEXT NOT NULL,
314
- workflow_key TEXT NOT NULL,
315
- run_id TEXT NOT NULL,
316
- status TEXT NOT NULL,
317
- state_json TEXT NOT NULL,
318
- created_at_ms INTEGER NOT NULL,
319
- updated_at_ms INTEGER NOT NULL
320
- )
321
- `);
322
- const loadStatement = prepareSqliteStatement(options.db, `SELECT state_json FROM ${tableName} WHERE workflow_state_key = ?`);
323
- const listStatement = prepareSqliteStatement(options.db, `SELECT state_json FROM ${tableName}
324
- WHERE app_name = ?
325
- AND user_id = ?
326
- AND (? IS NULL OR session_id = ?)
327
- AND (? IS NULL OR workflow_key = ?)
328
- AND (? IS NULL OR status = ?)
329
- ORDER BY updated_at_ms ASC, workflow_key ASC`);
330
- const saveStatement = prepareSqliteStatement(options.db, `
331
- INSERT INTO ${tableName} (
332
- workflow_state_key, app_name, user_id, session_id, workflow_key, run_id, status, state_json, created_at_ms, updated_at_ms
333
- )
334
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
335
- ON CONFLICT(workflow_state_key) DO UPDATE SET
336
- app_name = excluded.app_name,
337
- user_id = excluded.user_id,
338
- session_id = excluded.session_id,
339
- workflow_key = excluded.workflow_key,
340
- run_id = excluded.run_id,
341
- status = excluded.status,
342
- state_json = excluded.state_json,
343
- updated_at_ms = excluded.updated_at_ms
344
- `);
345
- const updateCasStatement = prepareSqliteStatement(options.db, `
346
- UPDATE ${tableName}
347
- SET app_name = ?,
348
- user_id = ?,
349
- session_id = ?,
350
- workflow_key = ?,
351
- run_id = ?,
352
- status = ?,
353
- state_json = ?,
354
- updated_at_ms = ?
355
- WHERE workflow_state_key = ?
356
- AND updated_at_ms = ?
357
- `);
358
- const deleteStatement = prepareSqliteStatement(options.db, `DELETE FROM ${tableName} WHERE workflow_state_key = ?`);
359
- const load = (input) => {
360
- for (const key of [workflowStateKey(input), legacyWorkflowStateKey(input)]) {
361
- const record = parseWorkflowStateJson(getRecordField(loadStatement.get([key]), ["state_json", "stateJson"]));
362
- if (record && matchesWorkflowStateLookup(record, input)) {
363
- return record;
364
- }
365
- }
366
- return undefined;
367
- };
368
- const save = (record, options) => {
369
- if (options?.expectedRevision !== undefined && options.existing) {
370
- const canonical = parseWorkflowStateJson(getRecordField(loadStatement.get([workflowStateKey(record)]), ["state_json", "stateJson"]));
371
- if (canonical && matchesWorkflowStateLookup(canonical, record)) {
372
- const result = updateCasStatement.run([
373
- record.appName,
374
- record.userId,
375
- record.sessionId,
376
- record.workflowKey,
377
- record.runId,
378
- record.status,
379
- JSON.stringify(record),
380
- record.updatedAt,
381
- workflowStateKey(record),
382
- options.existing.updatedAt
383
- ]);
384
- if (sqliteMutationCount(result) === 0) {
385
- throw new ConflictError("WorkflowStateRecord revision conflict.");
386
- }
387
- }
388
- else {
389
- const legacy = parseWorkflowStateJson(getRecordField(loadStatement.get([legacyWorkflowStateKey(record)]), ["state_json", "stateJson"]));
390
- if (!legacy || !matchesWorkflowStateLookup(legacy, record) || legacy.updatedAt !== options.existing.updatedAt) {
391
- throw new ConflictError("WorkflowStateRecord revision conflict.");
392
- }
393
- saveStatement.run([
394
- workflowStateKey(record),
395
- record.appName,
396
- record.userId,
397
- record.sessionId,
398
- record.workflowKey,
399
- record.runId,
400
- record.status,
401
- JSON.stringify(record),
402
- record.createdAt,
403
- record.updatedAt
404
- ]);
405
- }
406
- }
407
- else {
408
- saveStatement.run([
409
- workflowStateKey(record),
410
- record.appName,
411
- record.userId,
412
- record.sessionId,
413
- record.workflowKey,
414
- record.runId,
415
- record.status,
416
- JSON.stringify(record),
417
- record.createdAt,
418
- record.updatedAt
419
- ]);
420
- }
421
- const legacy = parseWorkflowStateJson(getRecordField(loadStatement.get([legacyWorkflowStateKey(record)]), ["state_json", "stateJson"]));
422
- if (legacy && matchesWorkflowStateLookup(legacy, record)) {
423
- deleteStatement.run([legacyWorkflowStateKey(record)]);
424
- }
425
- return cloneRecord(record);
426
- };
427
- return {
428
- saveWorkflowState(input) {
429
- const existing = load(input);
430
- assertExpectedRevision(existing, input.expectedRevision);
431
- return save(createRecord(input, existing), {
432
- existing,
433
- expectedRevision: input.expectedRevision
434
- });
435
- },
436
- loadWorkflowState(input) {
437
- return load(input);
438
- },
439
- listWorkflowStates(input) {
440
- const params = [
441
- input.appName,
442
- input.userId,
443
- input.sessionId ?? null,
444
- input.sessionId ?? null,
445
- input.workflowKey ?? null,
446
- input.workflowKey ?? null,
447
- input.status ?? null,
448
- input.status ?? null
449
- ];
450
- const rows = listStatement.all?.(params) ?? [];
451
- const records = new Map();
452
- for (const row of rows) {
453
- const record = parseWorkflowStateJson(getRecordField(row, ["state_json", "stateJson"]));
454
- if (record) {
455
- records.set(workflowStateKey(record), record);
456
- }
457
- }
458
- return [...records.values()];
459
- },
460
- deleteWorkflowState(input) {
461
- deleteStatement.run([workflowStateKey(input)]);
462
- const legacy = parseWorkflowStateJson(getRecordField(loadStatement.get([legacyWorkflowStateKey(input)]), ["state_json", "stateJson"]));
463
- if (legacy && matchesWorkflowStateLookup(legacy, input)) {
464
- deleteStatement.run([legacyWorkflowStateKey(input)]);
465
- }
466
- }
467
- };
468
- };
469
- export const createPostgresWorkflowStateService = (options) => {
470
- assertPostgresClient(options.client);
471
- const tableName = validateIdentifier(options.tableName ?? "zhivex_workflow_states", "tableName");
472
- const createSql = `
473
- CREATE TABLE IF NOT EXISTS ${tableName} (
474
- workflow_state_key TEXT PRIMARY KEY,
475
- app_name TEXT NOT NULL,
476
- user_id TEXT NOT NULL,
477
- session_id TEXT NOT NULL,
478
- workflow_key TEXT NOT NULL,
479
- run_id TEXT NOT NULL,
480
- status TEXT NOT NULL,
481
- state_json JSONB NOT NULL,
482
- created_at_ms BIGINT NOT NULL,
483
- updated_at_ms BIGINT NOT NULL
484
- )
485
- `;
486
- const load = async (input) => {
487
- await ensurePostgresTable(options.client, tableName, createSql);
488
- for (const key of [workflowStateKey(input), legacyWorkflowStateKey(input)]) {
489
- const result = await options.client.query(`SELECT state_json FROM ${tableName} WHERE workflow_state_key = $1`, [key]);
490
- const record = parseWorkflowStateJson(getRecordField(result.rows[0], ["state_json", "stateJson"]));
491
- if (record && matchesWorkflowStateLookup(record, input)) {
492
- return record;
493
- }
494
- }
495
- return undefined;
496
- };
497
- const save = async (record, saveOptions) => {
498
- await ensurePostgresTable(options.client, tableName, createSql);
499
- if (saveOptions?.expectedRevision !== undefined && saveOptions.existing) {
500
- const result = await options.client.query(`UPDATE ${tableName}
501
- SET app_name = $2,
502
- user_id = $3,
503
- session_id = $4,
504
- workflow_key = $5,
505
- run_id = $6,
506
- status = $7,
507
- state_json = $8::jsonb,
508
- updated_at_ms = $9
509
- WHERE workflow_state_key = $1
510
- AND updated_at_ms = $10
511
- RETURNING state_json`, [
512
- workflowStateKey(record),
513
- record.appName,
514
- record.userId,
515
- record.sessionId,
516
- record.workflowKey,
517
- record.runId,
518
- record.status,
519
- JSON.stringify(record),
520
- record.updatedAt,
521
- saveOptions.existing.updatedAt
522
- ]);
523
- if (result.rows.length === 0) {
524
- const migrated = await options.client.query(`UPDATE ${tableName}
525
- SET workflow_state_key = $1,
526
- app_name = $2,
527
- user_id = $3,
528
- session_id = $4,
529
- workflow_key = $5,
530
- run_id = $6,
531
- status = $7,
532
- state_json = $8::jsonb,
533
- updated_at_ms = $9
534
- WHERE workflow_state_key = $10
535
- AND updated_at_ms = $11
536
- RETURNING state_json`, [
537
- workflowStateKey(record),
538
- record.appName,
539
- record.userId,
540
- record.sessionId,
541
- record.workflowKey,
542
- record.runId,
543
- record.status,
544
- JSON.stringify(record),
545
- record.updatedAt,
546
- legacyWorkflowStateKey(record),
547
- saveOptions.existing.updatedAt
548
- ]);
549
- if (migrated.rows.length === 0) {
550
- throw new ConflictError("WorkflowStateRecord revision conflict.");
551
- }
552
- }
553
- }
554
- else {
555
- await options.client.query(`INSERT INTO ${tableName} (
556
- workflow_state_key, app_name, user_id, session_id, workflow_key, run_id, status, state_json, created_at_ms, updated_at_ms
557
- )
558
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)
559
- ON CONFLICT(workflow_state_key) DO UPDATE SET
560
- app_name = EXCLUDED.app_name,
561
- user_id = EXCLUDED.user_id,
562
- session_id = EXCLUDED.session_id,
563
- workflow_key = EXCLUDED.workflow_key,
564
- run_id = EXCLUDED.run_id,
565
- status = EXCLUDED.status,
566
- state_json = EXCLUDED.state_json,
567
- updated_at_ms = EXCLUDED.updated_at_ms`, [
568
- workflowStateKey(record),
569
- record.appName,
570
- record.userId,
571
- record.sessionId,
572
- record.workflowKey,
573
- record.runId,
574
- record.status,
575
- JSON.stringify(record),
576
- record.createdAt,
577
- record.updatedAt
578
- ]);
579
- }
580
- const legacyResult = await options.client.query(`SELECT state_json FROM ${tableName} WHERE workflow_state_key = $1`, [legacyWorkflowStateKey(record)]);
581
- const legacy = parseWorkflowStateJson(getRecordField(legacyResult.rows[0], ["state_json", "stateJson"]));
582
- if (legacy && matchesWorkflowStateLookup(legacy, record)) {
583
- await options.client.query(`DELETE FROM ${tableName} WHERE workflow_state_key = $1`, [legacyWorkflowStateKey(record)]);
584
- }
585
- return cloneRecord(record);
586
- };
587
- return {
588
- async saveWorkflowState(input) {
589
- const existing = await load(input);
590
- assertExpectedRevision(existing, input.expectedRevision);
591
- return save(createRecord(input, existing), {
592
- existing,
593
- expectedRevision: input.expectedRevision
594
- });
595
- },
596
- loadWorkflowState(input) {
597
- return load(input);
598
- },
599
- async listWorkflowStates(input) {
600
- await ensurePostgresTable(options.client, tableName, createSql);
601
- const result = await options.client.query(`SELECT state_json FROM ${tableName}
602
- WHERE app_name = $1
603
- AND user_id = $2
604
- AND ($3::text IS NULL OR session_id = $3)
605
- AND ($4::text IS NULL OR workflow_key = $4)
606
- AND ($5::text IS NULL OR status = $5)
607
- ORDER BY updated_at_ms ASC, workflow_key ASC`, [input.appName, input.userId, input.sessionId ?? null, input.workflowKey ?? null, input.status ?? null]);
608
- const records = new Map();
609
- for (const row of result.rows) {
610
- const record = parseWorkflowStateJson(getRecordField(row, ["state_json", "stateJson"]));
611
- if (record) {
612
- records.set(workflowStateKey(record), record);
613
- }
614
- }
615
- return [...records.values()];
616
- },
617
- async deleteWorkflowState(input) {
618
- await ensurePostgresTable(options.client, tableName, createSql);
619
- await options.client.query(`DELETE FROM ${tableName} WHERE workflow_state_key = $1`, [workflowStateKey(input)]);
620
- const legacyResult = await options.client.query(`SELECT state_json FROM ${tableName} WHERE workflow_state_key = $1`, [legacyWorkflowStateKey(input)]);
621
- const legacy = parseWorkflowStateJson(getRecordField(legacyResult.rows[0], ["state_json", "stateJson"]));
622
- if (legacy && matchesWorkflowStateLookup(legacy, input)) {
623
- await options.client.query(`DELETE FROM ${tableName} WHERE workflow_state_key = $1`, [legacyWorkflowStateKey(input)]);
624
- }
625
- }
626
- };
627
- };
3
+ export { normalizeWorkflowStateRecord, migrateWorkflowStateRecord } from "./workflow-state-service/shared.js";
4
+ export { createInMemoryWorkflowStateService } from "./workflow-state-service/memory.js";
5
+ export { createFileWorkflowStateService, pruneFileWorkflowStateStore } from "./workflow-state-service/file.js";
6
+ export { createSqliteWorkflowStateService } from "./workflow-state-service/sqlite.js";
7
+ export { createPostgresWorkflowStateService } from "./workflow-state-service/postgres.js";
628
8
  //# sourceMappingURL=workflow-state-service.js.map