@voltro/cli 0.4.0 → 0.6.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 (84) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/bin/voltro.mjs +54 -2
  3. package/dist/apiBuild-Bk4JBt-i.js +2 -0
  4. package/dist/{apiBuild-CvtQeBMs.js → apiBuild-BxY44VGj.js} +20 -20
  5. package/dist/bin.js +2 -2
  6. package/dist/{commands-DhyBIs1O.js → commands-My_YlUJV.js} +2823 -2265
  7. package/dist/{dev-CQxbrpDz.js → dev-Bjq-nIvH.js} +2650 -2230
  8. package/dist/dev-D6b74iXI.js +2 -0
  9. package/dist/devActivity-1WtIVyHc.js +153 -0
  10. package/dist/devActivity.d.ts +46 -0
  11. package/dist/devActivity.js +2 -0
  12. package/dist/index.js +1 -1
  13. package/dist/serveCommand-C-XQ89NJ.js +1110 -0
  14. package/dist/serveEntry.js +2 -2
  15. package/package.json +22 -17
  16. package/templates/AGENTS.core.md +119 -0
  17. package/templates/AGENTS.md +119 -0
  18. package/templates/agent-docs/_manifest.json +3 -3
  19. package/templates/agent-docs/ai.md +41 -5
  20. package/templates/agent-docs/authentication.md +238 -0
  21. package/templates/agent-docs/cli.md +142 -0
  22. package/templates/agent-docs/configuration.md +38 -0
  23. package/templates/agent-docs/data.md +718 -42
  24. package/templates/agent-docs/database/advancedqueries.md +21 -0
  25. package/templates/agent-docs/database/querying.md +166 -8
  26. package/templates/agent-docs/database/schema.md +6 -2
  27. package/templates/agent-docs/deployment.md +171 -0
  28. package/templates/agent-docs/internationalization.md +2 -0
  29. package/templates/agent-docs/plugins.md +4 -4
  30. package/templates/agent-docs/reference.md +90 -2
  31. package/templates/agent-docs/templates/apibackends.md +13 -2
  32. package/templates/agent-docs/testing.md +157 -3
  33. package/templates/agent-docs/workflows.md +11 -8
  34. package/templates/apps/api-ai/package.json +7 -7
  35. package/templates/apps/api-auth/app.config.ts +20 -13
  36. package/templates/apps/api-auth/package.json +8 -8
  37. package/templates/apps/api-backend/package.json +7 -7
  38. package/templates/apps/api-backend-deactivation/package.json +7 -7
  39. package/templates/apps/api-backend-mail/package.json +8 -8
  40. package/templates/apps/api-backend-mariadb/.env.example +10 -4
  41. package/templates/apps/api-backend-mariadb/package.json +9 -9
  42. package/templates/apps/api-backend-storage/package.json +8 -8
  43. package/templates/apps/api-data-advanced/app.config.ts +21 -8
  44. package/templates/apps/api-data-advanced/package.json +8 -8
  45. package/templates/apps/api-durable/package.json +8 -8
  46. package/templates/apps/api-feature-flags/package.json +9 -9
  47. package/templates/apps/api-governance/app.config.ts +15 -2
  48. package/templates/apps/api-governance/package.json +8 -8
  49. package/templates/apps/api-kv/package.json +8 -8
  50. package/templates/apps/api-moderation/package.json +8 -8
  51. package/templates/apps/api-observability/package.json +8 -8
  52. package/templates/apps/api-ratelimit/package.json +8 -8
  53. package/templates/apps/api-rbac/package.json +8 -8
  54. package/templates/apps/api-rest/package.json +7 -7
  55. package/templates/apps/api-saas/package.json +11 -11
  56. package/templates/apps/api-search/package.json +8 -8
  57. package/templates/apps/api-versioning/package.json +8 -8
  58. package/templates/apps/api-webhooks/app.config.ts +20 -1
  59. package/templates/apps/api-webhooks/package.json +8 -8
  60. package/templates/apps/changelog/package.json +6 -6
  61. package/templates/apps/edge-functions/package.json +2 -2
  62. package/templates/apps/frontend-admin/package.json +8 -8
  63. package/templates/apps/frontend-app/package.json +8 -8
  64. package/templates/apps/frontend-blank/package.json +7 -7
  65. package/templates/apps/frontend-contact/package.json +7 -7
  66. package/templates/apps/frontend-dashboard/package.json +7 -7
  67. package/templates/apps/frontend-docs/package.json +7 -7
  68. package/templates/apps/frontend-i18n/package.json +6 -6
  69. package/templates/apps/frontend-landing/package.json +7 -7
  70. package/templates/apps/frontend-spa/package.json +7 -7
  71. package/templates/apps/frontend-ssr/package.json +7 -7
  72. package/templates/apps/frontend-ssr-api/package.json +8 -8
  73. package/templates/apps/frontend-static-blog/package.json +6 -6
  74. package/templates/baselines/bare/.env.example +10 -3
  75. package/templates/baselines/compose/.env.example +10 -2
  76. package/templates/baselines/compose-mariadb/.env.example +10 -2
  77. package/templates/baselines/helm/.env.example +10 -3
  78. package/dist/apiBuild-DQBNqNZ8.js +0 -2
  79. package/dist/dev-DYjGqPGD.js +0 -2
  80. package/dist/serveCommand-BZzUJIyo.js +0 -1077
  81. package/templates/apps/api-auth/.env +0 -17
  82. package/templates/apps/api-data-advanced/.env +0 -17
  83. package/templates/apps/api-governance/.env +0 -4
  84. package/templates/apps/api-webhooks/.env +0 -6
