@voltro/cli 0.24.0 → 0.25.0

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 (90) hide show
  1. package/CHANGELOG.md +426 -0
  2. package/THIRD-PARTY-NOTICES.md +2 -2
  3. package/dist/{apiBuild-B2m4XK_8.js → apiBuild-BqhCSytw.js} +15 -15
  4. package/dist/apiBuild-N1R4V792.js +2 -0
  5. package/dist/bin.js +3 -3
  6. package/dist/{commands-CaIhTsC2.js → commands-7EmYJ9Xg.js} +1774 -1577
  7. package/dist/dbCommand-CIrdFLp9.js +2 -0
  8. package/dist/{dbCommand-CC61CsAc.js → dbCommand-FUU12FvD.js} +265 -256
  9. package/dist/{dev-DPkQVUTP.js → dev-BvHT7WZa.js} +1 -1
  10. package/dist/{dev-NCuEhNxs.js → dev-MacSQ1Ll.js} +2019 -1626
  11. package/dist/fileConventions-3bffWssN.js +30 -0
  12. package/dist/frameworkTableAssembly-BsnCKzQ6.js +2 -0
  13. package/dist/{frameworkTableAssembly-sg41s14F.js → frameworkTableAssembly-Cw5zJz6n.js} +2 -2
  14. package/dist/index.js +1 -1
  15. package/dist/inspect-C9gjHwBk.js +2 -0
  16. package/dist/{inspect-_ldwsAwH.js → inspect-DuLUrZp9.js} +14 -1
  17. package/dist/{inspectMetrics-dcC7gnxu.js → inspectMetrics-EQwH7BI4.js} +15 -15
  18. package/dist/manifestBuild-BVwS1Z_6.js +2 -0
  19. package/dist/{manifestBuild-Bs1Uw22_.js → manifestBuild-Dneq4_Jx.js} +1 -1
  20. package/dist/serveCommand-5ZFiNO1R.js +1241 -0
  21. package/dist/serveEntry.js +2 -2
  22. package/dist/{start-C_4VUDT8.js → start-C-ZWSDpg.js} +2 -2
  23. package/dist/startEntry.js +2 -2
  24. package/package.json +17 -17
  25. package/templates/AGENTS.core.md +12 -5
  26. package/templates/AGENTS.md +14 -7
  27. package/templates/agent-docs/_index.md +2 -2
  28. package/templates/agent-docs/_manifest.json +3 -3
  29. package/templates/agent-docs/cli.md +15 -0
  30. package/templates/agent-docs/data.md +306 -2
  31. package/templates/agent-docs/database/migrations.md +40 -0
  32. package/templates/agent-docs/database/schema.md +80 -0
  33. package/templates/agent-docs/deployment.md +9 -0
  34. package/templates/agent-docs/plugins.md +1 -1
  35. package/templates/agent-docs/reference.md +2 -2
  36. package/templates/agent-docs/security.md +18 -0
  37. package/templates/agent-docs/templates/apibackends.md +5 -5
  38. package/templates/agent-docs/templates/overview.md +1 -1
  39. package/templates/agent-docs/whats-new.md +263 -169
  40. package/templates/agent-docs/workflows.md +44 -20
  41. package/templates/apps/api-ai/package.json +7 -7
  42. package/templates/apps/api-auth/package.json +8 -8
  43. package/templates/apps/api-backend/package.json +7 -7
  44. package/templates/apps/api-backend-deactivation/package.json +7 -7
  45. package/templates/apps/api-backend-mail/package.json +8 -8
  46. package/templates/apps/api-backend-mariadb/package.json +9 -9
  47. package/templates/apps/api-backend-storage/package.json +8 -8
  48. package/templates/apps/api-data-advanced/package.json +8 -8
  49. package/templates/apps/api-durable/README.md +2 -1
  50. package/templates/apps/api-durable/events/orders.event.ts +18 -0
  51. package/templates/apps/api-durable/mutations/orders.place.mutation.server.ts +17 -15
  52. package/templates/apps/api-durable/package.json +8 -8
  53. package/templates/apps/api-durable/triggers/order.placed.trigger.tsx +6 -4
  54. package/templates/apps/api-feature-flags/package.json +9 -9
  55. package/templates/apps/api-governance/package.json +8 -8
  56. package/templates/apps/api-kv/package.json +8 -8
  57. package/templates/apps/api-moderation/package.json +8 -8
  58. package/templates/apps/api-observability/package.json +8 -8
  59. package/templates/apps/api-ratelimit/package.json +8 -8
  60. package/templates/apps/api-rbac/package.json +8 -8
  61. package/templates/apps/api-rest/package.json +7 -7
  62. package/templates/apps/api-saas/package.json +11 -11
  63. package/templates/apps/api-search/package.json +8 -8
  64. package/templates/apps/api-versioning/package.json +8 -8
  65. package/templates/apps/api-webhooks/README.md +2 -2
  66. package/templates/apps/api-webhooks/events/orders.event.ts +35 -0
  67. package/templates/apps/api-webhooks/package.json +9 -9
  68. package/templates/apps/api-webhooks/template.json +1 -1
  69. package/templates/apps/changelog/package.json +6 -6
  70. package/templates/apps/edge-functions/package.json +2 -2
  71. package/templates/apps/frontend-admin/package.json +8 -8
  72. package/templates/apps/frontend-app/package.json +8 -8
  73. package/templates/apps/frontend-blank/package.json +7 -7
  74. package/templates/apps/frontend-contact/package.json +7 -7
  75. package/templates/apps/frontend-dashboard/package.json +7 -7
  76. package/templates/apps/frontend-docs/package.json +7 -7
  77. package/templates/apps/frontend-i18n/package.json +6 -6
  78. package/templates/apps/frontend-landing/package.json +7 -7
  79. package/templates/apps/frontend-spa/package.json +7 -7
  80. package/templates/apps/frontend-ssr/package.json +7 -7
  81. package/templates/apps/frontend-ssr-api/package.json +8 -8
  82. package/templates/apps/frontend-static-blog/package.json +6 -6
  83. package/dist/apiBuild-UEM3QBke.js +0 -2
  84. package/dist/dbCommand-Cr__4ATv.js +0 -2
  85. package/dist/fileConventions-CBNPZVOV.js +0 -29
  86. package/dist/frameworkTableAssembly-DRJrAVr1.js +0 -2
  87. package/dist/inspect-BA67TF6v.js +0 -2
  88. package/dist/manifestBuild-i-fRHg_H.js +0 -2
  89. package/dist/serveCommand-C4gzDZzc.js +0 -1175
  90. package/templates/apps/api-webhooks/events/order.completed.webhook.tsx +0 -22
