@voltro/cli 0.1.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 (626) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +57 -0
  3. package/README.md +26 -0
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +20236 -0
  6. package/bin/voltro.mjs +43 -0
  7. package/dist/bin.d.ts +1 -0
  8. package/dist/bin.js +9 -0
  9. package/dist/commands-CfPH2Wf4.js +18061 -0
  10. package/dist/frameworkInspectState-CX2250XB.js +86 -0
  11. package/dist/index.d.ts +48 -0
  12. package/dist/index.js +5 -0
  13. package/dist/inspectState.d.ts +116 -0
  14. package/dist/inspectState.js +2 -0
  15. package/dist/startup.d.ts +26 -0
  16. package/dist/startup.js +2 -0
  17. package/dist/startupRunner-CRhuUl91.js +71 -0
  18. package/package.json +88 -0
  19. package/templates/AGENTS.core.md +258 -0
  20. package/templates/AGENTS.md +351 -0
  21. package/templates/agent-docs/_index.md +93 -0
  22. package/templates/agent-docs/_manifest.json +655 -0
  23. package/templates/agent-docs/ai.md +1845 -0
  24. package/templates/agent-docs/authentication.md +1788 -0
  25. package/templates/agent-docs/caching.md +624 -0
  26. package/templates/agent-docs/cli.md +1650 -0
  27. package/templates/agent-docs/configuration.md +295 -0
  28. package/templates/agent-docs/data.md +2172 -0
  29. package/templates/agent-docs/database/advancedqueries.md +1583 -0
  30. package/templates/agent-docs/database/columntypes.md +1200 -0
  31. package/templates/agent-docs/database/hosting.md +881 -0
  32. package/templates/agent-docs/database/migrations.md +2938 -0
  33. package/templates/agent-docs/database/misc.md +270 -0
  34. package/templates/agent-docs/database/overview.md +108 -0
  35. package/templates/agent-docs/database/querying.md +1622 -0
  36. package/templates/agent-docs/database/scaling.md +331 -0
  37. package/templates/agent-docs/database/schema.md +1458 -0
  38. package/templates/agent-docs/database/seedsdialects.md +1235 -0
  39. package/templates/agent-docs/database/transactions.md +285 -0
  40. package/templates/agent-docs/deployment.md +999 -0
  41. package/templates/agent-docs/internationalization.md +359 -0
  42. package/templates/agent-docs/introduction.md +438 -0
  43. package/templates/agent-docs/multi-tenancy.md +610 -0
  44. package/templates/agent-docs/observability.md +350 -0
  45. package/templates/agent-docs/plugins.md +1273 -0
  46. package/templates/agent-docs/reference.md +978 -0
  47. package/templates/agent-docs/routing.md +1553 -0
  48. package/templates/agent-docs/scheduling.md +666 -0
  49. package/templates/agent-docs/schema-driven-ui.md +607 -0
  50. package/templates/agent-docs/security.md +42 -0
  51. package/templates/agent-docs/templates/apibackends.md +3214 -0
  52. package/templates/agent-docs/templates/appshells.md +2062 -0
  53. package/templates/agent-docs/templates/custom.md +128 -0
  54. package/templates/agent-docs/templates/overview.md +122 -0
  55. package/templates/agent-docs/templates/serverless.md +315 -0
  56. package/templates/agent-docs/testing.md +376 -0
  57. package/templates/agent-docs/workflows.md +1351 -0
  58. package/templates/apps/api-ai/README.md +105 -0
  59. package/templates/apps/api-ai/actions/summarize.action.server.tsx +32 -0
  60. package/templates/apps/api-ai/actions/summarize.action.ts +33 -0
  61. package/templates/apps/api-ai/agents/support.agent.server.tsx +31 -0
  62. package/templates/apps/api-ai/agents/support.agent.tsx +27 -0
  63. package/templates/apps/api-ai/app.config.ts +57 -0
  64. package/templates/apps/api-ai/database/schema.ts +67 -0
  65. package/templates/apps/api-ai/package.json +27 -0
  66. package/templates/apps/api-ai/seeds/docs.seed.ts +67 -0
  67. package/templates/apps/api-ai/template.json +6 -0
  68. package/templates/apps/api-ai/tests/summarize.test.ts +50 -0
  69. package/templates/apps/api-ai/tools/searchDocs.tool.tsx +60 -0
  70. package/templates/apps/api-ai/tsconfig.json +5 -0
  71. package/templates/apps/api-auth/.env +17 -0
  72. package/templates/apps/api-auth/README.md +109 -0
  73. package/templates/apps/api-auth/actions/me.action.server.ts +20 -0
  74. package/templates/apps/api-auth/actions/me.action.ts +19 -0
  75. package/templates/apps/api-auth/app.config.ts +59 -0
  76. package/templates/apps/api-auth/database/schema.ts +26 -0
  77. package/templates/apps/api-auth/package.json +28 -0
  78. package/templates/apps/api-auth/template.json +6 -0
  79. package/templates/apps/api-auth/tests/me.test.ts +37 -0
  80. package/templates/apps/api-auth/tsconfig.json +5 -0
  81. package/templates/apps/api-backend/README.md +25 -0
  82. package/templates/apps/api-backend/app.config.ts +39 -0
  83. package/templates/apps/api-backend/database/schema.ts +57 -0
  84. package/templates/apps/api-backend/mutations/notes.create.mutation.server.ts +19 -0
  85. package/templates/apps/api-backend/mutations/notes.create.mutation.ts +37 -0
  86. package/templates/apps/api-backend/package.json +28 -0
  87. package/templates/apps/api-backend/queries/notes.query.server.ts +14 -0
  88. package/templates/apps/api-backend/queries/notes.query.ts +20 -0
  89. package/templates/apps/api-backend/template.json +6 -0
  90. package/templates/apps/api-backend/tests/notes.create.test.ts +50 -0
  91. package/templates/apps/api-backend/tsconfig.json +5 -0
  92. package/templates/apps/api-backend-deactivation/README.md +49 -0
  93. package/templates/apps/api-backend-deactivation/actions/users.get.action.server.ts +17 -0
  94. package/templates/apps/api-backend-deactivation/actions/users.get.action.ts +18 -0
  95. package/templates/apps/api-backend-deactivation/app.config.ts +20 -0
  96. package/templates/apps/api-backend-deactivation/database/schema.ts +41 -0
  97. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.server.ts +6 -0
  98. package/templates/apps/api-backend-deactivation/mutations/users.create.mutation.ts +16 -0
  99. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.server.ts +10 -0
  100. package/templates/apps/api-backend-deactivation/mutations/users.deactivate.mutation.ts +19 -0
  101. package/templates/apps/api-backend-deactivation/package.json +28 -0
  102. package/templates/apps/api-backend-deactivation/template.json +6 -0
  103. package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +47 -0
  104. package/templates/apps/api-backend-deactivation/tsconfig.json +5 -0
  105. package/templates/apps/api-backend-mail/README.md +39 -0
  106. package/templates/apps/api-backend-mail/actions/sendWelcome.action.server.ts +15 -0
  107. package/templates/apps/api-backend-mail/actions/sendWelcome.action.ts +21 -0
  108. package/templates/apps/api-backend-mail/app.config.ts +34 -0
  109. package/templates/apps/api-backend-mail/database/schema.ts +57 -0
  110. package/templates/apps/api-backend-mail/emails/welcome.email.tsx +106 -0
  111. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.server.ts +19 -0
  112. package/templates/apps/api-backend-mail/mutations/notes.create.mutation.ts +37 -0
  113. package/templates/apps/api-backend-mail/package.json +30 -0
  114. package/templates/apps/api-backend-mail/queries/notes.query.server.ts +14 -0
  115. package/templates/apps/api-backend-mail/queries/notes.query.ts +20 -0
  116. package/templates/apps/api-backend-mail/template.json +6 -0
  117. package/templates/apps/api-backend-mail/tests/notes.create.test.ts +50 -0
  118. package/templates/apps/api-backend-mail/tsconfig.json +5 -0
  119. package/templates/apps/api-backend-mariadb/.env.example +35 -0
  120. package/templates/apps/api-backend-mariadb/README.md +31 -0
  121. package/templates/apps/api-backend-mariadb/app.config.ts +68 -0
  122. package/templates/apps/api-backend-mariadb/database/schema.ts +57 -0
  123. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.server.ts +19 -0
  124. package/templates/apps/api-backend-mariadb/mutations/notes.create.mutation.ts +37 -0
  125. package/templates/apps/api-backend-mariadb/package.json +30 -0
  126. package/templates/apps/api-backend-mariadb/queries/notes.query.server.ts +14 -0
  127. package/templates/apps/api-backend-mariadb/queries/notes.query.ts +20 -0
  128. package/templates/apps/api-backend-mariadb/template.json +6 -0
  129. package/templates/apps/api-backend-mariadb/tests/notes.create.test.ts +50 -0
  130. package/templates/apps/api-backend-mariadb/tsconfig.json +5 -0
  131. package/templates/apps/api-backend-storage/README.md +86 -0
  132. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.server.ts +21 -0
  133. package/templates/apps/api-backend-storage/actions/uploadAvatar.action.ts +21 -0
  134. package/templates/apps/api-backend-storage/actions/uploadDocument.action.server.ts +21 -0
  135. package/templates/apps/api-backend-storage/actions/uploadDocument.action.ts +20 -0
  136. package/templates/apps/api-backend-storage/app.config.ts +38 -0
  137. package/templates/apps/api-backend-storage/database/schema.ts +57 -0
  138. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.server.ts +19 -0
  139. package/templates/apps/api-backend-storage/mutations/notes.create.mutation.ts +37 -0
  140. package/templates/apps/api-backend-storage/package.json +27 -0
  141. package/templates/apps/api-backend-storage/queries/notes.query.server.ts +14 -0
  142. package/templates/apps/api-backend-storage/queries/notes.query.ts +20 -0
  143. package/templates/apps/api-backend-storage/template.json +6 -0
  144. package/templates/apps/api-backend-storage/tests/notes.create.test.ts +50 -0
  145. package/templates/apps/api-backend-storage/tsconfig.json +5 -0
  146. package/templates/apps/api-data-advanced/.env +17 -0
  147. package/templates/apps/api-data-advanced/README.md +88 -0
  148. package/templates/apps/api-data-advanced/app.config.ts +56 -0
  149. package/templates/apps/api-data-advanced/database/actors.entity.ts +14 -0
  150. package/templates/apps/api-data-advanced/database/authors.entity.ts +30 -0
  151. package/templates/apps/api-data-advanced/database/authors.relations.ts +15 -0
  152. package/templates/apps/api-data-advanced/database/books.entity.ts +59 -0
  153. package/templates/apps/api-data-advanced/database/books.relations.ts +10 -0
  154. package/templates/apps/api-data-advanced/database/index.ts +23 -0
  155. package/templates/apps/api-data-advanced/database/tenants.entity.ts +11 -0
  156. package/templates/apps/api-data-advanced/package.json +28 -0
  157. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.server.ts +18 -0
  158. package/templates/apps/api-data-advanced/queries/authors.withBooks.query.ts +40 -0
  159. package/templates/apps/api-data-advanced/queries/books.search.query.server.ts +17 -0
  160. package/templates/apps/api-data-advanced/queries/books.search.query.ts +39 -0
  161. package/templates/apps/api-data-advanced/seeds/catalog.seed.ts +101 -0
  162. package/templates/apps/api-data-advanced/template.json +6 -0
  163. package/templates/apps/api-data-advanced/tests/queries.test.ts +124 -0
  164. package/templates/apps/api-data-advanced/tsconfig.json +5 -0
  165. package/templates/apps/api-durable/README.md +81 -0
  166. package/templates/apps/api-durable/aggregates/orderStats.aggregate.ts +49 -0
  167. package/templates/apps/api-durable/app.config.ts +41 -0
  168. package/templates/apps/api-durable/database/schema.ts +65 -0
  169. package/templates/apps/api-durable/mutations/orders.approve.mutation.server.ts +43 -0
  170. package/templates/apps/api-durable/mutations/orders.approve.mutation.ts +23 -0
  171. package/templates/apps/api-durable/mutations/orders.place.mutation.server.ts +45 -0
  172. package/templates/apps/api-durable/mutations/orders.place.mutation.ts +40 -0
  173. package/templates/apps/api-durable/package.json +28 -0
  174. package/templates/apps/api-durable/schedules/nightlyReport.cron.tsx +37 -0
  175. package/templates/apps/api-durable/startup/warm.startup.tsx +33 -0
  176. package/templates/apps/api-durable/subscribers/orderChanges.subscribe.ts +27 -0
  177. package/templates/apps/api-durable/template.json +6 -0
  178. package/templates/apps/api-durable/tests/orders.place.test.ts +91 -0
  179. package/templates/apps/api-durable/triggers/order.placed.trigger.tsx +21 -0
  180. package/templates/apps/api-durable/tsconfig.json +5 -0
  181. package/templates/apps/api-durable/workflows/order.fulfill.workflow.server.tsx +103 -0
  182. package/templates/apps/api-durable/workflows/order.fulfill.workflow.tsx +25 -0
  183. package/templates/apps/api-feature-flags/README.md +63 -0
  184. package/templates/apps/api-feature-flags/actions/notes.export.action.server.ts +11 -0
  185. package/templates/apps/api-feature-flags/actions/notes.export.action.ts +18 -0
  186. package/templates/apps/api-feature-flags/app.config.ts +41 -0
  187. package/templates/apps/api-feature-flags/database/schema.ts +37 -0
  188. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.server.ts +29 -0
  189. package/templates/apps/api-feature-flags/mutations/notes.create.mutation.ts +28 -0
  190. package/templates/apps/api-feature-flags/package.json +29 -0
  191. package/templates/apps/api-feature-flags/template.json +6 -0
  192. package/templates/apps/api-feature-flags/tests/notes.create.test.ts +67 -0
  193. package/templates/apps/api-feature-flags/tsconfig.json +5 -0
  194. package/templates/apps/api-governance/.env +4 -0
  195. package/templates/apps/api-governance/README.md +61 -0
  196. package/templates/apps/api-governance/actions/profiles.get.action.server.ts +17 -0
  197. package/templates/apps/api-governance/actions/profiles.get.action.ts +17 -0
  198. package/templates/apps/api-governance/app.config.ts +35 -0
  199. package/templates/apps/api-governance/database/schema.ts +41 -0
  200. package/templates/apps/api-governance/mutations/profiles.create.mutation.server.ts +17 -0
  201. package/templates/apps/api-governance/mutations/profiles.create.mutation.ts +21 -0
  202. package/templates/apps/api-governance/package.json +29 -0
  203. package/templates/apps/api-governance/template.json +6 -0
  204. package/templates/apps/api-governance/tests/profiles.create.test.ts +59 -0
  205. package/templates/apps/api-governance/tsconfig.json +5 -0
  206. package/templates/apps/api-kv/README.md +100 -0
  207. package/templates/apps/api-kv/actions/sync.pull.action.server.ts +75 -0
  208. package/templates/apps/api-kv/actions/sync.pull.action.ts +25 -0
  209. package/templates/apps/api-kv/actions/sync.reset.action.server.ts +25 -0
  210. package/templates/apps/api-kv/actions/sync.reset.action.ts +22 -0
  211. package/templates/apps/api-kv/actions/sync.status.action.server.ts +28 -0
  212. package/templates/apps/api-kv/actions/sync.status.action.ts +17 -0
  213. package/templates/apps/api-kv/app.config.ts +48 -0
  214. package/templates/apps/api-kv/database/schema.ts +62 -0
  215. package/templates/apps/api-kv/package.json +28 -0
  216. package/templates/apps/api-kv/queries/events.list.query.server.ts +14 -0
  217. package/templates/apps/api-kv/queries/events.list.query.ts +23 -0
  218. package/templates/apps/api-kv/template.json +6 -0
  219. package/templates/apps/api-kv/tests/sync.test.ts +103 -0
  220. package/templates/apps/api-kv/tsconfig.json +5 -0
  221. package/templates/apps/api-moderation/README.md +46 -0
  222. package/templates/apps/api-moderation/app.config.ts +33 -0
  223. package/templates/apps/api-moderation/database/schema.ts +45 -0
  224. package/templates/apps/api-moderation/mutations/comments.create.mutation.server.ts +8 -0
  225. package/templates/apps/api-moderation/mutations/comments.create.mutation.ts +20 -0
  226. package/templates/apps/api-moderation/mutations/posts.create.mutation.server.ts +9 -0
  227. package/templates/apps/api-moderation/mutations/posts.create.mutation.ts +25 -0
  228. package/templates/apps/api-moderation/package.json +29 -0
  229. package/templates/apps/api-moderation/template.json +6 -0
  230. package/templates/apps/api-moderation/tests/posts.create.test.ts +79 -0
  231. package/templates/apps/api-moderation/tsconfig.json +5 -0
  232. package/templates/apps/api-observability/README.md +106 -0
  233. package/templates/apps/api-observability/app.config.ts +32 -0
  234. package/templates/apps/api-observability/database/schema.ts +38 -0
  235. package/templates/apps/api-observability/mutations/notes.create.mutation.server.ts +33 -0
  236. package/templates/apps/api-observability/mutations/notes.create.mutation.ts +15 -0
  237. package/templates/apps/api-observability/package.json +29 -0
  238. package/templates/apps/api-observability/queries/notes.list.query.server.ts +7 -0
  239. package/templates/apps/api-observability/queries/notes.list.query.ts +14 -0
  240. package/templates/apps/api-observability/template.json +6 -0
  241. package/templates/apps/api-observability/tests/notes.create.test.ts +36 -0
  242. package/templates/apps/api-observability/tsconfig.json +5 -0
  243. package/templates/apps/api-ratelimit/README.md +49 -0
  244. package/templates/apps/api-ratelimit/app.config.ts +42 -0
  245. package/templates/apps/api-ratelimit/database/schema.ts +37 -0
  246. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.server.ts +16 -0
  247. package/templates/apps/api-ratelimit/mutations/notes.create.mutation.ts +34 -0
  248. package/templates/apps/api-ratelimit/package.json +29 -0
  249. package/templates/apps/api-ratelimit/template.json +6 -0
  250. package/templates/apps/api-ratelimit/tests/notes.create.test.ts +69 -0
  251. package/templates/apps/api-ratelimit/tsconfig.json +5 -0
  252. package/templates/apps/api-rbac/README.md +59 -0
  253. package/templates/apps/api-rbac/app.config.ts +48 -0
  254. package/templates/apps/api-rbac/database/schema.ts +37 -0
  255. package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +22 -0
  256. package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +26 -0
  257. package/templates/apps/api-rbac/package.json +29 -0
  258. package/templates/apps/api-rbac/template.json +6 -0
  259. package/templates/apps/api-rbac/tests/notes.create.test.ts +80 -0
  260. package/templates/apps/api-rbac/tsconfig.json +5 -0
  261. package/templates/apps/api-rest/README.md +85 -0
  262. package/templates/apps/api-rest/app.config.ts +70 -0
  263. package/templates/apps/api-rest/database/schema.ts +52 -0
  264. package/templates/apps/api-rest/lib/product.ts +30 -0
  265. package/templates/apps/api-rest/package.json +27 -0
  266. package/templates/apps/api-rest/routes/v1/products.create.route.tsx +45 -0
  267. package/templates/apps/api-rest/routes/v1/products.delete.route.tsx +25 -0
  268. package/templates/apps/api-rest/routes/v1/products.get.route.tsx +29 -0
  269. package/templates/apps/api-rest/routes/v1/products.list.route.tsx +43 -0
  270. package/templates/apps/api-rest/template.json +6 -0
  271. package/templates/apps/api-rest/tests/products.create.test.ts +53 -0
  272. package/templates/apps/api-rest/tsconfig.json +5 -0
  273. package/templates/apps/api-saas/README.md +106 -0
  274. package/templates/apps/api-saas/app.config.ts +51 -0
  275. package/templates/apps/api-saas/database/schema.ts +50 -0
  276. package/templates/apps/api-saas/mutations/projects.create.mutation.server.ts +52 -0
  277. package/templates/apps/api-saas/mutations/projects.create.mutation.ts +18 -0
  278. package/templates/apps/api-saas/package.json +31 -0
  279. package/templates/apps/api-saas/queries/projects.list.query.server.ts +7 -0
  280. package/templates/apps/api-saas/queries/projects.list.query.ts +18 -0
  281. package/templates/apps/api-saas/template.json +6 -0
  282. package/templates/apps/api-saas/tests/projects.create.test.ts +47 -0
  283. package/templates/apps/api-saas/tsconfig.json +5 -0
  284. package/templates/apps/api-search/README.md +68 -0
  285. package/templates/apps/api-search/app.config.ts +31 -0
  286. package/templates/apps/api-search/database/schema.ts +47 -0
  287. package/templates/apps/api-search/lib/search.ts +27 -0
  288. package/templates/apps/api-search/mutations/articles.create.mutation.server.ts +19 -0
  289. package/templates/apps/api-search/mutations/articles.create.mutation.ts +35 -0
  290. package/templates/apps/api-search/package.json +29 -0
  291. package/templates/apps/api-search/queries/articles.list.query.server.ts +14 -0
  292. package/templates/apps/api-search/queries/articles.list.query.ts +19 -0
  293. package/templates/apps/api-search/seeds/articles.seed.ts +41 -0
  294. package/templates/apps/api-search/startup/searchBackfill.startup.tsx +24 -0
  295. package/templates/apps/api-search/template.json +6 -0
  296. package/templates/apps/api-search/tests/articles.create.test.ts +69 -0
  297. package/templates/apps/api-search/tsconfig.json +5 -0
  298. package/templates/apps/api-versioning/README.md +51 -0
  299. package/templates/apps/api-versioning/actions/documents.asOf.action.server.ts +13 -0
  300. package/templates/apps/api-versioning/actions/documents.asOf.action.ts +14 -0
  301. package/templates/apps/api-versioning/actions/documents.history.action.server.ts +15 -0
  302. package/templates/apps/api-versioning/actions/documents.history.action.ts +17 -0
  303. package/templates/apps/api-versioning/app.config.ts +24 -0
  304. package/templates/apps/api-versioning/database/schema.ts +38 -0
  305. package/templates/apps/api-versioning/mutations/documents.create.mutation.server.ts +8 -0
  306. package/templates/apps/api-versioning/mutations/documents.create.mutation.ts +21 -0
  307. package/templates/apps/api-versioning/mutations/documents.update.mutation.server.ts +9 -0
  308. package/templates/apps/api-versioning/mutations/documents.update.mutation.ts +21 -0
  309. package/templates/apps/api-versioning/package.json +29 -0
  310. package/templates/apps/api-versioning/template.json +6 -0
  311. package/templates/apps/api-versioning/tests/documents.create.test.ts +37 -0
  312. package/templates/apps/api-versioning/tsconfig.json +5 -0
  313. package/templates/apps/api-webhooks/.env +6 -0
  314. package/templates/apps/api-webhooks/README.md +106 -0
  315. package/templates/apps/api-webhooks/app.config.ts +16 -0
  316. package/templates/apps/api-webhooks/database/schema.ts +49 -0
  317. package/templates/apps/api-webhooks/events/order.completed.webhook.tsx +22 -0
  318. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.server.ts +37 -0
  319. package/templates/apps/api-webhooks/mutations/orders.fulfill.mutation.ts +15 -0
  320. package/templates/apps/api-webhooks/package.json +28 -0
  321. package/templates/apps/api-webhooks/queries/orders.list.query.server.ts +7 -0
  322. package/templates/apps/api-webhooks/queries/orders.list.query.ts +15 -0
  323. package/templates/apps/api-webhooks/template.json +6 -0
  324. package/templates/apps/api-webhooks/tests/orders.fulfill.test.ts +51 -0
  325. package/templates/apps/api-webhooks/tsconfig.json +5 -0
  326. package/templates/apps/api-webhooks/webhooks/orders.webhook.tsx +35 -0
  327. package/templates/apps/changelog/README.md +77 -0
  328. package/templates/apps/changelog/app.config.ts +27 -0
  329. package/templates/apps/changelog/content/releases/0.1.0.mdx +19 -0
  330. package/templates/apps/changelog/content/releases/0.2.0.mdx +28 -0
  331. package/templates/apps/changelog/package.json +30 -0
  332. package/templates/apps/changelog/scripts/generate-rss.mjs +38 -0
  333. package/templates/apps/changelog/src/globals.css +66 -0
  334. package/templates/apps/changelog/src/globals.d.ts +16 -0
  335. package/templates/apps/changelog/src/lib/locale.test.ts +72 -0
  336. package/templates/apps/changelog/src/lib/locale.ts +55 -0
  337. package/templates/apps/changelog/src/lib/releases.ts +21 -0
  338. package/templates/apps/changelog/src/locales/de.ts +22 -0
  339. package/templates/apps/changelog/src/locales/en.ts +30 -0
  340. package/templates/apps/changelog/src/pages/[locale]/[slug].tsx +24 -0
  341. package/templates/apps/changelog/src/pages/[locale]/index.tsx +13 -0
  342. package/templates/apps/changelog/src/pages/[locale]/mirrors.test.tsx +95 -0
  343. package/templates/apps/changelog/src/pages/[slug].test.tsx +127 -0
  344. package/templates/apps/changelog/src/pages/[slug].tsx +52 -0
  345. package/templates/apps/changelog/src/pages/index.test.tsx +112 -0
  346. package/templates/apps/changelog/src/pages/index.tsx +55 -0
  347. package/templates/apps/changelog/src/pages/layout.tsx +84 -0
  348. package/templates/apps/changelog/template.json +6 -0
  349. package/templates/apps/changelog/tsconfig.json +11 -0
  350. package/templates/apps/edge-functions/README.md +55 -0
  351. package/templates/apps/edge-functions/functions/aiComplete.serverless.ts +58 -0
  352. package/templates/apps/edge-functions/functions/currencyConvert.serverless.ts +47 -0
  353. package/templates/apps/edge-functions/functions/geoGreeting.serverless.ts +44 -0
  354. package/templates/apps/edge-functions/functions/health.serverless.ts +29 -0
  355. package/templates/apps/edge-functions/functions/resolveLink.serverless.ts +32 -0
  356. package/templates/apps/edge-functions/functions/shareLink.serverless.ts +30 -0
  357. package/templates/apps/edge-functions/functions/slackNotify.serverless.ts +40 -0
  358. package/templates/apps/edge-functions/functions/verifySignature.serverless.ts +52 -0
  359. package/templates/apps/edge-functions/package.json +21 -0
  360. package/templates/apps/edge-functions/template.json +6 -0
  361. package/templates/apps/edge-functions/tsconfig.json +10 -0
  362. package/templates/apps/frontend-admin/README.md +40 -0
  363. package/templates/apps/frontend-admin/app.config.ts +37 -0
  364. package/templates/apps/frontend-admin/package.json +30 -0
  365. package/templates/apps/frontend-admin/src/config.ts +8 -0
  366. package/templates/apps/frontend-admin/src/globals.css +76 -0
  367. package/templates/apps/frontend-admin/src/globals.d.ts +6 -0
  368. package/templates/apps/frontend-admin/src/lib/admin.ts +16 -0
  369. package/templates/apps/frontend-admin/src/lib/auth.ts +24 -0
  370. package/templates/apps/frontend-admin/src/locales/de.ts +67 -0
  371. package/templates/apps/frontend-admin/src/locales/en.ts +79 -0
  372. package/templates/apps/frontend-admin/src/locales/index.ts +15 -0
  373. package/templates/apps/frontend-admin/src/pages/(marketing)/index.test.tsx +55 -0
  374. package/templates/apps/frontend-admin/src/pages/(marketing)/index.tsx +32 -0
  375. package/templates/apps/frontend-admin/src/pages/(marketing)/layout.tsx +29 -0
  376. package/templates/apps/frontend-admin/src/pages/(marketing)/login.test.tsx +73 -0
  377. package/templates/apps/frontend-admin/src/pages/(marketing)/login.tsx +35 -0
  378. package/templates/apps/frontend-admin/src/pages/admin/[entity].tsx +121 -0
  379. package/templates/apps/frontend-admin/src/pages/admin/entity.test.tsx +119 -0
  380. package/templates/apps/frontend-admin/src/pages/admin/error.tsx +20 -0
  381. package/templates/apps/frontend-admin/src/pages/admin/fallbacks.test.tsx +68 -0
  382. package/templates/apps/frontend-admin/src/pages/admin/index.test.tsx +88 -0
  383. package/templates/apps/frontend-admin/src/pages/admin/index.tsx +65 -0
  384. package/templates/apps/frontend-admin/src/pages/admin/layout.test.tsx +114 -0
  385. package/templates/apps/frontend-admin/src/pages/admin/layout.tsx +97 -0
  386. package/templates/apps/frontend-admin/src/pages/admin/loading.tsx +15 -0
  387. package/templates/apps/frontend-admin/src/pages/admin/not-found.tsx +15 -0
  388. package/templates/apps/frontend-admin/src/pages/layout.tsx +12 -0
  389. package/templates/apps/frontend-admin/src/pages/layouts.test.tsx +54 -0
  390. package/templates/apps/frontend-admin/template.json +6 -0
  391. package/templates/apps/frontend-admin/tsconfig.json +11 -0
  392. package/templates/apps/frontend-app/README.md +98 -0
  393. package/templates/apps/frontend-app/app.config.ts +43 -0
  394. package/templates/apps/frontend-app/package.json +30 -0
  395. package/templates/apps/frontend-app/src/locales/de.ts +36 -0
  396. package/templates/apps/frontend-app/src/locales/en.ts +43 -0
  397. package/templates/apps/frontend-app/src/locales/index.ts +15 -0
  398. package/templates/apps/frontend-app/src/pages/index.test.tsx +167 -0
  399. package/templates/apps/frontend-app/src/pages/index.tsx +136 -0
  400. package/templates/apps/frontend-app/src/pages/layout.tsx +41 -0
  401. package/templates/apps/frontend-app/src/pages/schema-ui.test.tsx +99 -0
  402. package/templates/apps/frontend-app/src/pages/schema-ui.tsx +74 -0
  403. package/templates/apps/frontend-app/template.json +6 -0
  404. package/templates/apps/frontend-app/tsconfig.json +11 -0
  405. package/templates/apps/frontend-blank/README.md +18 -0
  406. package/templates/apps/frontend-blank/app.config.ts +29 -0
  407. package/templates/apps/frontend-blank/package.json +29 -0
  408. package/templates/apps/frontend-blank/src/locales/de.ts +15 -0
  409. package/templates/apps/frontend-blank/src/locales/en.ts +22 -0
  410. package/templates/apps/frontend-blank/src/locales/index.ts +15 -0
  411. package/templates/apps/frontend-blank/src/pages/index.test.tsx +55 -0
  412. package/templates/apps/frontend-blank/src/pages/index.tsx +27 -0
  413. package/templates/apps/frontend-blank/src/pages/layout.test.tsx +54 -0
  414. package/templates/apps/frontend-blank/src/pages/layout.tsx +35 -0
  415. package/templates/apps/frontend-blank/template.json +6 -0
  416. package/templates/apps/frontend-blank/tsconfig.json +11 -0
  417. package/templates/apps/frontend-contact/README.md +65 -0
  418. package/templates/apps/frontend-contact/app.config.ts +25 -0
  419. package/templates/apps/frontend-contact/functions/sendMessage.serverless.ts +69 -0
  420. package/templates/apps/frontend-contact/package.json +33 -0
  421. package/templates/apps/frontend-contact/src/components/ContactForm.island.test.tsx +142 -0
  422. package/templates/apps/frontend-contact/src/components/ContactForm.island.tsx +104 -0
  423. package/templates/apps/frontend-contact/src/config.ts +12 -0
  424. package/templates/apps/frontend-contact/src/globals.css +84 -0
  425. package/templates/apps/frontend-contact/src/lib/locale.ts +55 -0
  426. package/templates/apps/frontend-contact/src/locales/de.ts +26 -0
  427. package/templates/apps/frontend-contact/src/locales/en.ts +29 -0
  428. package/templates/apps/frontend-contact/src/pages/[locale]/index.tsx +14 -0
  429. package/templates/apps/frontend-contact/src/pages/index.test.tsx +70 -0
  430. package/templates/apps/frontend-contact/src/pages/index.tsx +63 -0
  431. package/templates/apps/frontend-contact/src/pages/layout.tsx +65 -0
  432. package/templates/apps/frontend-contact/template.json +6 -0
  433. package/templates/apps/frontend-contact/tsconfig.json +11 -0
  434. package/templates/apps/frontend-dashboard/README.md +54 -0
  435. package/templates/apps/frontend-dashboard/app.config.ts +39 -0
  436. package/templates/apps/frontend-dashboard/package.json +29 -0
  437. package/templates/apps/frontend-dashboard/src/config.ts +8 -0
  438. package/templates/apps/frontend-dashboard/src/globals.css +72 -0
  439. package/templates/apps/frontend-dashboard/src/globals.d.ts +6 -0
  440. package/templates/apps/frontend-dashboard/src/lib/auth.ts +27 -0
  441. package/templates/apps/frontend-dashboard/src/locales/de.ts +49 -0
  442. package/templates/apps/frontend-dashboard/src/locales/en.ts +60 -0
  443. package/templates/apps/frontend-dashboard/src/locales/index.ts +15 -0
  444. package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.test.tsx +55 -0
  445. package/templates/apps/frontend-dashboard/src/pages/(marketing)/index.tsx +34 -0
  446. package/templates/apps/frontend-dashboard/src/pages/(marketing)/layout.tsx +32 -0
  447. package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.test.tsx +74 -0
  448. package/templates/apps/frontend-dashboard/src/pages/(marketing)/login.tsx +40 -0
  449. package/templates/apps/frontend-dashboard/src/pages/dashboard/error.tsx +21 -0
  450. package/templates/apps/frontend-dashboard/src/pages/dashboard/fallbacks.test.tsx +68 -0
  451. package/templates/apps/frontend-dashboard/src/pages/dashboard/index.test.tsx +55 -0
  452. package/templates/apps/frontend-dashboard/src/pages/dashboard/index.tsx +38 -0
  453. package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.test.tsx +88 -0
  454. package/templates/apps/frontend-dashboard/src/pages/dashboard/layout.tsx +69 -0
  455. package/templates/apps/frontend-dashboard/src/pages/dashboard/loading.tsx +21 -0
  456. package/templates/apps/frontend-dashboard/src/pages/dashboard/not-found.tsx +19 -0
  457. package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.test.tsx +69 -0
  458. package/templates/apps/frontend-dashboard/src/pages/dashboard/settings.tsx +35 -0
  459. package/templates/apps/frontend-dashboard/src/pages/layout.tsx +12 -0
  460. package/templates/apps/frontend-dashboard/src/pages/layouts.test.tsx +54 -0
  461. package/templates/apps/frontend-dashboard/template.json +6 -0
  462. package/templates/apps/frontend-dashboard/tsconfig.json +11 -0
  463. package/templates/apps/frontend-docs/README.md +19 -0
  464. package/templates/apps/frontend-docs/app.config.ts +25 -0
  465. package/templates/apps/frontend-docs/package.json +29 -0
  466. package/templates/apps/frontend-docs/src/globals.css +32 -0
  467. package/templates/apps/frontend-docs/src/lib/locale.test.ts +72 -0
  468. package/templates/apps/frontend-docs/src/lib/locale.ts +56 -0
  469. package/templates/apps/frontend-docs/src/locales/de.ts +24 -0
  470. package/templates/apps/frontend-docs/src/locales/en.ts +28 -0
  471. package/templates/apps/frontend-docs/src/pages/[locale]/docs/[...slug].tsx +18 -0
  472. package/templates/apps/frontend-docs/src/pages/[locale]/index.tsx +13 -0
  473. package/templates/apps/frontend-docs/src/pages/[locale]/mirrors.test.tsx +67 -0
  474. package/templates/apps/frontend-docs/src/pages/docs/[...slug].test.tsx +115 -0
  475. package/templates/apps/frontend-docs/src/pages/docs/[...slug].tsx +82 -0
  476. package/templates/apps/frontend-docs/src/pages/index.test.tsx +90 -0
  477. package/templates/apps/frontend-docs/src/pages/index.tsx +45 -0
  478. package/templates/apps/frontend-docs/src/pages/layout.test.tsx +84 -0
  479. package/templates/apps/frontend-docs/src/pages/layout.tsx +66 -0
  480. package/templates/apps/frontend-docs/template.json +6 -0
  481. package/templates/apps/frontend-docs/tsconfig.json +11 -0
  482. package/templates/apps/frontend-i18n/README.md +61 -0
  483. package/templates/apps/frontend-i18n/app.config.ts +33 -0
  484. package/templates/apps/frontend-i18n/package.json +28 -0
  485. package/templates/apps/frontend-i18n/src/globals.css +46 -0
  486. package/templates/apps/frontend-i18n/src/globals.d.ts +6 -0
  487. package/templates/apps/frontend-i18n/src/lib/locale.test.ts +72 -0
  488. package/templates/apps/frontend-i18n/src/lib/locale.ts +55 -0
  489. package/templates/apps/frontend-i18n/src/locales/de.ts +24 -0
  490. package/templates/apps/frontend-i18n/src/locales/en.ts +25 -0
  491. package/templates/apps/frontend-i18n/src/pages/[locale]/about.tsx +11 -0
  492. package/templates/apps/frontend-i18n/src/pages/[locale]/index.tsx +13 -0
  493. package/templates/apps/frontend-i18n/src/pages/[locale]/mirrors.test.tsx +50 -0
  494. package/templates/apps/frontend-i18n/src/pages/about.test.tsx +75 -0
  495. package/templates/apps/frontend-i18n/src/pages/about.tsx +31 -0
  496. package/templates/apps/frontend-i18n/src/pages/index.test.tsx +102 -0
  497. package/templates/apps/frontend-i18n/src/pages/index.tsx +43 -0
  498. package/templates/apps/frontend-i18n/src/pages/layout.test.tsx +86 -0
  499. package/templates/apps/frontend-i18n/src/pages/layout.tsx +70 -0
  500. package/templates/apps/frontend-i18n/template.json +6 -0
  501. package/templates/apps/frontend-i18n/tsconfig.json +11 -0
  502. package/templates/apps/frontend-landing/README.md +17 -0
  503. package/templates/apps/frontend-landing/app.config.ts +25 -0
  504. package/templates/apps/frontend-landing/package.json +29 -0
  505. package/templates/apps/frontend-landing/src/globals.css +23 -0
  506. package/templates/apps/frontend-landing/src/lib/locale.test.ts +72 -0
  507. package/templates/apps/frontend-landing/src/lib/locale.ts +55 -0
  508. package/templates/apps/frontend-landing/src/locales/de.ts +24 -0
  509. package/templates/apps/frontend-landing/src/locales/en.ts +26 -0
  510. package/templates/apps/frontend-landing/src/pages/[locale]/index.tsx +13 -0
  511. package/templates/apps/frontend-landing/src/pages/[locale]/mirrors.test.tsx +37 -0
  512. package/templates/apps/frontend-landing/src/pages/index.test.tsx +110 -0
  513. package/templates/apps/frontend-landing/src/pages/index.tsx +75 -0
  514. package/templates/apps/frontend-landing/src/pages/layout.test.tsx +84 -0
  515. package/templates/apps/frontend-landing/src/pages/layout.tsx +66 -0
  516. package/templates/apps/frontend-landing/template.json +6 -0
  517. package/templates/apps/frontend-landing/tsconfig.json +11 -0
  518. package/templates/apps/frontend-spa/README.md +45 -0
  519. package/templates/apps/frontend-spa/app.config.ts +27 -0
  520. package/templates/apps/frontend-spa/package.json +29 -0
  521. package/templates/apps/frontend-spa/src/globals.css +84 -0
  522. package/templates/apps/frontend-spa/src/locales/de.ts +22 -0
  523. package/templates/apps/frontend-spa/src/locales/en.ts +29 -0
  524. package/templates/apps/frontend-spa/src/locales/index.ts +15 -0
  525. package/templates/apps/frontend-spa/src/pages/index.test.tsx +137 -0
  526. package/templates/apps/frontend-spa/src/pages/index.tsx +123 -0
  527. package/templates/apps/frontend-spa/src/pages/layout.tsx +27 -0
  528. package/templates/apps/frontend-spa/template.json +6 -0
  529. package/templates/apps/frontend-spa/tsconfig.json +11 -0
  530. package/templates/apps/frontend-ssr/README.md +68 -0
  531. package/templates/apps/frontend-ssr/app.config.ts +32 -0
  532. package/templates/apps/frontend-ssr/package.json +29 -0
  533. package/templates/apps/frontend-ssr/src/globals.css +67 -0
  534. package/templates/apps/frontend-ssr/src/locales/de.ts +41 -0
  535. package/templates/apps/frontend-ssr/src/locales/en.ts +54 -0
  536. package/templates/apps/frontend-ssr/src/locales/index.ts +16 -0
  537. package/templates/apps/frontend-ssr/src/pages/feed-swr.test.tsx +69 -0
  538. package/templates/apps/frontend-ssr/src/pages/feed-swr.tsx +54 -0
  539. package/templates/apps/frontend-ssr/src/pages/feed.test.tsx +73 -0
  540. package/templates/apps/frontend-ssr/src/pages/feed.tsx +64 -0
  541. package/templates/apps/frontend-ssr/src/pages/index.test.tsx +89 -0
  542. package/templates/apps/frontend-ssr/src/pages/index.tsx +72 -0
  543. package/templates/apps/frontend-ssr/src/pages/layout.tsx +37 -0
  544. package/templates/apps/frontend-ssr/template.json +6 -0
  545. package/templates/apps/frontend-ssr/tsconfig.json +11 -0
  546. package/templates/apps/frontend-ssr-api/README.md +50 -0
  547. package/templates/apps/frontend-ssr-api/app.config.ts +43 -0
  548. package/templates/apps/frontend-ssr-api/package.json +30 -0
  549. package/templates/apps/frontend-ssr-api/src/globals.css +38 -0
  550. package/templates/apps/frontend-ssr-api/src/globals.d.ts +6 -0
  551. package/templates/apps/frontend-ssr-api/src/locales/de.ts +20 -0
  552. package/templates/apps/frontend-ssr-api/src/locales/en.ts +31 -0
  553. package/templates/apps/frontend-ssr-api/src/locales/index.ts +16 -0
  554. package/templates/apps/frontend-ssr-api/src/pages/index.test.tsx +105 -0
  555. package/templates/apps/frontend-ssr-api/src/pages/index.tsx +83 -0
  556. package/templates/apps/frontend-ssr-api/src/pages/layout.tsx +28 -0
  557. package/templates/apps/frontend-ssr-api/template.json +6 -0
  558. package/templates/apps/frontend-ssr-api/tsconfig.json +11 -0
  559. package/templates/apps/frontend-static-blog/README.md +49 -0
  560. package/templates/apps/frontend-static-blog/app.config.ts +34 -0
  561. package/templates/apps/frontend-static-blog/package.json +28 -0
  562. package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.test.tsx +65 -0
  563. package/templates/apps/frontend-static-blog/src/components/ReadingProgress.island.tsx +35 -0
  564. package/templates/apps/frontend-static-blog/src/content/posts.ts +64 -0
  565. package/templates/apps/frontend-static-blog/src/globals.css +75 -0
  566. package/templates/apps/frontend-static-blog/src/lib/locale.test.ts +72 -0
  567. package/templates/apps/frontend-static-blog/src/lib/locale.ts +55 -0
  568. package/templates/apps/frontend-static-blog/src/locales/de.ts +19 -0
  569. package/templates/apps/frontend-static-blog/src/locales/en.ts +26 -0
  570. package/templates/apps/frontend-static-blog/src/pages/[locale]/blog/[slug].tsx +20 -0
  571. package/templates/apps/frontend-static-blog/src/pages/[locale]/index.tsx +13 -0
  572. package/templates/apps/frontend-static-blog/src/pages/[locale]/mirrors.test.tsx +62 -0
  573. package/templates/apps/frontend-static-blog/src/pages/blog/[slug].test.tsx +116 -0
  574. package/templates/apps/frontend-static-blog/src/pages/blog/[slug].tsx +69 -0
  575. package/templates/apps/frontend-static-blog/src/pages/index.test.tsx +100 -0
  576. package/templates/apps/frontend-static-blog/src/pages/index.tsx +58 -0
  577. package/templates/apps/frontend-static-blog/src/pages/layout.tsx +63 -0
  578. package/templates/apps/frontend-static-blog/template.json +6 -0
  579. package/templates/apps/frontend-static-blog/tsconfig.json +11 -0
  580. package/templates/baselines/bare/.env.example +37 -0
  581. package/templates/baselines/bare/README.md +47 -0
  582. package/templates/baselines/bare/baseline.json +31 -0
  583. package/templates/baselines/bare/deploy/README.md +43 -0
  584. package/templates/baselines/bare/deploy/voltro.service.example +36 -0
  585. package/templates/baselines/compose/.env.example +46 -0
  586. package/templates/baselines/compose/README.md +69 -0
  587. package/templates/baselines/compose/baseline.json +51 -0
  588. package/templates/baselines/compose/docker/.dockerignore +38 -0
  589. package/templates/baselines/compose/docker/api.Dockerfile +57 -0
  590. package/templates/baselines/compose/docker/dev.Dockerfile +35 -0
  591. package/templates/baselines/compose/docker/web.Dockerfile +59 -0
  592. package/templates/baselines/compose/docker-compose.dev.yml +89 -0
  593. package/templates/baselines/compose/docker-compose.prod.yml +87 -0
  594. package/templates/baselines/compose/docker-compose.yml +41 -0
  595. package/templates/baselines/compose-mariadb/.env.example +57 -0
  596. package/templates/baselines/compose-mariadb/README.md +78 -0
  597. package/templates/baselines/compose-mariadb/baseline.json +51 -0
  598. package/templates/baselines/compose-mariadb/docker/.dockerignore +38 -0
  599. package/templates/baselines/compose-mariadb/docker/api.Dockerfile +57 -0
  600. package/templates/baselines/compose-mariadb/docker/dev.Dockerfile +35 -0
  601. package/templates/baselines/compose-mariadb/docker/mariadb-init.sql +6 -0
  602. package/templates/baselines/compose-mariadb/docker/web.Dockerfile +59 -0
  603. package/templates/baselines/compose-mariadb/docker-compose.dev.yml +117 -0
  604. package/templates/baselines/compose-mariadb/docker-compose.prod.yml +114 -0
  605. package/templates/baselines/compose-mariadb/docker-compose.yml +79 -0
  606. package/templates/baselines/helm/.env.example +39 -0
  607. package/templates/baselines/helm/README.md +98 -0
  608. package/templates/baselines/helm/baseline.json +53 -0
  609. package/templates/baselines/helm/charts/voltro-app/.helmignore +10 -0
  610. package/templates/baselines/helm/charts/voltro-app/Chart.yaml +10 -0
  611. package/templates/baselines/helm/charts/voltro-app/templates/_helpers.tpl +36 -0
  612. package/templates/baselines/helm/charts/voltro-app/templates/configmap.yaml +13 -0
  613. package/templates/baselines/helm/charts/voltro-app/templates/deployment-api.yaml +120 -0
  614. package/templates/baselines/helm/charts/voltro-app/templates/deployment-web.yaml +45 -0
  615. package/templates/baselines/helm/charts/voltro-app/templates/ingress.yaml +37 -0
  616. package/templates/baselines/helm/charts/voltro-app/templates/postgres-service.yaml +19 -0
  617. package/templates/baselines/helm/charts/voltro-app/templates/postgres-statefulset.yaml +73 -0
  618. package/templates/baselines/helm/charts/voltro-app/templates/secret.yaml +33 -0
  619. package/templates/baselines/helm/charts/voltro-app/templates/service-api.yaml +19 -0
  620. package/templates/baselines/helm/charts/voltro-app/templates/service-web.yaml +19 -0
  621. package/templates/baselines/helm/charts/voltro-app/values-dev.yaml +21 -0
  622. package/templates/baselines/helm/charts/voltro-app/values-prod.yaml +58 -0
  623. package/templates/baselines/helm/charts/voltro-app/values-staging.yaml +25 -0
  624. package/templates/baselines/helm/charts/voltro-app/values.yaml +109 -0
  625. package/templates/baselines/helm/deploy/README.md +94 -0
  626. package/templates/patches/@effect__cluster@0.59.0.patch +262 -0
