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