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