@voltro/cli 0.18.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 (56) hide show
  1. package/CHANGELOG.md +158 -3
  2. package/bin/voltro.mjs +11 -0
  3. package/dist/apiBuild-9NXH53Sd.js +2 -0
  4. package/dist/{apiBuild-CPDTJHkH.js → apiBuild-CY5pEwwq.js} +1 -1
  5. package/dist/bin.js +1 -1
  6. package/dist/{commands-laJDMj2m.js → commands-BvvoQL0v.js} +1410 -1203
  7. package/dist/{dev-BOFxC21E.js → dev-B6rfgKfo.js} +1424 -1392
  8. package/dist/{dev-DOK0w6ZW.js → dev-C_E1XxNF.js} +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/serveCommand-vPF5ucXC.js +1136 -0
  11. package/dist/serveEntry.js +1 -1
  12. package/package.json +17 -17
  13. package/templates/AGENTS.core.md +25 -9
  14. package/templates/AGENTS.md +26 -10
  15. package/templates/agent-docs/_index.md +1 -1
  16. package/templates/agent-docs/authentication.md +9 -0
  17. package/templates/agent-docs/database/misc.md +26 -3
  18. package/templates/agent-docs/database/querying.md +2 -0
  19. package/templates/agent-docs/whats-new.md +82 -161
  20. package/templates/apps/api-ai/package.json +7 -7
  21. package/templates/apps/api-auth/package.json +8 -8
  22. package/templates/apps/api-backend/package.json +7 -7
  23. package/templates/apps/api-backend-deactivation/package.json +7 -7
  24. package/templates/apps/api-backend-mail/package.json +8 -8
  25. package/templates/apps/api-backend-mariadb/package.json +9 -9
  26. package/templates/apps/api-backend-storage/package.json +8 -8
  27. package/templates/apps/api-data-advanced/package.json +8 -8
  28. package/templates/apps/api-durable/package.json +8 -8
  29. package/templates/apps/api-feature-flags/package.json +9 -9
  30. package/templates/apps/api-governance/package.json +8 -8
  31. package/templates/apps/api-kv/package.json +8 -8
  32. package/templates/apps/api-moderation/package.json +8 -8
  33. package/templates/apps/api-observability/package.json +8 -8
  34. package/templates/apps/api-ratelimit/package.json +8 -8
  35. package/templates/apps/api-rbac/package.json +8 -8
  36. package/templates/apps/api-rest/package.json +7 -7
  37. package/templates/apps/api-saas/package.json +11 -11
  38. package/templates/apps/api-search/package.json +8 -8
  39. package/templates/apps/api-versioning/package.json +8 -8
  40. package/templates/apps/api-webhooks/package.json +9 -9
  41. package/templates/apps/changelog/package.json +6 -6
  42. package/templates/apps/edge-functions/package.json +2 -2
  43. package/templates/apps/frontend-admin/package.json +8 -8
  44. package/templates/apps/frontend-app/package.json +8 -8
  45. package/templates/apps/frontend-blank/package.json +7 -7
  46. package/templates/apps/frontend-contact/package.json +7 -7
  47. package/templates/apps/frontend-dashboard/package.json +7 -7
  48. package/templates/apps/frontend-docs/package.json +7 -7
  49. package/templates/apps/frontend-i18n/package.json +6 -6
  50. package/templates/apps/frontend-landing/package.json +7 -7
  51. package/templates/apps/frontend-spa/package.json +7 -7
  52. package/templates/apps/frontend-ssr/package.json +7 -7
  53. package/templates/apps/frontend-ssr-api/package.json +8 -8
  54. package/templates/apps/frontend-static-blog/package.json +6 -6
  55. package/dist/apiBuild-D1UBJ4TM.js +0 -2
  56. package/dist/serveCommand-CxcxHc9Y.js +0 -1129
