@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,30 @@
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
+ "typecheck": "tsc --noEmit",
10
+ "test": "voltro test"
11
+ },
12
+ "dependencies": {
13
+ "@react-email/components": "^1.0.12",
14
+ "@react-email/render": "^1.4.0",
15
+ "@voltro/cli": "0.1.0",
16
+ "@voltro/database": "0.1.0",
17
+ "@voltro/env": "0.1.0",
18
+ "@voltro/plugin-mail": "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
+ "react": "^19.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@voltro/testing": "0.1.0",
27
+ "typescript": "^5.7.0",
28
+ "vitest": "^3.0.0"
29
+ }
30
+ }
@@ -0,0 +1,14 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+
3
+ const execute = (_input: Record<string, never>, _ctx: AppContext) => ({
4
+ descriptor: {
5
+ table: 'notes' as const,
6
+ predicate: undefined,
7
+ order: [{ column: 'createdAt' as const, direction: 'desc' as const }],
8
+ take: 100,
9
+ skip: undefined,
10
+ projection: undefined,
11
+ },
12
+ })
13
+
14
+ export default execute
@@ -0,0 +1,20 @@
1
+ // Streaming subscription: every change to `notes` for the caller's
2
+ // tenant lands as a delta. The runtime AND-merges tenant scope into
3
+ // the predicate via the `tenant()` mixin on the table — no manual
4
+ // `eq('tenantId', ...)` needed in the handler.
5
+
6
+ import { defineQuery } from '@voltro/protocol'
7
+ import { Schema } from 'effect'
8
+
9
+ export const listNotes = defineQuery({
10
+ name: 'notes.list',
11
+ input: Schema.Struct({}),
12
+ output: Schema.Struct({
13
+ id: Schema.String,
14
+ title: Schema.String,
15
+ body: Schema.String,
16
+ done: Schema.Boolean,
17
+ tenantId: Schema.String,
18
+ createdAt: Schema.Date,
19
+ }),
20
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "api-backend-mail",
3
+ "kind": "api",
4
+ "summary": "Voltro backend with transactional email wired: @voltro/plugin-mail + a React-Email welcome template you preview/send from the dashboard. Same minimal base as api-backend.",
5
+ "tags": ["api", "backend", "mail", "email", "starter"]
6
+ }
@@ -0,0 +1,50 @@
1
+ // Unit test with `@voltro/testing` — no database, no running server. Importing
2
+ // `../database/schema` registers the `notes` / `actors` / `tenants` tables
3
+ // globally, so `makeTestContext` auto-wires them into the in-memory store.
4
+ // `ctx.store` is the SAME mixin-wrapped store the handler gets in production,
5
+ // so tenant auto-scoping + audit auto-fill behave exactly as at runtime.
6
+ // Run with `voltro test` (vitest).
7
+
8
+ import { describe, it, expect } from 'vitest'
9
+ import { makeTestContext, mockStore } from '@voltro/testing'
10
+ import { database } from '../database/schema' // registers notes / actors / tenants
11
+ import { TenantMismatch } from '@voltro/plugin-multitenancy/guard'
12
+ import createNote from '../mutations/notes.create.mutation.server'
13
+
14
+ describe('notes.create', () => {
15
+ it('inserts a note stamped to the caller tenant', async () => {
16
+ const ctx = makeTestContext({
17
+ subject: { type: 'user', id: 'user_1', tenantId: 'acme' },
18
+ store: mockStore({ notes: [] }),
19
+ })
20
+ const row = await createNote({ tenantId: 'acme', title: 'Hello', body: 'World' }, ctx)
21
+
22
+ expect(row['title']).toBe('Hello')
23
+ expect(row['tenantId']).toBe('acme') // assertOwnTenant let it through + stamped
24
+ expect(row['done']).toBe(false)
25
+ expect(String(row['id'])).toMatch(/^note_/) // TypeID auto-injected from id()
26
+ })
27
+
28
+ it('rejects a cross-tenant spoof — input.tenantId must match the subject', async () => {
29
+ const ctx = makeTestContext({
30
+ subject: { type: 'user', id: 'user_1', tenantId: 'acme' },
31
+ store: mockStore({ notes: [] }),
32
+ })
33
+ await expect(
34
+ createNote({ tenantId: 'other-tenant', title: 'spoof', body: '' }, ctx),
35
+ ).rejects.toBeInstanceOf(TenantMismatch)
36
+ })
37
+
38
+ it('isolates tenants — t2 never sees t1 rows (REAL tenant scoping)', async () => {
39
+ const ctx = makeTestContext({
40
+ subject: { type: 'user', id: 'u1', tenantId: 't1' },
41
+ store: mockStore({ notes: [] }),
42
+ })
43
+ await createNote({ tenantId: 't1', title: 'secret', body: '' }, ctx)
44
+
45
+ // Re-scope the SAME store to a different tenant — the real WHERE filter
46
+ // (eq tenantId) hides t1's row from t2.
47
+ const seenByT2 = await ctx.withTenant('t2', (c) => c.store.query(database.notes.descriptor))
48
+ expect(seenByT2).toHaveLength(0)
49
+ })
50
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "exclude": ["node_modules", "dist"]
5
+ }
@@ -0,0 +1,35 @@
1
+ # {{capProjectName}} — MariaDB backend env. Copy to `.env` and adjust.
2
+
3
+ # ── Database (MariaDB + binlog CDC) ────────────────────────────────────
4
+ DB_DIALECT=mariadb
5
+ DB_URL=mysql://app:app@localhost:3307/{{projectNameSnake}}
6
+ # Push-based real-time across replicas via the binlog reader. Requires the
7
+ # DB to run with binlog_format=ROW + binlog_row_image=FULL (the compose
8
+ # baseline sets these) and a user with REPLICATION SLAVE, REPLICATION
9
+ # CLIENT. Set CDC=0 to fall back to single-process inline emit.
10
+ CDC=1
11
+
12
+ # ── File storage (A2) — MinIO locally, S3 in prod ──────────────────────
13
+ STORAGE_PROVIDER=minio
14
+ S3_ENDPOINT=http://localhost:9000
15
+ S3_BUCKET={{projectNameSnake}}
16
+ S3_ACCESS_KEY_ID=minioadmin
17
+ S3_SECRET_ACCESS_KEY=minioadmin
18
+ S3_FORCE_PATH_STYLE=1
19
+
20
+ # ── AI runtime (A3) — set a real provider + key to enable agents ───────
21
+ AI_PROVIDER=mock
22
+ # AI_PROVIDER=anthropic
23
+ # AI_MODEL=claude-opus-4-7
24
+ # ANTHROPIC_API_KEY=
25
+
26
+ # ── Auth ───────────────────────────────────────────────────────────────
27
+ # HMAC key for signed sessions — REQUIRED in production (refuses to boot
28
+ # without it). Generate: openssl rand -hex 32
29
+ VOLTRO_SESSION_SECRET=dev-only-change-me
30
+
31
+ # ── Cluster (K8s, >1 replica) ──────────────────────────────────────────
32
+ # The workflow runner must advertise a routable host so a workflow can
33
+ # resume on another pod. Inject POD_IP via the downward API in prod
34
+ # (fieldRef: status.podIP); leave unset for single-node local dev.
35
+ # VOLTRO_WORKFLOW_RUNNER_HOST=
@@ -0,0 +1,31 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro backend scaffold (template: **api-backend-mariadb**) — MariaDB-backed
4
+ with binlog CDC real-time + file storage.
5
+
6
+ ## Boot
7
+
8
+ ```bash
9
+ pnpm install # at the repo root
10
+ cp .env.example .env # then adjust DB_URL / secrets
11
+ # Start MariaDB (binlog ROW) + MinIO — see the compose baseline.
12
+ pnpm --filter @{{projectName}}/{{appName}} dev
13
+ # → http://localhost:4000
14
+ # → ws://localhost:4000/ws
15
+ ```
16
+
17
+ ## What's in here
18
+
19
+ | File | Role |
20
+ |---|---|
21
+ | `app.config.ts` | `store: 'mariadb'` (binlog CDC) + the storage plugin. |
22
+ | `.env.example` | DB / storage / AI / auth / cluster env. |
23
+ | `database/schema.ts` | One example table (`notes`) with the `tenant()` mixin. |
24
+ | `queries/notes.*` | Streaming subscription example. |
25
+ | `mutations/notes.create.*` | Tenant-guarded mutation example. |
26
+
27
+ `store: 'mariadb'` fans subscriptions out across replicas via the binary
28
+ log — the DB must run with `binlog_format=ROW` + `binlog_row_image=FULL`
29
+ and a replication user (the compose baseline sets this up). Drop more
30
+ `*.query.ts` + `*.query.server.ts`, `*.mutation.ts` + `*.mutation.server.ts`, `*.action.ts` + `*.action.server.ts`, or `*.stream.ts` + `*.stream.server.ts`, `*.workflow.tsx`, or `*.cron.tsx` files
31
+ anywhere in this tree — discovery is by file convention.
@@ -0,0 +1,68 @@
1
+ // Backend app for the {{projectName}} project, backed by MariaDB. Read by
2
+ // `voltro dev` (local) and `voltro serve` (production).
3
+ //
4
+ // `store: 'mariadb'` turns on the binlog CDC reader: real-time
5
+ // subscriptions fan out across every replica via the database's binary
6
+ // log (no Redis/NATS — the binlog IS the message bus). The DB must run
7
+ // with `binlog_format=ROW` + `binlog_row_image=FULL` and a user holding
8
+ // `REPLICATION SLAVE, REPLICATION CLIENT` — the compose baseline sets all
9
+ // of this up; in prod the Helm baseline wires the per-pod `server_id`.
10
+ //
11
+ // `plugins` composes cross-cutting behaviour. File storage is on by
12
+ // default (MinIO locally, S3 in prod).
13
+ import { defineEnv, envVar } from '@voltro/env'
14
+ import { storagePlugin } from '@voltro/plugin-storage'
15
+ // Auth strategies (uncomment + configure to enable — see `auth` below):
16
+ // import { jwtBearerStrategy } from '@voltro/protocol'
17
+ // import { apiKeyStrategy } from '@voltro/protocol/apikey'
18
+
19
+ // Typed environment — declare your env once; it's validated at boot (fail-fast)
20
+ // and read on the server via `serverEnv` / `getSecret` from '@voltro/env/server'.
21
+ // `access` is required: 'public' (browser-safe) or 'secret' (server-only, never
22
+ // bundled). Run `voltro env` to see the manifest. See the Environment docs.
23
+ export const env = defineEnv({
24
+ LOG_LEVEL: envVar.enum(['debug', 'info', 'warn', 'error'], { access: 'public', default: 'info' }),
25
+ // Add your own, e.g.:
26
+ // STRIPE_KEY: envVar.string({ access: 'secret' }),
27
+ })
28
+
29
+ export default {
30
+ type: 'api' as const,
31
+ name: '{{capProjectName}}{{capAppName}}',
32
+ store: 'mariadb' as const,
33
+ env,
34
+ plugins: [
35
+ // Blobs in object storage; metadata in `_voltro_storage_refs`.
36
+ // Provider resolved from `STORAGE_PROVIDER` (minio | s3 | filesystem).
37
+ storagePlugin(),
38
+ ],
39
+
40
+ // Auth: the built-in signed-cookie password strategy ALWAYS runs first;
41
+ // these run after it, in order, until one matches or rejects. The same
42
+ // chain serves dev and prod. Uncomment + configure for your IdP / keys.
43
+ //
44
+ // auth: {
45
+ // strategies: [
46
+ // // JWKS cookie sessions — verifies a JWT from your IdP against its
47
+ // // JWKS endpoint and maps a claim to the active org (tenantId).
48
+ // jwtBearerStrategy({
49
+ // id: 'idp',
50
+ // jwksUrl: process.env.JWKS_URL!,
51
+ // issuer: process.env.JWT_ISSUER,
52
+ // cookieName: '{{projectName}}-session',
53
+ // claimsToTenantId: (claims) => (claims.org as string) ?? null,
54
+ // }),
55
+ // // `{{projectName}}_`-prefixed API keys: the strategy strips the
56
+ // // prefix, sha256-hashes the token, and hands you the hash —
57
+ // // look it up in your key table and return id/tenantId/scopes.
58
+ // apiKeyStrategy({
59
+ // prefix: '{{projectName}}_',
60
+ // resolveKey: async (hash) => {
61
+ // // const row = await lookupApiKeyByHash(hash)
62
+ // // return row ? { id: row.id, tenantId: row.orgId, scopes: row.scopes } : null
63
+ // return null
64
+ // },
65
+ // }),
66
+ // ],
67
+ // },
68
+ }
@@ -0,0 +1,57 @@
1
+ // Schema for the {{projectName}} backend.
2
+ //
3
+ // Tables are auto-discovered: every exported `table(...)` in this file
4
+ // (or any `*.entity.ts` / `*.schema.ts` file) is registered by
5
+ // `voltro dev` — no manual barrel. `actors` + `tenants` are the
6
+ // framework's core tables: the built-in `audit()` / `tenant()` /
7
+ // `softDelete()` mixins reference them, so they must be declared (the
8
+ // CLI wires them into the mixin registry once it finds them).
9
+ //
10
+ // Add the `tenant()` mixin to a table to make it tenant-scoped — the
11
+ // runtime AND-merges `eq('tenantId', subject.tenantId)` into every
12
+ // subscription predicate, so cross-tenant reads can't leak.
13
+
14
+ import {
15
+ boolean,
16
+ databaseHandle,
17
+ id,
18
+ table,
19
+ text,
20
+ timestamp,
21
+ type InferRow,
22
+ } from '@voltro/database'
23
+ import { tenant } from '@voltro/plugin-multitenancy'
24
+
25
+ // ---------- Core tables (required by the audit / tenant mixins) ----------
26
+
27
+ export const actors = table('actors', {
28
+ id: id(),
29
+ kind: text().oneOf(['user', 'serviceAccount', 'apiKey', 'system']),
30
+ displayName: text().nullable(),
31
+ createdAt: timestamp().default('now'),
32
+ })
33
+
34
+ export const tenants = table('tenants', {
35
+ id: id(),
36
+ name: text(),
37
+ createdAt: timestamp().default('now'),
38
+ })
39
+
40
+ // ---------- Application tables — rename / replace with your own ----------
41
+
42
+ export const notes = table('notes', {
43
+ id: id({ prefix: 'note' }),
44
+ title: text(),
45
+ body: text(),
46
+ done: boolean().default(false),
47
+ })
48
+ // tenant() pulls audit() transitively → adds tenantId + createdAt /
49
+ // updatedAt / createdBy / updatedBy (auto-stamped by the runtime).
50
+ .with(tenant())
51
+ // Opt into the matcher engine: subscriptions against `notes` get a
52
+ // fresh snapshot/delta whenever a mutation writes the table.
53
+ .reactive()
54
+
55
+ export type Note = InferRow<typeof notes>
56
+
57
+ export const database = databaseHandle({ actors, tenants, notes })
@@ -0,0 +1,19 @@
1
+ import { assertOwnTenant } from '@voltro/plugin-multitenancy/guard'
2
+ import type { AppContext } from '@voltro/runtime'
3
+
4
+ const execute = async (
5
+ input: { tenantId: string; title: string; body: string },
6
+ ctx: AppContext,
7
+ ) => {
8
+ assertOwnTenant(input.tenantId, ctx.request.subject)
9
+ // Framework auto-injects a `note_…` id from the table's id() decl.
10
+ return ctx.store.insert('notes', {
11
+ title: input.title,
12
+ body: input.body,
13
+ done: false,
14
+ tenantId: input.tenantId,
15
+ createdAt: new Date(),
16
+ })
17
+ }
18
+
19
+ export default execute
@@ -0,0 +1,37 @@
1
+ // Creates a note. The handler's `assertOwnTenant` guard rejects
2
+ // cross-tenant spoofing — input.tenantId MUST match the resolved
3
+ // subject's tenantId, else the rpc layer surfaces a typed
4
+ // `TenantMismatch` error.
5
+
6
+ import { defineMutation } from '@voltro/protocol'
7
+ import { TenantMismatch } from '@voltro/plugin-multitenancy/guard'
8
+ import { Schema } from 'effect'
9
+
10
+ export const createNote = defineMutation({
11
+ name: 'notes.create',
12
+ target: {
13
+ table: 'notes',
14
+ op: 'insert',
15
+ shape: (input: { tenantId: string; title: string; body: string }) => ({
16
+ title: input.title,
17
+ body: input.body,
18
+ done: false,
19
+ tenantId: input.tenantId,
20
+ createdAt: new Date(),
21
+ }),
22
+ },
23
+ input: Schema.Struct({
24
+ tenantId: Schema.String,
25
+ title: Schema.NonEmptyString,
26
+ body: Schema.String,
27
+ }),
28
+ output: Schema.Struct({
29
+ id: Schema.String,
30
+ title: Schema.String,
31
+ body: Schema.String,
32
+ done: Schema.Boolean,
33
+ tenantId: Schema.String,
34
+ createdAt: Schema.Date,
35
+ }),
36
+ error: TenantMismatch,
37
+ })
@@ -0,0 +1,30 @@
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-multitenancy": "0.1.0",
19
+ "@voltro/plugin-storage": "0.1.0",
20
+ "@voltro/protocol": "0.1.0",
21
+ "@voltro/runtime": "0.1.0",
22
+ "@voltro/sql-mysql": "0.1.0",
23
+ "effect": "^3.21.2"
24
+ },
25
+ "devDependencies": {
26
+ "@voltro/testing": "0.1.0",
27
+ "typescript": "^5.7.0",
28
+ "vitest": "^3.0.0"
29
+ }
30
+ }
@@ -0,0 +1,14 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+
3
+ const execute = (_input: Record<string, never>, _ctx: AppContext) => ({
4
+ descriptor: {
5
+ table: 'notes' as const,
6
+ predicate: undefined,
7
+ order: [{ column: 'createdAt' as const, direction: 'desc' as const }],
8
+ take: 100,
9
+ skip: undefined,
10
+ projection: undefined,
11
+ },
12
+ })
13
+
14
+ export default execute
@@ -0,0 +1,20 @@
1
+ // Streaming subscription: every change to `notes` for the caller's
2
+ // tenant lands as a delta. The runtime AND-merges tenant scope into
3
+ // the predicate via the `tenant()` mixin on the table — no manual
4
+ // `eq('tenantId', ...)` needed in the handler.
5
+
6
+ import { defineQuery } from '@voltro/protocol'
7
+ import { Schema } from 'effect'
8
+
9
+ export const listNotes = defineQuery({
10
+ name: 'notes.list',
11
+ input: Schema.Struct({}),
12
+ output: Schema.Struct({
13
+ id: Schema.String,
14
+ title: Schema.String,
15
+ body: Schema.String,
16
+ done: Schema.Boolean,
17
+ tenantId: Schema.String,
18
+ createdAt: Schema.Date,
19
+ }),
20
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "api-backend-mariadb",
3
+ "kind": "api",
4
+ "summary": "MariaDB-backed Voltro backend: binlog CDC real-time, file storage (MinIO/S3), tenant-aware schema. The dogfooded shape for K8s multi-replica apps.",
5
+ "tags": ["api", "backend", "mariadb", "cdc", "storage", "k8s"]
6
+ }
@@ -0,0 +1,50 @@
1
+ // Unit test with `@voltro/testing` — no database, no running server. The
2
+ // MariaDB store dialect is IRRELEVANT here: `makeTestContext` runs the handler
3
+ // against the in-memory harness, so tenant auto-scoping + audit auto-fill
4
+ // behave exactly as at runtime regardless of the production store. Importing
5
+ // `../database/schema` registers the `notes` / `actors` / `tenants` tables
6
+ // globally. Run with `voltro test` (vitest).
7
+
8
+ import { describe, it, expect } from 'vitest'
9
+ import { makeTestContext, mockStore } from '@voltro/testing'
10
+ import { database } from '../database/schema' // registers notes / actors / tenants
11
+ import { TenantMismatch } from '@voltro/plugin-multitenancy/guard'
12
+ import createNote from '../mutations/notes.create.mutation.server'
13
+
14
+ describe('notes.create', () => {
15
+ it('inserts a note stamped to the caller tenant', async () => {
16
+ const ctx = makeTestContext({
17
+ subject: { type: 'user', id: 'user_1', tenantId: 'acme' },
18
+ store: mockStore({ notes: [] }),
19
+ })
20
+ const row = await createNote({ tenantId: 'acme', title: 'Hello', body: 'World' }, ctx)
21
+
22
+ expect(row['title']).toBe('Hello')
23
+ expect(row['tenantId']).toBe('acme') // assertOwnTenant let it through + stamped
24
+ expect(row['done']).toBe(false)
25
+ expect(String(row['id'])).toMatch(/^note_/) // TypeID auto-injected from id()
26
+ })
27
+
28
+ it('rejects a cross-tenant spoof — input.tenantId must match the subject', async () => {
29
+ const ctx = makeTestContext({
30
+ subject: { type: 'user', id: 'user_1', tenantId: 'acme' },
31
+ store: mockStore({ notes: [] }),
32
+ })
33
+ await expect(
34
+ createNote({ tenantId: 'other-tenant', title: 'spoof', body: '' }, ctx),
35
+ ).rejects.toBeInstanceOf(TenantMismatch)
36
+ })
37
+
38
+ it('isolates tenants — t2 never sees t1 rows (REAL tenant scoping)', async () => {
39
+ const ctx = makeTestContext({
40
+ subject: { type: 'user', id: 'u1', tenantId: 't1' },
41
+ store: mockStore({ notes: [] }),
42
+ })
43
+ await createNote({ tenantId: 't1', title: 'secret', body: '' }, ctx)
44
+
45
+ // Re-scope the SAME store to a different tenant — the real WHERE filter
46
+ // (eq tenantId) hides t1's row from t2.
47
+ const seenByT2 = await ctx.withTenant('t2', (c) => c.store.query(database.notes.descriptor))
48
+ expect(seenByT2).toHaveLength(0)
49
+ })
50
+ })
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "include": ["**/*.ts", "**/*.tsx"],
4
+ "exclude": ["node_modules", "dist"]
5
+ }
@@ -0,0 +1,86 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro backend scaffold (template: **api-backend-storage**).
4
+
5
+ ## Boot
6
+
7
+ ```bash
8
+ pnpm install # at the repo root
9
+ pnpm --filter @{{projectName}}/{{appName}} dev
10
+ # → http://localhost:4000
11
+ # → ws://localhost:4000/ws
12
+ ```
13
+
14
+ ## What's in here
15
+
16
+ | File | Role |
17
+ |---|---|
18
+ | `app.config.ts` | App declaration + `storagePlugin` wired (`memory` provider). |
19
+ | `database/schema.ts` | One example table (`notes`) with the `tenant()` mixin. |
20
+ | `queries/` + `mutations/` | Streaming subscription + tenant-guarded mutation examples. |
21
+ | `actions/uploadAvatar.{rpc,handler}.ts` | `storage.uploadAvatar` — stores a PUBLIC avatar, returns its URL. |
22
+ | `actions/uploadDocument.{rpc,handler}.ts` | `storage.uploadDocument` — stores a PRIVATE doc (owner + admin + tenant policy). |
23
+
24
+ ## Storage
25
+
26
+ File storage is wired out of the box via `@voltro/plugin-storage`:
27
+
28
+ - **Public objects** (`visibility: 'public'`) are served direct from the
29
+ bucket/CDN — set `cdnBaseUrl` on the plugin for production. The app's
30
+ `/_voltro/storage/:id` route is only a fallback for the `memory` /
31
+ `filesystem` providers in dev.
32
+ - **Private objects** (default) are gated by an **access policy** — any-of
33
+ rules over `owner` / `roles` / `groups` / `scopes` / `tenant` / `apiKey`
34
+ / `password` / a custom `guard` — PLUS **per-object grants** (share a
35
+ file with a specific user / group / api-key, optionally expiring).
36
+ - **Browse + share** stored objects from the dashboard's **Storage** tab
37
+ (`/_voltro/inspect/plugins/storage/*`).
38
+
39
+ ### Delivering a private file
40
+
41
+ ```ts
42
+ // In an action/handler — access-checked, returns a presigned URL (s3) or
43
+ // an app URL carrying a short-lived signed grant token (fs/memory):
44
+ import { StorageService } from '@voltro/plugin-storage'
45
+ const storage = yield* StorageService
46
+ const url = yield* storage.mintUrl(fileId, ctx.request.subject)
47
+ ```
48
+
49
+ Or use the plugin's built-in typed RPC routes from the client:
50
+ `storage.upload`, `storage.mintUrl`, `storage.mintUploadUrl` (presigned
51
+ PUT), `storage.share`, `storage.revoke`, `storage.listGrants`.
52
+
53
+ ### Switching providers
54
+
55
+ ```ts
56
+ storagePlugin({ provider: 's3', bucket: 'my-bucket', region: 'us-east-1',
57
+ cdnBaseUrl: 'https://cdn.example.com' }) // + S3_* env
58
+ storagePlugin({ provider: 'minio', bucket: 'my-bucket', endpoint: 'http://localhost:9000' })
59
+ storagePlugin({ provider: 'azure', bucket: 'my-container', accountName: 'acct' }) // + AZURE_STORAGE_KEY
60
+ storagePlugin({ provider: 'filesystem', root: '.voltro-storage' })
61
+ storagePlugin({ provider: 'database' }) // bytes in your DB — zero extra infra
62
+ ```
63
+
64
+ Any S3-compatible bucket works via `endpoint` (AWS, Cloudflare R2, GCS,
65
+ Backblaze B2, MinIO, Wasabi). `azure` covers Azure Blob; `database` keeps
66
+ small blobs in the app's DB. `_voltro_storage_refs` +
67
+ `_voltro_storage_grants` (+ `_voltro_storage_blobs` for the `database`
68
+ provider) are auto-migrated on `store: 'postgres'`.
69
+
70
+ ### Constraints, virus scanning & image transforms
71
+
72
+ ```ts
73
+ import { storagePlugin, clamavScanner } from '@voltro/plugin-storage'
74
+
75
+ storagePlugin({
76
+ provider: 'memory',
77
+ limits: { maxBytes: 10_000_000, allowedContentTypes: ['image/*', 'application/pdf'], sniff: true },
78
+ scan: clamavScanner({ host: '127.0.0.1', port: 3310 }), // optional — needs a clamd
79
+ })
80
+ ```
81
+
82
+ - **Constraints** reject oversized / wrong-type uploads (`sniff` magic-byte-checks
83
+ the bytes) with a typed `StorageRejected`.
84
+ - **Virus scan** runs on every `put`; a detection fails with `StorageScanRejected`.
85
+ - **Image transforms** are on-the-fly via the serve URL — `?w=400&format=webp&q=80`
86
+ (needs the optional `sharp` dependency).
@@ -0,0 +1,21 @@
1
+ import { Effect } from 'effect'
2
+ import type { AppContext } from '@voltro/runtime'
3
+ import { StorageService } from '@voltro/plugin-storage'
4
+
5
+ const execute = (input: { bytesBase64: string; contentType: string }, ctx: AppContext) =>
6
+ Effect.gen(function* () {
7
+ const storage = yield* StorageService
8
+ const bytes = new Uint8Array(Buffer.from(input.bytesBase64, 'base64'))
9
+ const ref = yield* storage.put({
10
+ bytes,
11
+ contentType: input.contentType,
12
+ visibility: 'public',
13
+ ownerId: ctx.request.subject.id,
14
+ tenantId: ctx.request.subject.tenantId,
15
+ key: `avatars/${ctx.request.subject.id ?? 'anon'}/avatar`,
16
+ })
17
+ const url = yield* storage.getUrl(ref.id)
18
+ return { id: ref.id, url }
19
+ })
20
+
21
+ export default execute
@@ -0,0 +1,21 @@
1
+ // `storage.uploadAvatar` — stores a PUBLIC avatar. Public objects are
2
+ // served direct from the bucket/CDN; the returned `url` is what you'd put
3
+ // in an <img src>. File upload is external I/O → an action.
4
+ //
5
+ // For large files prefer a presigned direct-to-bucket upload via the
6
+ // plugin's built-in `storage.mintUploadUrl` route.
7
+
8
+ import { Schema } from 'effect'
9
+ import { defineAction } from '@voltro/protocol'
10
+
11
+ export const uploadAvatar = defineAction({
12
+ name: 'storage.uploadAvatar',
13
+ input: Schema.Struct({
14
+ bytesBase64: Schema.String,
15
+ contentType: Schema.String,
16
+ }),
17
+ output: Schema.Struct({
18
+ id: Schema.String,
19
+ url: Schema.String,
20
+ }),
21
+ })