@voltro/cli 0.32.0 → 0.34.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 (339) hide show
  1. package/CHANGELOG.md +2006 -0
  2. package/THIRD-PARTY-NOTICES.md +1 -29
  3. package/bin/nodeEnvironment.d.mts +30 -0
  4. package/bin/nodeEnvironment.mjs +158 -0
  5. package/bin/voltro.mjs +69 -5
  6. package/dist/addCommand-BNeoeSxe.js +124 -0
  7. package/dist/addCommand-aXSQveak.js +2 -0
  8. package/dist/agentsMd-BTchIZku.js +2 -0
  9. package/dist/agentsMd-mhQMF1bx.js +254 -0
  10. package/dist/apiBuild-BICVGnEC.js +2 -0
  11. package/dist/{apiBuild-C4uEbs3s.js → apiBuild-DZF_f0_I.js} +46 -46
  12. package/dist/appPort-B_HpJ_ck.js +48 -0
  13. package/dist/baselineCommand-C2ClWZN3.js +2 -0
  14. package/dist/baselineCommand-DIttzO8A.js +227 -0
  15. package/dist/bin.js +71 -28
  16. package/dist/build-CE7Ca9gm.js +711 -0
  17. package/dist/cacheCommand-DA4OH9xt.js +42 -0
  18. package/dist/capabilitiesCommand-nq_pz5xd.js +123 -0
  19. package/dist/checkCommand-Dv8r9tGO.js +231 -0
  20. package/dist/checkCommand-YZDmkAGd.js +2 -0
  21. package/dist/{cliArgs-qdZSElM3.js → cliArgs-D4p8n7EE.js} +12 -1
  22. package/dist/cliError-BmdYnghb.js +10 -0
  23. package/dist/cliOutput-D1tSBoRM.js +15 -0
  24. package/dist/{cliRuntime-Oh517vCV.js → cliRuntime-Dh7UDinH.js} +20 -20
  25. package/dist/cloudClient-DWL-Hw_T.js +67 -0
  26. package/dist/cloudCmd-Cvv5HGaZ.js +364 -0
  27. package/dist/clusterCmd-CNXKlcvD.js +54 -0
  28. package/dist/codegen-CYM3Zqrf.js +605 -0
  29. package/dist/codegen-ChBi_hVa.js +2 -0
  30. package/dist/codegenCommand-DC6w2tNZ.js +30 -0
  31. package/dist/codemodRunner-DRRqXR74.js +5243 -0
  32. package/dist/commandRunner-BLAEFLjp.js +47 -0
  33. package/dist/commands-gutsz-Ac.js +808 -0
  34. package/dist/connectionConfig-UFlIEiys.js +66 -0
  35. package/dist/dashboardCommand-3YG8p-UA.js +25 -0
  36. package/dist/dataCommand-qL0r7fPO.js +535 -0
  37. package/dist/dataProfile-dW-PsfLB.js +15 -0
  38. package/dist/dbCommand-B6X0FZbq.js +1621 -0
  39. package/dist/dbCommand-CpdKLeQq.js +2 -0
  40. package/dist/{dev-5ficNnvF.js → dev-CerMd0mW.js} +3155 -3110
  41. package/dist/dev-CoG-ZPx8.js +3 -0
  42. package/dist/devActivity-Dx_3nnGv.js +100 -0
  43. package/dist/devActivity.js +1 -1
  44. package/dist/dialectDriver-CgXnDfec.js +39 -0
  45. package/dist/discover-C9XKJDco.js +25 -0
  46. package/dist/doctorCommand-BvqGBwNG.js +2 -0
  47. package/dist/{checkCommand-dm7OHtPt.js → doctorCommand-CnDXQxfa.js} +520 -1278
  48. package/dist/dormancyCommand-Dszo57d6.js +69 -0
  49. package/dist/e2eCmd-BRabZww-.js +147 -0
  50. package/dist/embeddingsCommand-C0sKVRo1.js +73 -0
  51. package/dist/envCommand-DPgdV1Bq.js +60 -0
  52. package/dist/evalCommand-6RUfPen4.js +118 -0
  53. package/dist/evolveCommand-DHpkgjgH.js +281 -0
  54. package/dist/fileTaxonomy-CJfgOllU.js +457 -0
  55. package/dist/frameworkTableAssembly-BGHmck-x.js +2 -0
  56. package/dist/{frameworkTableAssembly-BwIrO5nv.js → frameworkTableAssembly-DkkP6BgC.js} +184 -148
  57. package/dist/generateCommand-oibemh97.js +147 -0
  58. package/dist/index.d.ts +45 -0
  59. package/dist/index.js +4 -3
  60. package/dist/infoCommand-BJw9nLUR.js +60 -0
  61. package/dist/{inspect-BUUjt773.js → inspect-CBqFtAKA.js} +82 -40
  62. package/dist/inspect-C_T_WGvl.js +2 -0
  63. package/dist/inspectCmd-Bppy-GGw.js +224 -0
  64. package/dist/inspectFetch-Cm8_wVvp.js +151 -0
  65. package/dist/inspectMetrics-CfdKLh6t.js +72 -0
  66. package/dist/loadEnv-D9nEOClM.js +44 -0
  67. package/dist/logFileSink-C_D2wRN1.js +105 -0
  68. package/dist/logsCmd-CCca3KRZ.js +260 -0
  69. package/dist/manifestBuild-ChsKAhmn.js +2 -0
  70. package/dist/{manifestBuild-BLrVuSlM.js → manifestBuild-sxpwdKY1.js} +1 -1
  71. package/dist/metaCommands-7MJfZ5cf.js +196 -0
  72. package/dist/migrate-CBwOt_iV.js +83 -0
  73. package/dist/mssqlClusterPatch-_4cE_nun.js +44 -0
  74. package/dist/newCommand-COWOJ1_E.js +156 -0
  75. package/dist/nodeEnvironment-cGFAj1J8.js +28 -0
  76. package/dist/packageCommand-Cug_3Ogl.js +271 -0
  77. package/dist/pageConvention-cEiRxdab.js +5 -0
  78. package/dist/privacyCommand-C-Df56U_.js +146 -0
  79. package/dist/projectScaffold-DmzEKHib.js +2 -0
  80. package/dist/projectScaffold-LMMtaavR.js +814 -0
  81. package/dist/renderModeScan-D7J1B7Kw.js +105 -0
  82. package/dist/renderProfile-1OWWAAtx.js +81 -0
  83. package/dist/runtimeRegistry-DMeKfTHP.js +81 -0
  84. package/dist/runtimeTrace-CRxalXTs.js +91 -0
  85. package/dist/scheduleCmd--jksTrf6.js +69 -0
  86. package/dist/scheduleManifestCmd-D2x0CTTY.js +249 -0
  87. package/dist/schemaIr-UJybUUZW.js +103 -0
  88. package/dist/{sdkgen-B_5mHQS2.js → sdkgen-CYJscZC7.js} +111 -209
  89. package/dist/seedRunner-TFHHiToI.js +329 -0
  90. package/dist/serveCommand-B_isw7q4.js +1647 -0
  91. package/dist/serveCommand-DOvbgRnQ.js +2 -0
  92. package/dist/serveEntry.js +5 -5
  93. package/dist/serverlessCommand-CfJZy6dS.js +482 -0
  94. package/dist/start-9LiUOfES.js +1087 -0
  95. package/dist/start-B-9Nsp-S.js +3 -0
  96. package/dist/startEntry.js +2 -2
  97. package/dist/staticCommand-Dr2M6tpU.js +304 -0
  98. package/dist/storageCommand-Co6NfLqN.js +42 -0
  99. package/dist/templates-De8IR5-c.js +102 -0
  100. package/dist/test-CI6iDsYc.js +115 -0
  101. package/dist/tracesCmd-CkEZQrtt.js +232 -0
  102. package/dist/tsconfigPaths-BWXBWgcl.js +107 -0
  103. package/dist/tsxLoader-EuXmSJ1K.js +51 -0
  104. package/dist/typecheckCommand-BlsWiCNq.js +61 -0
  105. package/dist/updateCommand-Bkptutss.js +585 -0
  106. package/dist/updateCommand-us1_hdIC.js +2 -0
  107. package/dist/{inspectMetrics-BqO4E9G0.js → webDev-CBYvPqQr.js} +1006 -1567
  108. package/dist/webDev-Cg-fFiyd2.js +2 -0
  109. package/dist/webhookDiscovery-CrGAfhIG.js +2 -0
  110. package/dist/webhookDiscovery-D7VaeMlz.js +51 -0
  111. package/dist/webhooksCommand-CID96Rga.js +267 -0
  112. package/dist/workflowsCmd-D1VTmLMY.js +608 -0
  113. package/package.json +193 -18
  114. package/templates/AGENTS.core.md +58 -3
  115. package/templates/AGENTS.md +64 -7
  116. package/templates/agent-docs/_index.md +6 -4
  117. package/templates/agent-docs/_manifest.json +22 -5
  118. package/templates/agent-docs/ai.md +370 -0
  119. package/templates/agent-docs/authentication.md +265 -31
  120. package/templates/agent-docs/caching.md +6 -0
  121. package/templates/agent-docs/cli.md +794 -50
  122. package/templates/agent-docs/data.md +550 -11
  123. package/templates/agent-docs/database/migrations.md +174 -25
  124. package/templates/agent-docs/database/misc.md +193 -40
  125. package/templates/agent-docs/database/querying.md +19 -1
  126. package/templates/agent-docs/database/scaling.md +60 -0
  127. package/templates/agent-docs/database/schema.md +5 -2
  128. package/templates/agent-docs/database/seedsdialects.md +208 -19
  129. package/templates/agent-docs/database/transactions.md +68 -0
  130. package/templates/agent-docs/deployment.md +156 -4
  131. package/templates/agent-docs/introduction.md +87 -16
  132. package/templates/agent-docs/local-first-mobile.md +79 -4
  133. package/templates/agent-docs/multi-tenancy.md +95 -20
  134. package/templates/agent-docs/observability.md +58 -3
  135. package/templates/agent-docs/plugins/ai-flows.md +161 -2
  136. package/templates/agent-docs/plugins/analytics-postgres.md +1 -1
  137. package/templates/agent-docs/plugins/audit.md +37 -1
  138. package/templates/agent-docs/plugins/auth-social.md +143 -0
  139. package/templates/agent-docs/plugins/auth-workos.md +4 -2
  140. package/templates/agent-docs/plugins/auth.md +131 -6
  141. package/templates/agent-docs/plugins/billing.md +132 -15
  142. package/templates/agent-docs/plugins/cdc-out.md +46 -7
  143. package/templates/agent-docs/plugins/clickhouse.md +1 -1
  144. package/templates/agent-docs/plugins/duckdb.md +1 -1
  145. package/templates/agent-docs/plugins/flags.md +132 -0
  146. package/templates/agent-docs/plugins/governance.md +105 -7
  147. package/templates/agent-docs/plugins/multitenancy.md +9 -4
  148. package/templates/agent-docs/plugins/presence.md +13 -2
  149. package/templates/agent-docs/plugins/ratelimit.md +9 -0
  150. package/templates/agent-docs/plugins/search.md +157 -6
  151. package/templates/agent-docs/plugins/sso-saml.md +47 -8
  152. package/templates/agent-docs/plugins/webhooks.md +105 -0
  153. package/templates/agent-docs/plugins.md +200 -18
  154. package/templates/agent-docs/reference.md +60 -3
  155. package/templates/agent-docs/releases.md +1117 -0
  156. package/templates/agent-docs/routing.md +43 -25
  157. package/templates/agent-docs/scheduling.md +14 -1
  158. package/templates/agent-docs/schema-driven-ui.md +92 -12
  159. package/templates/agent-docs/security.md +449 -2
  160. package/templates/agent-docs/templates/apibackends.md +87 -18
  161. package/templates/agent-docs/templates/appshells.md +32 -14
  162. package/templates/agent-docs/templates/overview.md +13 -8
  163. package/templates/agent-docs/testing.md +211 -14
  164. package/templates/agent-docs/whats-new.md +1722 -84
  165. package/templates/agent-docs/workflows.md +130 -14
  166. package/templates/apps/api-ai/actions/summarize.action.ts +11 -0
  167. package/templates/apps/api-ai/package.json +8 -7
  168. package/templates/apps/api-auth/actions/me.action.ts +13 -0
  169. package/templates/apps/api-auth/package.json +9 -8
  170. package/templates/apps/api-backend/mutations/notes.create.mutation.ts +9 -0
  171. package/templates/apps/api-backend/package.json +12 -8
  172. package/templates/apps/api-backend/queries/notes.query.ts +30 -8
  173. package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +14 -0
  174. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +8 -0
  175. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +10 -0
  176. package/templates/apps/api-backend-deactivation/package.json +8 -7
  177. package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +17 -0
  178. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +9 -0
  179. package/templates/apps/api-backend-mail/package.json +9 -8
  180. package/templates/apps/api-backend-mail/queries/notes.query.ts +30 -8
  181. package/templates/apps/api-backend-mariadb/.env.example +14 -0
  182. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +9 -0
  183. package/templates/apps/api-backend-mariadb/package.json +10 -9
  184. package/templates/apps/api-backend-mariadb/queries/notes.query.ts +30 -8
  185. package/templates/apps/api-backend-sqlite/.env.example +14 -0
  186. package/templates/apps/api-backend-sqlite/mutations/notes.create.mutation.ts +9 -0
  187. package/templates/apps/api-backend-sqlite/package.json +9 -8
  188. package/templates/apps/api-backend-sqlite/queries/notes.query.ts +30 -8
  189. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +13 -0
  190. package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +12 -0
  191. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +9 -0
  192. package/templates/apps/api-backend-storage/package.json +9 -8
  193. package/templates/apps/api-backend-storage/queries/notes.query.ts +30 -8
  194. package/templates/apps/api-cms/actions/content.get.action.ts +7 -0
  195. package/templates/apps/api-cms/actions/content.types.action.ts +6 -0
  196. package/templates/apps/api-cms/actions/me.action.ts +13 -0
  197. package/templates/apps/api-cms/app.config.ts +19 -0
  198. package/templates/apps/api-cms/authz.ts +63 -0
  199. package/templates/apps/api-cms/mutations/content.publish.mutation.ts +10 -0
  200. package/templates/apps/api-cms/mutations/content.saveDraft.mutation.ts +10 -0
  201. package/templates/apps/api-cms/mutations/content.unpublish.mutation.ts +5 -0
  202. package/templates/apps/api-cms/package.json +11 -10
  203. package/templates/apps/api-cms/queries/content.list.query.ts +23 -7
  204. package/templates/apps/api-cms/tests/accessDecisions.test.ts +121 -0
  205. package/templates/apps/api-cms/tests/content.descriptors.test.ts +8 -4
  206. package/templates/apps/api-collab/mutations/documents.create.mutation.ts +8 -0
  207. package/templates/apps/api-collab/mutations/documents.setBody.mutation.ts +13 -0
  208. package/templates/apps/api-collab/package.json +9 -8
  209. package/templates/apps/api-collab/queries/documents.query.ts +19 -7
  210. package/templates/apps/api-data-advanced/package.json +9 -8
  211. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +12 -0
  212. package/templates/apps/api-data-advanced/queries/books.search.query.ts +9 -0
  213. package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +17 -0
  214. package/templates/apps/api-durable/mutations/orders.place.mutation.ts +9 -0
  215. package/templates/apps/api-durable/package.json +9 -8
  216. package/templates/apps/api-feature-flags/actions/notes.export.action.ts +16 -0
  217. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +12 -0
  218. package/templates/apps/api-feature-flags/package.json +10 -9
  219. package/templates/apps/api-governance/README.md +30 -8
  220. package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -1
  221. package/templates/apps/api-governance/actions/profiles.get.action.ts +29 -4
  222. package/templates/apps/api-governance/database/schema.ts +16 -4
  223. package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +12 -0
  224. package/templates/apps/api-governance/package.json +9 -8
  225. package/templates/apps/api-kv/actions/sync.pull.action.ts +15 -0
  226. package/templates/apps/api-kv/actions/sync.reset.action.ts +13 -0
  227. package/templates/apps/api-kv/actions/sync.status.action.ts +7 -0
  228. package/templates/apps/api-kv/package.json +9 -8
  229. package/templates/apps/api-kv/queries/events.list.query.ts +19 -8
  230. package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +11 -0
  231. package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +13 -0
  232. package/templates/apps/api-moderation/package.json +9 -8
  233. package/templates/apps/api-observability/mutations/notes.create.mutation.ts +8 -0
  234. package/templates/apps/api-observability/package.json +9 -8
  235. package/templates/apps/api-observability/queries/notes.list.query.ts +13 -0
  236. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +14 -0
  237. package/templates/apps/api-ratelimit/package.json +9 -8
  238. package/templates/apps/api-rbac/package.json +9 -8
  239. package/templates/apps/api-rest/package.json +8 -7
  240. package/templates/apps/api-saas/mutations/projects.create.mutation.ts +13 -0
  241. package/templates/apps/api-saas/package.json +12 -11
  242. package/templates/apps/api-saas/queries/projects.list.query.ts +11 -0
  243. package/templates/apps/api-saas-starter/actions/me.action.ts +13 -0
  244. package/templates/apps/api-saas-starter/app.config.ts +19 -0
  245. package/templates/apps/api-saas-starter/authz.ts +75 -0
  246. package/templates/apps/api-saas-starter/mutations/invites.create.mutation.ts +10 -0
  247. package/templates/apps/api-saas-starter/mutations/projects.create.mutation.ts +9 -0
  248. package/templates/apps/api-saas-starter/package.json +15 -11
  249. package/templates/apps/api-saas-starter/queries/invites.list.query.ts +19 -8
  250. package/templates/apps/api-saas-starter/queries/projects.list.query.ts +18 -7
  251. package/templates/apps/api-saas-starter/tests/accessDecisions.test.ts +135 -0
  252. package/templates/apps/api-search/mutations/articles.create.mutation.ts +14 -0
  253. package/templates/apps/api-search/package.json +9 -8
  254. package/templates/apps/api-search/queries/articles.list.query.ts +21 -8
  255. package/templates/apps/api-status/README.md +10 -3
  256. package/templates/apps/api-status/app.config.ts +8 -3
  257. package/templates/apps/api-status/authz.ts +5 -3
  258. package/templates/apps/api-status/package.json +9 -8
  259. package/templates/apps/api-status/queries/components.list.query.ts +14 -6
  260. package/templates/apps/api-status/queries/incidents.live.query.ts +23 -10
  261. package/templates/apps/api-status/queries/updates.list.query.ts +16 -9
  262. package/templates/apps/api-status/tests/status.test.ts +9 -1
  263. package/templates/apps/api-versioning/actions/documents.asOf.action.ts +12 -0
  264. package/templates/apps/api-versioning/actions/documents.history.action.ts +13 -0
  265. package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +9 -0
  266. package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +12 -0
  267. package/templates/apps/api-versioning/package.json +9 -8
  268. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +16 -0
  269. package/templates/apps/api-webhooks/package.json +10 -9
  270. package/templates/apps/api-webhooks/queries/orders.list.query.ts +10 -0
  271. package/templates/apps/changelog/package.json +8 -6
  272. package/templates/apps/edge-functions/package.json +2 -2
  273. package/templates/apps/frontend-admin/package.json +10 -8
  274. package/templates/apps/frontend-admin/src/lib/admin.ts +20 -9
  275. package/templates/apps/frontend-admin/src/locales/de.ts +11 -1
  276. package/templates/apps/frontend-admin/src/locales/en.ts +13 -1
  277. package/templates/apps/frontend-admin/src/pages/admin/[entity]/page.tsx +65 -22
  278. package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +130 -23
  279. package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +3 -2
  280. package/templates/apps/frontend-admin/src/pages/admin/page.test.tsx +19 -2
  281. package/templates/apps/frontend-admin/src/pages/admin/page.tsx +9 -4
  282. package/templates/apps/frontend-app/app.config.ts +4 -3
  283. package/templates/apps/frontend-app/package.json +11 -8
  284. package/templates/apps/frontend-app/src/lib/api.ts +25 -0
  285. package/templates/apps/frontend-app/src/pages/page.test.tsx +130 -82
  286. package/templates/apps/frontend-app/src/pages/page.tsx +14 -18
  287. package/templates/apps/frontend-auth/package.json +10 -8
  288. package/templates/apps/frontend-blank/package.json +9 -7
  289. package/templates/apps/frontend-cms/package.json +11 -9
  290. package/templates/apps/frontend-collab/package.json +12 -9
  291. package/templates/apps/frontend-collab/src/pages/page.test.tsx +122 -78
  292. package/templates/apps/frontend-contact/package.json +9 -7
  293. package/templates/apps/frontend-dashboard/package.json +9 -7
  294. package/templates/apps/frontend-docs/package.json +9 -7
  295. package/templates/apps/frontend-i18n/package.json +8 -6
  296. package/templates/apps/frontend-landing/package.json +9 -7
  297. package/templates/apps/frontend-portal/package.json +10 -8
  298. package/templates/apps/frontend-saas/app.config.ts +10 -6
  299. package/templates/apps/frontend-saas/package.json +10 -8
  300. package/templates/apps/frontend-saas/src/lib/api.ts +27 -32
  301. package/templates/apps/frontend-saas/src/pages/dashboard/billing/page.tsx +7 -8
  302. package/templates/apps/frontend-saas/src/pages/dashboard/page.test.tsx +27 -3
  303. package/templates/apps/frontend-saas/src/pages/dashboard/page.tsx +4 -4
  304. package/templates/apps/frontend-saas/src/pages/dashboard/team/page.tsx +3 -4
  305. package/templates/apps/frontend-spa/package.json +9 -7
  306. package/templates/apps/frontend-ssr/package.json +9 -7
  307. package/templates/apps/frontend-ssr-api/package.json +10 -8
  308. package/templates/apps/frontend-static-blog/package.json +8 -6
  309. package/templates/apps/frontend-status/package.json +10 -8
  310. package/templates/apps/mobile-app/README.md +1 -0
  311. package/templates/apps/mobile-app/package.json +4 -2
  312. package/templates/apps/mobile-app/src/app/index.tsx +22 -12
  313. package/templates/apps/mobile-app/src/app/orders/[id].tsx +1 -1
  314. package/templates/apps/mobile-app/src/lib/api.ts +34 -0
  315. package/templates/apps/mobile-app/voltro.mobile.ts +4 -2
  316. package/templates/baselines/bare/.env.example +14 -0
  317. package/templates/baselines/bare/baseline.json +4 -4
  318. package/templates/baselines/compose/.env.example +14 -0
  319. package/templates/baselines/compose/README.md +1 -1
  320. package/templates/baselines/compose/baseline.json +5 -5
  321. package/templates/baselines/compose-mariadb/.env.example +14 -0
  322. package/templates/baselines/compose-mariadb/README.md +1 -1
  323. package/templates/baselines/compose-mariadb/baseline.json +5 -5
  324. package/templates/baselines/helm/.env.example +14 -0
  325. package/templates/baselines/helm/baseline.json +4 -4
  326. package/dist/apiBuild-OJEjtwcn.js +0 -2
  327. package/dist/checkCommand-CwMrzAgV.js +0 -2
  328. package/dist/commands-C0nEePif.js +0 -11457
  329. package/dist/dbCommand-By__Ev0R.js +0 -2
  330. package/dist/dbCommand-ifOMafuG.js +0 -1311
  331. package/dist/dev-rc3fwPSZ.js +0 -3
  332. package/dist/devActivity-BhIu6ncs.js +0 -159
  333. package/dist/frameworkTableAssembly-D-EebUQX.js +0 -2
  334. package/dist/inspect-mmBuRXmy.js +0 -2
  335. package/dist/manifestBuild-Dj8Jjoto.js +0 -2
  336. package/dist/seedRunner-Bqxgp7HZ.js +0 -230
  337. package/dist/serveCommand-PxMmn96o.js +0 -1578
  338. package/dist/start-D1-8eKrO.js +0 -1084
  339. /package/templates/apps/api-ai/actions/{summarize.action.server.tsx → summarize.action.server.ts} +0 -0
