@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,36 @@
1
+ // German catalog. Mirrors every key in `en.ts` — `defineLocale<typeof en>()`
2
+ // fails the build if a key is missing or misspelled. Translate the prose only;
3
+ // keep ICU placeholders (`{tenant}`, `{revision}`, `{count}`, `{time}`, `{error}`)
4
+ // and rich tags (`<code>`, `<a>`, `<strong>`) identical to `en.ts`.
5
+
6
+ import { defineLocale } from '@voltro/i18n'
7
+ import en from './en'
8
+
9
+ export default defineLocale<typeof en>()({
10
+ 'meta.notes.title': 'Reaktive Notizen',
11
+ 'meta.schemaUi.title': 'Schema-getriebene UI',
12
+
13
+ 'nav.notes': 'Notizen',
14
+ 'nav.schemaUi': 'Schema-UI',
15
+ 'nav.tagline': 'Fullstack · reaktiv end-to-end',
16
+ 'lang.label': 'Sprache',
17
+
18
+ 'notes.heading': 'Reaktive Notizen',
19
+ 'notes.status.tenant': 'Mandant <code>{tenant}</code> · Revision {revision}',
20
+ 'notes.status.delta': ' · letztes Delta {time}',
21
+ 'notes.status.pending': ' · {count} ausstehend',
22
+ 'notes.status.loading': ' · lädt…',
23
+ 'notes.error': 'Subscription-Fehler — läuft die API? {error}',
24
+ 'notes.field.title': 'Titel',
25
+ 'notes.field.body': 'Text (optional)',
26
+ 'notes.add': 'Notiz hinzufügen',
27
+ 'notes.adding': 'Wird hinzugefügt…',
28
+ 'notes.empty': 'Noch keine Notizen — füge oben eine hinzu und sieh zu, wie sie sofort erscheint.',
29
+
30
+ 'schemaUi.heading': 'Schema-getriebene UI',
31
+ 'schemaUi.intro': 'Dieselben Notizen wie auf <a>der Startseite</a> — aber Formular + Tabelle sind hier <strong>an Deskriptoren gebunden</strong>, nicht handverdrahtet. Felder kommen aus dem Input-Schema von <code>notes.create</code>; Spalten aus dem Output-Schema von <code>notes.list</code>. Live + optimistisch, ohne Glue-Code.',
32
+ 'schemaUi.createHeading': 'Erstellen (gebunden an <code>notes.create</code>)',
33
+ 'schemaUi.listHeading': 'Liste (gebunden an <code>notes.list</code>)',
34
+ 'schemaUi.submitLabel': 'Notiz hinzufügen',
35
+ 'schemaUi.emptyText': 'Noch keine Notizen — füge oben eine hinzu.',
36
+ })
@@ -0,0 +1,43 @@
1
+ // Base catalog — the source of truth for this app's UI strings. Every key here
2
+ // MUST be mirrored in `de.ts` (and any other locale); `defineLocale<typeof en>()`
3
+ // enforces that parity at build time, so a missing translation fails typecheck
4
+ // rather than silently falling back.
5
+ //
6
+ // Messages use ICU syntax: `{name}` placeholders, `{n, plural, …}`, and rich
7
+ // tags like `<code>…</code>` (rendered by passing a matching function to
8
+ // `<T values={{ code: (c) => <code>{c}</code> }} />`).
9
+
10
+ import { defineCatalog } from '@voltro/i18n'
11
+
12
+ export default defineCatalog({
13
+ // Browser tab titles — locale-aware via each page's `meta({ locale })`.
14
+ 'meta.notes.title': 'Reactive notes',
15
+ 'meta.schemaUi.title': 'Schema-driven UI',
16
+
17
+ // ---- Layout shell (pages/layout.tsx) ----
18
+ 'nav.notes': 'Notes',
19
+ 'nav.schemaUi': 'Schema UI',
20
+ 'nav.tagline': 'fullstack · reactive end-to-end',
21
+ 'lang.label': 'Language',
22
+
23
+ // ---- Notes page (pages/index.tsx) ----
24
+ 'notes.heading': 'Reactive notes',
25
+ 'notes.status.tenant': 'Tenant <code>{tenant}</code> · revision {revision}',
26
+ 'notes.status.delta': ' · last delta {time}',
27
+ 'notes.status.pending': ' · {count} pending',
28
+ 'notes.status.loading': ' · loading…',
29
+ 'notes.error': 'subscription error — is the api running? {error}',
30
+ 'notes.field.title': 'Title',
31
+ 'notes.field.body': 'Body (optional)',
32
+ 'notes.add': 'Add note',
33
+ 'notes.adding': 'Adding…',
34
+ 'notes.empty': 'No notes yet — add one above and watch it appear instantly.',
35
+
36
+ // ---- Schema-driven UI page (pages/schema-ui.tsx) ----
37
+ 'schemaUi.heading': 'Schema-driven UI',
38
+ 'schemaUi.intro': 'The same notes as <a>the home page</a> — but the form + table here are <strong>bound to descriptors</strong>, not hand-wired. Fields come from <code>notes.create</code>’s input schema; columns from <code>notes.list</code>’s output schema. Live + optimistic, zero glue.',
39
+ 'schemaUi.createHeading': 'Create (bound to <code>notes.create</code>)',
40
+ 'schemaUi.listHeading': 'List (bound to <code>notes.list</code>)',
41
+ 'schemaUi.submitLabel': 'Add note',
42
+ 'schemaUi.emptyText': 'No notes yet — add one above.',
43
+ } as const)
@@ -0,0 +1,15 @@
1
+ // Catalog lookup OUTSIDE React — for a page's `meta({ locale })` locale-aware
2
+ // <title>. This app is cookie-i18n (no `/<locale>` URL prefix), so @voltro/web
3
+ // hands `meta` the active locale from the `voltro:lang` cookie. Inside React,
4
+ // use `<T>` / `useT()` via the framework's auto-wired <I18nProvider> instead.
5
+
6
+ import en from './en'
7
+ import de from './de'
8
+
9
+ // Both catalogs share `en`'s keys (defineLocale enforces the mirror), so a
10
+ // known-key lookup returns `string` — not `string | undefined` — which is what
11
+ // `PageMeta.title` requires under exactOptionalPropertyTypes.
12
+ export type Messages = Record<keyof typeof en, string>
13
+
14
+ export const getCatalog = (locale?: string): Messages =>
15
+ (locale === 'de' ? de : en) as Messages
@@ -0,0 +1,167 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/` — the reactive notes page. It binds `useSubscription('app','notes.list')`
4
+ // + `useMutation('app','notes.create')` from @voltro/client. We mock that module
5
+ // so the render is deterministic and assert the observable output: loading /
6
+ // empty / list states, optimistic-row styling, subscription-error banner, and
7
+ // the submit path calling create.mutate with the trimmed title + body + tenant.
8
+
9
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
10
+ import { act, createElement, type ReactNode } from 'react'
11
+ import { createRoot, type Root } from 'react-dom/client'
12
+ import { I18nProvider } from '@voltro/i18n'
13
+ import enCatalog from '../locales/en'
14
+
15
+ interface SubState {
16
+ data: unknown
17
+ revision?: number
18
+ emittedAt?: number
19
+ error?: unknown
20
+ pendingPatches?: number
21
+ }
22
+
23
+ const useSubscription = vi.fn<() => SubState>()
24
+ const mutate = vi.fn<(input: unknown) => Promise<unknown>>()
25
+ const useMutation = vi.fn(() => ({ mutate, pending: false, error: undefined, data: undefined }))
26
+
27
+ vi.mock('@voltro/client', () => ({
28
+ useSubscription: (...a: unknown[]) => useSubscription(...(a as [])),
29
+ useMutation: (...a: unknown[]) => useMutation(...(a as [])),
30
+ }))
31
+
32
+ const { default: IndexPage } = await import('./index')
33
+
34
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
35
+
36
+ let container: HTMLDivElement
37
+ let root: Root
38
+
39
+ // The page uses <T>/useTFn, so it needs an <I18nProvider>. Wrap with the real
40
+ // English catalog (the framework auto-wires this provider in the running app).
41
+ const render = (node: ReactNode): void => {
42
+ container = document.createElement('div')
43
+ document.body.appendChild(container)
44
+ act(() => {
45
+ root = createRoot(container)
46
+ root.render(
47
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
48
+ )
49
+ })
50
+ }
51
+
52
+ const setInput = (el: HTMLInputElement | HTMLTextAreaElement, value: string): void => {
53
+ const proto =
54
+ el instanceof window.HTMLTextAreaElement
55
+ ? window.HTMLTextAreaElement.prototype
56
+ : window.HTMLInputElement.prototype
57
+ const setter = Object.getOwnPropertyDescriptor(proto, 'value')!.set!
58
+ act(() => {
59
+ setter.call(el, value)
60
+ el.dispatchEvent(new Event('input', { bubbles: true }))
61
+ })
62
+ }
63
+
64
+ beforeEach(() => {
65
+ useSubscription.mockReset()
66
+ mutate.mockReset()
67
+ mutate.mockResolvedValue(undefined)
68
+ useMutation.mockClear()
69
+ useMutation.mockReturnValue({ mutate, pending: false, error: undefined, data: undefined })
70
+ })
71
+
72
+ afterEach(() => {
73
+ if (root) act(() => root.unmount())
74
+ container?.remove()
75
+ document.body.innerHTML = ''
76
+ })
77
+
78
+ describe('index — subscription states', () => {
79
+ test('shows the loading hint before the first snapshot (data undefined)', () => {
80
+ useSubscription.mockReturnValue({ data: undefined, revision: -1 })
81
+ render(createElement(IndexPage))
82
+ expect(container.textContent).toContain('loading…')
83
+ expect(container.querySelectorAll('li')).toHaveLength(0)
84
+ })
85
+
86
+ test('shows the empty state once a snapshot arrives with no rows', () => {
87
+ useSubscription.mockReturnValue({ data: [], revision: 0 })
88
+ render(createElement(IndexPage))
89
+ expect(container.textContent).toContain('No notes yet')
90
+ })
91
+
92
+ test('renders each note with its title and body', () => {
93
+ useSubscription.mockReturnValue({
94
+ data: [
95
+ { id: 'n_1', title: 'first', body: 'body one', done: false, tenantId: 'acme', createdAt: new Date(0) },
96
+ { id: 'n_2', title: 'second', body: '', done: false, tenantId: 'acme', createdAt: new Date(0) },
97
+ ],
98
+ revision: 3,
99
+ })
100
+ render(createElement(IndexPage))
101
+ const items = Array.from(container.querySelectorAll('li'))
102
+ expect(items).toHaveLength(2)
103
+ expect(container.textContent).toContain('first')
104
+ expect(container.textContent).toContain('body one')
105
+ expect(container.textContent).toContain('second')
106
+ })
107
+
108
+ test('renders optimistic rows faintly + italicised', () => {
109
+ useSubscription.mockReturnValue({
110
+ data: [
111
+ { id: 'n_opt', title: 'pending', body: '', done: false, tenantId: 'acme', createdAt: new Date(0), optimistic: true },
112
+ ],
113
+ revision: 1,
114
+ pendingPatches: 1,
115
+ })
116
+ render(createElement(IndexPage))
117
+ const li = container.querySelector('li')!
118
+ expect(li.style.opacity).toBe('0.5')
119
+ expect(li.style.fontStyle).toBe('italic')
120
+ expect(container.textContent).toContain('1 pending')
121
+ })
122
+
123
+ test('renders the subscription error banner when error is set', () => {
124
+ useSubscription.mockReturnValue({ data: undefined, error: 'boom', revision: -1 })
125
+ render(createElement(IndexPage))
126
+ expect(container.textContent).toContain('subscription error')
127
+ expect(container.textContent).toContain('boom')
128
+ })
129
+ })
130
+
131
+ describe('index — create form', () => {
132
+ test('the Add button is disabled until a non-empty title is typed', () => {
133
+ useSubscription.mockReturnValue({ data: [], revision: 0 })
134
+ render(createElement(IndexPage))
135
+ const button = container.querySelector('button[type="submit"]') as HTMLButtonElement
136
+ expect(button.disabled).toBe(true)
137
+ setInput(container.querySelector('input') as HTMLInputElement, 'a note')
138
+ expect(button.disabled).toBe(false)
139
+ })
140
+
141
+ test('submitting calls create.mutate with the trimmed title + body + tenant, then clears', async () => {
142
+ useSubscription.mockReturnValue({ data: [], revision: 0 })
143
+ render(createElement(IndexPage))
144
+ const input = container.querySelector('input') as HTMLInputElement
145
+ const textarea = container.querySelector('textarea') as HTMLTextAreaElement
146
+ setInput(input, ' my title ')
147
+ setInput(textarea, ' my body ')
148
+ const form = container.querySelector('form') as HTMLFormElement
149
+ await act(async () => {
150
+ form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }))
151
+ })
152
+ expect(mutate).toHaveBeenCalledWith({ tenantId: 'acme', title: 'my title', body: 'my body' })
153
+ expect(input.value).toBe('')
154
+ expect(textarea.value).toBe('')
155
+ })
156
+
157
+ test('a whitespace-only title does not fire a mutation', async () => {
158
+ useSubscription.mockReturnValue({ data: [], revision: 0 })
159
+ render(createElement(IndexPage))
160
+ setInput(container.querySelector('input') as HTMLInputElement, ' ')
161
+ const form = container.querySelector('form') as HTMLFormElement
162
+ await act(async () => {
163
+ form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }))
164
+ })
165
+ expect(mutate).not.toHaveBeenCalled()
166
+ })
167
+ })
@@ -0,0 +1,136 @@
1
+ // `/` — the notes page. Auto-mapped from src/pages/index.tsx by the
2
+ // framework's file-convention page discovery.
3
+ //
4
+ // THIS is the reactive end-to-end loop. `useSubscription('app',
5
+ // 'notes.list')` opens a live WebSocket subscription to the api's
6
+ // `notes.list` query; `useMutation('app', 'notes.create')` invokes the
7
+ // `notes.create` mutation. When the mutation commits, the server pushes a
8
+ // delta and this list re-renders — no refetch, no polling.
9
+ //
10
+ // Auto-optimistic: `notes.create` declares `target: { table: 'notes', op:
11
+ // 'insert' }` server-side, so the framework prepends an optimistic row to
12
+ // this subscription the instant you submit — and replaces it with the real
13
+ // row (or reverts it) when the rpc resolves. There is no `.withOptimistic`,
14
+ // no `useOptimistic`, no `startTransition` — just `create.mutate(input)`.
15
+
16
+ import { useMutation, useSubscription } from '@voltro/client'
17
+ import { useState, type FormEvent, type ReactNode } from 'react'
18
+ import type { PageMeta } from '@voltro/web'
19
+ import { T, useTFn } from '@voltro/i18n'
20
+ import { getCatalog } from '../locales'
21
+
22
+ // Locale-aware tab title: @voltro/web resolves meta({ locale }) from the
23
+ // active locale (the `voltro:lang` cookie in this cookie-i18n app).
24
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
25
+ title: getCatalog(locale)['meta.notes.title'],
26
+ })
27
+
28
+ // The dev AuthMiddleware resolves the tenant from the `x-tenant` header,
29
+ // defaulting to 'acme'. The `notes` table carries the `tenant()` mixin, so
30
+ // reads are auto-scoped to this tenant and `notes.create` guards that the
31
+ // submitted tenantId matches the caller's (a typed TenantMismatch otherwise).
32
+ const TENANT = 'acme'
33
+
34
+ interface Note {
35
+ readonly id: string
36
+ readonly title: string
37
+ readonly body: string
38
+ readonly done: boolean
39
+ readonly tenantId: string
40
+ readonly createdAt: Date
41
+ readonly optimistic?: boolean
42
+ }
43
+
44
+ const IndexPage = (): ReactNode => {
45
+ const { data, revision, emittedAt, error, pendingPatches } =
46
+ useSubscription<ReadonlyArray<Note>>('app', 'notes.list')
47
+
48
+ const create = useMutation<{ tenantId: string; title: string; body: string }>('app', 'notes.create')
49
+ const t = useTFn()
50
+
51
+ const notes = data ?? []
52
+ const [title, setTitle] = useState('')
53
+ const [body, setBody] = useState('')
54
+
55
+ const handleSubmit = async (event: FormEvent) => {
56
+ event.preventDefault()
57
+ const trimmedTitle = title.trim()
58
+ if (trimmedTitle.length === 0) return
59
+ setTitle('')
60
+ setBody('')
61
+ try {
62
+ await create.mutate({ tenantId: TENANT, title: trimmedTitle, body: body.trim() })
63
+ } catch (mutationError) {
64
+ // notes.create can fail with a typed TenantMismatch; surface it however
65
+ // your UI prefers. The optimistic row auto-reverts on failure.
66
+ console.error('notes.create failed:', mutationError)
67
+ }
68
+ }
69
+
70
+ return (
71
+ <section>
72
+ <h1 style={{ fontSize: 24, marginBottom: 4 }}><T id="notes.heading" /></h1>
73
+ <p style={{ color: '#666', marginTop: 0, fontSize: 13 }}>
74
+ <T
75
+ id="notes.status.tenant"
76
+ values={{ tenant: TENANT, revision, code: (c: ReactNode) => <code>{c}</code> }}
77
+ />
78
+ {emittedAt ? (
79
+ <T id="notes.status.delta" values={{ time: new Date(emittedAt).toLocaleTimeString() }} />
80
+ ) : null}
81
+ {pendingPatches > 0 && <T id="notes.status.pending" values={{ count: pendingPatches }} />}
82
+ {data === undefined && error === undefined && <T id="notes.status.loading" />}
83
+ </p>
84
+
85
+ {error !== undefined && (
86
+ <p style={{ color: '#c00', fontSize: 13 }}>
87
+ <T id="notes.error" values={{ error: String(error) }} />
88
+ </p>
89
+ )}
90
+
91
+ <form onSubmit={handleSubmit} style={{ display: 'grid', gap: 8, margin: '16px 0' }}>
92
+ <input
93
+ value={title}
94
+ onChange={(event) => setTitle(event.target.value)}
95
+ placeholder={t('notes.field.title')}
96
+ style={{ padding: '6px 10px', fontSize: 14 }}
97
+ />
98
+ <textarea
99
+ value={body}
100
+ onChange={(event) => setBody(event.target.value)}
101
+ placeholder={t('notes.field.body')}
102
+ rows={2}
103
+ style={{ padding: '6px 10px', fontSize: 14, resize: 'vertical' }}
104
+ />
105
+ <button type="submit" disabled={title.trim().length === 0 || create.pending} style={{ justifySelf: 'start' }}>
106
+ {create.pending ? t('notes.adding') : t('notes.add')}
107
+ </button>
108
+ </form>
109
+
110
+ {notes.length === 0 && data !== undefined && (
111
+ <p style={{ color: '#999' }}><T id="notes.empty" /></p>
112
+ )}
113
+
114
+ <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'grid', gap: 8 }}>
115
+ {notes.map((note) => (
116
+ <li
117
+ key={note.id}
118
+ style={{
119
+ border: '1px solid #eee',
120
+ borderRadius: 6,
121
+ padding: '10px 12px',
122
+ // Optimistic rows (not yet confirmed by the server) render faintly.
123
+ opacity: note.optimistic ? 0.5 : 1,
124
+ fontStyle: note.optimistic ? 'italic' : 'normal',
125
+ }}
126
+ >
127
+ <strong>{note.title}</strong>
128
+ {note.body && <p style={{ margin: '4px 0 0', color: '#444', fontSize: 14 }}>{note.body}</p>}
129
+ </li>
130
+ ))}
131
+ </ul>
132
+ </section>
133
+ )
134
+ }
135
+
136
+ export default IndexPage
@@ -0,0 +1,41 @@
1
+ // Root layout that wraps every page in this app. `<html>` / `<head>` /
2
+ // `<body>` are owned by the framework's index.html shell — don't render
3
+ // them here. Use a page's `meta` export for title + meta tags, and
4
+ // `theme: 'dark' | 'light' | 'system'` in app.config.ts for the dark class.
5
+ //
6
+ // The app is bilingual (see `locales` in app.config.ts): nav labels come from
7
+ // the catalog via `<T>`, and <LocaleSwitcher> writes the `voltro:lang` cookie
8
+ // + reloads so the framework re-renders in the chosen language.
9
+
10
+ import type { ReactNode } from 'react'
11
+ import { T, useLocale, useT } from '@voltro/i18n'
12
+ import { LocaleSwitcher } from '@voltro/ui-shadcn'
13
+
14
+ interface LayoutProps {
15
+ readonly children: ReactNode
16
+ }
17
+
18
+ const LOCALES = [
19
+ { code: 'en', label: 'English' },
20
+ { code: 'de', label: 'Deutsch' },
21
+ ]
22
+
23
+ export default function Layout({ children }: LayoutProps): ReactNode {
24
+ const locale = useLocale()
25
+ const langLabel = useT('lang.label')
26
+ return (
27
+ <div style={{ maxWidth: 640, margin: '0 auto', padding: '24px 16px', fontFamily: 'system-ui, sans-serif' }}>
28
+ <header style={{ display: 'flex', gap: 16, alignItems: 'baseline', marginBottom: 24 }}>
29
+ <strong style={{ fontSize: 16 }}>{{capProjectName}}</strong>
30
+ {/* Internal <a>s are SPA-intercepted by the Router (no full reload). */}
31
+ <nav style={{ display: 'flex', gap: 12, fontSize: 13 }}>
32
+ <a href="/"><T id="nav.notes" /></a>
33
+ <a href="/schema-ui"><T id="nav.schemaUi" /></a>
34
+ </nav>
35
+ <span style={{ color: '#999', fontSize: 12, marginLeft: 'auto' }}><T id="nav.tagline" /></span>
36
+ <LocaleSwitcher locales={LOCALES} current={locale} ariaLabel={langLabel} />
37
+ </header>
38
+ <main>{children}</main>
39
+ </div>
40
+ )
41
+ }
@@ -0,0 +1,99 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/schema-ui` — the schema-driven-UI twin of the notes page. It binds
4
+ // <AutoForm> to the `notes.create` mutation and <DataTable> to the `notes.list`
5
+ // query, with title + body Fields. The real AutoForm/DataTable need a live
6
+ // framework runtime; here we mock them (from @voltro/web) as prop-recording
7
+ // sentinels and assert the page passes the right descriptor bindings + defaults.
8
+
9
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
10
+ import { act, createElement, type ReactNode } from 'react'
11
+ import { createRoot, type Root } from 'react-dom/client'
12
+ import { I18nProvider } from '@voltro/i18n'
13
+ import enCatalog from '../locales/en'
14
+
15
+ interface AutoFormProps {
16
+ api: string
17
+ mutation: string
18
+ defaults?: Record<string, unknown>
19
+ submitLabel?: string
20
+ children?: () => ReactNode
21
+ }
22
+ interface DataTableProps {
23
+ api: string
24
+ query: string
25
+ emptyText?: string
26
+ }
27
+
28
+ const autoFormProps: AutoFormProps[] = []
29
+ const dataTableProps: DataTableProps[] = []
30
+
31
+ vi.mock('@voltro/web', () => ({
32
+ AutoForm: (props: AutoFormProps) => {
33
+ autoFormProps.push(props)
34
+ return createElement('div', { 'data-testid': 'auto-form' }, props.children?.())
35
+ },
36
+ DataTable: (props: DataTableProps) => {
37
+ dataTableProps.push(props)
38
+ return createElement('div', { 'data-testid': 'data-table' })
39
+ },
40
+ Field: ({ name }: { name: string }) =>
41
+ createElement('span', { 'data-testid': `field-${name}` }, name),
42
+ }))
43
+
44
+ const { default: SchemaUiPage } = await import('./schema-ui')
45
+
46
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
47
+
48
+ let container: HTMLDivElement
49
+ let root: Root
50
+
51
+ // The page uses <T>/useTFn, so it needs an <I18nProvider> (real English catalog).
52
+ const render = (node: ReactNode): void => {
53
+ container = document.createElement('div')
54
+ document.body.appendChild(container)
55
+ act(() => {
56
+ root = createRoot(container)
57
+ root.render(
58
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
59
+ )
60
+ })
61
+ }
62
+
63
+ beforeEach(() => {
64
+ autoFormProps.length = 0
65
+ dataTableProps.length = 0
66
+ })
67
+
68
+ afterEach(() => {
69
+ if (root) act(() => root.unmount())
70
+ container?.remove()
71
+ document.body.innerHTML = ''
72
+ })
73
+
74
+ describe('schema-ui — descriptor bindings', () => {
75
+ test('binds AutoForm to notes.create with the tenant default + title & body Fields', () => {
76
+ render(createElement(SchemaUiPage))
77
+ expect(autoFormProps).toHaveLength(1)
78
+ expect(autoFormProps[0]).toMatchObject({
79
+ api: 'app',
80
+ mutation: 'notes.create',
81
+ defaults: { tenantId: 'acme', done: false },
82
+ })
83
+ expect(container.querySelector('[data-testid="field-title"]')).toBeTruthy()
84
+ expect(container.querySelector('[data-testid="field-body"]')).toBeTruthy()
85
+ })
86
+
87
+ test('binds DataTable to the notes.list query with empty text', () => {
88
+ render(createElement(SchemaUiPage))
89
+ expect(dataTableProps).toHaveLength(1)
90
+ expect(dataTableProps[0]).toMatchObject({ api: 'app', query: 'notes.list' })
91
+ expect(dataTableProps[0]!.emptyText).toContain('No notes yet')
92
+ })
93
+
94
+ test('renders the Schema-driven UI heading', () => {
95
+ render(createElement(SchemaUiPage))
96
+ const headings = Array.from(container.querySelectorAll('h1,h2')).map((h) => h.textContent)
97
+ expect(headings.some((h) => h?.includes('Schema-driven UI'))).toBe(true)
98
+ })
99
+ })
@@ -0,0 +1,74 @@
1
+ // `/schema-ui` — the SAME notes as `/` (index.tsx), but rendered by the
2
+ // schema-driven UI components instead of hand-wired hooks. index.tsx wires
3
+ // useSubscription + useMutation + form state by hand (the reactive baseline);
4
+ // this page binds <DataTable> to `notes.list` and <AutoForm> to `notes.create`.
5
+ // The columns + fields come straight from the descriptors' effect/Schema, and
6
+ // validation, live updates, and auto-optimistic come for free — no glue code.
7
+ //
8
+ // Delete this page if you don't need it; it's here to show the binding.
9
+
10
+ import { AutoForm, DataTable, Field } from '@voltro/web'
11
+ import type { PageMeta } from '@voltro/web'
12
+ import type { ReactNode } from 'react'
13
+ import { T, useTFn } from '@voltro/i18n'
14
+ import { getCatalog } from '../locales'
15
+
16
+ const TENANT = 'acme'
17
+
18
+ // Locale-aware tab title (cookie-i18n — @voltro/web hands meta the active locale).
19
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
20
+ title: getCatalog(locale)['meta.schemaUi.title'],
21
+ })
22
+
23
+ const SchemaUiPage = (): ReactNode => {
24
+ const t = useTFn()
25
+ return (
26
+ <section style={{ display: 'grid', gap: '1.5rem' }}>
27
+ <header>
28
+ <h1 style={{ fontSize: 24, marginBottom: 4 }}><T id="schemaUi.heading" /></h1>
29
+ <p style={{ color: '#666', marginTop: 0, fontSize: 13 }}>
30
+ <T
31
+ id="schemaUi.intro"
32
+ values={{
33
+ a: (c: ReactNode) => <a href="/">{c}</a>,
34
+ strong: (c: ReactNode) => <strong>{c}</strong>,
35
+ code: (c: ReactNode) => <code>{c}</code>,
36
+ }}
37
+ />
38
+ </p>
39
+ </header>
40
+
41
+ <div>
42
+ <h2 style={{ fontSize: 16 }}>
43
+ <T id="schemaUi.createHeading" values={{ code: (c: ReactNode) => <code>{c}</code> }} />
44
+ </h2>
45
+ {/* Rung 3 — own the layout: show title + body; tenantId is a default. */}
46
+ <AutoForm
47
+ api="app"
48
+ mutation="notes.create"
49
+ defaults={{ tenantId: TENANT, done: false }}
50
+ submitLabel={t('schemaUi.submitLabel')}
51
+ >
52
+ {() => (
53
+ <>
54
+ <Field name="title" />
55
+ <Field name="body" />
56
+ </>
57
+ )}
58
+ </AutoForm>
59
+ </div>
60
+
61
+ <div>
62
+ <h2 style={{ fontSize: 16 }}>
63
+ <T id="schemaUi.listHeading" values={{ code: (c: ReactNode) => <code>{c}</code> }} />
64
+ </h2>
65
+ {/* Columns inferred from the query's output schema; rows are a live
66
+ subscription that updates on every notes.create. Add a `rowActions`
67
+ prop once your api defines a per-row mutation (e.g. notes.delete). */}
68
+ <DataTable api="app" query="notes.list" emptyText={t('schemaUi.emptyText')} />
69
+ </div>
70
+ </section>
71
+ )
72
+ }
73
+
74
+ export default SchemaUiPage
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "frontend-app",
3
+ "kind": "web",
4
+ "summary": "The reactive end-to-end loop — a web frontend wired to an api. A live notes list (useSubscription) + a create form (useMutation) with zero-boilerplate auto-optimistic updates. Pairs with api-backend: scaffold both with `create-project --api=api-backend --web=frontend-app`.",
5
+ "tags": ["web", "frontend", "fullstack", "reactive", "subscription", "mutation", "optimistic", "api-backend"]
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "lib": ["ES2024", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "moduleResolution": "Bundler"
8
+ },
9
+ "include": ["src/**/*"],
10
+ "exclude": ["node_modules", "dist", ".framework"]
11
+ }
@@ -0,0 +1,18 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Voltro web app scaffold (template: **frontend-blank**).
4
+
5
+ ## Boot
6
+
7
+ ```bash
8
+ pnpm install
9
+ pnpm --filter @{{projectName}}/{{appName}} dev
10
+ # → http://localhost:5173
11
+ ```
12
+
13
+ ## Routing
14
+
15
+ File-based. `src/pages/index.tsx` mounts at `/`. Add more `*.tsx`
16
+ files in `src/pages/` to create routes. See AGENTS.md for the
17
+ naming rules (`[id]`, `[...slug]`, `(group)`, `error.tsx`,
18
+ `not-found.tsx`, etc.).