@@ -1,1175 +0,0 @@
1
- import { ot as e, t } from "./inspectMetrics-dcC7gnxu.js";
2
- import { s as n } from "./seedRunner-D6eu-u5U.js";
3
- import { r, t as i } from "./appModuleLoader-C9r9mxZt.js";
4
- import { f as a, m as o, n as s, p as c, u as l } from "./frameworkTableAssembly-sg41s14F.js";
5
- import { l as u } from "./fileConventions-CBNPZVOV.js";
6
- import { p as d } from "./inspect-_ldwsAwH.js";
7
- import { A as f, B as p, C as ee, D as m, E as te, F as ne, G as re, H as h, I as g, J as ie, K as ae, L as _, M as oe, N as v, O as y, P as b, R as se, S as ce, T as le, U as ue, V as de, at as x, b as fe, c as pe, ct as me, dt as he, et as S, g as ge, h as C, i as _e, it as ve, j as ye, k as w, nt as T, o as E, ot as be, q as xe, r as Se, rt as D, st as Ce, t as we, tt as Te, u as Ee, ut as De, v as Oe, w as ke, x as Ae, y as je, z as O } from "./dev-NCuEhNxs.js";
8
- import { r as Me, u as k } from "./apiBuild-B2m4XK_8.js";
9
- import { t as A } from "./bootTiming-BdyP9nYw.js";
10
- import { n as Ne } from "./cliArgs-qdZSElM3.js";
11
- import { join as Pe } from "node:path";
12
- import { pathToFileURL as Fe } from "node:url";
13
- import { Cause as Ie, Effect as j, Layer as M, ManagedRuntime as Le } from "effect";
14
- import { createLogger as N } from "@voltro/logger";
15
- import { existsSync as Re } from "node:fs";
16
- import { AggregateRegistry as P, Dispatcher as ze, apiKeyManagementRoutes as Be, applySoftDeleteScope as Ve, applyTenantScope as He, attachAnalyticsMirror as Ue, awaitServerListening as We, bindMutation as F, bindStream as Ge, bindSubscription as I, buildTracingLayer as Ke, cancelWakeup as qe, compileCron as L, dataStoreApiKeyStore as Je, dataStoreIdempotencyStore as Ye, formatServerOnlyLeaks as Xe, frameworkApiKeyStrategy as Ze, installPolicyGuardResolver as Qe, loadResourceTuples as $e, makeActionRunner as R, makeAdvisoryLockCoordinator as et, makeApiKeyService as tt, makeApiKeyUsageBuffer as nt, makeApiKeyUsageFlusher as rt, makeAsyncKv as it, makeCoordinatedScheduler as at, makeEffectStoreLayer as ot, makeLazyWorkflowFacade as st, makeMutationOutputCodec as ct, makeMutationRunner as lt, makeOneShotQueryRunner as ut, makeQueryDescriptorProducer as dt, makeQueryReauthorizer as ft, makeQuerySubscriber as pt, makeSchemaRegistry as mt, makeWorkflowFacade as ht, makeWorkflowFacadeWithCallerContext as gt, makeWorkflowLayers as z, noopKv as _t, onProcessShutdown as vt, recordSubscriptionDelivery as yt, registerWakeup as bt, resolveSecretsBackend as xt, runProvidedEffect as St, setSecretsBackend as Ct, setSystemStoreHandle as wt, setTupleSource as Tt, singleCoordinator as Et, startRpcServer as Dt, startScheduler as B, workflowToRpc as V, wrapStoreWithBootCodec as Ot } from "@voltro/runtime";
17
- import { RpcGroup as kt } from "@effect/rpc";
18
- import { SqlClient as At } from "@effect/sql";
19
- import { and as jt, ensureTableRegistered as Mt, eq as H, or as Nt } from "@voltro/database";
20
- import { appStorageProvider as U, fromNodeReadable as Pt, getObjectStream as Ft, putObjectStream as W, toNodeReadable as It } from "@voltro/plugin-storage";
21
- import { AuthMiddleware as G, ConnectionInfoMiddleware as Lt, actionToRpc as K, anonymousSubject as Rt, isWireReachable as zt, mutationToRpc as Bt, queryToRpc as q, streamToRpc as Vt, workflowCancelDescriptor as Ht, workflowDomainEventsQueryDescriptor as Ut, workflowEventDeliveriesQueryDescriptor as J, workflowResumeDescriptor as Wt, workflowRunEventsQueryDescriptor as Y, workflowRunQueryDescriptor as Gt, workflowRunStepsQueryDescriptor as X, workflowRunsQueryDescriptor as Z, workflowSignalDescriptor as Kt, workflowUpdateDescriptor as qt } from "@voltro/protocol";
22
- import { assertProductionSessionSecret as Jt } from "@voltro/protocol/session";
23
- import { createHash as Yt, timingSafeEqual as Xt } from "node:crypto";
24
- import { declaredSnapshot as Zt, describeOutcome as Qt, runPlannedMigrations as $t } from "@voltro/database/sql";
25
- import { getAuthSessionStrategy as en } from "@voltro/plugin-auth";
26
- import { collectPublicApiRoutes as tn, restRoutesToHttpRoutes as nn } from "@voltro/protocol/rest";
27
- import { buildDeliverWebhookExecute as rn, buildWebhooksService as an, defaultIncomingPath as on, deliverWebhookWorkflow as sn, mountIncomingWebhook as cn } from "@voltro/plugin-webhooks";
28
- import { packBundle as ln, runExport as un, runImport as dn, storageBlobSink as fn, storageRefsBlobSource as pn, unpackBundle as mn, unpackBundleToDir as hn } from "@voltro/data-transfer";
29
- //#region src/bootRefusal.ts
30
- var gn = "VoltroBootRefusal", _n = (e) => {
31
- let t = Error(e);
32
- return t.name = gn, t;
33
- }, vn = "/_voltro/admin/import", yn = "/_voltro/admin/export", Q = (e, t) => ({
34
- status: e,
35
- contentType: "application/json; charset=utf-8",
36
- body: JSON.stringify(t)
37
- }), bn = (e) => {
38
- let t = e.authorization ?? e.Authorization, n = t ? /^Bearer\s+(.+)$/i.exec(t) : null;
39
- return n ? n[1] : null;
40
- }, xn = (e, t) => Xt(Yt("sha256").update(e).digest(), Yt("sha256").update(t).digest()), Sn = (e, t) => {
41
- if (e.method.toUpperCase() !== "POST") return Q(405, { error: "method not allowed" });
42
- if (!t || t.length < 16) return Q(503, { error: "data transfer misconfigured (no/weak secret)" });
43
- let n = bn(e.headers);
44
- return !n || !xn(n, t) ? Q(401, { error: "unauthorized" }) : null;
45
- }, Cn = N({ scope: "voltro:admin-import" }), wn = "VBUNDLE2", Tn = async function* (e) {
46
- yield e;
47
- }, En = (e) => async (t) => {
48
- let n = Sn(t, e.secret);
49
- if (n) return n;
50
- let r = t.headers["x-import-mode"], i = t.headers["x-import-on-conflict"], a = t.headers["x-import-atomic"] === "1" || t.headers["x-import-atomic"] === "true", o = t.headers["x-import-force"] === "1" || t.headers["x-import-force"] === "true", s = t.rawBody.byteLength >= 8 && Buffer.from(t.rawBody.subarray(0, 8)).toString("latin1") === wn, c, l;
51
- if (s) c = Tn(t.rawBody), l = "upload";
52
- else {
53
- let n;
54
- try {
55
- n = JSON.parse(Buffer.from(t.rawBody).toString("utf8") || "{}");
56
- } catch {
57
- return Q(400, { error: "body must be a packed bundle archive or { bundleKey } JSON" });
58
- }
59
- if (typeof n.bundleKey != "string" || !n.bundleKey) return Q(400, { error: "body.bundleKey (string) is required for the storage transport" });
60
- if (!e.openArchive) return Q(501, { error: "storage transport not configured on this instance" });
61
- c = e.openArchive(n.bundleKey), l = "storage";
62
- }
63
- let u = await import("node:os"), d = await import("node:fs/promises"), f = await import("node:path"), p = await d.mkdtemp(f.join(u.tmpdir(), "voltro-admin-import-"));
64
- try {
65
- e.assetSink ? await mn(c, {
66
- dir: p,
67
- blobs: e.assetSink
68
- }) : await hn(c, p);
69
- let t = await j.runPromiseExit(dn({
70
- store: e.store,
71
- bundleDir: p,
72
- ...r ? { mode: r } : {},
73
- ...i ? { onConflict: i } : {},
74
- ...a ? { atomic: a } : {},
75
- ...e.snapshot ? { targetSnapshot: e.snapshot } : {},
76
- force: o,
77
- onWarn: (e) => Cn.warn("admin.import", { message: e }),
78
- ...e.assetSink ? { assetsAlreadyRestored: !0 } : {}
79
- }));
80
- if (t._tag === "Failure") {
81
- let e = t.cause._tag === "Fail" ? t.cause.error : void 0;
82
- if (e && e._tag === "SchemaDriftError") {
83
- let t = e;
84
- return Cn.warn("admin.import refused (schema drift)", {
85
- transport: l,
86
- bundle: t.bundleFingerprint.slice(0, 16),
87
- target: t.targetFingerprint.slice(0, 16)
88
- }), Q(409, {
89
- error: "schema drift",
90
- bundleFingerprint: t.bundleFingerprint,
91
- targetFingerprint: t.targetFingerprint,
92
- diff: t.diff,
93
- hint: "re-export against the current schema, or resend with x-import-force: 1"
94
- });
95
- }
96
- throw Error(String(e?.message ?? e ?? "import failed"));
97
- }
98
- let n = t.value, s = n.tables.reduce((e, t) => e + t.rowCount, 0);
99
- return Cn.info("admin.import", {
100
- transport: l,
101
- tables: n.tables.length,
102
- rows: s,
103
- mode: r ?? "upsert",
104
- atomic: a
105
- }), Q(200, {
106
- tables: n.tables.length,
107
- rows: s,
108
- transport: l
109
- });
110
- } catch (e) {
111
- return Cn.warn("admin.import failed", {
112
- transport: l,
113
- error: e?.message ?? String(e)
114
- }), Q(500, {
115
- error: "import failed",
116
- message: e?.message ?? String(e)
117
- });
118
- } finally {
119
- await d.rm(p, {
120
- recursive: !0,
121
- force: !0
122
- });
123
- }
124
- }, Dn = N({ scope: "voltro:admin-export" }), On = async (e) => {
125
- let t = [];
126
- for await (let n of e) t.push(Buffer.from(n));
127
- return new Uint8Array(Buffer.concat(t));
128
- }, kn = (e) => typeof e.tenant == "string" && e.tenant ? {
129
- kind: "tenant",
130
- tenantId: e.tenant
131
- } : Array.isArray(e.tables) && e.tables.length ? {
132
- kind: "tables",
133
- tables: e.tables.filter((e) => typeof e == "string")
134
- } : { kind: "all" }, An = (e) => async (t) => {
135
- let n = Sn(t, e.secret);
136
- if (n) return n;
137
- let r;
138
- try {
139
- r = JSON.parse(Buffer.from(t.rawBody).toString("utf8") || "{}");
140
- } catch {
141
- return Q(400, { error: "body must be JSON: { profile?, tenant?, tables?, consistency?, compression?, bundleKey? }" });
142
- }
143
- let i = {};
144
- if (typeof r.profile == "string" && r.profile) {
145
- if (!e.loadProfile) return Q(501, { error: "server-side profiles not configured on this instance" });
146
- try {
147
- i = await e.loadProfile(r.profile);
148
- } catch (e) {
149
- return Q(400, {
150
- error: `profile '${r.profile}' could not be loaded`,
151
- message: e?.message ?? String(e)
152
- });
153
- }
154
- }
155
- let a = r.consistency === "snapshot" ? "snapshot" : i.consistency ?? "live", o = (typeof r.compression == "string" ? r.compression : void 0) ?? i.compression, s = i.scope ?? kn(r), c = typeof r.bundleKey == "string" && r.bundleKey.length > 0, l = r.assets === !0 && e.assetSource ? { blobs: e.assetSource } : {}, u = await import("node:os"), d = await import("node:fs/promises"), f = await import("node:path"), p = await d.mkdtemp(f.join(u.tmpdir(), "voltro-admin-export-"));
156
- try {
157
- let t = await j.runPromise(un({
158
- store: e.store,
159
- snapshot: e.snapshot,
160
- dialect: e.dialect,
161
- outDir: p,
162
- ...i.subset ? { subset: i.subset } : {
163
- scope: s,
164
- ...e.tenantTables && e.tenantTables.length > 0 ? { tenantTables: e.tenantTables } : {}
165
- },
166
- consistency: a,
167
- ...o ? { compression: o } : {},
168
- ...i.masking ? { masking: i.masking } : {}
169
- })), n = t.tables.reduce((e, t) => e + t.rowCount, 0), u = t.masking?.transformed.length ?? 0;
170
- if (c) {
171
- if (!e.putArchive) return Q(501, { error: "storage transport not configured on this instance" });
172
- let i = r.bundleKey;
173
- return await e.putArchive(i, () => ln({
174
- dir: p,
175
- ...l
176
- })), Dn.info("admin.export", {
177
- transport: "storage",
178
- tables: t.tables.length,
179
- rows: n,
180
- masked: u,
181
- bundleKey: i
182
- }), Q(200, {
183
- bundleKey: i,
184
- tables: t.tables.length,
185
- rows: n,
186
- masked: u,
187
- transport: "storage"
188
- });
189
- }
190
- let d = await On(ln({
191
- dir: p,
192
- ...l
193
- }));
194
- return Dn.info("admin.export", {
195
- transport: "download",
196
- tables: t.tables.length,
197
- rows: n,
198
- masked: u,
199
- bytes: d.byteLength
200
- }), {
201
- status: 200,
202
- contentType: "application/octet-stream",
203
- body: d,
204
- headers: {
205
- "x-export-tables": String(t.tables.length),
206
- "x-export-rows": String(n),
207
- "x-export-masked": String(u)
208
- }
209
- };
210
- } catch (e) {
211
- return Dn.warn("admin.export failed", { error: e?.message ?? String(e) }), Q(500, {
212
- error: "export failed",
213
- message: e?.message ?? String(e)
214
- });
215
- } finally {
216
- await d.rm(p, {
217
- recursive: !0,
218
- force: !0
219
- });
220
- }
221
- }, jn = async (e) => {
222
- let { resolve: t } = await import("node:path"), { existsSync: n } = await import("node:fs"), r = [
223
- e,
224
- `${e}.profile.ts`,
225
- `data-profiles/${e}.ts`,
226
- `data-profiles/${e}.profile.ts`
227
- ].map((e) => t(process.cwd(), e)), i = r.find((e) => n(e));
228
- if (!i) throw Error(`data profile '${e}' not found (looked for: ${r.join(", ")})`);
229
- let a = await import(i), o = a.default ?? a.profile;
230
- if (!o) throw Error(`data profile '${i}' has no default export`);
231
- return o;
232
- }, Mn = (e, t, n = {}) => (async function* () {
233
- let r = await It((await j.runPromise(Ft(e, t).pipe(j.timeout(n.openTimeout ?? "30 seconds")))).stream), i = n.stallMs ?? 12e4, a, o = () => {
234
- a && clearTimeout(a), a = setTimeout(() => r.destroy(/* @__PURE__ */ Error(`storage read stalled for ${i}ms reading '${t}'`)), i);
235
- };
236
- try {
237
- o();
238
- for await (let e of r) o(), yield e instanceof Uint8Array ? e : new Uint8Array(e);
239
- } finally {
240
- a && clearTimeout(a), r.destroy();
241
- }
242
- })(), Nn = {
243
- get: async () => void 0,
244
- set: async () => {},
245
- setWithTags: async () => {},
246
- remove: async () => !1,
247
- has: async () => !1,
248
- clear: async () => {},
249
- invalidateTag: async () => 0,
250
- wrap: async (e, t, n) => n()
251
- }, Pn = async (e) => {
252
- wt({
253
- dataStore: e.store,
254
- schemaRegistry: e.schemaRegistry
255
- });
256
- let t = new ze({
257
- store: e.store,
258
- ...e.snapshotCache ? { cache: e.snapshotCache } : {},
259
- recordDelivery: (e) => yt({
260
- label: e.label,
261
- kind: e.kind,
262
- durationMs: e.durationMs,
263
- rowCount: e.rowCount
264
- })
265
- }), n = e.cache ?? Nn, r = e.kv ?? _t, i, a, o, s = /* @__PURE__ */ new Map(), c = () => `wfctx_${globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}`, l = async (t, n, r) => {
266
- let i = {
267
- ...r,
268
- source: r.source ?? `workflow:${t}`
269
- };
270
- s.set(n, i);
271
- try {
272
- let r = await e.store.query({
273
- table: "_voltro_workflow_start_contexts",
274
- order: [],
275
- predicate: H("executionId", n),
276
- projection: ["id"],
277
- skip: void 0,
278
- take: 1
279
- }), a = {
280
- workflowName: t,
281
- executionId: n,
282
- subject: i.subject ?? null,
283
- traceId: i.traceId ?? null,
284
- source: i.source ?? null,
285
- parentExecutionId: i.parentExecutionId ?? null,
286
- parentClosePolicy: i.parentClosePolicy ?? null,
287
- createdAt: /* @__PURE__ */ new Date()
288
- };
289
- r[0] === void 0 ? await e.store.insert("_voltro_workflow_start_contexts", {
290
- id: c(),
291
- ...a
292
- }) : await e.store.update("_voltro_workflow_start_contexts", r[0].id, a);
293
- } catch (e) {
294
- process.stderr.write(`[workflow] failed to persist start context for ${t}/${n}: ${e?.message ?? String(e)}\n`);
295
- }
296
- }, u = async (t, n) => {
297
- let r = s.get(n);
298
- if (r !== void 0) return r;
299
- try {
300
- let t = (await e.store.query({
301
- table: "_voltro_workflow_start_contexts",
302
- order: [],
303
- predicate: H("executionId", n),
304
- projection: void 0,
305
- skip: void 0,
306
- take: 1
307
- }))[0];
308
- if (t === void 0) return;
309
- let r = {
310
- ...t.subject === null ? {} : { subject: t.subject },
311
- ...t.traceId === null ? {} : { traceId: t.traceId },
312
- ...t.source === null ? {} : { source: t.source },
313
- ...t.parentExecutionId === null ? {} : { parentExecutionId: t.parentExecutionId },
314
- ...t.parentClosePolicy === null ? {} : { parentClosePolicy: t.parentClosePolicy }
315
- };
316
- return s.set(n, r), r;
317
- } catch (e) {
318
- process.stderr.write(`[workflow] failed to load start context for ${n}: ${e?.message ?? String(e)}\n`);
319
- return;
320
- }
321
- }, d = (e.discovered.workflows?.length ?? 0) > 0 ? st(() => i) : void 0, f = (e.discovered.workflows?.length ?? 0) > 0 || (e.discovered.eventTriggers?.length ?? 0) > 0, p = f || (e.discovered.workflowWorkers?.length ?? 0) > 0 || e.scheduleCoordination === "cluster", te = e.tenantIsolation === "namespace", ne = (e.log ?? N({ scope: "voltro:serve" })).child("webhooks"), re, g = e.discovered.webhooks;
322
- if (g && g.outgoing.length > 0 && e.workflowEngineLayer !== void 0) {
323
- let t = e.workflowEngineLayer, i = x({
324
- store: e.store,
325
- schemaRegistry: e.schemaRegistry,
326
- cache: n,
327
- kv: r
328
- }), a = g.outgoing.map((e) => e.descriptor);
329
- re = an(i, async (e) => {
330
- let n = sn.execute(e).pipe(j.provide(sn.toLayer(rn(i, { events: a })).pipe(M.provideMerge(t))));
331
- j.runPromise(n).catch((t) => {
332
- ne.error("deliverWebhook workflow crashed", {
333
- deliveryId: e.deliveryId,
334
- targetId: e.targetId
335
- }, t);
336
- });
337
- }, { events: a });
338
- }
339
- let ie = /* @__PURE__ */ new Map();
340
- if (g) for (let e of g.incoming) {
341
- let t = e.descriptor.path ?? on(e.descriptor.id), n = `VOLTRO_WEBHOOK_SECRET_${e.descriptor.id.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, r = cn(e.descriptor, {
342
- resolveSecret: async () => process.env[n] ?? null,
343
- resolveWorkflows: () => d === void 0 ? void 0 : gt(d, {
344
- traceId: `incoming:${e.descriptor.id}`,
345
- source: `incoming:${e.descriptor.id}`
346
- }),
347
- log: (e) => {
348
- let t = {
349
- webhookId: e.webhookId,
350
- status: e.status,
351
- signatureOk: String(e.signatureOk),
352
- idempotency: e.idempotency,
353
- durationMs: e.durationMs
354
- };
355
- e.status >= 500 ? ne.error("incoming delivery failed", t) : e.status >= 400 ? ne.warn("incoming delivery rejected", t) : ne.info("incoming delivery handled", t);
356
- }
357
- });
358
- ie.set(t, { handle: r });
359
- }
360
- Qe(), Tt((t) => $e(e.store, t.subjectId, t.resourceType, t.resourceId));
361
- let ae = (e.discovered.outboxHandlers?.length ?? 0) > 0 ? de({
362
- handlers: e.discovered.outboxHandlers ?? [],
363
- store: e.store,
364
- log: (e.log ?? N({ scope: "voltro:serve" })).child("outbox")
365
- }) : void 0, _ = O({
366
- definitions: (e.discovered.connections ?? []).map((e) => e.definition),
367
- store: e.store,
368
- publicUrl: se(e.port ?? 4e3),
369
- log: (e.log ?? N({ scope: "voltro:serve" })).child("connections")
370
- }), b = ve({
371
- store: e.store,
372
- schemaRegistry: e.schemaRegistry,
373
- cache: n,
374
- kv: r,
375
- ...re === void 0 ? {} : { webhooksService: re },
376
- ...d === void 0 ? {} : { workflowsProxy: d },
377
- eventTriggers: e.discovered.eventTriggers ?? [],
378
- namespaceIsolationOn: te,
379
- ...ae === void 0 ? {} : { outbox: { nudge: ae.nudge } },
380
- ..._.active ? { connections: { registry: _.registry } } : {}
381
- }), le = M.succeed(P, y), ue = (t, n) => {
382
- let r = t.pipe(j.provide(ot(n)));
383
- return (e.baseLayer ? r.pipe(j.provide(e.baseLayer)) : r).pipe(j.provide(le));
384
- }, fe = (e, t) => St(ue(e, t)), pe = lt({
385
- store: e.store,
386
- buildContext: (e, t, n) => b(e, t, n),
387
- runEffect: fe,
388
- undoCapture: ee()
389
- }), me = ce(), he = R({
390
- buildContext: (e) => b(e),
391
- runEffect: fe
392
- }), ge = {
393
- buildContext: (e) => b(e),
394
- finalize: (t, n) => Ve(He(t, e.tenantScopedTables, n.subject.tenantId), e.softDeleteScopedTables),
395
- provideEffect: ue
396
- }, C = dt(ge), _e = ut({
397
- ...ge,
398
- queryRows: (t) => e.store.query(t)
399
- }), ye = pt({
400
- ...ge,
401
- subscribeDescriptor: (e, n, r) => t.subscribe(e, n, r),
402
- subscribeComputed: (e, n, r) => t.subscribeComputed(e, n, r)
403
- }), w = (e) => e.filter((e) => zt(e.descriptor)), T = {};
404
- for (let n of [
405
- ...w(e.discovered.queries),
406
- ...me.queries,
407
- ..._.queries
408
- ]) T[n.descriptor.name] = (e) => I(C(n, e), t, `subscription.${n.descriptor.name}`, void 0, void 0, ft(n, e));
409
- for (let t of [
410
- ...w(e.discovered.mutations),
411
- ...me.mutations,
412
- ..._.mutations
413
- ]) {
414
- let n = ct(t.descriptor.output);
415
- T[t.descriptor.name] = (r) => F(async (e, n) => pe(t, e, n), r, `mutation.${t.descriptor.name}`, n, e.idempotency);
416
- }
417
- for (let t of [...w(e.discovered.actions), ..._.actions]) {
418
- let n = ct(t.descriptor.output);
419
- T[t.descriptor.name] = (r) => F(async (e, n) => he(t, e, n), r, `action.${t.descriptor.name}`, n, e.idempotency);
420
- }
421
- let E = () => `public-${Math.random().toString(36).slice(2, 10)}`, be = [
422
- ...e.discovered.queries.filter((e) => e.descriptor.publicApi !== void 0).map((e) => ({
423
- descriptor: e.descriptor,
424
- invoke: (t, n) => _e(e, t, {
425
- subject: n.subject,
426
- traceId: E()
427
- }),
428
- subscribe: (t, n, r) => ye(e, t, {
429
- subject: n.subject,
430
- traceId: E()
431
- }, r)
432
- })),
433
- ...e.discovered.mutations.filter((e) => e.descriptor.publicApi !== void 0).map((e) => ({
434
- descriptor: e.descriptor,
435
- invoke: (t, n) => pe(e, t, {
436
- subject: n.subject,
437
- traceId: E()
438
- })
439
- })),
440
- ...e.discovered.actions.filter((e) => e.descriptor.publicApi !== void 0).map((e) => ({
441
- descriptor: e.descriptor,
442
- invoke: (t, n) => he(e, t, {
443
- subject: n.subject,
444
- traceId: E()
445
- })
446
- }))
447
- ], xe = be.length > 0 ? nn(tn(be), {
448
- store: e.store,
449
- resolveSubject: (t) => e.resolveSubject(t, -1)
450
- }) : [], Se = e.dataTransferSecret ?? process.env.VOLTRO_DATA_TRANSFER_SECRET, Ce = Se && Se.length >= 16 ? [{
451
- method: "POST",
452
- path: vn,
453
- handle: En({
454
- secret: Se,
455
- store: e.store,
456
- ...e.dataTransferSnapshot ? { snapshot: e.dataTransferSnapshot } : {},
457
- assetSink: fn(U()),
458
- openArchive: (e) => Mn(U(), e)
459
- })
460
- }, {
461
- method: "POST",
462
- path: yn,
463
- handle: An({
464
- secret: Se,
465
- store: e.store,
466
- snapshot: e.dataTransferSnapshot ?? { tables: [] },
467
- dialect: e.dataTransferDialect ?? "memory",
468
- tenantTables: [...e.tenantScopedTables],
469
- loadProfile: jn,
470
- assetSource: pn(U(), e.store),
471
- putArchive: async (e, t) => {
472
- let { Readable: n } = await import("node:stream"), r = U(), i = Pt("storage", () => n.from(t()));
473
- await j.runPromise(W(r, e, i, { contentType: "application/octet-stream" }));
474
- }
475
- })
476
- }] : [], we = [
477
- ...e.httpRoutes ?? [],
478
- ...xe,
479
- ...Ce,
480
- ..._.httpRoutes
481
- ];
482
- for (let t of w(e.discovered.streams ?? [])) T[t.descriptor.name] = (n) => Ge((r) => {
483
- let i = b(r), a = t.executor(n, i);
484
- if (j.isEffect(a)) {
485
- let t = a.pipe(j.provide(ot(i.store)));
486
- return (e.baseLayer ? t.pipe(j.provide(e.baseLayer)) : t).pipe(j.provide(le));
487
- }
488
- return typeof a == "object" && a && typeof a.then == "function" ? j.promise(() => a) : a;
489
- }, `stream.${t.descriptor.name}`);
490
- for (let t of e.discovered.workflows ?? []) T[t.definition.name] = (e) => F(async (e, n) => {
491
- let r = n;
492
- return gt(d, {
493
- subject: r.subject,
494
- traceId: r.traceId,
495
- source: "workflow-rpc"
496
- }).start(t.definition.name, e);
497
- }, e, `workflow.${t.definition.name}`);
498
- f && (T[Gt.name] = (e) => I(C({
499
- descriptor: Gt,
500
- executor: (e) => {
501
- let t = e.id;
502
- return {
503
- table: "_voltro_workflow_runs",
504
- order: [{
505
- column: "startedAt",
506
- direction: "desc"
507
- }],
508
- predicate: Nt(H("id", t), H("executionId", t)),
509
- take: 1,
510
- skip: void 0,
511
- projection: void 0
512
- };
513
- }
514
- }, e), t, `subscription.${Gt.name}`), T[Z.name] = (e) => I(C({
515
- descriptor: Z,
516
- executor: (e) => {
517
- let t = e, n = [...t.tag === void 0 ? [] : [H("tag", t.tag)], ...t.status === void 0 ? [] : [H("status", t.status)]], r = Number.isFinite(t.limit) && t.limit !== void 0 ? Math.min(Math.max(Math.floor(t.limit), 1), 500) : 100;
518
- return {
519
- table: "_voltro_workflow_runs",
520
- order: [{
521
- column: "startedAt",
522
- direction: "desc"
523
- }],
524
- predicate: n.length === 0 ? void 0 : n.length === 1 ? n[0] : jt(...n),
525
- take: r,
526
- skip: void 0,
527
- projection: void 0
528
- };
529
- }
530
- }, e), t, `subscription.${Z.name}`), T[X.name] = (e) => I(C({
531
- descriptor: X,
532
- executor: (e) => {
533
- let t = e.runId;
534
- return {
535
- table: "_voltro_workflow_run_steps",
536
- order: [{
537
- column: "startedAt",
538
- direction: "asc"
539
- }],
540
- predicate: H("runId", t),
541
- take: 1e3,
542
- skip: void 0,
543
- projection: void 0
544
- };
545
- }
546
- }, e), t, `subscription.${X.name}`), T[Y.name] = (e) => I(C({
547
- descriptor: Y,
548
- executor: (e) => {
549
- let t = e.runId;
550
- return {
551
- table: "_voltro_workflow_run_events",
552
- order: [{
553
- column: "occurredAt",
554
- direction: "asc"
555
- }],
556
- predicate: H("runId", t),
557
- take: 1e3,
558
- skip: void 0,
559
- projection: void 0
560
- };
561
- }
562
- }, e), t, `subscription.${Y.name}`), T[Ut.name] = (e) => I(C({
563
- descriptor: Ut,
564
- executor: (e) => {
565
- let t = e;
566
- return {
567
- table: "_voltro_workflow_events",
568
- order: [{
569
- column: "occurredAt",
570
- direction: "desc"
571
- }],
572
- predicate: t.name === void 0 ? void 0 : H("name", t.name),
573
- take: Math.max(1, Math.min(500, t.limit ?? 100)),
574
- skip: void 0,
575
- projection: void 0
576
- };
577
- }
578
- }, e), t, `subscription.${Ut.name}`), T[J.name] = (e) => I(C({
579
- descriptor: J,
580
- executor: (e) => {
581
- let t = e.eventId;
582
- return {
583
- table: "_voltro_workflow_event_deliveries",
584
- order: [{
585
- column: "createdAt",
586
- direction: "asc"
587
- }],
588
- predicate: H("eventId", t),
589
- take: 500,
590
- skip: void 0,
591
- projection: void 0
592
- };
593
- }
594
- }, e), t, `subscription.${J.name}`), T[Ht.name] = (t) => F(async (t, n) => {
595
- let r = t;
596
- return await D(e.store, n.subject, { executionId: r.executionId }), await d.cancel(r.workflowName, r.executionId), await Pe(r.workflowName, r.executionId, "workflow.cancel"), { ok: !0 };
597
- }, t, `action.${Ht.name}`), T[Wt.name] = (t) => F(async (t, n) => {
598
- let r = t;
599
- return await D(e.store, n.subject, { executionId: r.executionId }), await d.resume(r.workflowName, r.executionId), { ok: !0 };
600
- }, t, `action.${Wt.name}`), T[Kt.name] = (t) => F(async (t, n) => {
601
- let r = t;
602
- return await D(e.store, n.subject, { id: r.id }), d.signal({ id: r.id }, r.signalName, r.payload);
603
- }, t, `action.${Kt.name}`), T[qt.name] = (t) => F(async (t, n) => {
604
- let r = t;
605
- return await D(e.store, n.subject, { id: r.id }), d.update({ id: r.id }, r.updateName, r.payload, r.timeoutMs === void 0 ? void 0 : { timeoutMs: r.timeoutMs });
606
- }, t, `action.${qt.name}`));
607
- let Te = [
608
- ...w(e.discovered.queries).map((e) => q(e.descriptor)),
609
- ...w(e.discovered.mutations).map((e) => Bt(e.descriptor)),
610
- ...w(e.discovered.actions).map((e) => K(e.descriptor)),
611
- ...me.queries.map((e) => q(e.descriptor)),
612
- ...me.mutations.map((e) => Bt(e.descriptor)),
613
- ..._.queries.map((e) => q(e.descriptor)),
614
- ..._.mutations.map((e) => Bt(e.descriptor)),
615
- ..._.actions.map((e) => K(e.descriptor)),
616
- ...w(e.discovered.streams ?? []).map((e) => Vt(e.descriptor)),
617
- ...(e.discovered.workflows ?? []).map((e) => V(e.definition)),
618
- ...f ? [
619
- q(Gt),
620
- q(Z),
621
- q(X),
622
- q(Y),
623
- q(Ut),
624
- q(J),
625
- K(Ht),
626
- K(Wt),
627
- K(Kt),
628
- K(qt)
629
- ] : []
630
- ], Ee = kt.make(...Te).middleware(G).middleware(Lt), De = M.succeed(G, G.of(({ headers: t, clientId: n }) => j.promise(() => e.resolveSubject(t, n)))), ke = M.succeed(Lt, Lt.of(({ headers: e, clientId: t }) => j.succeed({
631
- clientId: t,
632
- ...e["idempotency-key"] ? { idempotencyKey: e["idempotency-key"] } : {}
633
- }))), Ae = e.dormancyTenantId ?? "default", Me = e.dormancy === "sleep" ? {
634
- register: (t, n, r) => bt(e.store, {
635
- tenantId: r ?? Ae,
636
- kind: "workflow",
637
- refId: t,
638
- wakeAt: n
639
- }),
640
- cancel: (t, n) => qe(e.store, {
641
- tenantId: n ?? Ae,
642
- kind: "workflow",
643
- refId: t
644
- }).then(() => {})
645
- } : void 0, k = p ? await import("@voltro/workflow") : void 0, A = k?.makeWorkflowRunRecorder({
646
- store: e.store,
647
- ...Me === void 0 ? {} : { wakeups: Me }
648
- }), Ne = async (t, n) => {
649
- await k.closeWorkflowChildrenForParent({
650
- store: e.store,
651
- parentExecutionId: t,
652
- parentStatus: n,
653
- recorder: A,
654
- log: { warn: (e, t) => {
655
- process.stderr.write(`[workflow] ${e} ${t ? JSON.stringify(t) : ""}\n`);
656
- } },
657
- interruptChild: async (t, n) => {
658
- let r = (e.discovered.workflows ?? []).find((e) => e.definition.name === t);
659
- if (!r) throw Error(`Unknown child workflow: ${t}`);
660
- if (!a) throw Error("Workflow runtime is not ready");
661
- await a.runPromise(r.definition.interrupt(n));
662
- }
663
- });
664
- }, Pe = async (t, n, r) => {
665
- let i = (await e.store.query({
666
- table: "_voltro_workflow_runs",
667
- order: [],
668
- predicate: H("executionId", n),
669
- projection: void 0,
670
- skip: void 0,
671
- take: 1
672
- }))[0];
673
- if (i === void 0) return;
674
- let a = await e.store.update("_voltro_workflow_runs", i.id, {
675
- status: "cancelled",
676
- cancelled: !0,
677
- completedAt: /* @__PURE__ */ new Date()
678
- }), o = i.subject?.tenantId ?? void 0;
679
- a && await A.recordEvent({
680
- runId: i.id,
681
- eventType: "run-cancelled",
682
- payload: {
683
- reason: r,
684
- workflowName: t,
685
- executionId: n,
686
- ...o == null ? {} : { tenantId: o }
687
- }
688
- }), a && await Ne(n, "cancelled");
689
- }, Fe = [...z(e.discovered.workflows ?? [], {
690
- buildContext: (t, n) => e.buildContextForWorkflow?.(t, n) ?? b({
691
- subject: t.subject,
692
- traceId: t.traceId
693
- }, e.store, void 0, `workflow:${n.workflowName}`, { parentExecutionId: n.executionId }),
694
- resolveStartContext: u
695
- }, (t, n, r) => {
696
- let i = k.getWorkflowVersionMetadata(t.definition);
697
- return k.wrapWorkflowExecuteWithRunRecording({
698
- name: t.definition.name,
699
- store: e.store,
700
- subject: r.subject,
701
- source: r.source ?? null,
702
- traceId: r.traceId,
703
- workflowVersion: i.version,
704
- workflowCompatibleVersions: i.compatibleWith,
705
- workflowPatches: i.patches,
706
- parentExecutionId: r?.parentExecutionId ?? null,
707
- parentClosePolicy: r?.parentClosePolicy ?? null,
708
- onParentClose: ({ executionId: e, status: t }) => Ne(e, t),
709
- recorder: A
710
- }, n);
711
- }), ...e.discovered.workflowWorkers ?? []], Ie = Fe.length > 0 ? M.mergeAll(...Fe) : M.empty;
712
- if (((e.discovered.workflows?.length ?? 0) > 0 || (e.discovered.workflowWorkers?.length ?? 0) > 0 || e.scheduleCoordination === "cluster") && e.workflowEngineLayer !== void 0) {
713
- let t = Ie.pipe(M.provideMerge(e.workflowEngineLayer));
714
- a = Le.make(e.baseLayer === void 0 ? t : t.pipe(M.provideMerge(e.baseLayer))), await a.runPromise(j.void), i = (e.discovered.workflows?.length ?? 0) > 0 ? ht({
715
- workflows: e.discovered.workflows ?? [],
716
- runEffect: (e) => a.runPromise(e),
717
- rememberStartContext: l,
718
- signal: async (t, n, r) => {
719
- let i = await k.sendWorkflowSignal({
720
- store: e.store,
721
- recorder: A,
722
- target: t,
723
- signalName: n,
724
- payload: r
725
- });
726
- return await a.runPromise(k.completeSuspendingSignal({
727
- store: e.store,
728
- target: t,
729
- signalName: n,
730
- payload: r
731
- })).catch(() => {}), i;
732
- },
733
- update: (t, n, r, i) => k.sendWorkflowUpdate({
734
- store: e.store,
735
- recorder: A,
736
- target: t,
737
- updateName: n,
738
- payload: r,
739
- ...i === void 0 ? {} : { options: i }
740
- }),
741
- listRuns: (t) => Oe(e.store, t),
742
- retry: (t, n) => je({
743
- store: e.store,
744
- workflows: e.discovered.workflows ?? [],
745
- runPromise: (e) => a.runPromise(e)
746
- }, t, n)
747
- }) : void 0;
748
- }
749
- let Re = M.mergeAll(Ee.toLayer(T), De, ke), Be = S(T, e.discovered.queries.map((e) => e.descriptor.name), f), Ue = M.mergeAll(Ee.toLayer(Be), De, ke), L = e.observability, Je = await Ke({
750
- ...L && L.spanProcessors.length > 0 ? { extraSpanProcessors: L.spanProcessors } : {},
751
- ...L && L.metricReaders.length > 0 ? { extraMetricReaders: L.metricReaders } : {},
752
- ...L && Object.keys(L.resourceAttributes).length > 0 ? { resourceAttributes: L.resourceAttributes } : {},
753
- ...L && L.sampler !== void 0 ? { sampler: L.sampler } : {}
754
- }), Ye = !1, Xe = e.store.ping ? () => e.store.ping().then(() => !0).catch(() => !1) : void 0, { server: Ze, shutdown: tt } = Dt({
755
- group: Ee,
756
- handlersLayer: Re,
757
- httpHandlersLayer: Ue,
758
- port: e.port ?? 4e3,
759
- ...e.host === void 0 ? {} : { host: e.host },
760
- path: e.path ?? "/ws",
761
- tracerLayer: Je.layer,
762
- healthCheck: {
763
- isReady: () => Ye,
764
- ...Xe ? { ping: Xe } : {}
765
- },
766
- ...we.length > 0 ? { httpRoutes: we } : {},
767
- ...e.getStore === void 0 ? {} : { getStore: e.getStore },
768
- ...ie.size > 0 ? { webhookRoutes: ie } : {},
769
- ...e.inspectRoute === void 0 ? {} : { inspectRoute: e.inspectRoute }
770
- });
771
- if (await We(Ze), (e.discovered.schedules?.length ?? 0) > 0) {
772
- let t = (e.scheduleCoordination ?? "single") === "advisoryLock" ? et(e.store, e.scheduleReplicaId ?? `pid-${process.pid}`) : Et;
773
- o = await B(e.discovered.schedules ?? [], {
774
- store: e.store,
775
- coordinator: t,
776
- defaultTrigger: e.scheduleDefaultTrigger ?? "self",
777
- replicaId: e.scheduleReplicaId ?? `pid-${process.pid}`,
778
- armSelf: e.scheduleArmSelf ?? !0,
779
- dormancy: e.dormancy ?? "always-on",
780
- ...e.dormancyTenantId === void 0 ? {} : { dormancyTenantId: e.dormancyTenantId },
781
- buildContext: ({ traceId: t, scheduleName: n, subject: r }) => b({
782
- subject: r,
783
- traceId: t
784
- }, e.store, void 0, `schedule:${n}`),
785
- log: {
786
- info: (e, t) => {
787
- process.stdout.write(`[schedule] ${e} ${t ? JSON.stringify(t) : ""}\n`);
788
- },
789
- warn: (e, t) => {
790
- process.stderr.write(`[schedule] ${e} ${t ? JSON.stringify(t) : ""}\n`);
791
- },
792
- error: (e, t) => {
793
- process.stderr.write(`[schedule] ERROR ${e} ${t ? JSON.stringify(t) : ""}\n`);
794
- },
795
- debug: () => {}
796
- },
797
- ...e.scheduleFireInterceptor === void 0 ? {} : { interceptFire: e.scheduleFireInterceptor },
798
- ...e.onScheduleRunEvent === void 0 ? {} : { onRunEvent: e.onScheduleRunEvent }
799
- }), e.onSchedulerReady?.(o);
800
- }
801
- let nt = e.log ?? N({ scope: "voltro:serve" }), rt, it;
802
- if ((e.discovered.subscribers?.length ?? 0) > 0 && (rt = h(e.discovered.subscribers ?? [], e.store, nt.child("subscribe"), e.schemaRegistry)), (e.discovered.reactions?.length ?? 0) > 0) {
803
- let t = nt.child("reaction");
804
- it = oe(e.discovered.reactions ?? [], e.store, {
805
- runAct: async (n, r) => {
806
- if (n.kind === "workflow") {
807
- if (d === void 0) {
808
- t.warn("reaction workflow act skipped — no workflow engine in this app", { workflow: n.workflow });
809
- return;
810
- }
811
- let e = r.new ?? r.old ?? {};
812
- await gt(d, {
813
- traceId: `reaction:${n.workflow}`,
814
- source: `reaction:${n.workflow}`
815
- }).start(n.workflow, e);
816
- return;
817
- }
818
- await v(n.agent, r, {
819
- findAgentSend: (t) => e.discovered.actions.find((e) => e.descriptor.name === `${t}.send`),
820
- runAction: (e, t, n) => Promise.resolve(he(e, t, n)),
821
- makeSubject: (e) => Rt(e),
822
- now: () => Date.now(),
823
- log: t
824
- });
825
- },
826
- checkBudget: async (n, r) => {
827
- try {
828
- let { requireAiBudget: t } = await import("@voltro/ai");
829
- return (await j.runPromise(j.either(t(e.store, {
830
- tenantId: n,
831
- limitUsd: r
832
- }))))._tag === "Right";
833
- } catch (e) {
834
- return t.warn("reaction budget check failed — refusing the act", { tenantId: n }, e), !1;
835
- }
836
- }
837
- }, t);
838
- }
839
- let at;
840
- return (e.discovered.aggregates?.length ?? 0) > 0 && (at = await m({
841
- discovered: e.discovered.aggregates ?? [],
842
- store: e.store,
843
- log: nt.child("aggregate"),
844
- ...e.analytics === void 0 ? {} : { analytics: e.analytics },
845
- ...e.aggregateStorage === void 0 ? {} : { storage: e.aggregateStorage },
846
- ...e.aggregateCoordinator === void 0 ? {} : { coordinator: e.aggregateCoordinator }
847
- }), le = M.succeed(P, at.registry)), Ye = !0, e.bootTiming?.mark("ready"), {
848
- dispatcher: t,
849
- server: Ze,
850
- scheduler: o,
851
- close: async () => {
852
- Ye = !1, at?.detach(), it?.(), rt?.(), await o?.shutdown(), t.close(), await a?.dispose(), await new Promise((e) => Ze.close(() => e())), await tt();
853
- }
854
- };
855
- }, $ = N({ scope: "voltro:serve" }), Fn = (e, t, n) => (e === "production" || e === "staging") && t !== "memory" && n !== "0", In = Ne, Ln = async (e) => {
856
- let t = k(process.cwd());
857
- if (Re(t)) {
858
- let n;
859
- try {
860
- let e = await import(Fe(t).href);
861
- typeof e.runServe == "function" ? n = e.runServe : $.warn("serve bundle has no runServe export — using the standard serve path");
862
- } catch (e) {
863
- $.warn("serve bundle failed to load — using the standard serve path", {}, e);
864
- }
865
- if (n) return $.info("serve: booting from the precompiled serve bundle"), n(e);
866
- }
867
- return Rn(e);
868
- }, Rn = async (ee) => {
869
- let m = A();
870
- process.env.NODE_ENV || (process.env.NODE_ENV = "production");
871
- try {
872
- Jt();
873
- } catch (e) {
874
- throw _n(e instanceof Error ? e.message : String(e));
875
- }
876
- let h = process.cwd(), oe = Number(process.env.PORT ?? In(ee, "--port") ?? 4e3), v = await pe(h);
877
- Ct(xt(v?.secrets)), await e({
878
- rawEnv: v?.env,
879
- appType: "api",
880
- root: h,
881
- log: $,
882
- generateTypes: !1
883
- }), m.mark("config");
884
- let y = (process.env.DB_DIALECT ?? v?.store ?? "memory").toLowerCase(), se = (y === "mariadb" || y === "postgres" || y === "mssql") && (process.env.CDC ?? "1") !== "0", ce = y === "mariadb" ? "mariadb" : y === "mssql" ? "mssql" : void 0, de = Me(h);
885
- if (!i() && Re(de)) try {
886
- let e = await import(Fe(de).href);
887
- if (e.modules) {
888
- let t = {};
889
- for (let [n, r] of Object.entries(e.modules)) t[Pe(h, n)] = r;
890
- r(t), $.info("precompiled api bundle loaded", { modules: Object.keys(t).length });
891
- }
892
- } catch (e) {
893
- $.warn("precompiled api bundle failed to load — falling back to source", {}, e);
894
- }
895
- let x = await C(h), S = await Ee(x, { cdc: se && ce !== void 0 });
896
- {
897
- let e = _(S.serverOnlyLeaks, g(process.env, "strict"), Xe, "`voltro serve`");
898
- if (e.action === "fail") throw _n(e.message ?? "");
899
- e.action === "warn" && $.warn(e.message ?? "");
900
- }
901
- let ve = x.filter((e) => le.test(e)), D = ve.length > 0 ? await te(ve, $.child("webhooks")) : void 0, Oe = s({
902
- mix: S.featureMix,
903
- plugins: v?.plugins ?? [],
904
- cdc: se && ce !== void 0,
905
- ...ce ? { cdcDialect: ce } : {}
906
- }), je = v?.analytics !== void 0 && v.analytics.kind !== "noop" && y !== "memory" ? (await n(y)).makeSqlLayer(E()) : void 0, O = await ae({
907
- spec: v?.analytics,
908
- sqlLayer: je,
909
- log: $
910
- }), k = (() => {
911
- let e = new Set(S.tables.map((e) => e.tableName)), t = [...S.tables];
912
- for (let n of [...Oe, ...O.tables]) e.has(n.tableName) || (e.add(n.tableName), t.push(n));
913
- return t;
914
- })();
915
- for (let e of k) Mt(e);
916
- let Ne = (process.env.NODE_ENV ?? "").toLowerCase();
917
- if (Fn(Ne, y, process.env.VOLTRO_AUTO_MIGRATE)) {
918
- let e = (await n(y)).makeSqlLayer(E()), t = await j.runPromise(At.SqlClient.pipe(j.flatMap((e) => $t(e, k, {
919
- appliedBy: `serve:${Ne}`,
920
- environment: "prod",
921
- dialectId: y
922
- })), j.provide(e)));
923
- t.kind === "prod-mismatch" && ($.error(Qt(t, y)), $.error("serve: refusing to boot — apply the schema first (voltro db apply in a pre-deploy step), or set VOLTRO_AUTO_MIGRATE=0 to bypass this check."), process.exit(1)), $.info(Qt(t, y));
924
- }
925
- let N = mt(k);
926
- m.mark("discover");
927
- let P = await _e(v, void 0), ze = Ot(P, y);
928
- for (let e of me({
929
- dialect: String(v?.store ?? process.env.DB_DIALECT ?? "postgres"),
930
- changeStrategy: (process.env.CDC ?? "1") === "0" ? "inline" : "cdc",
931
- dbUrl: process.env.DB_URL,
932
- tables: S.tables.map((e) => ({
933
- tableName: e.tableName,
934
- isReactive: e.isReactive === !0
935
- })),
936
- querySources: S.queries.flatMap((e) => {
937
- let t = e.descriptor.source;
938
- return t === void 0 ? [] : typeof t == "string" ? [t] : [...t];
939
- })
940
- })) e.level === "warn" ? $.warn(e.message) : $.info(e.message);
941
- v?.cache && !process.env.CACHE_BACKEND && (process.env.CACHE_BACKEND = v.cache), v?.cacheRedisUrl && !process.env.CACHE_REDIS_URL && (process.env.CACHE_REDIS_URL = v.cacheRedisUrl), v?.cacheRedisDriver && !process.env.CACHE_REDIS_DRIVER && (process.env.CACHE_REDIS_DRIVER = v.cacheRedisDriver), v?.cacheKeyPrefix && !process.env.CACHE_KEY_PREFIX && (process.env.CACHE_KEY_PREFIX = v.cacheKeyPrefix);
942
- let { service: Ve, invalidationBus: He, snapshotCache: We, cache: F, backend: Ge, dispose: I } = await Ce({ env: process.env });
943
- $.info(`cache backend resolved: ${Ge}` + (Ge === "redis" ? ` (driver ${process.env.CACHE_REDIS_DRIVER ?? "resp"})` : " — in-process, not cross-instance")), P.onChange((e) => {
944
- j.runFork(He.publish(e.table));
945
- }), v?.kv && !process.env.KV_BACKEND && (process.env.KV_BACKEND = v.kv), v?.kvRedisUrl && !process.env.KV_REDIS_URL && (process.env.KV_REDIS_URL = v.kvRedisUrl), v?.kvKeyPrefix && !process.env.KV_KEY_PREFIX && (process.env.KV_KEY_PREFIX = v.kvKeyPrefix);
946
- let { kv: Ke, service: qe } = await it({ store: P });
947
- m.mark("store");
948
- let Qe = Ue({
949
- store: P,
950
- sink: O.sink,
951
- log: $
952
- }), $e = be({
953
- store: P,
954
- dialect: y
955
- }), R = v?.plugins ?? [], ot = process.env.POD_NAME ?? process.env.HOSTNAME ?? `serve-${process.pid}`, st, ct;
956
- y !== "memory" && (st = Le.make((await n(y)).makeSqlLayer(E())), ct = await st.runPromise(At.SqlClient));
957
- let lt = at({
958
- coordinator: [
959
- "postgres",
960
- "mariadb",
961
- "mysql",
962
- "mssql"
963
- ].includes(y) ? et(P, ot, $) : Et,
964
- replicaId: ot,
965
- log: $
966
- }), ut = [], dt = {
967
- ...ct ? { sql: ct } : {},
968
- scheduleCoordinated: (e, t, n) => {
969
- let r = lt(e, t, n);
970
- return ut.push(r), r;
971
- }
972
- };
973
- for (let e of R) e.bindDataStore?.(P, dt);
974
- let ft = R.filter((e) => typeof e.onChangeEvent == "function");
975
- if (ft.length > 0) {
976
- let e = P.changeScope ?? "local";
977
- P.onChange((t) => {
978
- let n = ne(t, e);
979
- for (let e of ft) j.runFork(e.onChangeEvent(n).pipe(j.catchAllCause((t) => j.sync(() => $.warn(`plugin ${e.name} onChangeEvent failed`, { error: Ie.pretty(t) })))));
980
- });
981
- }
982
- let pt = Ae({
983
- plugins: R,
984
- appName: v?.name ?? "voltro-api",
985
- appType: "api",
986
- voltroVersion: process.env.npm_package_version ?? "0.0.0",
987
- log: $
988
- });
989
- R.length && await pt.activate(), m.mark("plugins");
990
- let ht = await pt.gatherObservability(), gt = await ge(P, v, y, {
991
- info: (e, t) => process.stdout.write(`[broadcast] ${e} ${t ? JSON.stringify(t) : ""}\n`),
992
- warn: (e, t) => process.stderr.write(`[broadcast] ${e} ${t ? JSON.stringify(t) : ""}\n`),
993
- debug: () => {}
994
- }), z = v?.apiKeys, _t = (typeof z == "object" ? z.prefix : void 0) ?? "voltro_", yt = z ? Je(P) : void 0, bt = yt ? nt({ flush: rt(yt) }) : void 0;
995
- bt && vt(() => bt.shutdown());
996
- let St = yt ? tt(yt, {
997
- prefix: _t,
998
- ...bt ? { usage: bt } : {}
999
- }) : void 0, wt = St ? [Ze(St, { prefix: _t })] : [], Tt = Se([...v?.auth?.strategies ?? [], ...wt], en(v?.plugins ?? []), v?.auth?.anonymousTenantRequired ?? !1, v?.auth?.resolveScopes, () => ze), Dt = [...v?.restRoutes ?? [], ...St ? Be(St, (typeof z == "object" ? z.managementPath : void 0) ?? "/v1/api-keys") : []], B = v?.idempotency, V = B ? {
1000
- store: Ye(P),
1001
- header: (typeof B == "object" ? B.header : void 0) ?? "Idempotency-Key",
1002
- ttlMs: (typeof B == "object" ? B.ttlMs : void 0) ?? 864e5
1003
- } : void 0, kt = Dt.length > 0 ? nn(Dt, {
1004
- store: P,
1005
- resolveSubject: (e) => Tt({
1006
- headers: e,
1007
- clientId: -1
1008
- }),
1009
- ...V ? { idempotency: V } : {}
1010
- }) : [], jt = R.map((e) => e.services).filter((e) => e !== void 0), H = M.mergeAll(T({
1011
- analyticsLayer: O.layer,
1012
- cacheService: Ve,
1013
- kvService: qe,
1014
- pluginServices: jt,
1015
- userLayers: v?.layers ?? []
1016
- }), Te(v?.http ?? {})), Nt = v?.scheduling ?? {}, U = Nt.trigger ?? "self", Pt = /* @__PURE__ */ new Set([
1017
- "postgres",
1018
- "mysql",
1019
- "mariadb",
1020
- "mssql"
1021
- ]), Ft = Nt.coordination ?? (Pt.has(y) ? "advisoryLock" : "single"), W = Ft === "cluster" && Pt.has(y), It = W ? "cluster" : Ft === "advisoryLock" && Pt.has(y) ? "advisoryLock" : "single";
1022
- Ft === "cluster" && !W && $.warn("scheduling.coordination=cluster needs a sql-backed store except sqlite — falling back to single"), Ft === "advisoryLock" && !Pt.has(y) && $.warn("scheduling.coordination=advisoryLock needs a SQL store (the claim-row gate) — falling back to single");
1023
- let G, Lt = S.workflows.length > 0 || S.workflowWorkers.length > 0 || S.eventTriggers.length > 0 || (D?.outgoing.length ?? 0) > 0 || W, K;
1024
- if (Lt) {
1025
- if (y === "mssql") {
1026
- let e = await re(process.cwd());
1027
- e && $.warn(e);
1028
- }
1029
- let [{ WorkflowEngine: e }, { makeClusterCronLayer: t, workflowEngineLayer: r, resolveRunnerStorage: i }] = await Promise.all([import("@effect/workflow"), import("@voltro/workflow/cluster")]), a = W ? S.schedules.filter((e) => (e.trigger ?? U) === "self").map((e) => t({
1030
- name: e.name,
1031
- cron: L(e),
1032
- execute: async () => {
1033
- await G?.fireFromCluster(e.name);
1034
- }
1035
- })) : [];
1036
- K = y === "memory" ? e.layerMemory : await (async () => {
1037
- let e = await n(y), t = i({ sqliteFamily: e.id === "sqlite" || e.id === "turso" });
1038
- return $.info(`workflow engine: cluster-${t}, dialect=${e.id}` + (t === "memory" ? " — single-process durable replay, no cross-pod shard handoff" + (e.id !== "sqlite" && e.id !== "turso" ? " (VOLTRO_WORKFLOW_RUNNER_STORAGE=memory: SqlRunnerStorage/cluster_runners + GET_LOCK skipped)" : "") : "")), r({
1039
- sqlClientLayer: e.makeSqlLayer(E()),
1040
- runnerStorage: t,
1041
- dialectId: e.id,
1042
- ...process.env.VOLTRO_WORKFLOW_RUNNER_PORT ? { runnerListenPort: Number(process.env.VOLTRO_WORKFLOW_RUNNER_PORT) } : {},
1043
- ...a.length > 0 ? { extraShardingLayers: a } : {}
1044
- });
1045
- })();
1046
- }
1047
- let Rt = fe(R, t()), zt = x.filter((e) => /\.subscribe\.tsx?$/.test(e)), Bt = zt.length > 0 ? await ue(zt, $) : [], q = x.filter((e) => /\.reaction\.tsx?$/.test(e)), Vt = q.length > 0 ? await b(q, $) : [], Ht = x.filter((e) => u.test(e)), Ut = Ht.length > 0 ? await p(Ht, $) : [], J = x.filter((e) => /\.aggregate\.tsx?$/.test(e)), Wt = J.length > 0 ? await w(J, $) : [], Y = f();
1048
- if (Wt.length > 0 && y !== "memory") try {
1049
- Y = ye((await n(y)).makeSqlLayer(E()));
1050
- } catch (e) {
1051
- $.warn("aggregate: SQL storage init failed — falling back to in-process", { err: String(e) });
1052
- }
1053
- let Gt = y === "memory" ? Et : et(P, `aggregate@${process.pid}`, $), X = [], Z = [], Kt = x.filter((e) => l.test(e));
1054
- if (Kt.length > 0) {
1055
- let e = $.child("agent"), t = x.filter((e) => a.test(e));
1056
- t.length > 0 && await o(t, e);
1057
- let n = await c(Kt, e);
1058
- for (let e of n.agents) for (let t of ke(e)) (t.kind === "action" ? X : Z).push({
1059
- file: t.file,
1060
- descriptor: t.descriptor,
1061
- executor: t.executor
1062
- });
1063
- n.agents.length > 0 && e.info("synthesized agent routes", { agents: n.agents.map((e) => e.descriptor.name) });
1064
- }
1065
- m.mark("workflow");
1066
- let qt = await Pn({
1067
- bootTiming: m,
1068
- ...V ? { idempotency: {
1069
- store: V.store,
1070
- ttlMs: V.ttlMs
1071
- } } : {},
1072
- discovered: {
1073
- queries: [...S.queries, ...Z],
1074
- mutations: S.mutations,
1075
- actions: [...S.actions, ...X],
1076
- streams: S.streams,
1077
- workflows: S.workflows,
1078
- workflowWorkers: S.workflowWorkers,
1079
- eventTriggers: S.eventTriggers,
1080
- schedules: S.schedules,
1081
- subscribers: Bt,
1082
- outboxHandlers: Ut,
1083
- connections: S.connections,
1084
- reactions: Vt,
1085
- aggregates: Wt,
1086
- ...D === void 0 ? {} : { webhooks: D }
1087
- },
1088
- log: $,
1089
- analytics: O.sink,
1090
- aggregateStorage: Y,
1091
- aggregateCoordinator: Gt,
1092
- store: P,
1093
- kv: Ke,
1094
- cache: F,
1095
- snapshotCache: We,
1096
- schemaRegistry: N,
1097
- tenantScopedTables: S.tenantScopedTables,
1098
- softDeleteScopedTables: S.softDeleteScopedTables,
1099
- dataTransferSnapshot: Zt(k),
1100
- dataTransferDialect: y,
1101
- tenantIsolation: (process.env.VOLTRO_TENANT_ISOLATION ?? v?.tenancy?.isolation) === "namespace" ? "namespace" : "shared-schema",
1102
- resolveSubject: (e, t) => Tt({
1103
- headers: e,
1104
- clientId: t
1105
- }),
1106
- httpRoutes: [...R.flatMap((e) => e.httpRoutes ?? []), ...kt],
1107
- getStore: () => ze,
1108
- ...H ? { baseLayer: H } : {},
1109
- ...K === void 0 ? {} : { workflowEngineLayer: K },
1110
- scheduleDefaultTrigger: U,
1111
- scheduleCoordination: It,
1112
- scheduleArmSelf: !W,
1113
- dormancy: process.env.VOLTRO_DORMANCY === "sleep" || process.env.VOLTRO_DORMANCY === "always-on" ? process.env.VOLTRO_DORMANCY : v?.dormancy ?? "always-on",
1114
- scheduleReplicaId: process.env.HOSTNAME ?? `pid-${process.pid}`,
1115
- ...Rt === void 0 ? {} : { scheduleFireInterceptor: Rt },
1116
- onSchedulerReady: (e) => {
1117
- G = e;
1118
- },
1119
- inspectRoute: { handle: (e, t, n, r) => d(e, {
1120
- kind: "api",
1121
- meta: {
1122
- name: v?.name ?? "voltro-api",
1123
- voltroVersion: we,
1124
- port: oe,
1125
- mode: "start",
1126
- store: y,
1127
- cdc: se ? "on" : "off"
1128
- },
1129
- rpc: De(S, h),
1130
- workflows: he(S, h),
1131
- inspectFireSchedule: async ({ name: e, trigger: t }) => {
1132
- if (!G) throw Error("scheduler not started — this app registers no self-triggered schedules (all schedules are trigger:'external', or there are none).");
1133
- return { runId: await G.fireNow(e, t) ?? null };
1134
- }
1135
- }, t, {
1136
- method: n,
1137
- ...r === void 0 ? {} : { body: r }
1138
- }) ?? {
1139
- status: 404,
1140
- contentType: "application/json",
1141
- body: JSON.stringify({ error: "not an inspect route" })
1142
- } },
1143
- observability: ht,
1144
- port: oe,
1145
- ...v?.transport?.wsPath ? { path: v.transport.wsPath } : {}
1146
- });
1147
- return ie(xe([
1148
- S.queries,
1149
- S.mutations,
1150
- S.actions,
1151
- S.streams
1152
- ]), (e) => {
1153
- $.warn(e);
1154
- }), $.info(`API listening on :${oe}`, {
1155
- dialect: y,
1156
- queries: S.queries.length,
1157
- mutations: S.mutations.length,
1158
- actions: S.actions.length,
1159
- streams: S.streams.length,
1160
- workflows: S.workflows.length,
1161
- workflowWorkers: S.workflowWorkers.length,
1162
- schedules: S.schedules.length,
1163
- scheduleCoordination: It
1164
- }), m.finish($), vt(async () => {
1165
- for (let e of ut) e.stop();
1166
- Qe.detach(), $e.stop(), I(), st?.dispose();
1167
- try {
1168
- await pt.deactivate(), await gt?.close(), await O.dispose(), await qt.close(), await P.close?.();
1169
- } catch (e) {
1170
- console.error("serve: shutdown step failed, exiting anyway:", e);
1171
- }
1172
- }), await new Promise(() => {}), 0;
1173
- };
1174
- //#endregion
1175
- export { Ln as n, jn as r, Rn as t };