@@ -1,1311 +0,0 @@
1
- import { i as e, n as t, r as n, s as r, t as i } from "./seedRunner-Bqxgp7HZ.js";
2
- import { n as a } from "./appModuleLoader-C9r9mxZt.js";
3
- import { n as o } from "./frameworkTableAssembly-BwIrO5nv.js";
4
- import { b as s } from "./fileConventions-Cof68_BL.js";
5
- import { a as c, n as l, t as u } from "./cliArgs-qdZSElM3.js";
6
- import { basename as d, join as f, relative as p, resolve as m } from "node:path";
7
- import { pathToFileURL as h } from "node:url";
8
- import { Effect as g } from "effect";
9
- import { createLogger as _ } from "@voltro/logger";
10
- import { promises as v, writeSync as y } from "node:fs";
11
- import { InMemoryDataStore as ee } from "@voltro/runtime";
12
- import { SqlClient as b } from "@effect/sql";
13
- import { actorsTable as te, frameworkTables as x, isMigrationDefinition as S, quoteIdent as ne, registerCoreTables as re } from "@voltro/database";
14
- import { createHash as ie } from "node:crypto";
15
- import { DEFAULT_CDC_CHANNEL as ae, applyPlan as oe, applySchema as C, assessRollingDeployGate as se, declaredSnapshot as ce, destructiveScope as le, detectReactiveTriggerDrift as ue, fingerprintSchema as w, ignoreTablesFromEnv as T, introspectSchema as de, pendingFileMigrationIds as fe, planMigrations as E, reactiveTriggerRepairSql as pe, rollbackFileBasedMigration as me, rollingDeployUnsafeOps as he, runFileBasedMigrations as ge, shortFingerprint as D, squashMigrationPlans as _e, unblockLossy as ve } from "@voltro/database/sql";
16
- //#region src/cliError.ts
17
- var O = class extends Error {
18
- isCliError = !0;
19
- code;
20
- constructor(e, t = 1) {
21
- super(e), this.name = "CliError", this.code = t;
22
- }
23
- }, ye = (e) => typeof e == "object" && !!e && e.isCliError === !0, be = (e) => typeof e != "string", xe = (e, t, n, r) => {
24
- let i = [], a = new Map(t.map((e) => [e.name, e])), o = new Map(n.map((e) => [e.name, e])), s = new Set(e.leaveUnset ?? []);
25
- r > 0 && i.push({
26
- kind: "target-not-empty",
27
- detail: `'${e.into}' already holds ${r} row(s) — adopt MOVES rows into a table, it does not merge into one`,
28
- fatal: !0
29
- });
30
- let c = [], l = /* @__PURE__ */ new Set();
31
- for (let [t, n] of Object.entries(e.map)) {
32
- if (!o.has(t)) {
33
- i.push({
34
- kind: "unknown-target-column",
35
- detail: `'${e.into}' has no column '${t}'`,
36
- fatal: !0
37
- });
38
- continue;
39
- }
40
- if (be(n)) {
41
- c.push({
42
- target: t,
43
- source: n.expr,
44
- raw: !0
45
- });
46
- continue;
47
- }
48
- if (!a.has(n)) {
49
- i.push({
50
- kind: "unknown-source-column",
51
- detail: `'${e.from}' has no column '${n}' (mapped to '${t}')`,
52
- fatal: !0
53
- });
54
- continue;
55
- }
56
- l.add(n), c.push({
57
- target: t,
58
- source: n,
59
- raw: !1
60
- });
61
- }
62
- for (let t of n) t.name in e.map || s.has(t.name) || t.nullable || t.hasDefault || i.push({
63
- kind: "required-target-unmapped",
64
- detail: `'${e.into}.${t.name}' is NOT NULL with no default and nothing maps to it`,
65
- fatal: !0
66
- });
67
- for (let n of t) l.has(n.name) || i.push({
68
- kind: "source-column-unmapped",
69
- detail: `'${e.from}.${n.name}' is not carried across — its values are lost when the table is dropped`,
70
- fatal: !1
71
- });
72
- let u = t.find((e) => e.idPrefix !== void 0), d = n.find((e) => e.idPrefix !== void 0), f = u !== void 0 && d !== void 0 && u.idPrefix !== d.idPrefix;
73
- return f && i.push({
74
- kind: "id-prefix-differs",
75
- detail: `id prefix '${u.idPrefix}' → '${d.idPrefix}': every row gets a NEW id, so every reference to '${e.from}' elsewhere must be rewritten from the translation table — including ids inside JSON columns`,
76
- fatal: !1
77
- }), {
78
- problems: i,
79
- assignments: c.sort((e, t) => e.target.localeCompare(t.target)),
80
- remintIds: f,
81
- fatal: i.some((e) => e.fatal)
82
- };
83
- }, Se = (e, t) => [
84
- `back up '${e.from}' to a restorable dump`,
85
- `copy rows: INSERT INTO ${e.into} (${t.assignments.map((e) => e.target).join(", ")}) SELECT … FROM ${e.from}`,
86
- ...t.remintIds ? ["record old id → new id in a translation table", `rewrite every reference to '${e.from}', JSON columns included`] : [],
87
- "verify: row counts match and a sample round-trips",
88
- `drop '${e.from}' — LAST, and only after the verify`
89
- ], Ce = (e, t, n) => {
90
- let r = [`adopt · ${e.from} (${n} row(s)) → ${e.into}`, ""];
91
- for (let e of t.assignments) r.push(` ${e.target.padEnd(24)} ← ${e.raw ? `${e.source} (raw)` : e.source}`);
92
- t.problems.length > 0 && r.push("");
93
- for (let e of t.problems) r.push(` ${e.fatal ? "✗" : "⚠"} ${e.detail}`);
94
- if (r.push(""), t.fatal) return r.push(" REFUSED — fix the problems above. Nothing was written."), r;
95
- r.push(" would run, in this order:");
96
- for (let [n, i] of Se(e, t).entries()) r.push(` ${n + 1}. ${i}`);
97
- return r;
98
- }, we = (e) => e === "mysql" || e === "mariadb" ? (e) => `\`${e}\`` : e === "mssql" ? (e) => `[${e}]` : (e) => `"${e}"`, Te = (e) => `${e}__adopt_snapshot`, Ee = (e, t, n, r, i) => {
99
- let a = we(n), o = Te(e.from), s = t.assignments.map((e) => e.target), c = t.assignments.map((e) => e.raw ? e.source : a(e.source));
100
- return i !== void 0 && (s.unshift(r), c.unshift(i)), {
101
- snapshot: n === "mssql" ? `SELECT * INTO ${a(o)} FROM ${a(e.from)}` : `CREATE TABLE ${a(o)} AS SELECT * FROM ${a(e.from)}`,
102
- copy: `INSERT INTO ${a(e.into)} (${s.map(a).join(", ")}) SELECT ${c.join(", ")} FROM ${a(e.from)}`,
103
- translations: i === void 0 ? [] : [`CREATE TABLE ${a(`${o}__ids`)} (old_id TEXT, new_id TEXT)`],
104
- verifySource: `SELECT COUNT(*) AS n FROM ${a(e.from)}`,
105
- verifyTarget: `SELECT COUNT(*) AS n FROM ${a(e.into)}`,
106
- drop: `DROP TABLE ${a(e.from)}`,
107
- dropSnapshot: `DROP TABLE ${a(o)}`
108
- };
109
- }, De = (e) => {
110
- let t = e[0];
111
- if (t === void 0) return 0;
112
- let n = t.n ?? t.N ?? Object.values(t)[0];
113
- return Number(n ?? 0);
114
- }, Oe = async (e, t, n, r, i, a, o = {}) => {
115
- if (t.fatal) throw Error("adopt: the plan was refused — nothing was run");
116
- let s = Ee(e, t, n, r, i), c = Te(e.from), l = De(await a(s.verifySource));
117
- await a(s.snapshot);
118
- for (let e of s.translations) await a(e);
119
- await a(s.copy);
120
- let u = De(await a(s.verifyTarget));
121
- return u === l ? o.keepSource === !0 ? {
122
- copied: u,
123
- sourceRows: l,
124
- verified: !0,
125
- snapshotTable: c,
126
- sourceDropped: !1
127
- } : (await a(s.drop), {
128
- copied: u,
129
- sourceRows: l,
130
- verified: !0,
131
- snapshotTable: c,
132
- sourceDropped: !0
133
- }) : {
134
- copied: u,
135
- sourceRows: l,
136
- verified: !1,
137
- snapshotTable: c,
138
- sourceDropped: !1
139
- };
140
- }, k = [
141
- "token",
142
- "secret",
143
- "password",
144
- "apikey",
145
- "api_key",
146
- "credential",
147
- "privatekey",
148
- "private_key"
149
- ], ke = [
150
- {
151
- table: "_voltro_audit_log",
152
- column: "subject"
153
- },
154
- {
155
- table: "_voltro_audit_log",
156
- column: "actor"
157
- },
158
- {
159
- table: "_voltro_audit_log",
160
- column: "scope"
161
- },
162
- {
163
- table: "_voltro_audit_log",
164
- column: "metadata"
165
- },
166
- {
167
- table: "_voltro_audit_log",
168
- column: "input"
169
- },
170
- {
171
- table: "_voltro_audit_log",
172
- column: "outcome"
173
- },
174
- {
175
- table: "_voltro_audit_log",
176
- column: "subjectId"
177
- },
178
- {
179
- table: "_voltro_row_history",
180
- column: "data"
181
- },
182
- {
183
- table: "_voltro_row_history",
184
- column: "actor"
185
- },
186
- {
187
- table: "_voltro_row_history",
188
- column: "scope"
189
- },
190
- {
191
- table: "_voltro_row_history",
192
- column: "subjectId"
193
- }
194
- ], Ae = (e, t) => {
195
- switch (t) {
196
- case "postgres": return `LOWER(CAST(${e} AS text))`;
197
- case "mysql":
198
- case "mariadb": return `LOWER(CAST(${e} AS CHAR))`;
199
- case "mssql": return `LOWER(CAST(${e} AS NVARCHAR(MAX)))`;
200
- case "sqlite":
201
- case "turso": return `LOWER(CAST(${e} AS TEXT))`;
202
- }
203
- }, je = (e, t, n = k) => n.map((n) => `${Ae(e, t)} LIKE '%${n}%'`).join("\n OR "), A = async (e, t) => {
204
- let n = await g.runPromise(e.unsafe(t));
205
- return Number(Object.values(n[0] ?? { n: 0 })[0] ?? 0);
206
- }, Me = async (e, t, n, r) => {
207
- let i = [];
208
- for (let a of n) {
209
- let n = r(a.table), o;
210
- try {
211
- o = await A(e, `SELECT COUNT(*) AS n FROM ${n}`);
212
- } catch {
213
- i.push({
214
- table: a.table,
215
- column: a.column,
216
- scanned: void 0,
217
- hits: void 0,
218
- unavailable: "table"
219
- });
220
- continue;
221
- }
222
- try {
223
- let s = await A(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${je(r(a.column), t)}`), c = [];
224
- if (s > 0) for (let i of k) try {
225
- let o = await A(e, `SELECT COUNT(*) AS n FROM ${n}\n WHERE ${je(r(a.column), t, [i])}`);
226
- o > 0 && c.push({
227
- needle: i,
228
- rows: o
229
- });
230
- } catch {}
231
- i.push({
232
- table: a.table,
233
- column: a.column,
234
- scanned: o,
235
- hits: s,
236
- matchedNeedles: c
237
- });
238
- } catch {
239
- i.push({
240
- table: a.table,
241
- column: a.column,
242
- scanned: o,
243
- hits: void 0,
244
- unavailable: "column"
245
- });
246
- }
247
- }
248
- return i;
249
- }, Ne = (e, t) => {
250
- let n = k.length, r = [`credential scan · dialect ${t}`, ""], i = /* @__PURE__ */ new Set();
251
- for (let t of e) {
252
- if (t.unavailable === "column") {
253
- r.push(` · ${t.table}.${t.column} — column is not present on this deployment (${t.scanned} row(s) exist but this column was not scanned)`);
254
- continue;
255
- }
256
- if (t.scanned === void 0) {
257
- i.has(t.table) || (i.add(t.table), r.push(` · ${t.table} — table not present (nothing scanned)`));
258
- continue;
259
- }
260
- if (t.scanned === 0) {
261
- r.push(` · ${t.table} — table is EMPTY (0 rows scanned; this is not a clean bill of health)`);
262
- continue;
263
- }
264
- let e = (t.hits ?? 0) > 0 ? "✗" : "✓";
265
- r.push(` ${e} ${t.table}.${t.column} — ${t.hits} of ${t.scanned} row(s) match a credential-shaped key`), (t.matchedNeedles?.length ?? 0) > 0 && r.push(` matched (rows per needle, may overlap): ${t.matchedNeedles.map((e) => `${e.needle} (${e.rows})`).join(", ")}`);
266
- }
267
- let a = e.reduce((e, t) => e + (t.hits ?? 0), 0);
268
- return r.push(""), a > 0 ? r.push(` ${a} row(s) carry something credential-shaped.`, " Purge them AND rotate the credentials — assume anything written to a log", " table has been read. Then stop putting the credential on the Subject:", " `connectionCredentials(...)` keeps it in the framework vault.") : e.every((e) => e.scanned === void 0 || e.scanned === 0 || e.unavailable !== void 0) ? r.push(" NOTHING WAS SCANNED. This run proves nothing about your data.") : r.push(" No credential-shaped keys found in the rows that exist."), r.push("", ` These are NAME heuristics (${n} of them), not proof. A credential in a`, " column whose key is not credential-shaped — `keyValue`, `pat`, `authz` —", " is invisible here. A clean run means \"no credential-SHAPED key found\",", " which is not the same as \"no credential\".", "", " Run this on EVERY environment. A dev database is not a sample of production."), r.join("\n");
269
- }, Pe = (e) => e.some((e) => (e.hits ?? 0) > 0) ? 1 : e.every((e) => e.unavailable !== void 0 || e.scanned === void 0 || e.scanned === 0) ? 2 : 0, j = /\.migration\.ts$/, M = async (e, t) => {
270
- let n = [];
271
- for (let r of e) {
272
- let e;
273
- try {
274
- e = await import(h(r).href);
275
- } catch (e) {
276
- t.warn("migration: failed to import", { file: r }, e);
277
- continue;
278
- }
279
- let i = (e.default && S(e.default) ? e.default : void 0) ?? Object.values(e).find(S);
280
- if (!i) {
281
- t.warn("migration: no defineMigration export", { file: r });
282
- continue;
283
- }
284
- i.id !== d(r).replace(/\.migration\.ts$/, "") && t.warn("migration: id does not match filename — id wins for ordering, but rename the file for clarity", {
285
- file: r,
286
- idInFile: i.id,
287
- idFromFile: d(r).replace(/\.migration\.ts$/, "")
288
- });
289
- let a = await v.readFile(r, "utf8").catch(() => ""), o = ie("sha256").update(a).digest("hex").slice(0, 16);
290
- n.push({
291
- file: r,
292
- definition: i,
293
- hash: o
294
- });
295
- }
296
- return [...n].sort((e, t) => e.definition.id < t.definition.id ? -1 : 1);
297
- }, N = (e) => {
298
- let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase(), n = t === "memory" ? "postgres" : t;
299
- return g.runPromise(C(x, n).pipe(g.provide(e)));
300
- }, P = (e) => g.runPromise(g.gen(function* () {
301
- let e = yield* (yield* b.SqlClient)`SELECT id, status, hash, "appliedAt" FROM "_voltro_migrations"`.pipe(g.orElseSucceed(() => []));
302
- return new Map(e.map((e) => [e.id, e]));
303
- }).pipe(g.provide(e))), F = (e, t) => g.runPromise(g.gen(function* () {
304
- yield* (yield* b.SqlClient)`
305
- INSERT INTO "_voltro_migrations"
306
- (id, name, hash, status, "appliedAt", "durationMs", "errorMessage", "errorStack")
307
- VALUES
308
- (${t.id}, ${t.name}, ${t.hash}, ${t.status}, ${t.appliedAt}, ${t.durationMs}, ${t.errorMessage}, ${t.errorStack})
309
- ON CONFLICT (id) DO UPDATE SET
310
- name = EXCLUDED.name,
311
- hash = EXCLUDED.hash,
312
- status = EXCLUDED.status,
313
- "appliedAt" = EXCLUDED."appliedAt",
314
- "durationMs" = EXCLUDED."durationMs",
315
- "errorMessage"= EXCLUDED."errorMessage",
316
- "errorStack" = EXCLUDED."errorStack",
317
- "updatedAt" = now()
318
- `;
319
- }).pipe(g.provide(e))), Fe = async (e, t, n) => {
320
- if (e.length === 0) return {
321
- applied: [],
322
- failed: null,
323
- skipped: []
324
- };
325
- await N(t);
326
- let r = await P(t), i = [], a = [], o = null;
327
- for (let s of e) {
328
- let e = r.get(s.definition.id);
329
- if (e && e.status === "applied") {
330
- e.hash !== s.hash && n.warn("migration: applied migration has a different hash on disk", {
331
- id: s.definition.id,
332
- appliedHash: e.hash,
333
- fileHash: s.hash
334
- }), a.push({
335
- migrationId: s.definition.id,
336
- status: "skipped",
337
- durationMs: 0,
338
- steps: []
339
- });
340
- continue;
341
- }
342
- n.info("migration: applying", {
343
- id: s.definition.id,
344
- name: s.definition.name
345
- });
346
- let c = Date.now(), l = [];
347
- await F(t, {
348
- id: s.definition.id,
349
- name: s.definition.name,
350
- hash: s.hash,
351
- status: "running",
352
- appliedAt: null,
353
- durationMs: null,
354
- errorMessage: null,
355
- errorStack: null
356
- });
357
- let u = !1;
358
- for (let e of s.definition.steps) {
359
- let n = Date.now();
360
- try {
361
- await g.runPromise(e.apply.pipe(g.provide(t))), l.push({
362
- stepName: e.name,
363
- status: "applied",
364
- durationMs: Date.now() - n
365
- });
366
- } catch (r) {
367
- let a = r, d = {
368
- stepName: e.name,
369
- status: "failed",
370
- durationMs: Date.now() - n,
371
- error: {
372
- message: a.message,
373
- ...a.stack ? { stack: a.stack } : {}
374
- }
375
- };
376
- l.push(d), u = !0;
377
- let f = {
378
- migrationId: s.definition.id,
379
- status: "failed",
380
- durationMs: Date.now() - c,
381
- steps: l,
382
- error: {
383
- stepName: e.name,
384
- message: a.message,
385
- ...a.stack ? { stack: a.stack } : {}
386
- }
387
- };
388
- o = f, i.push(f), await F(t, {
389
- id: s.definition.id,
390
- name: s.definition.name,
391
- hash: s.hash,
392
- status: "failed",
393
- appliedAt: null,
394
- durationMs: Date.now() - c,
395
- errorMessage: a.message,
396
- errorStack: a.stack ?? null
397
- });
398
- break;
399
- }
400
- }
401
- if (u) break;
402
- i.push({
403
- migrationId: s.definition.id,
404
- status: "applied",
405
- durationMs: Date.now() - c,
406
- steps: l
407
- }), await F(t, {
408
- id: s.definition.id,
409
- name: s.definition.name,
410
- hash: s.hash,
411
- status: "applied",
412
- appliedAt: /* @__PURE__ */ new Date(),
413
- durationMs: Date.now() - c,
414
- errorMessage: null,
415
- errorStack: null
416
- }), n.info("migration: applied", {
417
- id: s.definition.id,
418
- durationMs: Date.now() - c,
419
- stepCount: l.length
420
- });
421
- }
422
- return {
423
- applied: i.filter((e) => e.status === "applied"),
424
- failed: o,
425
- skipped: a
426
- };
427
- }, Ie = async (e, t, n, r = {}) => {
428
- await N(t);
429
- let i = await P(t), a = e.filter((e) => i.get(e.definition.id)?.status === "applied");
430
- if (a.length === 0) return n.info("migration: nothing to roll back"), {
431
- applied: [],
432
- failed: null,
433
- skipped: []
434
- };
435
- let o = [];
436
- for (let e = a.length - 1; e >= 0; e--) {
437
- let t = a[e];
438
- if (o.push(t), !r.to && o.length === 1 || r.to && t.definition.id === r.to) break;
439
- }
440
- let s = [], c = null;
441
- for (let e of o) {
442
- n.info("migration: rolling back", { id: e.definition.id });
443
- let r = Date.now(), i = [], a = !1;
444
- for (let n = e.definition.steps.length - 1; n >= 0; n--) {
445
- let o = e.definition.steps[n], s = Date.now();
446
- try {
447
- await g.runPromise(o.undo.pipe(g.provide(t))), i.push({
448
- stepName: o.name,
449
- status: "applied",
450
- durationMs: Date.now() - s
451
- });
452
- } catch (t) {
453
- let n = t;
454
- i.push({
455
- stepName: o.name,
456
- status: "failed",
457
- durationMs: Date.now() - s,
458
- error: {
459
- message: n.message,
460
- ...n.stack ? { stack: n.stack } : {}
461
- }
462
- }), a = !0, c = {
463
- migrationId: e.definition.id,
464
- status: "failed",
465
- durationMs: Date.now() - r,
466
- steps: i,
467
- error: {
468
- stepName: o.name,
469
- message: n.message,
470
- ...n.stack ? { stack: n.stack } : {}
471
- }
472
- };
473
- break;
474
- }
475
- }
476
- if (a) break;
477
- s.push({
478
- migrationId: e.definition.id,
479
- status: "applied",
480
- durationMs: Date.now() - r,
481
- steps: i
482
- }), await F(t, {
483
- id: e.definition.id,
484
- name: e.definition.name,
485
- hash: e.hash,
486
- status: "reverted",
487
- appliedAt: null,
488
- durationMs: Date.now() - r,
489
- errorMessage: null,
490
- errorStack: null
491
- }), n.info("migration: rolled back", { id: e.definition.id });
492
- }
493
- return {
494
- applied: s,
495
- failed: c,
496
- skipped: []
497
- };
498
- }, I = async (e, t) => {
499
- await N(t);
500
- let n = await P(t);
501
- return e.map((e) => {
502
- let t = n.get(e.definition.id);
503
- return t ? {
504
- id: e.definition.id,
505
- name: e.definition.name,
506
- status: t.status === "running" ? "failed" : t.status,
507
- appliedAt: t.appliedAt,
508
- hashMatches: t.hash === e.hash
509
- } : {
510
- id: e.definition.id,
511
- name: e.definition.name,
512
- status: "pending",
513
- appliedAt: null,
514
- hashMatches: !0
515
- };
516
- });
517
- }, L = (e) => {
518
- if (!e.failed) return "";
519
- let t = e.failed, n = [
520
- `✗ Migration failed: ${t.migrationId} / step '${t.error?.stepName ?? "?"}'`,
521
- ` Reason: ${t.error?.message ?? "unknown"}`,
522
- "",
523
- "Next steps:",
524
- " voltro db status # full migration timeline",
525
- " voltro db rollback # revert to last good state",
526
- " voltro db migrate # retry after fixing the cause",
527
- ""
528
- ];
529
- return e.applied.length > 0 && n.unshift("", `(${e.applied.length} migration(s) applied successfully before the failure.)`), n.join("\n");
530
- }, R = _({ scope: "voltro:db" }), Le = /* @__PURE__ */ new Set([
531
- "node_modules",
532
- "dist",
533
- "build",
534
- ".turbo",
535
- ".vite",
536
- ".next",
537
- ".git"
538
- ]), z = async (e, t) => {
539
- let n = [], r = async (e) => {
540
- let i = await v.readdir(e, { withFileTypes: !0 }).catch(() => []);
541
- for (let a of i) {
542
- if (Le.has(a.name)) continue;
543
- let i = f(e, a.name);
544
- a.isDirectory() ? await r(i) : a.isFile() && t.test(a.name) && n.push(i);
545
- }
546
- };
547
- return await r(e), n;
548
- }, B = (e) => m(e.find((e) => !e.startsWith("-")) ?? process.cwd()), V = () => {
549
- let e = process.env.DB_MAX_CONNECTIONS ?? process.env.PG_MAX_CONNECTIONS, t = e !== void 0 && e !== "" ? Number(e) : NaN, n = Number.isInteger(t) && t > 0 ? { maxConnections: t } : {}, r = process.env.DB_SCHEMA, i = r && r.length > 0 ? { schema: r } : {}, a = process.env.DB_DIRECT_URL ?? process.env.DB_MIGRATE_URL ?? process.env.DB_URL ?? process.env.DB_PRIMARY_URL;
550
- return a ? {
551
- url: a,
552
- ...n,
553
- ...i
554
- } : {
555
- host: process.env.DB_HOST ?? process.env.PG_HOST ?? "localhost",
556
- port: Number(process.env.DB_PORT ?? process.env.PG_PORT ?? 5432),
557
- username: process.env.DB_USER ?? process.env.PG_USER ?? "app",
558
- password: process.env.DB_PASSWORD ?? process.env.PG_PASSWORD ?? "app",
559
- database: process.env.DB_DATABASE ?? process.env.PG_DATABASE ?? "app",
560
- ...n,
561
- ...i
562
- };
563
- }, H = (e) => {
564
- let t = e;
565
- if (typeof t != "object" || !t) return !1;
566
- if (t.code === "ERR_OUT_OF_RANGE" || t.cause?.code === "ERR_OUT_OF_RANGE") return !0;
567
- let n = `${t.message ?? ""} ${t.cause?.message ?? ""} ${t.stack ?? ""}`;
568
- return /ERR_OUT_OF_RANGE|out of range/i.test(n) && /pg-protocol|parseDataRow|buffer-reader|BufferReader/i.test(n);
569
- }, U = "Live-DB introspection got a corrupt / misaligned response from the database. This happens when `voltro db plan` / `apply` / `drift` / `migrate` runs through a connection POOLER (Supabase Supavisor / PgBouncer) on a LARGE schema — the pooler mis-frames a big catalog response. The introspection already batches by table to keep responses small; if a batch still trips it:\n 1. Lower the batch: set `VOLTRO_INTROSPECT_BATCH` to a smaller number of tables (default 20 — try 5 or 1). This keeps `db plan` on the normal pooler, no direct connection needed.\n 2. Or use a DIRECT (non-pooler) connection: set `DB_DIRECT_URL` (or `DB_MIGRATE_URL`) to the direct database URL — the runtime keeps `DB_URL`, so only the migration path is affected. (Supabase: direct = `db.<project-ref>.supabase.co` [IPv6-only on newer projects]; pooler = `aws-0-<region>.pooler.supabase.com`.)", W = () => {
570
- let e = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
571
- if (e === "memory") throw new O("voltro db: subcommands require a real dialect, not DB_DIALECT=memory.");
572
- return e;
573
- }, G = (e) => ne(e, W()), K = (e) => e === "mysql" || e === "mariadb" ? "table_schema = DATABASE()" : e === "mssql" ? "table_schema = SCHEMA_NAME()" : "table_schema = 'public'", q = async () => (await r(W())).makeSqlLayer(V()), Re = async (e) => {
574
- let t = B(e), n = e.includes("--dry-run"), r = await M(await z(t, j), R);
575
- if (r.length === 0) return R.info("no migrations found", { root: t }), 0;
576
- if (n) {
577
- let e = /* @__PURE__ */ new Set();
578
- try {
579
- let t = await I(r, await q());
580
- e = new Set(t.filter((e) => e.status === "applied").map((e) => e.id));
581
- } catch {
582
- R.warn("migrate --dry-run: could not read the migration ledger — showing ALL as pending");
583
- }
584
- let t = r.filter((t) => !e.has(t.definition.id));
585
- if (t.length === 0) return R.info("migrate --dry-run: nothing pending — every migration is applied"), 0;
586
- R.info(`migrate --dry-run: ${t.length} pending (nothing applied)`);
587
- for (let e of t) console.log(` pending ${e.definition.id}`);
588
- return 0;
589
- }
590
- let i = await Fe(r, await q(), R);
591
- return i.failed ? (process.stderr.write(L(i) + "\n"), 1) : (R.info("migrate complete", {
592
- applied: i.applied.length,
593
- skipped: i.skipped.length
594
- }), 0);
595
- }, ze = async (e) => {
596
- let t = B(e), n = l(e, "--to"), r = await M(await z(t, j), R);
597
- if (r.length === 0) return R.info("no migrations found", { root: t }), 0;
598
- let i = await Ie(r, await q(), R, n ? { to: n } : {});
599
- return i.failed ? (process.stderr.write(L(i) + "\n"), 1) : (R.info("rollback complete", { reverted: i.applied.length }), 0);
600
- }, Be = async (e) => {
601
- let t = await M(await z(B(e), j), R);
602
- if (t.length === 0) return console.log("no migrations found"), 0;
603
- let n = await I(t, await q());
604
- for (let e of n) {
605
- let t = e.status === "applied" ? "✓" : e.status === "failed" ? "✗" : e.status === "reverted" ? "↩" : "·", n = e.hashMatches ? "" : " (hash drift!)", r = e.appliedAt ? ` @ ${e.appliedAt.toISOString()}` : "";
606
- console.log(` ${t} ${e.id} [${e.status}] ${e.name}${r}${n}`);
607
- }
608
- return 0;
609
- }, Ve = async (e) => {
610
- let t = (l(e, "--store") ?? process.env.DB_DIALECT ?? "postgres").toLowerCase();
611
- if (t === "memory") return R.warn("voltro db seed: using in-memory store (explicit opt-in via --store memory / DB_DIALECT=memory)"), R.warn(" rows written by this run will NOT persist beyond the process. set DB_DIALECT=postgres or unset to seed the real DB."), {
612
- store: new ee(),
613
- dispose: async () => {},
614
- dialectId: "memory"
615
- };
616
- let n = await r(t);
617
- R.info(`voltro db seed: target store=${n.id} — rows will persist`);
618
- let i = await n.makeStore({
619
- sqlLayer: n.makeSqlLayer(V()),
620
- changeStrategy: "inline"
621
- }), a = i;
622
- return {
623
- store: i,
624
- dispose: async () => {
625
- typeof a.close == "function" && await a.close(5e3);
626
- },
627
- dialectId: n.id
628
- };
629
- }, He = async (r) => {
630
- let a = B(r), o = l(r, "--id"), s = l(r, "--lifecycle"), c = await t(await z(a, i), R);
631
- if (c.length === 0) return R.info("no seeds found", { root: a }), 0;
632
- let { store: u, dispose: d, dialectId: f } = await Ve(r);
633
- try {
634
- return o ? +((await e(c, o, u, R)).status === "failed") : +((await n((s ? c.filter((e) => e.definition.lifecycle === s) : c.filter((e) => e.definition.lifecycle === "boot")).map((e) => ({
635
- ...e,
636
- definition: {
637
- ...e.definition,
638
- lifecycle: "boot"
639
- }
640
- })), u, R, { force: !0 })).filter((e) => e.status === "failed").length > 0);
641
- } finally {
642
- await d().catch((e) => {
643
- R.warn("voltro db seed: store dispose failed", { error: String(e) });
644
- });
645
- }
646
- }, Ue = (e) => typeof e == "object" && !!e && "tableName" in e && "fields" in e && typeof e.tableName == "string", We = async (e) => {
647
- let t = await z(e, s), n = [];
648
- for (let r of t) {
649
- let t;
650
- try {
651
- t = await import(h(r).href);
652
- } catch (t) {
653
- R.warn("db: failed to import schema file", {
654
- file: p(e, r),
655
- error: String(t)
656
- });
657
- continue;
658
- }
659
- for (let e of Object.values(t)) Ue(e) && n.push(e);
660
- }
661
- return n;
662
- }, Ge = (e) => {
663
- let t = new Map(e.map((e) => [e.tableName, e]));
664
- t.has("actors") || t.set("actors", te);
665
- let n = t.get("actors"), r = t.get("tenants");
666
- return re({
667
- actors: () => n,
668
- ...r === void 0 ? {} : { tenants: () => r }
669
- }), [...t.values()];
670
- }, Ke = (e) => {
671
- let t = /* @__PURE__ */ new Map();
672
- for (let n of e) {
673
- let e = n.tableName;
674
- e !== void 0 && !t.has(e) && t.set(e, n);
675
- }
676
- return [...t.values()];
677
- }, qe = (e) => {
678
- let t = le(process.env.VOLTRO_DESTRUCTIVE_OK);
679
- if (t === void 0 || !e.operations.filter((e) => e.blocked).every((e) => e.classification === "lossy")) return {
680
- plan: e,
681
- acknowledged: !1
682
- };
683
- let n = ve(e, t);
684
- return {
685
- plan: n,
686
- acknowledged: !n.operations.some((e) => e.blocked)
687
- };
688
- }, J = async (e, t) => g.runPromise(t.pipe(g.provide(e))), Y = async (e) => {
689
- try {
690
- return await J(e, b.SqlClient.pipe(g.flatMap(de)));
691
- } catch (e) {
692
- let t = String(e?.message ?? e);
693
- if (H(e) || /connection error/i.test(t)) {
694
- let n = /* @__PURE__ */ Error(`${U}\n\nOriginal error: ${t}`);
695
- throw n.cause = e, n;
696
- }
697
- throw e;
698
- }
699
- }, Je = {
700
- safe: "\x1B[32m✓\x1B[0m",
701
- "needs-default": "\x1B[32m⊕\x1B[0m",
702
- "needs-backfill": "\x1B[33m⊕\x1B[0m",
703
- "needs-rename-annotation": "\x1B[33m⟲\x1B[0m",
704
- lossy: "\x1B[31m✗\x1B[0m",
705
- "online-required": "\x1B[36m◷\x1B[0m",
706
- "multi-step": "\x1B[35m⇉\x1B[0m"
707
- }, Ye = (e) => {
708
- let t = e.op, n;
709
- switch (t.kind) {
710
- case "create-table":
711
- n = `CREATE TABLE ${t.table} (${t.columns.length} cols)`;
712
- break;
713
- case "drop-table":
714
- n = `DROP TABLE ${t.table}`;
715
- break;
716
- case "add-column":
717
- n = `ALTER TABLE ${t.table} ADD COLUMN ${t.column.name} ${t.column.type}${t.column.nullable ? "" : " NOT NULL"}`;
718
- break;
719
- case "drop-column":
720
- n = `ALTER TABLE ${t.table} DROP COLUMN ${t.column}`;
721
- break;
722
- case "rename-column":
723
- n = `ALTER TABLE ${t.table} RENAME COLUMN ${t.from} TO ${t.to}`;
724
- break;
725
- case "alter-column-nullability":
726
- n = `ALTER TABLE ${t.table} ALTER COLUMN ${t.column} ${t.toNullable ? "DROP NOT NULL" : "SET NOT NULL"}`;
727
- break;
728
- case "alter-column-type":
729
- n = `ALTER TABLE ${t.table} ALTER COLUMN ${t.column} TYPE ${t.to}`;
730
- break;
731
- case "alter-column-default":
732
- n = `ALTER TABLE ${t.table} ALTER COLUMN ${t.column} ${t.hasDefault ? `SET DEFAULT ${JSON.stringify(t.defaultValue)}` : "DROP DEFAULT"}`;
733
- break;
734
- case "add-index":
735
- n = `CREATE INDEX ${t.index.name} ON ${t.table} (${t.index.columns.join(", ")})`;
736
- break;
737
- case "drop-index":
738
- n = `DROP INDEX ${t.index}`;
739
- break;
740
- case "rename-index":
741
- n = `ALTER INDEX ${t.from} RENAME TO ${t.to}`;
742
- break;
743
- case "rename-table":
744
- n = `ALTER TABLE ${t.from} RENAME TO ${t.to}`;
745
- break;
746
- case "add-unique":
747
- n = `ALTER TABLE ${t.table} ADD UNIQUE (${t.column})`;
748
- break;
749
- case "drop-unique":
750
- n = `ALTER TABLE ${t.table} DROP UNIQUE (${t.column})`;
751
- break;
752
- case "add-unique-composite":
753
- n = `ALTER TABLE ${t.table} ADD CONSTRAINT ${t.name} UNIQUE (${t.fields.join(", ")})`;
754
- break;
755
- case "drop-unique-composite":
756
- n = `ALTER TABLE ${t.table} DROP CONSTRAINT ${t.name}`;
757
- break;
758
- case "add-foreign-key":
759
- n = `ALTER TABLE ${t.table} ADD FK ${t.column} → ${t.targetTable}.${t.targetColumn}`;
760
- break;
761
- case "drop-foreign-key":
762
- n = `ALTER TABLE ${t.table} DROP FK ${t.column}`;
763
- break;
764
- case "add-check":
765
- n = `ALTER TABLE ${t.table} ADD CHECK (${t.column} IN (${t.values.join(", ")}))`;
766
- break;
767
- case "drop-check":
768
- n = `ALTER TABLE ${t.table} DROP CHECK ${t.column}`;
769
- break;
770
- }
771
- let r = Je[e.classification], i = e.reason ? ` # ${e.reason}` : "", a = e.blocked ? `\n ! ${e.blocked.fix}` : "";
772
- return ` ${r} ${n}${i}${a}`;
773
- }, Xe = async (e, t) => {
774
- let n = e.operations.filter((e) => e.classification === "needs-default" && e.op.kind === "add-column");
775
- if (n.length === 0) return;
776
- let r = [];
777
- for (let e of n) {
778
- let n = e.op, i = n.table, a = n.column?.name;
779
- if (i === void 0 || a === void 0) continue;
780
- let o = 0;
781
- try {
782
- let e = await J(t, b.SqlClient.pipe(g.flatMap((e) => e.unsafe(`SELECT COUNT(*) AS n FROM ${ne(i, W())}`))));
783
- o = Number(Object.values(e[0] ?? { n: 0 })[0] ?? 0);
784
- } catch {
785
- continue;
786
- }
787
- o !== 0 && r.push(` ${o.toLocaleString("en-US")} existing row(s) in ${i} will get the default for ${a}`);
788
- }
789
- if (r.length !== 0) {
790
- console.log("\n existing rows that a default will fill:");
791
- for (let e of r) console.log(e);
792
- console.log(" (the shape is correct either way — this is the VALUE a state diff cannot know)");
793
- }
794
- }, X = async (e, t) => {
795
- if (W() !== "postgres") return;
796
- let n = ae, r;
797
- try {
798
- r = await J(t, b.SqlClient.pipe(g.flatMap((t) => ue(t, e, n))));
799
- } catch {
800
- return;
801
- }
802
- let i = pe({
803
- tables: e,
804
- dialect: "postgres",
805
- missing: r.missing,
806
- stale: r.stale,
807
- channel: n
808
- });
809
- if (i.length === 0) return;
810
- R.info(`db apply: installing change triggers on ${r.missing.length} table(s)` + (r.stale.length > 0 ? `, removing ${r.stale.length} stale one(s)` : ""));
811
- let a = 0;
812
- for (let e of i) await J(t, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(e)))), a += 1;
813
- R.info(`db apply: change triggers converged (${a} statement(s))`, {
814
- installed: r.missing.length,
815
- removed: r.stale.length
816
- });
817
- }, Z = (e) => {
818
- let t = e.summary, n = e.operations.length;
819
- if (console.log(`\nschema diff: ${n} operation${n === 1 ? "" : "s"}, ${t.blocked} blocked\n`), n === 0) {
820
- console.log(" (schema is up to date)\n");
821
- return;
822
- }
823
- for (let t of e.operations) console.log(Ye(t));
824
- console.log(), console.log(` safe: ${t.safe} needs-default: ${t.needsDefault} needs-backfill: ${t.needsBackfill}`), console.log(` rename: ${t.needsRenameAnnotation} lossy: ${t.lossy} blocked: ${t.blocked}`), console.log(` fingerprint: ${e.fromFingerprint.slice(0, 16)} → ${e.toFingerprint.slice(0, 16)}\n`), Ze(e);
825
- }, Ze = (e) => {
826
- let t = he(e.operations);
827
- if (t.length !== 0) {
828
- console.log(` ⚠ ${t.length} operation(s) UNSAFE under a rolling deploy`), console.log(" (old + new instances overlap → old code breaks against the new schema):");
829
- for (let e of t) console.log(` • ${e.op.op.kind}: ${e.reason}`), console.log(` → ${e.remedy}`);
830
- console.log(" Deploy with a maintenance window / scale-to-zero, or split into"), console.log(" expand → deploy → contract. See docs: deployment/production-hardening.\n");
831
- }
832
- }, Qe = (e, t) => {
833
- let n = se({
834
- enabled: process.env.VOLTRO_ROLLING_DEPLOY === "1",
835
- forced: t.includes("--force"),
836
- unsafeCount: he(e.operations).length
837
- });
838
- return n.refuse ? (R.error(`db apply: ${n.message}`), !0) : (n.warnForced && R.warn(`db apply: ${n.message}`), !1);
839
- }, $e = (e) => {
840
- let t = l(e, "--online-after") ?? process.env.VOLTRO_ONLINE_THRESHOLD;
841
- if (t === void 0) return;
842
- let n = Number(t);
843
- if (!Number.isInteger(n) || n < 0) throw Error(`--online-after / VOLTRO_ONLINE_THRESHOLD must be a non-negative integer, got "${t}"`);
844
- return n;
845
- }, Q = async (e) => {
846
- let t = await We(e);
847
- if (t.length === 0) return;
848
- let n = await o({ root: e });
849
- return Ge(Ke([
850
- ...t,
851
- ...x,
852
- ...n
853
- ]));
854
- }, et = async (e) => {
855
- let t = $e(e), n = B(e), r = await Q(n);
856
- if (r === void 0) return R.warn("db plan: no schema files found", {
857
- root: n,
858
- hint: "looked for *.entity.ts / *.schema.ts / schema.ts"
859
- }), 1;
860
- let i = l(e, "--against");
861
- if (i) {
862
- let n = i, a = l(e, "--token") ?? process.env.VOLTRO_INSPECT_TOKEN, o = { accept: "application/json" };
863
- a && (o.authorization = `Bearer ${a}`);
864
- try {
865
- let e = n.endsWith("/_voltro/inspect/migrations") ? n : `${n.replace(/\/+$/, "")}/_voltro/inspect/migrations`, i = await fetch(e, { headers: o });
866
- if (!i.ok) return R.error(`db plan --against: remote returned ${i.status}`, { url: e }), 1;
867
- let a = (await i.json()).drift?.liveSnapshot;
868
- if (!a) return R.error("db plan --against: remote inspect payload missing drift.liveSnapshot", { url: e }), 1;
869
- let s = E({
870
- declared: r,
871
- live: a,
872
- dialect: W(),
873
- ...T(),
874
- ...t === void 0 ? {} : { onlineAfter: t }
875
- });
876
- return console.log(`\n[--against ${e}] — diff vs remote live schema:\n`), Z(s), s.summary.blocked > 0 ? 2 : 0;
877
- } catch (e) {
878
- return R.error(`db plan --against: ${e.message}`), 1;
879
- }
880
- }
881
- let a = E({
882
- declared: r,
883
- live: await Y(await q()),
884
- dialect: W(),
885
- ...T(),
886
- ...t === void 0 ? {} : { onlineAfter: t }
887
- });
888
- return e.includes("--json") ? (y(1, `${JSON.stringify(a, null, 2)}\n`), a.summary.blocked > 0 ? 2 : 0) : (Z(a), a.summary.blocked > 0 ? 2 : 0);
889
- }, tt = async (e, t, n) => {
890
- let r;
891
- try {
892
- let t = await v.readFile(m(e), "utf8");
893
- r = JSON.parse(t);
894
- } catch (t) {
895
- return R.error(`db apply --plan: cannot read/parse plan file '${e}': ${t.message}`), 1;
896
- }
897
- if (!Array.isArray(r?.operations) || typeof r?.fromFingerprint != "string" || typeof r?.toFingerprint != "string") return R.error(`db apply --plan: '${e}' is not a valid plan file (expected the output of \`voltro db plan --json\`).`), 1;
898
- let i = await Q(n);
899
- if (i === void 0) return R.warn("db apply --plan: no schema files found", { root: n }), 1;
900
- let a = await q();
901
- await J(a, C(x, W()));
902
- let o = await J(a, b.SqlClient.pipe(g.flatMap((e) => fe(e, n)))).catch(() => []);
903
- if (o.length > 0) return R.error(`db apply --plan: refusing — ${o.length} pending file-based migration(s).`), console.error(` ${o.join("\n ")}`), console.error(""), console.error(" These perform the changes a state diff cannot infer, so they change the shape"), console.error(" this plan was computed against. Apply them and regenerate the plan:"), console.error(""), console.error(" voltro db files ."), console.error(" voltro db plan --json > plan.json"), console.error(" voltro db apply --plan plan.json"), 1;
904
- let s = E({
905
- declared: i,
906
- live: await Y(a),
907
- dialect: W(),
908
- ...T()
909
- });
910
- if (s.fromFingerprint !== r.fromFingerprint) return R.error("db apply --plan: refusing — the live schema has drifted since this plan was generated."), console.error(` plan.from=${r.fromFingerprint.slice(0, 16)} live=${s.fromFingerprint.slice(0, 16)}`), console.error(" Regenerate against the current live schema: `voltro db plan --json > plan.json`"), 2;
911
- if (s.toFingerprint !== r.toFingerprint) return R.error("db apply --plan: refusing — the declared schema differs from what this plan targets."), console.error(` plan.to=${r.toFingerprint.slice(0, 16)} declared=${s.toFingerprint.slice(0, 16)}`), console.error(" The schema files changed since the plan was generated. Regenerate the plan."), 2;
912
- let c = qe(s), u = c.plan;
913
- if (u.summary.blocked > 0 && !c.acknowledged) return Z(u), R.error(`db apply --plan: refusing — ${s.summary.blocked} blocked operation(s). See the fix hints above.`), process.env.VOLTRO_DESTRUCTIVE_OK !== void 0 && (R.error(" VOLTRO_DESTRUCTIVE_OK is set but did not cover this plan — it only relaxes"), R.error(" `lossy` operations, and only the tables it names. Anything else stays refused.")), 2;
914
- if (c.acknowledged && R.warn("db apply --plan: proceeding with acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)"), Qe(u, t)) return 2;
915
- if (u.operations.length === 0) return R.info("db apply --plan: schema is up to date — no DDL to apply (change triggers are reconciled separately below)"), await X(i, a), 0;
916
- Z(u);
917
- let d = (process.env.NODE_ENV ?? "dev").toLowerCase(), f = l(t, "--note"), p = await J(a, b.SqlClient.pipe(g.flatMap((e) => oe(e, u, {
918
- declared: i,
919
- appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:plan",
920
- environment: d === "production" ? "prod" : d === "staging" ? "staging" : "dev",
921
- source: "file",
922
- ...f ? { notes: f } : {},
923
- replan: () => g.promise(() => Y(a)).pipe(g.map((e) => E({
924
- declared: i,
925
- live: e,
926
- dialect: W(),
927
- ...T()
928
- })))
929
- }))));
930
- return R.info(`db apply --plan: applied ${p.appliedOps} op(s) in ${p.durationMs}ms`, {
931
- id: p.id,
932
- fingerprint: p.fingerprint.slice(0, 16)
933
- }), await X(i, a), 0;
934
- }, nt = async (e) => {
935
- let t = B(e), n = $e(e), r = l(e, "--plan");
936
- if (r) return tt(r, e, t);
937
- if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return R.error("voltro db apply: refusing — auto-apply on prod is not allowed."), console.error("In production, schema changes go through `voltro db plan --json > plan.json`"), console.error("then `voltro db apply --plan plan.json` as an explicit step in your deploy pipeline."), 3;
938
- let i = await Q(t);
939
- if (i === void 0) return R.warn("db apply: no schema files found", { root: t }), 1;
940
- let a = await q(), o = await dt(t, a);
941
- if ("failed" in o) return R.error("db apply: a file-based migration FAILED — the schema diff was NOT run"), console.error(o.failed), console.error("Fix the migration and re-run. `voltro db files` runs them alone."), 1;
942
- await J(a, C(x, W()));
943
- let s = E({
944
- declared: i,
945
- live: await Y(a),
946
- dialect: W(),
947
- ...T(),
948
- ...n === void 0 ? {} : { onlineAfter: n }
949
- });
950
- Z(s), await Xe(s, a);
951
- let c = qe(s), u = c.plan;
952
- if (u.summary.blocked > 0 && !c.acknowledged) return R.error(`db apply: refusing — ${u.summary.blocked} blocked operation(s). See the fix hints above.`), process.env.VOLTRO_DESTRUCTIVE_OK !== void 0 && (R.error(" VOLTRO_DESTRUCTIVE_OK is set but did not cover this plan — it only relaxes"), R.error(" `lossy` operations, and only the tables it names. Anything else stays refused.")), 2;
953
- if (c.acknowledged && R.warn(`db apply: proceeding with ${s.summary.blocked} acknowledged lossy operation(s) (VOLTRO_DESTRUCTIVE_OK)`), Qe(u, e)) return 2;
954
- if (u.operations.length === 0) return R.info("db apply: schema is up to date — no DDL to apply (change triggers are reconciled separately below)"), await st(a), l(e, "--note") !== void 0 && (R.warn("db apply: --note was ignored — an empty plan writes no history row to attach it to."), console.error("To record that the CURRENT live schema is the accepted baseline, use `voltro db drift --accept`.")), await X(i, a), 0;
955
- let d = l(e, "--note"), f = await J(a, b.SqlClient.pipe(g.flatMap((e) => oe(e, u, {
956
- declared: i,
957
- appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user",
958
- environment: (process.env.NODE_ENV ?? "dev").toLowerCase() === "staging" ? "staging" : "dev",
959
- source: "auto-diff",
960
- ...d ? { notes: d } : {},
961
- replan: () => g.promise(() => Y(a)).pipe(g.map((e) => E({
962
- declared: i,
963
- live: e,
964
- dialect: W(),
965
- ...T(),
966
- ...n === void 0 ? {} : { onlineAfter: n }
967
- })))
968
- }))));
969
- return R.info(`db apply: applied ${f.appliedOps} op(s) in ${f.durationMs}ms`, {
970
- id: f.id,
971
- fingerprint: f.fingerprint.slice(0, 16)
972
- }), await X(i, a), 0;
973
- }, rt = async (e) => {
974
- let t = Math.max(1, Number(l(e, "--limit") ?? "20")), n = await J(await q(), b.SqlClient.pipe(g.flatMap((e) => e`
975
- SELECT ${e("id")}, ${e("fingerprint")}, ${e("operations")},
976
- ${e("appliedBy")}, ${e("environment")}, ${e("source")},
977
- ${e("durationMs")}, ${e("notes")}, ${e("appliedAt")}
978
- FROM ${e("_voltro_migration_plans")}
979
- ORDER BY ${e("appliedAt")} DESC
980
- LIMIT ${t}
981
- `)));
982
- if (n.length === 0) return R.info("db plans: no planner-based migrations applied yet"), console.log("Run `voltro db apply` after a schema change to start a plan history."), 0;
983
- console.log(`\n${n.length} plan${n.length === 1 ? "" : "s"} (newest first):\n`);
984
- for (let e of n) {
985
- let t = 0;
986
- try {
987
- t = JSON.parse(ct(e.operations)).length;
988
- } catch {}
989
- console.log(` ${e.id} fp=${D(e.fingerprint)} env=${e.environment} src=${e.source} ${t} op(s) ${e.durationMs}ms ${$(e.appliedAt)} by=${e.appliedBy}`), e.notes && console.log(` [2mnote: ${e.notes}[0m`);
990
- }
991
- return console.log(), 0;
992
- }, it = async (e) => {
993
- let t = e[0];
994
- if (!t) return console.error("voltro db restore-snapshot <plan-id>"), console.error(" Renames soft-dropped columns/tables from a plan back to their original names."), console.error(" Requires the plan to have been applied with VOLTRO_SOFT_DROP=1."), 2;
995
- let n = await q(), r = await J(n, b.SqlClient.pipe(g.flatMap((e) => e`SELECT ${e("id")}, ${e("operations")}
996
- FROM ${e("_voltro_migration_plans")} WHERE ${e("id")} = ${t}`)));
997
- if (r.length === 0) return console.error(`restore-snapshot: plan '${t}' not found`), 1;
998
- let i;
999
- try {
1000
- i = JSON.parse(ct(r[0].operations));
1001
- } catch {
1002
- return console.error(`restore-snapshot: plan '${t}' has corrupted operations JSON`), 1;
1003
- }
1004
- let a = [];
1005
- for (let e of i) e.op?.kind === "drop-column" && e.op.table && e.op.column && a.push({
1006
- table: e.op.table,
1007
- column: e.op.column
1008
- });
1009
- let o = [];
1010
- for (let e of i) e.op?.kind === "drop-table" && e.op.table && o.push({ table: e.op.table });
1011
- if (a.length === 0 && o.length === 0) return console.log(`restore-snapshot: plan '${t}' has no drop-column / drop-table ops to restore`), 0;
1012
- let s = 0;
1013
- for (let e of a) {
1014
- let t = await J(n, b.SqlClient.pipe(g.flatMap((t) => t`
1015
- SELECT column_name FROM information_schema.columns
1016
- WHERE ${t.unsafe(K(W()))}
1017
- AND table_name = ${e.table}
1018
- AND column_name LIKE ${e.column + "__dropped_%"}
1019
- ORDER BY column_name DESC LIMIT 1
1020
- `)));
1021
- if (t.length === 0) {
1022
- console.warn(`restore-snapshot: no snapshot found for ${e.table}.${e.column} — was the plan applied with VOLTRO_SOFT_DROP=1?`);
1023
- continue;
1024
- }
1025
- let r = t[0].column_name;
1026
- await J(n, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table)} RENAME COLUMN ${G(r)} TO ${G(e.column)}`)))), s++, console.log(` ↩ restored ${e.table}.${e.column} (from ${r})`);
1027
- }
1028
- let c = 0;
1029
- for (let e of o) {
1030
- let t = await J(n, b.SqlClient.pipe(g.flatMap((t) => t`
1031
- SELECT table_name FROM information_schema.tables
1032
- WHERE ${t.unsafe(K(W()))}
1033
- AND table_name LIKE ${e.table + "__dropped_%"}
1034
- ORDER BY table_name DESC LIMIT 1
1035
- `)));
1036
- if (t.length === 0) {
1037
- console.warn(`restore-snapshot: no snapshot found for table ${e.table} — was the plan applied with VOLTRO_SOFT_DROP=1?`);
1038
- continue;
1039
- }
1040
- let r = t[0].table_name;
1041
- await J(n, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(`ALTER TABLE ${G(r)} RENAME TO ${G(e.table)}`)))), c++, console.log(` ↩ restored table ${e.table} (from ${r})`);
1042
- }
1043
- return console.log(`\n✓ restored ${s} column(s) + ${c} table(s) from plan '${t}'\n`), 0;
1044
- }, at = async (e) => {
1045
- let t = l(e, "--before");
1046
- if (!t) return console.error("voltro db gc-snapshots --before <date> [--dry-run]"), console.error(" Permanently drops soft-dropped columns/tables (<name>__dropped_<ts>) older than <date>."), console.error(" <date> is ISO — e.g. 2026-01-01 or 2026-01-01T00:00:00Z. NOT reversible."), 2;
1047
- let n = t.replace(/[^0-9]/g, "");
1048
- if (n.length < 8) return console.error(`gc-snapshots: --before must be at least a full date (YYYY-MM-DD), got "${t}"`), 2;
1049
- let r = (n + "00000000000000").slice(0, 14), i = e.includes("--dry-run"), a = await q(), o = await J(a, b.SqlClient.pipe(g.flatMap((e) => e`
1050
- SELECT table_name, column_name FROM information_schema.columns
1051
- WHERE ${e.unsafe(K(W()))} AND column_name LIKE ${"%__dropped_%"}
1052
- `))), s = await J(a, b.SqlClient.pipe(g.flatMap((e) => e`
1053
- SELECT table_name FROM information_schema.tables
1054
- WHERE ${e.unsafe(K(W()))} AND table_name LIKE ${"%__dropped_%"}
1055
- `))), c = (e) => {
1056
- let t = /__dropped_(\d{14})$/.exec(e);
1057
- return t ? t[1] : null;
1058
- }, u = 0;
1059
- for (let e of o) {
1060
- let t = c(e.column_name);
1061
- t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop column" : "dropping column"} ${e.table_name}.${e.column_name}`), i || await J(a, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(`ALTER TABLE ${G(e.table_name)} DROP COLUMN ${G(e.column_name)}`)))), u++);
1062
- }
1063
- for (let e of s) {
1064
- let t = c(e.table_name);
1065
- t === null || t >= r || (console.log(` ${i ? "[dry-run] would drop table" : "dropping table"} ${e.table_name}`), i || await J(a, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(`DROP TABLE ${G(e.table_name)}`)))), u++);
1066
- }
1067
- return console.log(`\n${i ? `[dry-run] ${u} snapshot(s) would be dropped` : `✓ dropped ${u} snapshot(s)`} (older than ${r}).\n`), 0;
1068
- }, ot = async (e) => {
1069
- let t = l(e, "--before");
1070
- if (!t) return console.error("voltro db squash --before <iso-date> [--note \"<text>\"]"), 2;
1071
- let n = t;
1072
- if (Number.isNaN(new Date(n).getTime())) return console.error(`voltro db squash: --before '${n}' is not a valid ISO date`), 2;
1073
- let r = l(e, "--note"), i = B(e), a = await Q(i);
1074
- if (a === void 0) return R.warn("db squash: no schema files found", { root: i }), 1;
1075
- let o = w(ce(a)), s = await q();
1076
- try {
1077
- let e = await J(s, _e({
1078
- before: n,
1079
- fingerprint: o,
1080
- appliedBy: process.env.USER ?? "cli",
1081
- environment: process.env.NODE_ENV === "production" ? "prod" : "dev",
1082
- ...r === void 0 ? {} : { note: r }
1083
- }));
1084
- return console.log(`\n✓ squashed ${e.squashedCount} migration plan(s)\n snapshot id: ${e.snapshotId}\n fingerprint: ${D(e.snapshotFingerprint)}\n`), 0;
1085
- } catch (e) {
1086
- return console.error(`squash refused: ${e.message}`), 1;
1087
- }
1088
- }, st = async (e) => {
1089
- try {
1090
- let t = w(await Y(e));
1091
- await J(e, b.SqlClient.pipe(g.flatMap((e) => e`
1092
- UPDATE ${e("_voltro_migration_plans")}
1093
- SET ${e("liveFingerprint")} = ${t}
1094
- WHERE ${e("id")} = (
1095
- SELECT ${e("id")} FROM (
1096
- SELECT ${e("id")} FROM ${e("_voltro_migration_plans")}
1097
- ORDER BY ${e("appliedAt")} DESC LIMIT 1
1098
- ) AS ${e("newest")}
1099
- )
1100
- AND ${e("liveFingerprint")} IS NULL
1101
- `)));
1102
- } catch {}
1103
- }, ct = (e) => typeof e == "string" ? e : e == null ? "" : JSON.stringify(e), $ = (e) => e instanceof Date ? e.toISOString() : String(e ?? ""), lt = (e) => e === void 0 ? {
1104
- accept: !1,
1105
- reason: "no-declared-schema"
1106
- } : e > 0 ? {
1107
- accept: !1,
1108
- reason: "pending"
1109
- } : {
1110
- accept: !0,
1111
- reason: "converged"
1112
- }, ut = async (e) => {
1113
- let t = e.includes("--accept"), n = await q(), r = await J(n, b.SqlClient.pipe(g.flatMap((e) => e`
1114
- SELECT * FROM ${e("_voltro_migration_plans")}
1115
- ORDER BY ${e("appliedAt")} DESC
1116
- LIMIT 1
1117
- `))), i = await Y(n), a = w(i);
1118
- if (r.length === 0) return R.info("db drift: no _voltro_migration_plans rows yet"), console.log(`live user-schema fingerprint: ${D(a)}`), console.log("No baseline to compare against. Run `voltro db apply` to lock in the current state."), 0;
1119
- let o = r[0];
1120
- if (o.liveFingerprint === null || o.liveFingerprint === void 0) return R.warn("db drift: no drift baseline recorded yet — cannot compare"), console.log(), console.log(` last applied: ${o.id} at ${$(o.appliedAt)}`), console.log(` live now: ${D(a)}`), console.log(), console.log("That row was written before the framework recorded a live-schema baseline,"), console.log("and the value it does carry is the DECLARED snapshot's hash — not comparable"), console.log("with a live one. Run `voltro db apply` once to establish the baseline (a no-op"), console.log("apply backfills it too); use `voltro db plan` meanwhile, which compares declared"), console.log("against live directly."), console.log(), console.log("Exit code 3 — NOT 0. \"Did not compare\" is not \"clean\", and a gate on the exit"), console.log("code has to be able to tell them apart."), 3;
1121
- if (o.liveFingerprint === a) return R.info(`db drift: live matches last applied (${D(a)})`), 0;
1122
- let s = await (async () => {
1123
- try {
1124
- let t = await Q(B(e));
1125
- return t === void 0 ? void 0 : E({
1126
- declared: t,
1127
- live: i,
1128
- dialect: W(),
1129
- ...T()
1130
- }).operations;
1131
- } catch {
1132
- return;
1133
- }
1134
- })();
1135
- if (t) {
1136
- let e = lt(s?.length);
1137
- if (e.reason === "no-declared-schema") return R.error("db drift --accept: no schema files found — cannot verify the live schema is current."), 1;
1138
- if (!e.accept && s !== void 0) {
1139
- R.error(`db drift --accept: refusing — ${s.length} operation(s) still pending against your declared schema.`), console.log();
1140
- for (let e of s.slice(0, 10)) console.log(` - ${e.op.kind} ${"table" in e.op ? `[${e.op.table}]` : ""}`);
1141
- return s.length > 10 && console.log(` … and ${s.length - 10} more`), console.log(), console.log("`--accept` records the CURRENT live schema as the applied baseline. It is for a"), console.log("change that already landed out of band and left the schema correct — not for one"), console.log("that has not landed. Run `voltro db apply` instead; it writes a real baseline."), 4;
1142
- }
1143
- return await J(n, b.SqlClient.pipe(g.flatMap((e) => e`
1144
- UPDATE ${e("_voltro_migration_plans")}
1145
- SET ${e("liveFingerprint")} = ${a}
1146
- WHERE ${e("id")} = (
1147
- SELECT ${e("id")} FROM (
1148
- SELECT ${e("id")} FROM ${e("_voltro_migration_plans")}
1149
- ORDER BY ${e("appliedAt")} DESC LIMIT 1
1150
- ) AS ${e("newest")}
1151
- )
1152
- `))), R.info(`db drift: accepted the live schema as the baseline (${D(a)})`), console.log(), console.log("`voltro db plan` reports 0 operations against this schema, so the live state already"), console.log("matches your declaration — only the ledger did not know. It does now."), console.log(), console.log("No history entry was invented: the latest row's baseline was updated in place,"), console.log("because no migration ran."), 0;
1153
- }
1154
- return R.error("db drift: live schema DIVERGED from last applied state"), console.log(), console.log(` baseline: ${D(o.liveFingerprint)} at ${$(o.appliedAt)} (${o.id})`), console.log(` live now: ${D(a)}`), console.log(), console.log("Something changed the live schema after the last apply. This command can see"), console.log("THAT it changed, not what or who — the fingerprints are hashes, not a diff."), console.log(), s === void 0 ? (console.log("No schema files found here, so the declared side could not be compared."), console.log("Run `voltro db plan` from your project root for the actual difference."), 4) : s.length === 0 ? (console.log("Your DECLARED schema is already satisfied — `voltro db plan` reports 0 operations"), console.log("against this database. So the live schema is not wrong, only unrecorded: something"), console.log("applied a change without going through the planner (a hand-run ALTER, a DBA"), console.log("window, a restored dump), or it touched a table your code does not declare."), console.log(), console.log("If that was deliberate and the schema is right, record it:"), console.log(), console.log(" voltro db drift --accept"), console.log(), console.log("It updates the latest ledger row's baseline to the live schema and invents no"), console.log("history entry. Drift then measures from here."), 4) : (console.log(`\`voltro db plan\` reports ${s.length} operation(s) still pending against your`), console.log("declared schema, so this is not merely an unrecorded change — run it for the diff,"), console.log("then `voltro db apply`, which writes a fresh baseline of its own."), 4);
1155
- }, dt = async (e, t) => {
1156
- let n = (process.env.NODE_ENV ?? "").toLowerCase() === "production" ? "prod" : (process.env.NODE_ENV ?? "").toLowerCase() === "staging" ? "staging" : "dev";
1157
- try {
1158
- let r = await J(t, b.SqlClient.pipe(g.flatMap((t) => ge(t, {
1159
- projectRoot: e,
1160
- env: n,
1161
- appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
1162
- }))));
1163
- return r.applied.length > 0 && R.info(`db apply: applied ${r.applied.length} pending file-based migration(s) first`, { applied: r.applied.map((e) => `${e.id} (${e.durationMs}ms)`) }), { applied: r.applied.length };
1164
- } catch (e) {
1165
- return { failed: e };
1166
- }
1167
- }, ft = async (e) => {
1168
- let t = B(e), n = await q(), r = (process.env.NODE_ENV ?? "").toLowerCase() === "production" ? "prod" : (process.env.NODE_ENV ?? "").toLowerCase() === "staging" ? "staging" : "dev";
1169
- await J(n, C(x, W()));
1170
- let i = await J(n, b.SqlClient.pipe(g.flatMap((e) => ge(e, {
1171
- projectRoot: t,
1172
- env: r,
1173
- appliedBy: process.env.USER ? `cli:${process.env.USER}` : "cli:user"
1174
- }))));
1175
- return i.applied.length === 0 ? (R.info(`db files: no pending file-based migrations (${i.skipped.length} already applied)`), 0) : (R.info(`db files: applied ${i.applied.length} migration(s)`, {
1176
- applied: i.applied.map((e) => `${e.id} (${e.durationMs}ms)`),
1177
- skipped: i.skipped.length
1178
- }), 0);
1179
- }, pt = async (e) => {
1180
- let t = B(e), n = e.find((e) => !e.startsWith("--"));
1181
- if (!n) return R.error("voltro db rollback-file <migration-id>"), 2;
1182
- if ((process.env.NODE_ENV ?? "").toLowerCase() === "production") return R.error("voltro db rollback-file: refusing on prod — schema rollback runs as an explicit deploy step."), 3;
1183
- let r = await J(await q(), b.SqlClient.pipe(g.flatMap((e) => me(e, {
1184
- projectRoot: t,
1185
- id: n
1186
- }))));
1187
- return R.info(`db rollback-file: rolled back ${r.id} in ${r.durationMs}ms`), 0;
1188
- }, mt = () => {
1189
- let e = /* @__PURE__ */ new Date();
1190
- return [
1191
- e.getUTCFullYear(),
1192
- String(e.getUTCMonth() + 1).padStart(2, "0"),
1193
- String(e.getUTCDate()).padStart(2, "0"),
1194
- String(e.getUTCHours()).padStart(2, "0"),
1195
- String(e.getUTCMinutes()).padStart(2, "0"),
1196
- String(e.getUTCSeconds()).padStart(2, "0")
1197
- ].join("");
1198
- }, ht = (e) => e.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "migration", gt = (e, t) => `import { defineMigration, SqlClient } from '@voltro/database'
1199
- import { Effect } from 'effect'
1200
-
1201
- // A hand-written migration. Reach for this when the DECLARATIVE differ can't
1202
- // express the change — a data backfill, a value re-encode, a table rename that
1203
- // must preserve rows. For plain schema shape changes (add a column/table/index)
1204
- // you usually DON'T need this: edit the entity + run \`voltro db apply\`, which
1205
- // diffs your declared schema against the live DB automatically.
1206
- //
1207
- // \`voltro db migrate\` applies every pending *.migration.ts in timestamp order
1208
- // and records each in \`_voltro_migrations\`; \`voltro db rollback\` runs \`undo\`.
1209
- export default defineMigration({
1210
- id: '${e}',
1211
- name: '${t}',
1212
- steps: ({ step }) => [
1213
- step('${t}', {
1214
- // Forward migration. Runs inside a transaction; the SqlClient is provided.
1215
- apply: Effect.gen(function* () {
1216
- const sql = yield* SqlClient.SqlClient
1217
- // TODO: your change, e.g.
1218
- // yield* sql\`ALTER TABLE widgets ADD COLUMN archived boolean NOT NULL DEFAULT false\`
1219
- }),
1220
- // The inverse — what \`voltro db rollback\` runs to undo the step. Keep it
1221
- // an exact reverse so a rollback restores the prior state.
1222
- undo: Effect.gen(function* () {
1223
- const sql = yield* SqlClient.SqlClient
1224
- // TODO: reverse the apply above, e.g.
1225
- // yield* sql\`ALTER TABLE widgets DROP COLUMN archived\`
1226
- }),
1227
- }),
1228
- ],
1229
- })
1230
- `, _t = {
1231
- plan: et,
1232
- apply: nt,
1233
- plans: rt,
1234
- drift: ut,
1235
- files: ft,
1236
- "rollback-file": pt,
1237
- migrate: Re,
1238
- rollback: ze,
1239
- status: Be,
1240
- seed: He,
1241
- generate: async (e) => {
1242
- let { value: t, rest: n } = c(e, "--root"), { value: r, rest: i } = c(n, "--name"), a = t ? m(t) : process.cwd(), o = ht(r ?? u(i) ?? "migration"), s = `${mt()}_${o}`, l = f(a, "migrations"), d = f(l, `${s}.migration.ts`);
1243
- return await v.mkdir(l, { recursive: !0 }), await v.writeFile(d, gt(s, o), "utf8"), R.info(`created ${p(a, d)}`), console.error("Fill in the apply/undo steps, then run `voltro db migrate` (rollback with `voltro db rollback`)."), console.error("For a plain schema shape change you may not need this — `voltro db apply` diffs declared vs live."), 0;
1244
- },
1245
- squash: ot,
1246
- "restore-snapshot": it,
1247
- "gc-snapshots": at,
1248
- adopt: async (e) => {
1249
- let t = (t) => {
1250
- let n = e.indexOf(`--${t}`);
1251
- return n === -1 ? void 0 : e[n + 1];
1252
- }, n = t("from"), r = t("into"), i = t("map");
1253
- if (n === void 0 || r === void 0 || i === void 0) return console.error("voltro db adopt --from <table> --into <table> --map <file.ts> [--apply] [--keep-source]"), console.error(" Dry run unless --apply. The map file default-exports { map, leaveUnset? }."), 1;
1254
- let o = (await a(m(process.cwd(), i))).default;
1255
- if (o?.map === void 0) return console.error(`voltro db adopt: ${i} must default-export { map: { <targetColumn>: <source> } }`), 1;
1256
- let s = {
1257
- from: n,
1258
- into: r,
1259
- map: o.map,
1260
- ...o.leaveUnset ? { leaveUnset: o.leaveUnset } : {}
1261
- }, c = W(), l = await q(), u = await J(l, b.SqlClient.pipe(g.flatMap(de))), d = (e) => u.tables.find((t) => t.name === e)?.columns.map((e) => ({
1262
- name: e.name,
1263
- nullable: e.nullable,
1264
- hasDefault: e.defaultValue !== void 0 && e.defaultValue !== null
1265
- })), f = d(n), p = d(r);
1266
- if (f === void 0) return console.error(`voltro db adopt: '${n}' does not exist in the database`), 1;
1267
- if (p === void 0) return console.error(`voltro db adopt: '${r}' does not exist in the database — boot once so the plugin's table is created`), 1;
1268
- let h = async (e) => await J(l, b.SqlClient.pipe(g.flatMap((t) => t.unsafe(e)))), _ = async (e) => Number(Object.values((await h(`SELECT COUNT(*) AS n FROM "${e}"`))[0] ?? { n: 0 })[0] ?? 0), v = xe(s, f, p, await _(r));
1269
- for (let e of Ce(s, v, await _(n))) console.log(e);
1270
- if (v.fatal) return 1;
1271
- if (!e.includes("--apply")) return console.log(""), console.log(" (dry run — nothing written. Re-run with --apply.)"), 0;
1272
- let y = await Oe(s, v, c, "id", void 0, h, { keepSource: e.includes("--keep-source") });
1273
- return console.log(""), console.log(` copied ${y.copied}/${y.sourceRows} row(s)`), console.log(` snapshot: ${y.snapshotTable} — restore from here, then drop it yourself`), y.verified ? (console.log(y.sourceDropped ? ` dropped ${n}` : ` ${n} left in place (--keep-source)`), 0) : (console.error(" ✗ counts DIFFER — the source was NOT dropped. Compare the two tables before doing anything else."), 1);
1274
- },
1275
- "scan-credentials": async (e) => {
1276
- let t = W(), n = [];
1277
- for (let t = 0; t < e.length; t += 1) {
1278
- if (e[t] !== "--table") continue;
1279
- let r = e[t + 1];
1280
- if (r === void 0) throw new O("voltro db scan-credentials: --table needs a value");
1281
- let [i, a = "subject"] = r.split(":");
1282
- n.push({
1283
- table: i,
1284
- column: a
1285
- });
1286
- }
1287
- let r = [...ke, ...n], i = await J(await q(), b.SqlClient.pipe(g.flatMap((e) => g.promise(() => Me(e, t, r, G)))));
1288
- return console.log(Ne(i, t)), Pe(i);
1289
- }
1290
- }, vt = async (e) => {
1291
- let [t, ...n] = e;
1292
- if (!t) {
1293
- console.error("voltro db <subcommand> [args]"), console.error("subcommands:");
1294
- for (let e of Object.keys(_t)) console.error(` ${e}`);
1295
- return 1;
1296
- }
1297
- let r = _t[t];
1298
- if (!r) return console.error(`voltro db: unknown subcommand '${t}'`), 2;
1299
- (process.env.DB_DIRECT_URL !== void 0 || process.env.DB_MIGRATE_URL !== void 0) && R.info("using a DIRECT (non-pooler) connection for the db-command path (DB_DIRECT_URL/DB_MIGRATE_URL set)");
1300
- let i = (e) => {
1301
- H(e) ? R.error(U) : console.error(e), process.exit(1);
1302
- };
1303
- process.on("uncaughtException", i);
1304
- try {
1305
- return await r(n);
1306
- } finally {
1307
- process.off("uncaughtException", i);
1308
- }
1309
- };
1310
- //#endregion
1311
- export { Ge as a, O as c, lt as i, ye as l, V as n, H as o, We as r, vt as s, U as t };