@@ -1,1077 +0,0 @@
1
- import { $ as e, A as t, B as n, C as r, D as i, E as a, G as o, H as s, J as c, K as l, M as u, O as d, Q as ee, R as f, S as p, T as m, U as h, V as te, W as g, X as ne, Z as re, _ as ie, at as _, b as ae, d as v, f as oe, g as se, h as y, i as b, j as ce, k as le, m as ue, n as x, nt as S, o as C, qt as w, s as de, t as fe, v as T, w as E, x as pe, y as me, z as he } from "./dev-CQxbrpDz.js";
2
- import { a as ge, r as _e } from "./startupRunner-DhlX9nqd.js";
3
- import { a as ve, t as ye } from "./apiBuild-CvtQeBMs.js";
4
- import { join as be } from "node:path";
5
- import { pathToFileURL as xe } from "node:url";
6
- import { Cause as Se, Effect as D, Layer as O, ManagedRuntime as Ce } from "effect";
7
- import { createLogger as k } from "@voltro/logger";
8
- import { existsSync as we } from "node:fs";
9
- import { AggregateRegistry as Te, Dispatcher as A, apiKeyManagementRoutes as j, applySoftDeleteScope as Ee, applyTenantScope as De, attachAnalyticsMirror as M, awaitServerListening as Oe, bindMutation as N, bindStream as ke, bindSubscription as P, buildTracingLayer as Ae, cancelWakeup as je, compileCron as Me, dataStoreApiKeyStore as Ne, dataStoreIdempotencyStore as Pe, frameworkApiKeyStrategy as Fe, makeActionRunner as Ie, makeAdvisoryLockCoordinator as Le, makeApiKeyService as Re, makeAsyncKv as ze, makeCoordinatedScheduler as Be, makeEffectStoreLayer as Ve, makeLazyWorkflowFacade as He, makeMutationRunner as Ue, makeQueryDescriptorProducer as We, makeSchemaRegistry as F, makeWorkflowFacade as Ge, makeWorkflowFacadeWithCallerContext as I, makeWorkflowLayers as Ke, noopKv as qe, recordSubscriptionDelivery as Je, registerWakeup as Ye, resolveSecretsBackend as Xe, runProvidedEffect as Ze, setSecretsBackend as Qe, singleCoordinator as $e, startRpcServer as et, startScheduler as tt, workflowToRpc as nt, wrapStoreWithMixinBehaviour as rt } from "@voltro/runtime";
10
- import { createHash as L, timingSafeEqual as R } from "node:crypto";
11
- import { assertProductionSessionSecret as it } from "@voltro/protocol/session";
12
- import { RpcGroup as at } from "@effect/rpc";
13
- import { SqlClient as ot } from "@effect/sql";
14
- import { and as z, ensureTableRegistered as st, eq as B, or as ct } from "@voltro/database";
15
- import { fromNodeReadable as lt, getObjectStream as V, putObjectStream as ut, resolveStorageProvider as H, toNodeReadable as dt } from "@voltro/plugin-storage";
16
- import { AuthMiddleware as U, ConnectionInfoMiddleware as ft, 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 Y, workflowRunEventsQueryDescriptor as X, workflowRunQueryDescriptor as gt, workflowRunStepsQueryDescriptor as Z, workflowRunsQueryDescriptor as _t, workflowSignalDescriptor as vt, workflowUpdateDescriptor as yt } 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) => R(L("sha256").update(e).digest(), L("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 = k({ 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"), ee = await import("node:path"), f = await d.mkdtemp(ee.join(u.tmpdir(), "voltro-admin-import-"));
83
- try {
84
- e.assetSink ? await It(c, {
85
- dir: f,
86
- blobs: e.assetSink
87
- }) : await Lt(c, f);
88
- let t = await D.runPromiseExit(Nt({
89
- store: e.store,
90
- bundleDir: f,
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(f, {
139
- recursive: !0,
140
- force: !0
141
- });
142
- }
143
- }, Yt = k({ 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"), ee = await import("node:path"), f = await d.mkdtemp(ee.join(u.tmpdir(), "voltro-admin-export-"));
175
- try {
176
- let t = await D.runPromise(Mt({
177
- store: e.store,
178
- snapshot: e.snapshot,
179
- dialect: e.dialect,
180
- outDir: f,
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: f,
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: f,
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(f, {
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 (e) => {
261
- let t = new A({
262
- store: e.store,
263
- ...e.snapshotCache ? { cache: e.snapshotCache } : {},
264
- recordDelivery: (e) => Je({
265
- label: e.label,
266
- kind: e.kind,
267
- durationMs: e.durationMs,
268
- rowCount: e.rowCount
269
- })
270
- }), i = e.cache ?? en, a = e.kv ?? qe, o, s, c, l = /* @__PURE__ */ new Map(), u = () => `wfctx_${globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}`, ee = async (t, n, r) => {
271
- let i = {
272
- ...r,
273
- source: r.source ?? `workflow:${t}`
274
- };
275
- l.set(n, i);
276
- try {
277
- let r = await e.store.query({
278
- table: "_voltro_workflow_start_contexts",
279
- order: [],
280
- predicate: B("executionId", n),
281
- projection: ["id"],
282
- skip: void 0,
283
- take: 1
284
- }), a = {
285
- workflowName: t,
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 e.store.insert("_voltro_workflow_start_contexts", {
295
- id: u(),
296
- ...a
297
- }) : await e.store.update("_voltro_workflow_start_contexts", r[0].id, a);
298
- } catch (e) {
299
- process.stderr.write(`[workflow] failed to persist start context for ${t}/${n}: ${e?.message ?? String(e)}\n`);
300
- }
301
- }, f = async (t, n) => {
302
- let r = l.get(n);
303
- if (r !== void 0) return r;
304
- try {
305
- let t = (await e.store.query({
306
- table: "_voltro_workflow_start_contexts",
307
- order: [],
308
- predicate: B("executionId", n),
309
- projection: void 0,
310
- skip: void 0,
311
- take: 1
312
- }))[0];
313
- if (t === void 0) return;
314
- let r = {
315
- ...t.subject === null ? {} : { subject: t.subject },
316
- ...t.traceId === null ? {} : { traceId: t.traceId },
317
- ...t.source === null ? {} : { source: t.source },
318
- ...t.parentExecutionId === null ? {} : { parentExecutionId: t.parentExecutionId },
319
- ...t.parentClosePolicy === null ? {} : { parentClosePolicy: t.parentClosePolicy }
320
- };
321
- return l.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
- }, p = (e.discovered.workflows?.length ?? 0) > 0 ? He(() => o) : void 0, m = (e.discovered.workflows?.length ?? 0) > 0 || (e.discovered.eventTriggers?.length ?? 0) > 0, te = m || (e.discovered.workflowWorkers?.length ?? 0) > 0 || e.scheduleCoordination === "cluster", ne = e.tenantIsolation === "namespace", re = (e.log ?? k({ scope: "voltro:serve" })).child("webhooks"), ie, _ = e.discovered.webhooks;
327
- if (_ && _.outgoing.length > 0 && e.workflowEngineLayer !== void 0) {
328
- let t = e.workflowEngineLayer, n = {
329
- store: rt(e.store, {
330
- subject: G(null),
331
- schemaRegistry: e.schemaRegistry
332
- }),
333
- request: {
334
- subject: G(null),
335
- traceId: "webhooks:trigger"
336
- },
337
- cache: i,
338
- kv: a
339
- }, r = _.outgoing.map((e) => e.descriptor);
340
- ie = Dt(n, async (e) => {
341
- let i = kt.execute(e).pipe(D.provide(kt.toLayer(Et(n, { events: r })).pipe(O.provideMerge(t))));
342
- D.runPromise(i).catch((t) => {
343
- re.error("deliverWebhook workflow crashed", {
344
- deliveryId: e.deliveryId,
345
- targetId: e.targetId
346
- }, t);
347
- });
348
- }, { events: r });
349
- }
350
- let ae = /* @__PURE__ */ new Map();
351
- if (_) for (let e of _.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: () => p === void 0 ? void 0 : I(p, {
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 ? re.error("incoming delivery failed", t) : e.status >= 400 ? re.warn("incoming delivery rejected", t) : re.info("incoming delivery handled", t);
367
- }
368
- });
369
- ae.set(t, { handle: r });
370
- }
371
- let v = g({
372
- store: e.store,
373
- schemaRegistry: e.schemaRegistry,
374
- cache: i,
375
- kv: a,
376
- ...ie === void 0 ? {} : { webhooksService: ie },
377
- ...p === void 0 ? {} : { workflowsProxy: p },
378
- eventTriggers: e.discovered.eventTriggers ?? [],
379
- namespaceIsolationOn: ne
380
- }), oe = O.succeed(Te, E), se = (t, n) => {
381
- let r = t.pipe(D.provide(Ve(n)));
382
- return Ze((e.baseLayer ? r.pipe(D.provide(e.baseLayer)) : r).pipe(D.provide(oe)));
383
- }, b = Ue({
384
- store: e.store,
385
- buildContext: (e, t, n) => v(e, t, n),
386
- runEffect: se,
387
- undoCapture: me()
388
- }), x = T(), S = Ie({
389
- buildContext: (e) => v(e),
390
- runEffect: se
391
- }), C = We({
392
- buildContext: (e) => v(e),
393
- finalize: (t, n) => Ee(De(t, e.tenantScopedTables, n.subject.tenantId), e.softDeleteScopedTables),
394
- provideEffect: (e, t) => e.pipe(D.provide(Ve(t)))
395
- }), w = {};
396
- for (let n of [...e.discovered.queries, ...x.queries]) w[n.descriptor.name] = (e) => P(C(n, e), t, `subscription.${n.descriptor.name}`);
397
- for (let t of [...e.discovered.mutations, ...x.mutations]) w[t.descriptor.name] = (e) => N(async (e, n) => b(t, e, n), e, `mutation.${t.descriptor.name}`);
398
- for (let t of e.discovered.actions) w[t.descriptor.name] = (e) => N(async (e, n) => S(t, e, n), e, `action.${t.descriptor.name}`);
399
- let de = () => `public-${Math.random().toString(36).slice(2, 10)}`, fe = [...e.discovered.mutations.filter((e) => e.descriptor.publicApi !== void 0).map((e) => ({
400
- descriptor: e.descriptor,
401
- invoke: (t, n) => b(e, t, {
402
- subject: n.subject,
403
- traceId: de()
404
- })
405
- })), ...e.discovered.actions.filter((e) => e.descriptor.publicApi !== void 0).map((e) => ({
406
- descriptor: e.descriptor,
407
- invoke: (t, n) => S(e, t, {
408
- subject: n.subject,
409
- traceId: de()
410
- })
411
- }))], pe = fe.length > 0 ? Tt(wt(fe), {
412
- store: e.store,
413
- resolveSubject: (t) => e.resolveSubject(t, -1)
414
- }) : [], he = e.dataTransferSecret ?? process.env.VOLTRO_DATA_TRANSFER_SECRET, ge = he && he.length >= 16 ? [{
415
- method: "POST",
416
- path: Bt,
417
- handle: Jt({
418
- secret: he,
419
- store: e.store,
420
- ...e.dataTransferSnapshot ? { snapshot: e.dataTransferSnapshot } : {},
421
- assetSink: Pt(H({})),
422
- openArchive: (e) => (async function* () {
423
- let t = H({}), n = await dt((await D.runPromise(V(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: he,
432
- store: e.store,
433
- snapshot: e.dataTransferSnapshot ?? { tables: [] },
434
- dialect: e.dataTransferDialect ?? "memory",
435
- tenantTables: [...e.tenantScopedTables],
436
- loadProfile: $t,
437
- assetSource: Ft(H({}), e.store),
438
- putArchive: async (e, t) => {
439
- let { Readable: n } = await import("node:stream"), r = H({}), i = lt("storage", () => n.from(t()));
440
- await D.runPromise(ut(r, e, i, { contentType: "application/octet-stream" }));
441
- }
442
- })
443
- }] : [], _e = [
444
- ...e.httpRoutes ?? [],
445
- ...pe,
446
- ...ge
447
- ];
448
- for (let t of e.discovered.streams ?? []) w[t.descriptor.name] = (n) => ke((r) => {
449
- let i = v(r), a = t.executor(n, i);
450
- if (D.isEffect(a)) {
451
- let t = a.pipe(D.provide(Ve(i.store)));
452
- return (e.baseLayer ? t.pipe(D.provide(e.baseLayer)) : t).pipe(D.provide(oe));
453
- }
454
- return typeof a == "object" && a && typeof a.then == "function" ? D.promise(() => a) : a;
455
- }, `stream.${t.descriptor.name}`);
456
- for (let t of e.discovered.workflows ?? []) w[t.definition.name] = (e) => N(async (e, n) => {
457
- let r = n;
458
- return I(p, {
459
- subject: r.subject,
460
- traceId: r.traceId,
461
- source: "workflow-rpc"
462
- }).start(t.definition.name, e);
463
- }, e, `workflow.${t.definition.name}`);
464
- m && (w[gt.name] = (e) => P(C({
465
- descriptor: gt,
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: ct(B("id", t), B("executionId", t)),
475
- take: 1,
476
- skip: void 0,
477
- projection: void 0
478
- };
479
- }
480
- }, e), t, `subscription.${gt.name}`), w[_t.name] = (e) => P(C({
481
- descriptor: _t,
482
- executor: (e) => {
483
- 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;
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] : z(...n),
491
- take: r,
492
- skip: void 0,
493
- projection: void 0
494
- };
495
- }
496
- }, e), t, `subscription.${_t.name}`), w[Z.name] = (e) => P(C({
497
- descriptor: Z,
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: B("runId", t),
507
- take: 1e3,
508
- skip: void 0,
509
- projection: void 0
510
- };
511
- }
512
- }, e), t, `subscription.${Z.name}`), w[X.name] = (e) => P(C({
513
- descriptor: X,
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: B("runId", t),
523
- take: 1e3,
524
- skip: void 0,
525
- projection: void 0
526
- };
527
- }
528
- }, e), t, `subscription.${X.name}`), w[ht.name] = (e) => P(C({
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 : B("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), t, `subscription.${ht.name}`), w[J.name] = (e) => P(C({
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: B("eventId", t),
555
- take: 500,
556
- skip: void 0,
557
- projection: void 0
558
- };
559
- }
560
- }, e), t, `subscription.${J.name}`), w[mt.name] = (t) => N(async (t, n) => {
561
- let r = t;
562
- return await h(e.store, n.subject, { executionId: r.executionId }), await p.cancel(r.workflowName, r.executionId), await Ne(r.workflowName, r.executionId, "workflow.cancel"), { ok: !0 };
563
- }, t, `action.${mt.name}`), w[Y.name] = (t) => N(async (t, n) => {
564
- let r = t;
565
- return await h(e.store, n.subject, { executionId: r.executionId }), await p.resume(r.workflowName, r.executionId), { ok: !0 };
566
- }, t, `action.${Y.name}`), w[vt.name] = (t) => N(async (t, n) => {
567
- let r = t;
568
- return await h(e.store, n.subject, { id: r.id }), p.signal({ id: r.id }, r.signalName, r.payload);
569
- }, t, `action.${vt.name}`), w[yt.name] = (t) => N(async (t, n) => {
570
- let r = t;
571
- return await h(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 });
572
- }, t, `action.${yt.name}`));
573
- let ve = [
574
- ...e.discovered.queries.map((e) => q(e.descriptor)),
575
- ...e.discovered.mutations.map((e) => K(e.descriptor)),
576
- ...e.discovered.actions.map((e) => W(e.descriptor)),
577
- ...x.queries.map((e) => q(e.descriptor)),
578
- ...x.mutations.map((e) => K(e.descriptor)),
579
- ...(e.discovered.streams ?? []).map((e) => pt(e.descriptor)),
580
- ...(e.discovered.workflows ?? []).map((e) => nt(e.definition)),
581
- ...m ? [
582
- q(gt),
583
- q(_t),
584
- q(Z),
585
- q(X),
586
- q(ht),
587
- q(J),
588
- W(mt),
589
- W(Y),
590
- W(vt),
591
- W(yt)
592
- ] : []
593
- ], ye = at.make(...ve).middleware(U).middleware(ft), be = O.succeed(U, U.of(({ headers: t, clientId: n }) => D.promise(() => e.resolveSubject(t, n)))), xe = O.succeed(ft, ft.of(({ clientId: e }) => D.succeed({ clientId: e }))), Se = e.dormancyTenantId ?? "default", we = e.dormancy === "sleep" ? {
594
- register: (t, n, r) => Ye(e.store, {
595
- tenantId: r ?? Se,
596
- kind: "workflow",
597
- refId: t,
598
- wakeAt: n
599
- }),
600
- cancel: (t, n) => je(e.store, {
601
- tenantId: n ?? Se,
602
- kind: "workflow",
603
- refId: t
604
- }).then(() => {})
605
- } : void 0, j = te ? await import("@voltro/workflow") : void 0, M = j?.makeWorkflowRunRecorder({
606
- store: e.store,
607
- ...we === void 0 ? {} : { wakeups: we }
608
- }), Me = async (t, n) => {
609
- await j.closeWorkflowChildrenForParent({
610
- store: e.store,
611
- parentExecutionId: t,
612
- parentStatus: n,
613
- recorder: M,
614
- log: { warn: (e, t) => {
615
- process.stderr.write(`[workflow] ${e} ${t ? JSON.stringify(t) : ""}\n`);
616
- } },
617
- interruptChild: async (t, n) => {
618
- let r = (e.discovered.workflows ?? []).find((e) => e.definition.name === t);
619
- if (!r) throw Error(`Unknown child workflow: ${t}`);
620
- if (!s) throw Error("Workflow runtime is not ready");
621
- await s.runPromise(r.definition.interrupt(n));
622
- }
623
- });
624
- }, Ne = async (t, n, r) => {
625
- let i = (await e.store.query({
626
- table: "_voltro_workflow_runs",
627
- order: [],
628
- predicate: B("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 e.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 M.recordEvent({
640
- runId: i.id,
641
- eventType: "run-cancelled",
642
- payload: {
643
- reason: r,
644
- workflowName: t,
645
- executionId: n,
646
- ...o == null ? {} : { tenantId: o }
647
- }
648
- }), a && await Me(n, "cancelled");
649
- }, Pe = [...Ke(e.discovered.workflows ?? [], {
650
- buildContext: (t, n) => {
651
- let r = t?.subject ?? {
652
- type: "anonymous",
653
- id: null,
654
- tenantId: null
655
- };
656
- return e.buildContextForWorkflow?.(t, n) ?? v({
657
- subject: r,
658
- traceId: t?.traceId ?? "workflow-bootstrap"
659
- }, e.store, void 0, `workflow:${n.workflowName}`, { parentExecutionId: n.executionId });
660
- },
661
- resolveStartContext: f
662
- }, (t, n, r) => {
663
- let i = j.getWorkflowVersionMetadata(t.definition);
664
- return j.wrapWorkflowExecuteWithRunRecording({
665
- name: t.definition.name,
666
- store: e.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 }) => Me(e, t),
676
- recorder: M
677
- }, n);
678
- }), ...e.discovered.workflowWorkers ?? []], Fe = Pe.length > 0 ? O.mergeAll(...Pe) : O.empty;
679
- ((e.discovered.workflows?.length ?? 0) > 0 || (e.discovered.workflowWorkers?.length ?? 0) > 0 || e.scheduleCoordination === "cluster") && e.workflowEngineLayer !== void 0 && (s = Ce.make(Fe.pipe(O.provideMerge(e.workflowEngineLayer))), await s.runPromise(D.void), o = (e.discovered.workflows?.length ?? 0) > 0 ? Ge({
680
- workflows: e.discovered.workflows ?? [],
681
- runEffect: (e) => s.runPromise(e),
682
- rememberStartContext: ee,
683
- signal: async (t, n, r) => {
684
- let i = await j.sendWorkflowSignal({
685
- store: e.store,
686
- recorder: M,
687
- target: t,
688
- signalName: n,
689
- payload: r
690
- });
691
- return await s.runPromise(j.completeSuspendingSignal({
692
- store: e.store,
693
- target: t,
694
- signalName: n,
695
- payload: r
696
- })).catch(() => {}), i;
697
- },
698
- update: (t, n, r, i) => j.sendWorkflowUpdate({
699
- store: e.store,
700
- recorder: M,
701
- target: t,
702
- updateName: n,
703
- payload: r,
704
- ...i === void 0 ? {} : { options: i }
705
- }),
706
- listRuns: (t) => ue(e.store, t),
707
- retry: (t, n) => y({
708
- store: e.store,
709
- workflows: e.discovered.workflows ?? [],
710
- runPromise: (e) => s.runPromise(e)
711
- }, t, n)
712
- }) : void 0);
713
- let Re = O.mergeAll(ye.toLayer(w), be, xe), ze = n(w, e.discovered.queries.map((e) => e.descriptor.name), m), Be = O.mergeAll(ye.toLayer(ze), be, xe), F = e.observability, Xe = await Ae({
714
- ...F && F.spanProcessors.length > 0 ? { extraSpanProcessors: F.spanProcessors } : {},
715
- ...F && F.metricReaders.length > 0 ? { extraMetricReaders: F.metricReaders } : {},
716
- ...F && Object.keys(F.resourceAttributes).length > 0 ? { resourceAttributes: F.resourceAttributes } : {},
717
- ...F && F.sampler !== void 0 ? { sampler: F.sampler } : {}
718
- }), Qe = !1, L = e.store.ping ? () => e.store.ping().then(() => !0).catch(() => !1) : void 0, R = et({
719
- group: ye,
720
- handlersLayer: Re,
721
- httpHandlersLayer: Be,
722
- port: e.port ?? 4e3,
723
- path: e.path ?? "/ws",
724
- tracerLayer: Xe.layer,
725
- healthCheck: {
726
- isReady: () => Qe,
727
- ...L ? { ping: L } : {}
728
- },
729
- ..._e.length > 0 ? { httpRoutes: _e } : {},
730
- ...ae.size > 0 ? { webhookRoutes: ae } : {}
731
- });
732
- if (await Oe(R), (e.discovered.schedules?.length ?? 0) > 0) {
733
- let t = (e.scheduleCoordination ?? "single") === "advisoryLock" ? Le(e.store, e.scheduleReplicaId ?? `pid-${process.pid}`) : $e;
734
- c = await tt(e.discovered.schedules ?? [], {
735
- store: e.store,
736
- coordinator: t,
737
- defaultTrigger: e.scheduleDefaultTrigger ?? "self",
738
- replicaId: e.scheduleReplicaId ?? `pid-${process.pid}`,
739
- armSelf: e.scheduleArmSelf ?? !0,
740
- dormancy: e.dormancy ?? "always-on",
741
- dormancyTenantId: e.dormancyTenantId ?? "default",
742
- buildContext: ({ traceId: t, scheduleName: n }) => v({
743
- subject: {
744
- type: "anonymous",
745
- id: null,
746
- tenantId: null
747
- },
748
- traceId: t
749
- }, e.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
- ...e.scheduleFireInterceptor === void 0 ? {} : { interceptFire: e.scheduleFireInterceptor },
760
- ...e.onScheduleRunEvent === void 0 ? {} : { onRunEvent: e.onScheduleRunEvent }
761
- }), e.onSchedulerReady?.(c);
762
- }
763
- let it = e.log ?? k({ scope: "voltro:serve" }), ot, st;
764
- if ((e.discovered.subscribers?.length ?? 0) > 0 && (ot = ce(e.discovered.subscribers ?? [], e.store, it.child("subscribe"))), (e.discovered.reactions?.length ?? 0) > 0) {
765
- let t = it.child("reaction");
766
- st = d(e.discovered.reactions ?? [], e.store, {
767
- runAct: async (n, r) => {
768
- if (n.kind === "workflow") {
769
- if (p === void 0) {
770
- t.warn("reaction workflow act skipped — no workflow engine in this app", { workflow: n.workflow });
771
- return;
772
- }
773
- let e = r.new ?? r.old ?? {};
774
- await I(p, {
775
- traceId: `reaction:${n.workflow}`,
776
- source: `reaction:${n.workflow}`
777
- }).start(n.workflow, e);
778
- return;
779
- }
780
- await le(n.agent, r, {
781
- findAgentSend: (t) => e.discovered.actions.find((e) => e.descriptor.name === `${t}.send`),
782
- runAction: (e, t, n) => Promise.resolve(S(e, t, n)),
783
- makeSubject: (e) => G(e),
784
- now: () => Date.now(),
785
- log: t
786
- });
787
- },
788
- checkBudget: async (n, r) => {
789
- try {
790
- let { requireAiBudget: t } = await import("@voltro/ai");
791
- return (await D.runPromise(D.either(t(e.store, {
792
- tenantId: n,
793
- limitUsd: r
794
- }))))._tag === "Right";
795
- } catch (e) {
796
- return t.warn("reaction budget check failed — refusing the act", { tenantId: n }, e), !1;
797
- }
798
- }
799
- }, t);
800
- }
801
- let bt;
802
- return (e.discovered.aggregates?.length ?? 0) > 0 && (bt = await r({
803
- discovered: e.discovered.aggregates ?? [],
804
- store: e.store,
805
- log: it.child("aggregate"),
806
- ...e.analytics === void 0 ? {} : { analytics: e.analytics },
807
- ...e.aggregateStorage === void 0 ? {} : { storage: e.aggregateStorage },
808
- ...e.aggregateCoordinator === void 0 ? {} : { coordinator: e.aggregateCoordinator }
809
- }), oe = O.succeed(Te, bt.registry)), Qe = !0, e.bootTiming?.mark("ready"), {
810
- dispatcher: t,
811
- server: R,
812
- scheduler: c,
813
- close: async () => {
814
- Qe = !1, bt?.detach(), st?.(), ot?.(), await c?.shutdown(), t.close(), await s?.dispose(), await new Promise((e) => R.close(() => e()));
815
- }
816
- };
817
- }, $ = k({ 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 = ve(process.cwd());
822
- if (we(t)) {
823
- let n;
824
- try {
825
- let e = await import(xe(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 (n) => {
834
- let r = zt();
835
- process.env.NODE_ENV || (process.env.NODE_ENV = "production"), it();
836
- let d = process.cwd(), h = Number(process.env.PORT ?? rn(n, "--port") ?? 4e3), g = await C(d);
837
- Qe(Xe(g?.secrets)), await w({
838
- rawEnv: g?.env,
839
- appType: "api",
840
- root: d,
841
- log: $,
842
- generateTypes: !1
843
- }), r.mark("config");
844
- let y = (process.env.DB_DIALECT ?? g?.store ?? "memory").toLowerCase(), ce = (y === "mariadb" || y === "postgres" || y === "mssql") && (process.env.CDC ?? "1") !== "0", le = y === "mariadb" ? "mariadb" : y === "mssql" ? "mssql" : void 0, ue = ye(d);
845
- if (!_e() && we(ue)) try {
846
- let e = await import(xe(ue).href);
847
- if (e.modules) {
848
- let t = {};
849
- for (let [n, r] of Object.entries(e.modules)) t[be(d, n)] = r;
850
- ge(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 T = await v(d), E = await de(T, { cdc: ce && le !== void 0 }), me = T.filter((e) => pe.test(e)), ve = me.length > 0 ? await p(me, $.child("webhooks")) : void 0, k = c({
856
- mix: E.featureMix,
857
- plugins: g?.plugins ?? [],
858
- cdc: ce && le !== void 0,
859
- ...le ? { cdcDialect: le } : {}
860
- }), Te = g?.analytics !== void 0 && g.analytics.kind !== "noop" && y !== "memory" ? (await S(y)).makeSqlLayer(b()) : void 0, A = await he({
861
- spec: g?.analytics,
862
- sqlLayer: Te,
863
- log: $
864
- }), Ee = (() => {
865
- let e = new Set(E.tables.map((e) => e.tableName)), t = [...E.tables];
866
- for (let n of [...k, ...A.tables]) e.has(n.tableName) || (e.add(n.tableName), t.push(n));
867
- return t;
868
- })();
869
- for (let e of Ee) st(e);
870
- let De = (process.env.NODE_ENV ?? "").toLowerCase();
871
- if (nn(De, y, process.env.VOLTRO_AUTO_MIGRATE)) {
872
- let e = (await S(y)).makeSqlLayer(b()), t = await D.runPromise(ot.SqlClient.pipe(D.flatMap((e) => St(e, Ee, {
873
- appliedBy: `serve:${De}`,
874
- environment: "prod",
875
- dialectId: y
876
- })), D.provide(e)));
877
- t.kind === "prod-mismatch" && ($.error(xt(t, y)), $.error("serve: refusing to boot — apply the schema first (voltro db apply in a pre-deploy step), or set VOLTRO_AUTO_MIGRATE=0 to bypass this check."), process.exit(1)), $.info(xt(t, y));
878
- }
879
- let Oe = F(Ee);
880
- r.mark("discover");
881
- let N = await x(g, void 0);
882
- g?.cache && !process.env.CACHE_BACKEND && (process.env.CACHE_BACKEND = g.cache), g?.cacheRedisUrl && !process.env.CACHE_REDIS_URL && (process.env.CACHE_REDIS_URL = g.cacheRedisUrl), g?.cacheRedisDriver && !process.env.CACHE_REDIS_DRIVER && (process.env.CACHE_REDIS_DRIVER = g.cacheRedisDriver), g?.cacheKeyPrefix && !process.env.CACHE_KEY_PREFIX && (process.env.CACHE_KEY_PREFIX = g.cacheKeyPrefix);
883
- let { service: ke, invalidationBus: P, snapshotCache: Ae, cache: je, backend: Ie, dispose: Ve } = await l({ env: process.env });
884
- $.info(`cache backend resolved: ${Ie}` + (Ie === "redis" ? ` (driver ${process.env.CACHE_REDIS_DRIVER ?? "resp"})` : " — in-process, not cross-instance")), N.onChange((e) => {
885
- D.runFork(P.publish(e.table));
886
- }), g?.kv && !process.env.KV_BACKEND && (process.env.KV_BACKEND = g.kv), g?.kvRedisUrl && !process.env.KV_REDIS_URL && (process.env.KV_REDIS_URL = g.kvRedisUrl), g?.kvKeyPrefix && !process.env.KV_KEY_PREFIX && (process.env.KV_KEY_PREFIX = g.kvKeyPrefix);
887
- let { kv: He, service: Ue } = await ze({ store: N });
888
- r.mark("store");
889
- let We = M({
890
- store: N,
891
- sink: A.sink,
892
- log: $
893
- }), Ge = o({
894
- store: N,
895
- dialect: y
896
- }), I = g?.plugins ?? [], Ke = process.env.POD_NAME ?? process.env.HOSTNAME ?? `serve-${process.pid}`, qe, Je;
897
- y !== "memory" && (qe = Ce.make((await S(y)).makeSqlLayer(b())), Je = await qe.runPromise(ot.SqlClient));
898
- let Ye = Be({
899
- coordinator: [
900
- "postgres",
901
- "mariadb",
902
- "mysql",
903
- "mssql"
904
- ].includes(y) ? Le(N, Ke, $) : $e,
905
- replicaId: Ke,
906
- log: $
907
- }), Ze = [], et = {
908
- ...Je ? { sql: Je } : {},
909
- scheduleCoordinated: (e, t, n) => {
910
- let r = Ye(e, t, n);
911
- return Ze.push(r), r;
912
- }
913
- };
914
- for (let e of I) e.bindDataStore?.(N, et);
915
- let tt = I.filter((e) => typeof e.onChangeEvent == "function");
916
- if (tt.length > 0) {
917
- let e = N.changeScope ?? "local";
918
- N.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 tt) D.runFork(e.onChangeEvent(n).pipe(D.catchAllCause((t) => D.sync(() => $.warn(`plugin ${e.name} onChangeEvent failed`, { error: Se.pretty(t) })))));
928
- });
929
- }
930
- let nt = ie({
931
- plugins: I,
932
- appName: g?.name ?? "voltro-api",
933
- appType: "api",
934
- voltroVersion: process.env.npm_package_version ?? "0.0.0",
935
- log: $
936
- });
937
- I.length && await nt.activate(), r.mark("plugins");
938
- let rt = await nt.gatherObservability(), L = await oe(N, g, y, {
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
- }), R = g?.apiKeys, at = (typeof R == "object" ? R.prefix : void 0) ?? "voltro_", z = R ? Re(Ne(N), { prefix: at }) : void 0, B = z ? [Fe(z, { prefix: at })] : [], ct = fe([...g?.auth?.strategies ?? [], ...B], Ct(g?.plugins ?? []), g?.auth?.anonymousTenantRequired ?? !1), lt = [...g?.restRoutes ?? [], ...z ? j(z, (typeof R == "object" ? R.managementPath : void 0) ?? "/v1/api-keys") : []], V = g?.idempotency, ut = V ? {
943
- store: Pe(N),
944
- header: (typeof V == "object" ? V.header : void 0) ?? "Idempotency-Key",
945
- ttlMs: (typeof V == "object" ? V.ttlMs : void 0) ?? 864e5
946
- } : void 0, H = lt.length > 0 ? Tt(lt, {
947
- store: N,
948
- resolveSubject: (e) => ct({
949
- headers: e,
950
- clientId: -1
951
- }),
952
- ...ut ? { idempotency: ut } : {}
953
- }) : [], dt = I.map((e) => e.services).filter((e) => e !== void 0), U = O.mergeAll(s({
954
- analyticsLayer: A.layer,
955
- cacheService: ke,
956
- kvService: Ue,
957
- pluginServices: dt,
958
- userLayers: g?.layers ?? []
959
- }), te), ft = g?.scheduling ?? {}, W = ft.trigger ?? "self", G = /* @__PURE__ */ new Set([
960
- "postgres",
961
- "mysql",
962
- "mariadb",
963
- "mssql"
964
- ]), K = ft.coordination ?? (G.has(y) ? "advisoryLock" : "single"), q = K === "cluster" && G.has(y), pt = q ? "cluster" : K === "advisoryLock" && G.has(y) ? "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(y) && $.warn("scheduling.coordination=advisoryLock needs a SQL store (the claim-row gate) — falling back to single");
966
- let mt, ht = E.workflows.length > 0 || E.workflowWorkers.length > 0 || E.eventTriggers.length > 0 || (ve?.outgoing.length ?? 0) > 0 || q, J;
967
- if (ht) {
968
- if (y === "mssql") {
969
- let e = await f(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 ? E.schedules.filter((e) => (e.trigger ?? W) === "self").map((e) => t({
973
- name: e.name,
974
- cron: Me(e),
975
- execute: async () => {
976
- await mt?.fireFromCluster(e.name);
977
- }
978
- })) : [];
979
- J = y === "memory" ? e.layerMemory : await (async () => {
980
- let e = await S(y), 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(b()),
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 Y = se(I, _()), X = T.filter((e) => /\.subscribe\.tsx?$/.test(e)), gt = X.length > 0 ? await u(X, $) : [], Z = T.filter((e) => /\.reaction\.tsx?$/.test(e)), _t = Z.length > 0 ? await t(Z, $) : [], vt = T.filter((e) => /\.aggregate\.tsx?$/.test(e)), yt = vt.length > 0 ? await m(vt, $) : [], wt = a();
991
- if (yt.length > 0 && y !== "memory") try {
992
- wt = i((await S(y)).makeSqlLayer(b()));
993
- } catch (e) {
994
- $.warn("aggregate: SQL storage init failed — falling back to in-process", { err: String(e) });
995
- }
996
- let Et = y === "memory" ? $e : Le(N, `aggregate@${process.pid}`, $), Dt = [], Ot = [], kt = T.filter((e) => ne.test(e));
997
- if (kt.length > 0) {
998
- let t = $.child("agent"), n = T.filter((e) => re.test(e));
999
- n.length > 0 && await e(n, t);
1000
- let r = await ee(kt, t);
1001
- for (let e of r.agents) for (let t of ae(e)) (t.kind === "action" ? Dt : Ot).push({
1002
- file: t.file,
1003
- descriptor: t.descriptor,
1004
- executor: t.executor
1005
- });
1006
- r.agents.length > 0 && t.info("synthesized agent routes", { agents: r.agents.map((e) => e.descriptor.name) });
1007
- }
1008
- r.mark("workflow");
1009
- let At = await tn({
1010
- bootTiming: r,
1011
- discovered: {
1012
- queries: [...E.queries, ...Ot],
1013
- mutations: E.mutations,
1014
- actions: [...E.actions, ...Dt],
1015
- streams: E.streams,
1016
- workflows: E.workflows,
1017
- workflowWorkers: E.workflowWorkers,
1018
- eventTriggers: E.eventTriggers,
1019
- schedules: E.schedules,
1020
- subscribers: gt,
1021
- reactions: _t,
1022
- aggregates: yt,
1023
- ...ve === void 0 ? {} : { webhooks: ve }
1024
- },
1025
- log: $,
1026
- analytics: A.sink,
1027
- aggregateStorage: wt,
1028
- aggregateCoordinator: Et,
1029
- store: N,
1030
- kv: He,
1031
- cache: je,
1032
- snapshotCache: Ae,
1033
- schemaRegistry: Oe,
1034
- tenantScopedTables: E.tenantScopedTables,
1035
- softDeleteScopedTables: E.softDeleteScopedTables,
1036
- dataTransferSnapshot: bt(Ee),
1037
- dataTransferDialect: y,
1038
- tenantIsolation: (process.env.VOLTRO_TENANT_ISOLATION ?? g?.tenancy?.isolation) === "namespace" ? "namespace" : "shared-schema",
1039
- resolveSubject: (e, t) => ct({
1040
- headers: e,
1041
- clientId: t
1042
- }),
1043
- httpRoutes: [...I.flatMap((e) => e.httpRoutes ?? []), ...H],
1044
- ...U ? { baseLayer: U } : {},
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 : g?.dormancy ?? "always-on",
1050
- scheduleReplicaId: process.env.HOSTNAME ?? `pid-${process.pid}`,
1051
- ...Y === void 0 ? {} : { scheduleFireInterceptor: Y },
1052
- onSchedulerReady: (e) => {
1053
- mt = e;
1054
- },
1055
- observability: rt,
1056
- port: h,
1057
- ...g?.transport?.wsPath ? { path: g.transport.wsPath } : {}
1058
- });
1059
- $.info(`API listening on :${h}`, {
1060
- dialect: y,
1061
- queries: E.queries.length,
1062
- mutations: E.mutations.length,
1063
- actions: E.actions.length,
1064
- streams: E.streams.length,
1065
- workflows: E.workflows.length,
1066
- workflowWorkers: E.workflowWorkers.length,
1067
- schedules: E.schedules.length,
1068
- scheduleCoordination: pt
1069
- }), r.finish($);
1070
- let jt = () => {
1071
- for (let e of Ze) e.stop();
1072
- We.detach(), Ge.stop(), Ve(), qe?.dispose(), Promise.resolve(nt.deactivate()).then(() => L?.close()).then(() => A.dispose()).then(() => At.close()).then(() => N.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 };