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