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