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