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