@@ -1,1129 +0,0 @@
1
- import { st as e, t } from "./inspectMetrics-D1DmLeJs.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 f, B as p, C as ee, D as te, E as ne, F as m, H as re, I as ie, J as h, L as ae, M as g, N as oe, O as _, P as se, Q as v, S as ce, T as le, V as y, X as b, Y as ue, Z as x, _ as de, a as S, b as C, c as fe, et as pe, f as me, g as he, h as ge, j as w, k as _e, n as ve, nt as ye, p as T, r as be, s as xe, tt as Se, v as Ce, w as we, x as Te, y as E, z as Ee } from "./dev-BOFxC21E.js";
7
- import { c as D, r as De } from "./apiBuild-CPDTJHkH.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 qe, makeActionRunner as I, makeAdvisoryLockCoordinator as Je, makeApiKeyService as Ye, makeApiKeyUsageBuffer as L, makeApiKeyUsageFlusher as Xe, makeAsyncKv as Ze, makeCoordinatedScheduler as Qe, makeEffectStoreLayer as $e, makeLazyWorkflowFacade as et, makeMutationRunner as tt, makeOneShotQueryRunner as nt, makeQueryDescriptorProducer as rt, makeQueryReauthorizer as it, makeQuerySubscriber as at, makeSchemaRegistry as ot, makeWorkflowFacade as st, makeWorkflowFacadeWithCallerContext as ct, makeWorkflowLayers as lt, noopKv as R, recordSubscriptionDelivery as ut, registerWakeup as dt, resolveSecretsBackend as ft, runProvidedEffect as pt, setSecretsBackend as mt, setSystemStoreHandle as ht, setTupleSource as gt, singleCoordinator as _t, startRpcServer as vt, startScheduler as yt, workflowToRpc as z, wrapStoreWithBootCodec as bt } from "@voltro/runtime";
16
- import { RpcGroup as xt } from "@effect/rpc";
17
- import { SqlClient as St } from "@effect/sql";
18
- import { and as Ct, ensureTableRegistered as wt, eq as B, or as Tt } from "@voltro/database";
19
- import { appStorageProvider as V, fromNodeReadable as Et, getObjectStream as H, putObjectStream as U, toNodeReadable as W } from "@voltro/plugin-storage";
20
- import { AuthMiddleware as Dt, ConnectionInfoMiddleware as Ot, actionToRpc as G, anonymousSubject as kt, mutationToRpc as At, queryToRpc as K, streamToRpc as jt, workflowCancelDescriptor as q, workflowDomainEventsQueryDescriptor as Mt, workflowEventDeliveriesQueryDescriptor as J, workflowResumeDescriptor as Nt, workflowRunEventsQueryDescriptor as Y, workflowRunQueryDescriptor as X, workflowRunStepsQueryDescriptor as Z, workflowRunsQueryDescriptor as Pt, workflowSignalDescriptor as Ft, workflowUpdateDescriptor as It } from "@voltro/protocol";
21
- import { assertProductionSessionSecret as Lt } from "@voltro/protocol/session";
22
- import { createHash as Rt, timingSafeEqual as zt } from "node:crypto";
23
- import { declaredSnapshot as Bt, describeOutcome as Vt, runPlannedMigrations as Ht } from "@voltro/database/sql";
24
- import { getAuthSessionStrategy as Ut } from "@voltro/plugin-auth";
25
- import { collectPublicApiRoutes as Wt, restRoutesToHttpRoutes as Gt } from "@voltro/protocol/rest";
26
- import { buildDeliverWebhookExecute as Kt, buildWebhooksService as qt, defaultIncomingPath as Jt, deliverWebhookWorkflow as Yt, mountIncomingWebhook as Xt } from "@voltro/plugin-webhooks";
27
- import { packBundle as Zt, runExport as Qt, runImport as $t, storageBlobSink as en, storageRefsBlobSource as tn, unpackBundle as nn, unpackBundleToDir as rn } from "@voltro/data-transfer";
28
- //#region src/adminAuth.ts
29
- var an = "/_voltro/admin/import", on = "/_voltro/admin/export", Q = (e, t) => ({
30
- status: e,
31
- contentType: "application/json; charset=utf-8",
32
- body: JSON.stringify(t)
33
- }), sn = (e) => {
34
- let t = e.authorization ?? e.Authorization, n = t ? /^Bearer\s+(.+)$/i.exec(t) : null;
35
- return n ? n[1] : null;
36
- }, cn = (e, t) => zt(Rt("sha256").update(e).digest(), Rt("sha256").update(t).digest()), ln = (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 = sn(e.headers);
40
- return !n || !cn(n, t) ? Q(401, { error: "unauthorized" }) : null;
41
- }, un = j({ scope: "voltro:admin-import" }), dn = "VBUNDLE2", fn = async function* (e) {
42
- yield e;
43
- }, pn = (e) => async (t) => {
44
- let n = ln(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") === dn, c, l;
47
- if (s) c = fn(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"), f = await import("node:path"), p = await d.mkdtemp(f.join(u.tmpdir(), "voltro-admin-import-"));
60
- try {
61
- e.assetSink ? await nn(c, {
62
- dir: p,
63
- blobs: e.assetSink
64
- }) : await rn(c, p);
65
- let t = await k.runPromiseExit($t({
66
- store: e.store,
67
- bundleDir: p,
68
- ...r ? { mode: r } : {},
69
- ...i ? { onConflict: i } : {},
70
- ...a ? { atomic: a } : {},
71
- ...e.snapshot ? { targetSnapshot: e.snapshot } : {},
72
- force: o,
73
- onWarn: (e) => un.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 un.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 un.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 un.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(p, {
116
- recursive: !0,
117
- force: !0
118
- });
119
- }
120
- }, mn = j({ scope: "voltro:admin-export" }), hn = 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
- }, gn = (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" }, _n = (e) => async (t) => {
131
- let n = ln(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 ?? gn(r), c = typeof r.bundleKey == "string" && r.bundleKey.length > 0, l = r.assets === !0 && e.assetSource ? { blobs: e.assetSource } : {}, u = await import("node:os"), d = await import("node:fs/promises"), f = await import("node:path"), p = await d.mkdtemp(f.join(u.tmpdir(), "voltro-admin-export-"));
152
- try {
153
- let t = await k.runPromise(Qt({
154
- store: e.store,
155
- snapshot: e.snapshot,
156
- dialect: e.dialect,
157
- outDir: p,
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, () => Zt({
170
- dir: p,
171
- ...l
172
- })), mn.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 hn(Zt({
187
- dir: p,
188
- ...l
189
- }));
190
- return mn.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 mn.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(p, {
213
- recursive: !0,
214
- force: !0
215
- });
216
- }
217
- }, vn = 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
- }, yn = (e, t, n = {}) => (async function* () {
229
- let r = await W((await k.runPromise(H(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
- })(), bn = {
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
- }, xn = async (e) => {
248
- ht({
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) => ut({
256
- label: e.label,
257
- kind: e.kind,
258
- durationMs: e.durationMs,
259
- rowCount: e.rowCount
260
- })
261
- }), n = e.cache ?? bn, r = e.kv ?? R, 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: B("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: B("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
- }, p = (e.discovered.workflows?.length ?? 0) > 0 ? et(() => i) : void 0, ee = (e.discovered.workflows?.length ?? 0) > 0 || (e.discovered.eventTriggers?.length ?? 0) > 0, te = ee || (e.discovered.workflowWorkers?.length ?? 0) > 0 || e.scheduleCoordination === "cluster", ne = e.tenantIsolation === "namespace", re = (e.log ?? j({ scope: "voltro:serve" })).child("webhooks"), ae, _ = e.discovered.webhooks;
318
- if (_ && _.outgoing.length > 0 && e.workflowEngineLayer !== void 0) {
319
- let t = e.workflowEngineLayer, i = d({
320
- store: e.store,
321
- schemaRegistry: e.schemaRegistry,
322
- cache: n,
323
- kv: r
324
- }), a = _.outgoing.map((e) => e.descriptor);
325
- ae = qt(i, async (e) => {
326
- let n = Yt.execute(e).pipe(k.provide(Yt.toLayer(Kt(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 se = /* @__PURE__ */ new Map();
336
- if (_) for (let e of _.incoming) {
337
- let t = e.descriptor.path ?? Jt(e.descriptor.id), n = `VOLTRO_WEBHOOK_SECRET_${e.descriptor.id.toUpperCase().replace(/[^A-Z0-9]/g, "_")}`, r = Xt(e.descriptor, {
338
- resolveSecret: async () => process.env[n] ?? null,
339
- resolveWorkflows: () => p === void 0 ? void 0 : ct(p, {
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
- se.set(t, { handle: r });
355
- }
356
- Ke(), gt((t) => qe(e.store, t.subjectId, t.resourceType, t.resourceId));
357
- let ce = (e.discovered.outboxHandlers?.length ?? 0) > 0 ? m({
358
- handlers: e.discovered.outboxHandlers ?? [],
359
- store: e.store,
360
- log: (e.log ?? j({ scope: "voltro:serve" })).child("outbox")
361
- }) : void 0, y = oe({
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
- }), b = v({
367
- store: e.store,
368
- schemaRegistry: e.schemaRegistry,
369
- cache: n,
370
- kv: r,
371
- ...ae === void 0 ? {} : { webhooksService: ae },
372
- ...p === void 0 ? {} : { workflowsProxy: p },
373
- eventTriggers: e.discovered.eventTriggers ?? [],
374
- namespaceIsolationOn: ne,
375
- ...ce === void 0 ? {} : { outbox: { nudge: ce.nudge } },
376
- ...y.active ? { connections: { registry: y.registry } } : {}
377
- }), ue = A.succeed(N, le), de = (t, n) => {
378
- let r = t.pipe(k.provide($e(n)));
379
- return pt((e.baseLayer ? r.pipe(k.provide(e.baseLayer)) : r).pipe(k.provide(ue)));
380
- }, S = tt({
381
- store: e.store,
382
- buildContext: (e, t, n) => b(e, t, n),
383
- runEffect: de,
384
- undoCapture: C()
385
- }), fe = E(), pe = I({
386
- buildContext: (e) => b(e),
387
- runEffect: de
388
- }), me = {
389
- buildContext: (e) => b(e),
390
- finalize: (t, n) => Fe(Ie(t, e.tenantScopedTables, n.subject.tenantId), e.softDeleteScopedTables),
391
- provideEffect: (e, t) => e.pipe(k.provide($e(t)))
392
- }, w = rt(me), ve = nt({
393
- ...me,
394
- queryRows: (t) => e.store.query(t)
395
- }), ye = at({
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
- ...fe.queries,
403
- ...y.queries
404
- ]) T[n.descriptor.name] = (e) => F(w(n, e), t, `subscription.${n.descriptor.name}`, void 0, void 0, it(n, e));
405
- for (let t of [
406
- ...e.discovered.mutations,
407
- ...fe.mutations,
408
- ...y.mutations
409
- ]) T[t.descriptor.name] = (e) => P(async (e, n) => S(t, e, n), e, `mutation.${t.descriptor.name}`);
410
- for (let t of [...e.discovered.actions, ...y.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) => ve(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) => S(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 ? Gt(Wt(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: an,
443
- handle: pn({
444
- secret: Ce,
445
- store: e.store,
446
- ...e.dataTransferSnapshot ? { snapshot: e.dataTransferSnapshot } : {},
447
- assetSink: en(V()),
448
- openArchive: (e) => yn(V(), e)
449
- })
450
- }, {
451
- method: "POST",
452
- path: on,
453
- handle: _n({
454
- secret: Ce,
455
- store: e.store,
456
- snapshot: e.dataTransferSnapshot ?? { tables: [] },
457
- dialect: e.dataTransferDialect ?? "memory",
458
- tenantTables: [...e.tenantScopedTables],
459
- loadProfile: vn,
460
- assetSource: tn(V(), e.store),
461
- putArchive: async (e, t) => {
462
- let { Readable: n } = await import("node:stream"), r = V(), i = Et("storage", () => n.from(t()));
463
- await k.runPromise(U(r, e, i, { contentType: "application/octet-stream" }));
464
- }
465
- })
466
- }] : [], Ee = [
467
- ...e.httpRoutes ?? [],
468
- ...Se,
469
- ...Te,
470
- ...y.httpRoutes
471
- ];
472
- for (let t of e.discovered.streams ?? []) T[t.descriptor.name] = (n) => ze((r) => {
473
- let i = b(r), a = t.executor(n, i);
474
- if (k.isEffect(a)) {
475
- let t = a.pipe(k.provide($e(i.store)));
476
- return (e.baseLayer ? t.pipe(k.provide(e.baseLayer)) : t).pipe(k.provide(ue));
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 ct(p, {
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
- ee && (T[X.name] = (e) => F(w({
489
- descriptor: X,
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: Tt(B("id", t), B("executionId", t)),
499
- take: 1,
500
- skip: void 0,
501
- projection: void 0
502
- };
503
- }
504
- }, e), t, `subscription.${X.name}`), T[Pt.name] = (e) => F(w({
505
- descriptor: Pt,
506
- executor: (e) => {
507
- let t = e, n = [...t.tag === void 0 ? [] : [B("tag", t.tag)], ...t.status === void 0 ? [] : [B("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] : Ct(...n),
515
- take: r,
516
- skip: void 0,
517
- projection: void 0
518
- };
519
- }
520
- }, e), t, `subscription.${Pt.name}`), T[Z.name] = (e) => F(w({
521
- descriptor: Z,
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: B("runId", t),
531
- take: 1e3,
532
- skip: void 0,
533
- projection: void 0
534
- };
535
- }
536
- }, e), t, `subscription.${Z.name}`), T[Y.name] = (e) => F(w({
537
- descriptor: Y,
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: B("runId", t),
547
- take: 1e3,
548
- skip: void 0,
549
- projection: void 0
550
- };
551
- }
552
- }, e), t, `subscription.${Y.name}`), T[Mt.name] = (e) => F(w({
553
- descriptor: Mt,
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 : B("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.${Mt.name}`), T[J.name] = (e) => F(w({
569
- descriptor: J,
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: B("eventId", t),
579
- take: 500,
580
- skip: void 0,
581
- projection: void 0
582
- };
583
- }
584
- }, e), t, `subscription.${J.name}`), T[q.name] = (t) => P(async (t, n) => {
585
- let r = t;
586
- return await x(e.store, n.subject, { executionId: r.executionId }), await p.cancel(r.workflowName, r.executionId), await Le(r.workflowName, r.executionId, "workflow.cancel"), { ok: !0 };
587
- }, t, `action.${q.name}`), T[Nt.name] = (t) => P(async (t, n) => {
588
- let r = t;
589
- return await x(e.store, n.subject, { executionId: r.executionId }), await p.resume(r.workflowName, r.executionId), { ok: !0 };
590
- }, t, `action.${Nt.name}`), T[Ft.name] = (t) => P(async (t, n) => {
591
- let r = t;
592
- return await x(e.store, n.subject, { id: r.id }), p.signal({ id: r.id }, r.signalName, r.payload);
593
- }, t, `action.${Ft.name}`), T[It.name] = (t) => P(async (t, n) => {
594
- let r = t;
595
- return await x(e.store, n.subject, { id: r.id }), p.update({ id: r.id }, r.updateName, r.payload, r.timeoutMs === void 0 ? void 0 : { timeoutMs: r.timeoutMs });
596
- }, t, `action.${It.name}`));
597
- let D = [
598
- ...e.discovered.queries.map((e) => K(e.descriptor)),
599
- ...e.discovered.mutations.map((e) => At(e.descriptor)),
600
- ...e.discovered.actions.map((e) => G(e.descriptor)),
601
- ...fe.queries.map((e) => K(e.descriptor)),
602
- ...fe.mutations.map((e) => At(e.descriptor)),
603
- ...y.queries.map((e) => K(e.descriptor)),
604
- ...y.mutations.map((e) => At(e.descriptor)),
605
- ...y.actions.map((e) => G(e.descriptor)),
606
- ...(e.discovered.streams ?? []).map((e) => jt(e.descriptor)),
607
- ...(e.discovered.workflows ?? []).map((e) => z(e.definition)),
608
- ...ee ? [
609
- K(X),
610
- K(Pt),
611
- K(Z),
612
- K(Y),
613
- K(Mt),
614
- K(J),
615
- G(q),
616
- G(Nt),
617
- G(Ft),
618
- G(It)
619
- ] : []
620
- ], De = xt.make(...D).middleware(Dt).middleware(Ot), Oe = A.succeed(Dt, Dt.of(({ headers: t, clientId: n }) => k.promise(() => e.resolveSubject(t, n)))), ke = A.succeed(Ot, Ot.of(({ clientId: e }) => k.succeed({ clientId: e }))), Ae = e.dormancyTenantId ?? "default", je = e.dormancy === "sleep" ? {
621
- register: (t, n, r) => dt(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: B("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 = [...lt(e.discovered.workflows ?? [], {
677
- buildContext: (t, n) => e.buildContextForWorkflow?.(t, n) ?? b({
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 ? st({
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 = h(T, e.discovered.queries.map((e) => e.descriptor.name), ee), 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: ot, shutdown: ft } = vt({
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
- ...se.size > 0 ? { webhookRoutes: se } : {}
755
- });
756
- if (await Re(ot), (e.discovered.schedules?.length ?? 0) > 0) {
757
- let t = (e.scheduleCoordination ?? "single") === "advisoryLock" ? Je(e.store, e.scheduleReplicaId ?? `pid-${process.pid}`) : _t;
758
- o = await yt(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 }) => b({
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 mt = e.log ?? j({ scope: "voltro:serve" }), bt, St;
787
- if ((e.discovered.subscribers?.length ?? 0) > 0 && (bt = ie(e.discovered.subscribers ?? [], e.store, mt.child("subscribe"), e.schemaRegistry)), (e.discovered.reactions?.length ?? 0) > 0) {
788
- let t = mt.child("reaction");
789
- St = _e(e.discovered.reactions ?? [], e.store, {
790
- runAct: async (n, r) => {
791
- if (n.kind === "workflow") {
792
- if (p === 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 ct(p, {
798
- traceId: `reaction:${n.workflow}`,
799
- source: `reaction:${n.workflow}`
800
- }).start(n.workflow, e);
801
- return;
802
- }
803
- await f(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) => kt(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 wt;
825
- return (e.discovered.aggregates?.length ?? 0) > 0 && (wt = await we({
826
- discovered: e.discovered.aggregates ?? [],
827
- store: e.store,
828
- log: mt.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
- }), ue = A.succeed(N, wt.registry)), Ze = !0, e.bootTiming?.mark("ready"), {
833
- dispatcher: t,
834
- server: ot,
835
- scheduler: o,
836
- close: async () => {
837
- Ze = !1, wt?.detach(), St?.(), bt?.(), await o?.shutdown(), t.close(), await a?.dispose(), await new Promise((e) => ot.close(() => e())), await ft();
838
- }
839
- };
840
- }, $ = j({ scope: "voltro:serve" }), Sn = (e, t, n) => (e === "production" || e === "staging") && t !== "memory" && n !== "0", Cn = ke, wn = 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 Tn(e);
853
- }, Tn = async (d) => {
854
- let f = Oe();
855
- process.env.NODE_ENV || (process.env.NODE_ENV = "production"), Lt();
856
- let m = process.cwd(), ie = Number(process.env.PORT ?? Cn(d, "--port") ?? 4e3), h = await xe(m);
857
- mt(ft(h?.secrets)), await e({
858
- rawEnv: h?.env,
859
- appType: "api",
860
- root: m,
861
- log: $,
862
- generateTypes: !1
863
- }), f.mark("config");
864
- let g = (process.env.DB_DIALECT ?? h?.store ?? "memory").toLowerCase(), oe = (g === "mariadb" || g === "postgres" || g === "mssql") && (process.env.CDC ?? "1") !== "0", v = g === "mariadb" ? "mariadb" : g === "mssql" ? "mssql" : void 0, le = De(m);
865
- if (!i() && M(le)) try {
866
- let e = await import(je(le).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 me(m), C = await fe(x, { cdc: oe && v !== void 0 }), he = x.filter((e) => ce.test(e)), ge = he.length > 0 ? await ee(he, $.child("webhooks")) : void 0, _e = s({
876
- mix: C.featureMix,
877
- plugins: h?.plugins ?? [],
878
- cdc: oe && v !== void 0,
879
- ...v ? { cdcDialect: v } : {}
880
- }), we = h?.analytics !== void 0 && h.analytics.kind !== "noop" && g !== "memory" ? (await n(g)).makeSqlLayer(S()) : void 0, E = await p({
881
- spec: h?.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 [..._e, ...E.tables]) e.has(n.tableName) || (e.add(n.tableName), t.push(n));
887
- return t;
888
- })();
889
- for (let e of D) wt(e);
890
- let ke = (process.env.NODE_ENV ?? "").toLowerCase();
891
- if (Sn(ke, g, process.env.VOLTRO_AUTO_MIGRATE)) {
892
- let e = (await n(g)).makeSqlLayer(S()), t = await k.runPromise(St.SqlClient.pipe(k.flatMap((e) => Ht(e, D, {
893
- appliedBy: `serve:${ke}`,
894
- environment: "prod",
895
- dialectId: g
896
- })), k.provide(e)));
897
- t.kind === "prod-mismatch" && ($.error(Vt(t, g)), $.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(Vt(t, g));
898
- }
899
- let j = ot(D);
900
- f.mark("discover");
901
- let N = await be(h, void 0), Ne = bt(N, g);
902
- for (let e of ye({
903
- dialect: String(h?.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
- 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);
916
- let { service: Fe, invalidationBus: Ie, snapshotCache: Re, cache: P, backend: ze, dispose: F } = await Se({ env: process.env });
917
- $.info(`cache backend resolved: ${ze}` + (ze === "redis" ? ` (driver ${process.env.CACHE_REDIS_DRIVER ?? "resp"})` : " — in-process, not cross-instance")), N.onChange((e) => {
918
- k.runFork(Ie.publish(e.table));
919
- }), 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);
920
- let { kv: Be, service: Ve } = await Ze({ store: N });
921
- f.mark("store");
922
- let Ke = Le({
923
- store: N,
924
- sink: E.sink,
925
- log: $
926
- }), qe = pe({
927
- store: N,
928
- dialect: g
929
- }), I = h?.plugins ?? [], $e = process.env.POD_NAME ?? process.env.HOSTNAME ?? `serve-${process.pid}`, et, tt;
930
- g !== "memory" && (et = Me.make((await n(g)).makeSqlLayer(S())), tt = await et.runPromise(St.SqlClient));
931
- let nt = Qe({
932
- coordinator: [
933
- "postgres",
934
- "mariadb",
935
- "mysql",
936
- "mssql"
937
- ].includes(g) ? Je(N, $e, $) : _t,
938
- replicaId: $e,
939
- log: $
940
- }), rt = [], it = {
941
- ...tt ? { sql: tt } : {},
942
- scheduleCoordinated: (e, t, n) => {
943
- let r = nt(e, t, n);
944
- return rt.push(r), r;
945
- }
946
- };
947
- for (let e of I) e.bindDataStore?.(N, it);
948
- let at = I.filter((e) => typeof e.onChangeEvent == "function");
949
- if (at.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 at) 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 st = Ce({
964
- plugins: I,
965
- appName: h?.name ?? "voltro-api",
966
- appType: "api",
967
- voltroVersion: process.env.npm_package_version ?? "0.0.0",
968
- log: $
969
- });
970
- I.length && await st.activate(), f.mark("plugins");
971
- let ct = await st.gatherObservability(), lt = await T(N, h, 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
- }), R = h?.apiKeys, ut = (typeof R == "object" ? R.prefix : void 0) ?? "voltro_", dt = R ? Ue(N) : void 0, pt = dt ? L({ flush: Xe(dt) }) : void 0;
976
- pt && process.once("exit", () => {
977
- pt.shutdown();
978
- });
979
- let ht = dt ? Ye(dt, {
980
- prefix: ut,
981
- ...pt ? { usage: pt } : {}
982
- }) : void 0, gt = ht ? [Ge(ht, { prefix: ut })] : [], vt = ve([...h?.auth?.strategies ?? [], ...gt], Ut(h?.plugins ?? []), h?.auth?.anonymousTenantRequired ?? !1, h?.auth?.resolveScopes, () => Ne), yt = [...h?.restRoutes ?? [], ...ht ? Pe(ht, (typeof R == "object" ? R.managementPath : void 0) ?? "/v1/api-keys") : []], z = h?.idempotency, xt = z ? {
983
- store: We(N),
984
- header: (typeof z == "object" ? z.header : void 0) ?? "Idempotency-Key",
985
- ttlMs: (typeof z == "object" ? z.ttlMs : void 0) ?? 864e5
986
- } : void 0, Ct = yt.length > 0 ? Gt(yt, {
987
- store: N,
988
- resolveSubject: (e) => vt({
989
- headers: e,
990
- clientId: -1
991
- }),
992
- ...xt ? { idempotency: xt } : {}
993
- }) : [], B = I.map((e) => e.services).filter((e) => e !== void 0), Tt = A.mergeAll(b({
994
- analyticsLayer: E.layer,
995
- cacheService: Fe,
996
- kvService: Ve,
997
- pluginServices: B,
998
- userLayers: h?.layers ?? []
999
- }), ue(h?.http ?? {})), V = h?.scheduling ?? {}, Et = V.trigger ?? "self", H = /* @__PURE__ */ new Set([
1000
- "postgres",
1001
- "mysql",
1002
- "mariadb",
1003
- "mssql"
1004
- ]), U = V.coordination ?? (H.has(g) ? "advisoryLock" : "single"), W = U === "cluster" && H.has(g), Dt = W ? "cluster" : U === "advisoryLock" && H.has(g) ? "advisoryLock" : "single";
1005
- U === "cluster" && !W && $.warn("scheduling.coordination=cluster needs a sql-backed store except sqlite — falling back to single"), U === "advisoryLock" && !H.has(g) && $.warn("scheduling.coordination=advisoryLock needs a SQL store (the claim-row gate) — falling back to single");
1006
- let Ot, G = C.workflows.length > 0 || C.workflowWorkers.length > 0 || C.eventTriggers.length > 0 || (ge?.outgoing.length ?? 0) > 0 || W, kt;
1007
- if (G) {
1008
- if (g === "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 ?? Et) === "self").map((e) => t({
1013
- name: e.name,
1014
- cron: He(e),
1015
- execute: async () => {
1016
- await Ot?.fireFromCluster(e.name);
1017
- }
1018
- })) : [];
1019
- kt = g === "memory" ? e.layerMemory : await (async () => {
1020
- let e = await n(g), 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 At = de(I, t()), K = x.filter((e) => /\.subscribe\.tsx?$/.test(e)), jt = K.length > 0 ? await ae(K, $) : [], q = x.filter((e) => /\.reaction\.tsx?$/.test(e)), Mt = q.length > 0 ? await w(q, $) : [], J = x.filter((e) => u.test(e)), Nt = J.length > 0 ? await se(J, $) : [], Y = x.filter((e) => /\.aggregate\.tsx?$/.test(e)), X = Y.length > 0 ? await ne(Y, $) : [], Z = te();
1031
- if (X.length > 0 && g !== "memory") try {
1032
- Z = _((await n(g)).makeSqlLayer(S()));
1033
- } catch (e) {
1034
- $.warn("aggregate: SQL storage init failed — falling back to in-process", { err: String(e) });
1035
- }
1036
- let Pt = g === "memory" ? _t : Je(N, `aggregate@${process.pid}`, $), Ft = [], It = [], Rt = x.filter((e) => l.test(e));
1037
- if (Rt.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(Rt, e);
1041
- for (let e of n.agents) for (let t of Te(e)) (t.kind === "action" ? Ft : It).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
- f.mark("workflow");
1049
- let zt = await xn({
1050
- bootTiming: f,
1051
- discovered: {
1052
- queries: [...C.queries, ...It],
1053
- mutations: C.mutations,
1054
- actions: [...C.actions, ...Ft],
1055
- streams: C.streams,
1056
- workflows: C.workflows,
1057
- workflowWorkers: C.workflowWorkers,
1058
- eventTriggers: C.eventTriggers,
1059
- schedules: C.schedules,
1060
- subscribers: jt,
1061
- outboxHandlers: Nt,
1062
- connections: C.connections,
1063
- reactions: Mt,
1064
- aggregates: X,
1065
- ...ge === void 0 ? {} : { webhooks: ge }
1066
- },
1067
- log: $,
1068
- analytics: E.sink,
1069
- aggregateStorage: Z,
1070
- aggregateCoordinator: Pt,
1071
- store: N,
1072
- kv: Be,
1073
- cache: P,
1074
- snapshotCache: Re,
1075
- schemaRegistry: j,
1076
- tenantScopedTables: C.tenantScopedTables,
1077
- softDeleteScopedTables: C.softDeleteScopedTables,
1078
- dataTransferSnapshot: Bt(D),
1079
- dataTransferDialect: g,
1080
- tenantIsolation: (process.env.VOLTRO_TENANT_ISOLATION ?? h?.tenancy?.isolation) === "namespace" ? "namespace" : "shared-schema",
1081
- resolveSubject: (e, t) => vt({
1082
- headers: e,
1083
- clientId: t
1084
- }),
1085
- httpRoutes: [...I.flatMap((e) => e.httpRoutes ?? []), ...Ct],
1086
- getStore: () => Ne,
1087
- ...Tt ? { baseLayer: Tt } : {},
1088
- ...kt === void 0 ? {} : { workflowEngineLayer: kt },
1089
- scheduleDefaultTrigger: Et,
1090
- scheduleCoordination: Dt,
1091
- scheduleArmSelf: !W,
1092
- dormancy: process.env.VOLTRO_DORMANCY === "sleep" || process.env.VOLTRO_DORMANCY === "always-on" ? process.env.VOLTRO_DORMANCY : h?.dormancy ?? "always-on",
1093
- scheduleReplicaId: process.env.HOSTNAME ?? `pid-${process.pid}`,
1094
- ...At === void 0 ? {} : { scheduleFireInterceptor: At },
1095
- onSchedulerReady: (e) => {
1096
- Ot = e;
1097
- },
1098
- observability: ct,
1099
- port: ie,
1100
- ...h?.transport?.wsPath ? { path: h.transport.wsPath } : {}
1101
- });
1102
- re(y([
1103
- C.queries,
1104
- C.mutations,
1105
- C.actions,
1106
- C.streams
1107
- ]), (e) => {
1108
- $.warn(e);
1109
- }), $.info(`API listening on :${ie}`, {
1110
- dialect: g,
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: Dt
1119
- }), f.finish($);
1120
- let Wt = () => {
1121
- for (let e of rt) e.stop();
1122
- Ke.detach(), qe.stop(), F(), et?.dispose(), setTimeout(() => process.exit(0), 1e4).unref?.(), Promise.resolve(st.deactivate()).then(() => lt?.close()).then(() => E.dispose()).then(() => zt.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", Wt), process.on("SIGTERM", Wt), await new Promise(() => {}), 0;
1127
- };
1128
- //#endregion
1129
- export { wn as n, vn as r, Tn as t };