@@ -0,0 +1,41 @@
1
+ // Feature-flag backend for the {{projectName}} project.
2
+ //
3
+ // `flagsPlugin` declares flags AS CODE and gates rpc calls two ways:
4
+ // - declaratively via `gatedBy` (an off flag fails typed FlagDisabled
5
+ // BEFORE the handler runs), and
6
+ // - in-handler via `requireFlag(ctx, key)` / `isFlagEnabled(ctx, key)`.
7
+ // A flag is a bare boolean (kill-switch) OR a rich definition with a
8
+ // deterministic `% rollout` and OR-of-rules `targeting`. `store: 'memory'`
9
+ // keeps this zero-infra; `store: 'postgres'` adds runtime-toggleable flags
10
+ // overlaid on the code baseline.
11
+ import { defineEnv, envVar } from '@voltro/env'
12
+ import { flagsPlugin } from '@voltro/plugin-flags'
13
+
14
+ export const env = defineEnv({
15
+ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }),
16
+ })
17
+
18
+ export default {
19
+ type: 'api' as const,
20
+ name: '{{capProjectName}}{{capAppName}}',
21
+ store: 'memory' as const,
22
+ plugins: [
23
+ flagsPlugin({
24
+ flags: {
25
+ // Bare boolean = kill-switch. `newEditor` is ON — the in-handler
26
+ // requireFlag guard on notes.create passes.
27
+ newEditor: true,
28
+ // OFF — the gatedBy map below blocks notes.export with FlagDisabled.
29
+ betaExport: false,
30
+ // Targeting: only subjects whose metadata says plan=pro see it.
31
+ proDashboard: { targeting: [{ metadata: { plan: 'pro' } }], description: 'Pro-plan dashboard.' },
32
+ // Deterministic % rollout — a given subject is stably in or out.
33
+ gradualRollout: { rollout: 25, description: '25% gradual rollout, bucketed by subject.' },
34
+ },
35
+ // Declarative gate: tag → flag. An off flag fails FlagDisabled pre-handler.
36
+ gatedBy: { 'notes.export': 'betaExport' },
37
+ store: 'memory',
38
+ }),
39
+ ],
40
+ env,
41
+ }
@@ -0,0 +1,37 @@
1
+ // Schema for the {{projectName}} feature-flags backend — a tiny `notes`
2
+ // domain to gate. `actors` + `tenants` are the framework core tables.
3
+
4
+ import {
5
+ databaseHandle,
6
+ id,
7
+ table,
8
+ text,
9
+ timestamp,
10
+ type InferRow,
11
+ } from '@voltro/database'
12
+ import { tenant } from '@voltro/plugin-multitenancy'
13
+
14
+ export const actors = table('actors', {
15
+ id: id(),
16
+ kind: text().oneOf(['user', 'serviceAccount', 'apiKey', 'system']),
17
+ displayName: text().nullable(),
18
+ createdAt: timestamp().default('now'),
19
+ })
20
+
21
+ export const tenants = table('tenants', {
22
+ id: id(),
23
+ name: text(),
24
+ createdAt: timestamp().default('now'),
25
+ })
26
+
27
+ export const notes = table('notes', {
28
+ id: id({ prefix: 'note' }),
29
+ title: text(),
30
+ body: text(),
31
+ })
32
+ .with(tenant())
33
+ .reactive()
34
+
35
+ export type Note = InferRow<typeof notes>
36
+
37
+ export const database = databaseHandle({ actors, tenants, notes })
@@ -0,0 +1,29 @@
1
+ import { EffectStore } from '@voltro/runtime'
2
+ import type { AppContext } from '@voltro/runtime'
3
+ import { requireFlag } from '@voltro/plugin-flags'
4
+ import { Effect } from 'effect'
5
+
6
+ const execute = (
7
+ input: { tenantId: string; title: string; body: string },
8
+ ctx: AppContext,
9
+ ) =>
10
+ Effect.gen(function* () {
11
+ // In-handler flag guard — short-circuits with typed FlagDisabled when the
12
+ // flag is off. Same shape as `requireScope` / `requireEntitlement`.
13
+ yield* requireFlag(ctx, 'newEditor')
14
+
15
+ const store = yield* EffectStore
16
+ const row = yield* store.insert('notes', {
17
+ title: input.title,
18
+ body: input.body,
19
+ tenantId: input.tenantId,
20
+ })
21
+ return {
22
+ id: row['id'] as string,
23
+ title: row['title'] as string,
24
+ body: row['body'] as string,
25
+ tenantId: row['tenantId'] as string,
26
+ }
27
+ })
28
+
29
+ export default execute
@@ -0,0 +1,28 @@
1
+ // Creates a note — but only if the `newEditor` flag is on for the caller.
2
+ // The executor uses the IN-HANDLER guard `requireFlag(ctx, 'newEditor')`, which
3
+ // fails typed `FlagDisabled` when the flag is off. Declaring `error: FlagDisabled`
4
+ // here surfaces that to the client as a typed, pattern-matchable failure.
5
+ //
6
+ // `FlagDisabled` is imported from the browser-safe `/errors` subpath (no
7
+ // node/db imports) so this descriptor stays safe for the client bundle.
8
+
9
+ import { defineMutation } from '@voltro/protocol'
10
+ import { FlagDisabled } from '@voltro/plugin-flags/errors'
11
+ import { Schema } from 'effect'
12
+
13
+ export const createNote = defineMutation({
14
+ name: 'notes.create',
15
+ target: { table: 'notes', op: 'insert' },
16
+ input: Schema.Struct({
17
+ tenantId: Schema.String,
18
+ title: Schema.NonEmptyString,
19
+ body: Schema.String,
20
+ }),
21
+ output: Schema.Struct({
22
+ id: Schema.String,
23
+ title: Schema.String,
24
+ body: Schema.String,
25
+ tenantId: Schema.String,
26
+ }),
27
+ error: FlagDisabled,
28
+ })
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@{{projectName}}/{{appName}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "voltro dev .",
8
+ "migrate": "voltro migrate",
9
+ "test": "voltro test",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@effect/platform": "^0.96.1",
14
+ "@effect/rpc": "^0.75.1",
15
+ "@voltro/cli": "0.1.0",
16
+ "@voltro/database": "0.1.0",
17
+ "@voltro/env": "0.1.0",
18
+ "@voltro/plugin-flags": "0.1.0",
19
+ "@voltro/plugin-multitenancy": "0.1.0",
20
+ "@voltro/protocol": "0.1.0",
21
+ "@voltro/runtime": "0.1.0",
22
+ "effect": "^3.21.2"
23
+ },
24
+ "devDependencies": {
25
+ "@voltro/testing": "0.1.0",
26
+ "typescript": "^5.7.0",
27
+ "vitest": "^3.0.0"
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "api-feature-flags",
3
+ "kind": "api",
4
+ "summary": "Feature flags wired turnkey — @voltro/plugin-flags: flags as code (kill-switch / % rollout / targeting), a declarative gatedBy map that fails typed FlagDisabled before the handler, an in-handler requireFlag guard, and the flags.evaluate query for useFlag() on the web. Memory store, zero infra.",
5
+ "tags": ["api", "feature-flags", "rollout", "kill-switch", "targeting", "plugin"]
6
+ }
@@ -0,0 +1,67 @@
1
+ // Unit test for `notes.create` — driven through `@voltro/testing`.
2
+ //
3
+ // This executor is Effect-native: it `yield*`s the flag guard
4
+ // `requireFlag(ctx, 'newEditor')` (fails typed `FlagDisabled` when the flag is
5
+ // off for the caller) and then `yield* EffectStore` to insert. The flag registry
6
+ // is populated by flagsPlugin at BOOT from app.config.ts — a step the unit
7
+ // harness deliberately doesn't run, so under test every flag reads as off and
8
+ // `requireFlag` fails `FlagDisabled`. We assert that REAL guard behavior (no
9
+ // faking the plugin) + pin the descriptor's contract. `makeTestContext` exposes
10
+ // the mixin-wrapped store as `ctx.store`, provided to the Effect as the
11
+ // `EffectStore` layer via `makeEffectStoreLayer`. Run with `voltro test`.
12
+
13
+ import { describe, it, expect } from 'vitest'
14
+ import { Cause, Effect, Exit, Option, Schema } from 'effect'
15
+ import { makeTestContext, mockStore } from '@voltro/testing'
16
+ import { makeEffectStoreLayer } from '@voltro/runtime'
17
+ import { database } from '../database/schema' // registers actors / tenants / notes
18
+ import { createNote } from '../mutations/notes.create.mutation'
19
+ import createNoteHandler from '../mutations/notes.create.mutation.server'
20
+ import { FlagDisabled } from '@voltro/plugin-flags/errors'
21
+
22
+ // Run the Effect-native executor with the test store provided as EffectStore,
23
+ // returning the raw Exit so a typed failure can be inspected WITHOUT the
24
+ // `FiberFailure` wrapper `Effect.runPromise` throws (which would defeat a plain
25
+ // `instanceof FlagDisabled` assertion). Unwrap the Cause to get the real error.
26
+ const runExit = (
27
+ input: { tenantId: string; title: string; body: string },
28
+ ctx: ReturnType<typeof makeTestContext>,
29
+ ) => Effect.runPromiseExit(createNoteHandler(input, ctx).pipe(Effect.provide(makeEffectStoreLayer(ctx.store))))
30
+
31
+ describe('notes.create', () => {
32
+ it('fails typed FlagDisabled when the newEditor flag is off — nothing written', async () => {
33
+ // No plugin boot under unit test ⇒ the flag registry is empty ⇒ the flag is
34
+ // off ⇒ the in-handler requireFlag guard short-circuits before the insert.
35
+ const ctx = makeTestContext({
36
+ subject: { type: 'user', id: 'u1', tenantId: 'acme' },
37
+ store: mockStore({ notes: [] }),
38
+ })
39
+
40
+ const exit = await runExit({ tenantId: 'acme', title: 'Hello', body: 'World' }, ctx)
41
+
42
+ expect(Exit.isFailure(exit)).toBe(true)
43
+ const failure = Exit.isFailure(exit) ? Cause.failureOption(exit.cause) : Option.none()
44
+ expect(Option.getOrThrow(failure)).toBeInstanceOf(FlagDisabled)
45
+
46
+ const rows = await ctx.store.query(database.notes.descriptor)
47
+ expect(rows).toHaveLength(0)
48
+ })
49
+
50
+ it('pins the descriptor: name, input decode + the declared FlagDisabled error', () => {
51
+ expect(createNote.name).toBe('notes.create')
52
+
53
+ const decoded = Schema.decodeUnknownSync(createNote.input)({
54
+ tenantId: 'acme',
55
+ title: 'ok',
56
+ body: 'b',
57
+ })
58
+ expect(decoded).toEqual({ tenantId: 'acme', title: 'ok', body: 'b' })
59
+ // Empty title is rejected at the input Schema (NonEmptyString).
60
+ expect(() =>
61
+ Schema.decodeUnknownSync(createNote.input)({ tenantId: 'acme', title: '', body: '' }),
62
+ ).toThrow()
63
+
64
+ const disabled = new FlagDisabled({ flag: 'newEditor' })
65
+ expect(Schema.is(FlagDisabled)(disabled)).toBe(true)
66
+ })
67
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "exclude": ["node_modules", "dist"]
5
+ }
@@ -0,0 +1,4 @@
1
+ # AES-256-GCM key for `.encrypted()` columns (32 bytes / 64 hex chars).
2
+ # DEV PLACEHOLDER — generate your own (`openssl rand -hex 32`) and keep it in a
3
+ # real secret store for production. LOSE THIS KEY, LOSE THE ENCRYPTED DATA.
4
+ VOLTRO_FIELD_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
@@ -0,0 +1,61 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro API scaffold (template: **api-governance**) — data governance with
4
+ `@voltro/plugin-governance`: field encryption, GDPR, consent, retention.
5
+
6
+ ## Boot
7
+
8
+ ```bash
9
+ pnpm install
10
+ pnpm --filter @{{projectName}}/{{appName}} dev
11
+ # → http://localhost:4000 (store: memory — zero infra)
12
+ ```
13
+
14
+ The `.env` ships a DEV encryption key. Generate your own with
15
+ `openssl rand -hex 32` and keep it in a secret store for production.
16
+
17
+ ## What this shows
18
+
19
+ - **Field encryption** — `profiles.ssn` is `text().encrypted()`. You pass
20
+ plaintext; the store middleware encrypts it (AES-256-GCM) on write and
21
+ decrypts on read, so handlers always see plaintext while the column holds an
22
+ opaque `enc:v1:…` string at rest. `governancePlugin({ fieldEncryption: true })`
23
+ registers the cipher from `VOLTRO_FIELD_ENCRYPTION_KEY`. Boot fails loud if an
24
+ `.encrypted()` column exists but no cipher is registered.
25
+ - **GDPR** — admin-gated `governance.export` / `governance.erase` walk the
26
+ declared `subjectScopes` (`[{ table: 'profiles', subjectField: 'id' }]`) to
27
+ bundle or erase everything belonging to a subject.
28
+ - **Consent ledger** — `governance.consent` records a grant; `governance.hasConsent`
29
+ checks it. `GovernanceService` exposes the same in-handler.
30
+ - **Retention** — `retention: [{ table, ttlMs, action }]` runs a periodic
31
+ sweep that deletes (or anonymises) rows past their TTL.
32
+
33
+ ## Try it
34
+
35
+ ```bash
36
+ # create a profile, then read it back — ssn round-trips as plaintext:
37
+ ID=$(curl -s localhost:4000/_voltro/inspect/invoke -H 'content-type: application/json' \
38
+ -d '{"tag":"profiles.create","input":{"name":"Ada","email":"ada@acme.com","ssn":"123-45-6789"}}' | python3 -c 'import sys,json;print(json.load(sys.stdin)["result"]["id"])')
39
+ curl -s localhost:4000/_voltro/inspect/invoke -H 'content-type: application/json' \
40
+ -d "{\"tag\":\"profiles.get\",\"input\":{\"id\":\"$ID\"}}"
41
+ # → { ok:true, result:{ …, ssn:"123-45-6789" } } (plaintext — cipher decrypted it)
42
+
43
+ # record consent (a mutation):
44
+ curl -s localhost:4000/_voltro/inspect/invoke -H 'content-type: application/json' \
45
+ -d '{"tag":"governance.consent","input":{"purpose":"marketing","granted":true}}'
46
+ # → { ok:true, result:{ ok:true } }
47
+ ```
48
+
49
+ `governance.hasConsent` is a reactive QUERY (not invoke-able) — subscribe to it
50
+ on the web, or call `GovernanceService.hasConsent(subjectId, purpose)` in a handler.
51
+
52
+ `governance.export` / `governance.erase` are admin-gated — call them as a
53
+ subject with the `admin:full` scope (see [`api-rbac`](https://voltro.cloud/docs/templates/api-rbac)).
54
+
55
+ ## Rules
56
+
57
+ - **Don't encrypt what you filter on.** An `.encrypted()` column is ciphertext
58
+ on disk — you can't `WHERE`/`ORDER BY` it in SQL. Encrypt fields you read back
59
+ whole (PII, tokens, notes).
60
+ - **The key is everything.** GCM fails closed on a bad key — you get an error,
61
+ never silent corruption. Back the key up; rotating it needs re-encrypting.
@@ -0,0 +1,17 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+ import { eq } from '@voltro/database'
3
+ import { database } from '../database/schema'
4
+
5
+ const execute = async (input: { id: string }, ctx: AppContext) => {
6
+ const rows = await ctx.store.query(database.profiles.where(eq('id', input.id)).descriptor)
7
+ const p = rows[0]
8
+ if (!p) return null
9
+ return {
10
+ id: p['id'] as string,
11
+ name: p['name'] as string,
12
+ email: p['email'] as string,
13
+ ssn: p['ssn'] as string, // decrypted by the store middleware
14
+ }
15
+ }
16
+
17
+ export default execute
@@ -0,0 +1,17 @@
1
+ // Reads a profile back — `ssn` comes out as PLAINTEXT. The store middleware
2
+ // decrypts the `.encrypted()` column on read; the handler never touches the
3
+ // `enc:v1:…` ciphertext. (In a real app you'd gate this read behind auth.)
4
+
5
+ import { defineAction } from '@voltro/protocol'
6
+ import { Schema } from 'effect'
7
+
8
+ export const getProfile = defineAction({
9
+ name: 'profiles.get',
10
+ input: Schema.Struct({ id: Schema.String }),
11
+ output: Schema.NullOr(Schema.Struct({
12
+ id: Schema.String,
13
+ name: Schema.String,
14
+ email: Schema.String,
15
+ ssn: Schema.String,
16
+ })),
17
+ })
@@ -0,0 +1,35 @@
1
+ // Data-governance backend for the {{projectName}} project — field encryption,
2
+ // GDPR export/erase, a consent ledger, and retention sweeps in one plugin.
3
+ //
4
+ // `@voltro/plugin-governance` does four things:
5
+ // - fieldEncryption: registers the AES-256-GCM cipher for `.encrypted()`
6
+ // columns (key from the secret VOLTRO_FIELD_ENCRYPTION_KEY). Handlers see
7
+ // plaintext; the column stores an opaque `enc:v1:…` string at rest.
8
+ // - GDPR: synthesizes admin-gated `governance.export` / `governance.erase`
9
+ // that walk the declared `subjectScopes`.
10
+ // - consent: `governance.consent` / `governance.hasConsent` + the service.
11
+ // - retention: a periodic sweep that deletes/anonymises rows past their TTL.
12
+ import { defineEnv, envVar } from '@voltro/env'
13
+ import { governancePlugin } from '@voltro/plugin-governance'
14
+
15
+ export const env = defineEnv({
16
+ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }),
17
+ })
18
+
19
+ export default {
20
+ type: 'api' as const,
21
+ name: '{{capProjectName}}{{capAppName}}',
22
+ store: 'memory' as const,
23
+ plugins: [
24
+ governancePlugin({
25
+ // Reads the secret VOLTRO_FIELD_ENCRYPTION_KEY (see .env). LOSE THE KEY,
26
+ // LOSE THE DATA — GCM fails closed, it never silently corrupts.
27
+ fieldEncryption: true,
28
+ // GDPR export/erase walk these (table + the column holding the subject id).
29
+ subjectScopes: [{ table: 'profiles', subjectField: 'id' }],
30
+ // Delete profiles untouched for a year (the sweep runs periodically).
31
+ retention: [{ table: 'profiles', ttlMs: 365 * 86_400_000, action: 'delete' }],
32
+ }),
33
+ ],
34
+ env,
35
+ }
@@ -0,0 +1,41 @@
1
+ // Schema for the {{projectName}} governance backend — a `profiles` table with
2
+ // an ENCRYPTED column. `actors` + `tenants` are the framework core tables.
3
+
4
+ import {
5
+ databaseHandle,
6
+ id,
7
+ table,
8
+ text,
9
+ timestamp,
10
+ type InferRow,
11
+ } from '@voltro/database'
12
+ import { audit } from '@voltro/plugin-audit'
13
+
14
+ export const actors = table('actors', {
15
+ id: id(),
16
+ kind: text().oneOf(['user', 'serviceAccount', 'apiKey', 'system']),
17
+ displayName: text().nullable(),
18
+ createdAt: timestamp().default('now'),
19
+ })
20
+
21
+ export const tenants = table('tenants', {
22
+ id: id(),
23
+ name: text(),
24
+ createdAt: timestamp().default('now'),
25
+ })
26
+
27
+ export const profiles = table('profiles', {
28
+ id: id({ prefix: 'prof' }),
29
+ name: text(),
30
+ email: text(),
31
+ // .encrypted() → AES-256-GCM at rest. The handler always sees plaintext; the
32
+ // stored value is an opaque `enc:v1:…` string. Encrypt only what you read
33
+ // back WHOLE (you can't filter/sort on it in SQL — it's ciphertext on disk).
34
+ ssn: text().encrypted(),
35
+ })
36
+ .with(audit()) // createdAt drives the retention sweep
37
+ .reactive()
38
+
39
+ export type Profile = InferRow<typeof profiles>
40
+
41
+ export const database = databaseHandle({ actors, tenants, profiles })
@@ -0,0 +1,17 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+
3
+ const execute = async (
4
+ input: { name: string; email: string; ssn: string },
5
+ ctx: AppContext,
6
+ ) => {
7
+ // ssn is encrypted on write by the store middleware — we just pass plaintext.
8
+ const row = await ctx.store.insert('profiles', {
9
+ name: input.name,
10
+ email: input.email,
11
+ ssn: input.ssn,
12
+ })
13
+ // Don't echo the ssn back here — read it via profiles.get when you need it.
14
+ return { id: row['id'] as string, name: row['name'] as string, email: row['email'] as string }
15
+ }
16
+
17
+ export default execute
@@ -0,0 +1,21 @@
1
+ // Creates a profile. `ssn` is an `.encrypted()` column — you pass plaintext,
2
+ // the store middleware encrypts it on write (the cipher is registered by
3
+ // governancePlugin's fieldEncryption). Nothing special in the handler.
4
+
5
+ import { defineMutation } from '@voltro/protocol'
6
+ import { Schema } from 'effect'
7
+
8
+ export const createProfile = defineMutation({
9
+ name: 'profiles.create',
10
+ target: { table: 'profiles', op: 'insert' },
11
+ input: Schema.Struct({
12
+ name: Schema.NonEmptyString,
13
+ email: Schema.String,
14
+ ssn: Schema.String,
15
+ }),
16
+ output: Schema.Struct({
17
+ id: Schema.String,
18
+ name: Schema.String,
19
+ email: Schema.String,
20
+ }),
21
+ })
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@{{projectName}}/{{appName}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "voltro dev .",
8
+ "migrate": "voltro migrate",
9
+ "test": "voltro test",
10
+ "typecheck": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@effect/platform": "^0.96.1",
14
+ "@effect/rpc": "^0.75.1",
15
+ "@voltro/cli": "0.1.0",
16
+ "@voltro/database": "0.1.0",
17
+ "@voltro/env": "0.1.0",
18
+ "@voltro/plugin-audit": "0.1.0",
19
+ "@voltro/plugin-governance": "0.1.0",
20
+ "@voltro/protocol": "0.1.0",
21
+ "@voltro/runtime": "0.1.0",
22
+ "effect": "^3.21.2"
23
+ },
24
+ "devDependencies": {
25
+ "@voltro/testing": "0.1.0",
26
+ "typescript": "^5.7.0",
27
+ "vitest": "^3.0.0"
28
+ }
29
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "api-governance",
3
+ "kind": "api",
4
+ "summary": "Data governance in one plugin — @voltro/plugin-governance: AES-256-GCM field encryption for .encrypted() columns (handler sees plaintext, ciphertext at rest), admin-gated GDPR governance.export/erase over declared subjectScopes, a consent ledger, and retention TTL sweeps. Memory store, zero infra.",
5
+ "tags": ["api", "governance", "encryption", "gdpr", "compliance", "retention", "plugin"]
6
+ }
@@ -0,0 +1,59 @@
1
+ // Unit test for `profiles.create` — driven through `@voltro/testing`.
2
+ //
3
+ // The governance features (field encryption, retention TTL sweep, GDPR
4
+ // export/erase) are wired by governancePlugin at boot — store middleware +
5
+ // scheduled sweeps that the unit harness does NOT run. So this test targets the
6
+ // executor's OWN observable behavior: a plain audited insert that echoes back
7
+ // { id, name, email } (never the ssn). `makeTestContext` hands the handler the
8
+ // SAME mixin-wrapped `ctx.store` it gets in production, so the audit() mixin
9
+ // auto-fills createdAt/createdBy exactly as at runtime.
10
+ // Run with `voltro test` (vitest).
11
+
12
+ import { afterAll, beforeAll, describe, it, expect } from 'vitest'
13
+ import { makeFieldCipher, setFieldCipher } from '@voltro/runtime'
14
+ import { makeTestContext, mockStore, invoke } from '@voltro/testing'
15
+ import { database } from '../database/schema' // registers actors / tenants / profiles
16
+ import { createProfile } from '../mutations/profiles.create.mutation'
17
+ import createProfileHandler from '../mutations/profiles.create.mutation.server'
18
+
19
+ const subject = { type: 'user', id: 'admin_1', tenantId: 'acme' } as const
20
+
21
+ // `profiles.ssn` is an `.encrypted()` column, so the store middleware refuses to
22
+ // write it unless a field cipher is registered — normally `governancePlugin({
23
+ // fieldEncryption: true })` does that at boot from VOLTRO_FIELD_ENCRYPTION_KEY,
24
+ // a step the unit harness doesn't run. We register the SAME AES-256-GCM cipher
25
+ // process-globally here so the encrypted insert exercises the real write path
26
+ // (plaintext in, ciphertext at rest), then clear it so the global doesn't leak.
27
+ beforeAll(() => setFieldCipher(makeFieldCipher('unit-test-field-encryption-key')))
28
+ afterAll(() => setFieldCipher(undefined))
29
+
30
+ describe('profiles.create', () => {
31
+ it('inserts a profile + echoes back { id, name, email } with a prof_ TypeID', async () => {
32
+ const ctx = makeTestContext({ subject, store: mockStore({ profiles: [] }) })
33
+
34
+ const row = (await invoke(
35
+ createProfile,
36
+ createProfileHandler,
37
+ { name: 'Ada Lovelace', email: 'ada@example.com', ssn: '123-45-6789' },
38
+ ctx,
39
+ )) as { id: string; name: string; email: string }
40
+
41
+ expect(row.name).toBe('Ada Lovelace')
42
+ expect(row.email).toBe('ada@example.com')
43
+ expect(row.id).toMatch(/^prof_/)
44
+ // The handler deliberately does NOT echo the ssn — only id/name/email.
45
+ expect(row).not.toHaveProperty('ssn')
46
+
47
+ // The row is really persisted — the live query sees it.
48
+ const rows = await ctx.store.query(database.profiles.descriptor)
49
+ expect(rows).toHaveLength(1)
50
+ })
51
+
52
+ it('rejects an empty name at the input-schema decode (NonEmptyString)', async () => {
53
+ const ctx = makeTestContext({ subject, store: mockStore({ profiles: [] }) })
54
+
55
+ await expect(
56
+ invoke(createProfile, createProfileHandler, { name: '', email: 'x@y.z', ssn: '000' }, ctx),
57
+ ).rejects.toThrow()
58
+ })
59
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "exclude": ["node_modules", "dist"]
5
+ }