@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,38 @@
1
+ // Dashboard overview — URL `/dashboard`. `renderMode: 'ssr'` so the parent
2
+ // layout's auth-gate loader runs per request (see dashboard/layout.tsx).
3
+ // A real app would read live data with `useSubscription` from an api here;
4
+ // this template keeps it backend-free, so the figures are placeholders.
5
+ import type { ReactNode } from 'react'
6
+ import type { PageMeta } from '@voltro/web'
7
+ import { T } from '@voltro/i18n'
8
+ import { getCatalog } from '../../locales'
9
+
10
+ export const renderMode = 'ssr' as const
11
+
12
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
13
+ title: getCatalog(locale)['meta.overview.title'],
14
+ })
15
+
16
+ const stats = [
17
+ { labelId: 'overview.stat.projects', value: '12' },
18
+ { labelId: 'overview.stat.members', value: '37' },
19
+ { labelId: 'overview.stat.issues', value: '4' },
20
+ { labelId: 'overview.stat.uptime', value: '99.9%' },
21
+ ] as const
22
+
23
+ export default function Overview(): ReactNode {
24
+ return (
25
+ <section>
26
+ <h1><T id="overview.heading" /></h1>
27
+ <p className="muted"><T id="overview.intro" /></p>
28
+ <div className="cards" style={{ marginTop: '1.25rem' }}>
29
+ {stats.map((s) => (
30
+ <div className="card" key={s.labelId}>
31
+ <div className="label"><T id={s.labelId} /></div>
32
+ <div className="value">{s.value}</div>
33
+ </div>
34
+ ))}
35
+ </div>
36
+ </section>
37
+ )
38
+ }
@@ -0,0 +1,88 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // The dashboard shell + AUTH GATE. The loader redirects an unauthenticated
4
+ // request (throws RedirectError) and otherwise returns the shared user data the
5
+ // layout renders. We mock the framework hooks (useLoaderData / useLocation) so
6
+ // the render is standalone, and import the REAL RedirectError so the loader's
7
+ // throw is observable.
8
+
9
+ import { afterEach, 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 { RedirectError } from '@voltro/web'
13
+ import { I18nProvider } from '@voltro/i18n'
14
+ import enCatalog from '../../locales/en'
15
+
16
+ const loaderData = vi.fn<() => unknown>()
17
+ const location = vi.fn<() => string>()
18
+
19
+ vi.mock('@voltro/web', async () => {
20
+ const actual = await vi.importActual<typeof import('@voltro/web')>('@voltro/web')
21
+ return { ...actual, useLoaderData: () => loaderData(), useLocation: () => location() }
22
+ })
23
+
24
+ const { default: DashboardLayout, loader } = await import('./layout')
25
+
26
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
27
+
28
+ let container: HTMLDivElement
29
+ let root: Root
30
+
31
+ // DashboardLayout uses <T>/useLocale + <LocaleSwitcher>, so wrap renders in the
32
+ // framework's <I18nProvider> (auto-wired in the running app).
33
+ const render = (node: ReactNode): void => {
34
+ container = document.createElement('div')
35
+ document.body.appendChild(container)
36
+ act(() => {
37
+ root = createRoot(container)
38
+ root.render(
39
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
40
+ )
41
+ })
42
+ }
43
+
44
+ afterEach(() => {
45
+ loaderData.mockReset()
46
+ location.mockReset()
47
+ if (root) act(() => root.unmount())
48
+ container?.remove()
49
+ document.body.innerHTML = ''
50
+ })
51
+
52
+ describe('dashboard layout — loader (auth gate)', () => {
53
+ test('redirects to /login (remembering the destination) when no session cookie is present', async () => {
54
+ const err = await Promise.resolve(loader({ headers: {} } as never)).catch((e: unknown) => e)
55
+ expect(err).toBeInstanceOf(RedirectError)
56
+ expect((err as RedirectError).location).toBe('/login?from=/dashboard')
57
+ })
58
+
59
+ test('returns the shared user for a signed-in request', async () => {
60
+ const data = await loader({ headers: { cookie: 'demo_session=ok' } } as never)
61
+ expect(data.user.name).toBe('Demo User')
62
+ expect(data.user.plan).toBe('Pro')
63
+ })
64
+ })
65
+
66
+ describe('dashboard layout — render', () => {
67
+ test('renders the user, plan, and nav links', () => {
68
+ loaderData.mockReturnValue({ user: { name: 'Ada', plan: 'Enterprise' } })
69
+ location.mockReturnValue('/dashboard')
70
+ render(createElement(DashboardLayout, { children: createElement('p', null, 'page body') }))
71
+ expect(container.textContent).toContain('Ada')
72
+ expect(container.textContent).toContain('Enterprise plan')
73
+ const hrefs = Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
74
+ expect(hrefs).toContain('/dashboard')
75
+ expect(hrefs).toContain('/dashboard/settings')
76
+ expect(container.querySelector('main')!.textContent).toContain('page body')
77
+ })
78
+
79
+ test('marks the active nav link with aria-current for the current path', () => {
80
+ loaderData.mockReturnValue({ user: { name: 'Ada', plan: 'Pro' } })
81
+ location.mockReturnValue('/dashboard/settings')
82
+ render(createElement(DashboardLayout, { children: null }))
83
+ const active = Array.from(container.querySelectorAll('a')).find(
84
+ (a) => a.getAttribute('aria-current') === 'page',
85
+ )!
86
+ expect(active.getAttribute('href')).toBe('/dashboard/settings')
87
+ })
88
+ })
@@ -0,0 +1,69 @@
1
+ // The dashboard shell — and the AUTH GATE. This nested layout wraps every
2
+ // page under `/dashboard`, and its `loader` runs ONCE for all of them,
3
+ // server-side, BEFORE the page renders. That makes it the right seam to
4
+ // validate the session + preload shared data in one place.
5
+ //
6
+ // Throwing RedirectError short-circuits the whole subtree: on SSR it emits a
7
+ // 303 + Location; on a client navigation it `navigate(.., { replace:true })`
8
+ // so Back doesn't bounce onto the redirecting page. The pages under here are
9
+ // `renderMode: 'ssr'` precisely so this runs per request — a `static` page
10
+ // can't redirect per-visitor, and the build rejects a RedirectError there.
11
+ import type { ReactNode } from 'react'
12
+ import { RedirectError, useLoaderData, useLocation, type LoaderFn } from '@voltro/web'
13
+ import { T, useLocale, useT } from '@voltro/i18n'
14
+ import { LocaleSwitcher } from '@voltro/ui-shadcn'
15
+ import { APP_NAME } from '../../config'
16
+ import { isSignedIn } from '../../lib/auth'
17
+
18
+ const LOCALES = [
19
+ { code: 'en', label: 'English' },
20
+ { code: 'de', label: 'Deutsch' },
21
+ ]
22
+
23
+ interface DashboardData {
24
+ readonly user: { readonly name: string; readonly plan: string }
25
+ }
26
+
27
+ export const loader: LoaderFn<DashboardData> = async ({ headers }) => {
28
+ if (!isSignedIn(headers)) {
29
+ // No session → bounce to login, remembering where they were headed.
30
+ throw new RedirectError('/login?from=/dashboard')
31
+ }
32
+ // Shared data, loaded once for every page beneath this layout and read
33
+ // via useLoaderData<DashboardData>() right here in the layout.
34
+ return { user: { name: 'Demo User', plan: 'Pro' } }
35
+ }
36
+
37
+ export default function DashboardLayout({ children }: { readonly children: ReactNode }): ReactNode {
38
+ const { user } = useLoaderData<DashboardData>()
39
+ const pathname = useLocation()
40
+ const locale = useLocale()
41
+ const langLabel = useT('lang.label')
42
+ const navItem = (href: string, label: ReactNode): ReactNode => (
43
+ <a href={href} aria-current={pathname === href ? 'page' : undefined}>
44
+ {label}
45
+ </a>
46
+ )
47
+
48
+ return (
49
+ <div className="dash">
50
+ <aside>
51
+ <div className="brand">{APP_NAME}</div>
52
+ <nav>
53
+ {navItem('/dashboard', <T id="dash.nav.overview" />)}
54
+ {navItem('/dashboard/settings', <T id="dash.nav.settings" />)}
55
+ <a href="/"><T id="dash.nav.backToSite" /></a>
56
+ </nav>
57
+ </aside>
58
+ <main>
59
+ <div className="topbar">
60
+ <strong>{user.name}</strong>
61
+ <span className="muted"><T id="dash.planSuffix" values={{ plan: user.plan }} /></span>
62
+ <span className="spacer" />
63
+ <LocaleSwitcher locales={LOCALES} current={locale} ariaLabel={langLabel} />
64
+ </div>
65
+ {children}
66
+ </main>
67
+ </div>
68
+ )
69
+ }
@@ -0,0 +1,21 @@
1
+ // OPT-IN loading skeleton for /dashboard pages. By default navigation is
2
+ // deferred (the previous page stays until the loader settles — no overlay).
3
+ // Adding `loading.tsx` opts THIS subtree into swapping in immediately and
4
+ // showing a skeleton instead, which suits a data-backed dashboard where the
5
+ // loader may take a beat.
6
+ import type { ReactNode } from 'react'
7
+
8
+ export default function DashboardLoading(): ReactNode {
9
+ return (
10
+ <div className="dash">
11
+ <main>
12
+ <div className="cards" aria-hidden="true">
13
+ <div className="skeleton" />
14
+ <div className="skeleton" />
15
+ <div className="skeleton" />
16
+ <div className="skeleton" />
17
+ </div>
18
+ </main>
19
+ </div>
20
+ )
21
+ }
@@ -0,0 +1,19 @@
1
+ // Scoped 404 for the /dashboard subtree. Fires when a URL is under
2
+ // `/dashboard/...` but no concrete page matches (e.g. /dashboard/nope), and
3
+ // when a loader throws NotFoundError. The router picks the deepest matching
4
+ // not-found scope, so this handles dashboard misses while the rest of the
5
+ // app falls back to the router default.
6
+ import type { ReactNode } from 'react'
7
+ import { T } from '@voltro/i18n'
8
+
9
+ export default function DashboardNotFound(): ReactNode {
10
+ return (
11
+ <div className="dash">
12
+ <main>
13
+ <h1><T id="notFound.heading" /></h1>
14
+ <p className="muted"><T id="notFound.body" /></p>
15
+ <p style={{ marginTop: '1rem' }}><a href="/dashboard"><T id="notFound.back" /></a></p>
16
+ </main>
17
+ </div>
18
+ )
19
+ }
@@ -0,0 +1,69 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/dashboard/settings` — SSR page whose only behaviour is a "sign out" button
4
+ // that clears the demo cookie + hard-navigates to `/`. We assert the config
5
+ // exports and that clicking Sign out expires the SESSION_COOKIE.
6
+
7
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
8
+ import { act, createElement, type ReactNode } from 'react'
9
+ import { createRoot, type Root } from 'react-dom/client'
10
+ import { I18nProvider } from '@voltro/i18n'
11
+ import enCatalog from '../../locales/en'
12
+
13
+ const { default: Settings, meta, renderMode } = await import('./settings')
14
+
15
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
16
+
17
+ let container: HTMLDivElement
18
+ let root: Root
19
+
20
+ // The page uses <T>, so wrap renders in the framework's <I18nProvider>.
21
+ const render = (node: ReactNode): void => {
22
+ container = document.createElement('div')
23
+ document.body.appendChild(container)
24
+ act(() => {
25
+ root = createRoot(container)
26
+ root.render(
27
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
28
+ )
29
+ })
30
+ }
31
+
32
+ beforeEach(() => {
33
+ // Seed a session cookie so we can observe it being cleared.
34
+ document.cookie = 'demo_session=ok; path=/'
35
+ })
36
+
37
+ afterEach(() => {
38
+ if (root) act(() => root.unmount())
39
+ container?.remove()
40
+ document.body.innerHTML = ''
41
+ vi.restoreAllMocks()
42
+ vi.unstubAllGlobals()
43
+ })
44
+
45
+ describe('settings — config', () => {
46
+ test('is an SSR page titled Settings', () => {
47
+ expect(renderMode).toBe('ssr')
48
+ expect(meta({ locale: 'en' }).title).toBe('Settings')
49
+ })
50
+ })
51
+
52
+ describe('settings — sign out', () => {
53
+ test('expires the session cookie and hard-navigates home', () => {
54
+ // jsdom's location.assign is a non-configurable no-op that throws "not
55
+ // implemented"; replace the whole location object so we can observe the
56
+ // hard-navigation target.
57
+ const assign = vi.fn()
58
+ vi.stubGlobal('location', { ...window.location, assign, href: '' })
59
+
60
+ render(createElement(Settings))
61
+ const btn = Array.from(container.querySelectorAll('button')).find(
62
+ (b) => (b.textContent ?? '').includes('Sign out'),
63
+ )!
64
+ act(() => { btn.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
65
+
66
+ expect(document.cookie).not.toContain('demo_session=ok')
67
+ expect(assign).toHaveBeenCalledWith('/')
68
+ })
69
+ })
@@ -0,0 +1,35 @@
1
+ // Settings — URL `/dashboard/settings`. Also `renderMode: 'ssr'`, so it's
2
+ // gated by the same parent layout loader. The "sign out" button clears the
3
+ // demo cookie and hard-navigates to `/` so the next visit to /dashboard
4
+ // hits the gate fresh and is redirected to /login.
5
+ import type { ReactNode } from 'react'
6
+ import type { PageMeta } from '@voltro/web'
7
+ import { T } from '@voltro/i18n'
8
+ import { getCatalog } from '../../locales'
9
+ import { SESSION_COOKIE } from '../../lib/auth'
10
+
11
+ export const renderMode = 'ssr' as const
12
+
13
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
14
+ title: getCatalog(locale)['meta.settings.title'],
15
+ })
16
+
17
+ export default function Settings(): ReactNode {
18
+ const signOut = (): void => {
19
+ // Expire the cookie, then hard-navigate so the gate re-evaluates.
20
+ document.cookie = `${SESSION_COOKIE}=; path=/; max-age=0`
21
+ window.location.assign('/')
22
+ }
23
+
24
+ return (
25
+ <section>
26
+ <h1><T id="settings.heading" /></h1>
27
+ <p className="muted"><T id="settings.intro" /></p>
28
+ <p style={{ marginTop: '1.5rem' }}>
29
+ <button type="button" className="btn" onClick={signOut}>
30
+ <T id="settings.signOut" />
31
+ </button>
32
+ </p>
33
+ </section>
34
+ )
35
+ }
@@ -0,0 +1,12 @@
1
+ // Root layout — wraps EVERY page (marketing + dashboard). It's intentionally
2
+ // thin: it loads the stylesheet and lets each AREA layout
3
+ // ((marketing)/layout.tsx, dashboard/layout.tsx) supply its own chrome.
4
+ // Layouts nest, so a dashboard page is wrapped root → dashboard.
5
+ //
6
+ // Don't render <html>/<head>/<body> here — the framework shell owns them.
7
+ import type { ReactNode } from 'react'
8
+ import '../globals.css'
9
+
10
+ export default function RootLayout({ children }: { readonly children: ReactNode }): ReactNode {
11
+ return <>{children}</>
12
+ }
@@ -0,0 +1,54 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // Render smokes for the root layout (passes children through) and the
4
+ // (marketing) group layout (brand header + nav links wrapping the children).
5
+
6
+ import { afterEach, describe, expect, test } from 'vitest'
7
+ import { act, createElement, type ReactNode } from 'react'
8
+ import { createRoot, type Root } from 'react-dom/client'
9
+ import { I18nProvider } from '@voltro/i18n'
10
+ import enCatalog from '../locales/en'
11
+
12
+ const { default: RootLayout } = await import('./layout')
13
+ const { default: MarketingLayout } = await import('./(marketing)/layout')
14
+
15
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
16
+
17
+ let container: HTMLDivElement
18
+ let root: Root
19
+
20
+ // MarketingLayout uses <T>/useLocale + <LocaleSwitcher>, so wrap renders in the
21
+ // framework's <I18nProvider> (auto-wired in the running app).
22
+ const render = (node: ReactNode): void => {
23
+ container = document.createElement('div')
24
+ document.body.appendChild(container)
25
+ act(() => {
26
+ root = createRoot(container)
27
+ root.render(
28
+ createElement(I18nProvider, { locale: 'en', messages: enCatalog, defaultLocale: 'en', children: node }),
29
+ )
30
+ })
31
+ }
32
+
33
+ afterEach(() => {
34
+ if (root) act(() => root.unmount())
35
+ container?.remove()
36
+ document.body.innerHTML = ''
37
+ })
38
+
39
+ describe('root layout', () => {
40
+ test('renders its children unchanged', () => {
41
+ render(createElement(RootLayout, { children: createElement('p', null, 'hello') }))
42
+ expect(container.textContent).toContain('hello')
43
+ })
44
+ })
45
+
46
+ describe('marketing layout', () => {
47
+ test('renders the header nav (Dashboard + Sign in) around the children', () => {
48
+ render(createElement(MarketingLayout, { children: createElement('p', null, 'body') }))
49
+ const hrefs = Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
50
+ expect(hrefs).toContain('/dashboard')
51
+ expect(hrefs).toContain('/login')
52
+ expect(container.textContent).toContain('body')
53
+ })
54
+ })
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "frontend-dashboard",
3
+ "kind": "web",
4
+ "summary": "An authenticated dashboard shell — a silent (marketing) route group for public pages, a /dashboard area gated by a nested layout loader that RedirectErrors to /login when there's no session, and scoped error/loading/not-found special files. SSR auth gate, no backend.",
5
+ "tags": ["web", "frontend", "dashboard", "auth", "route-groups", "ssr", "layouts"]
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,19 @@
1
+ # {{projectName}} / {{appName}}
2
+
3
+ Documentation site (template: **frontend-docs**).
4
+
5
+ `src/pages/docs/[...slug].tsx` is the catch-all doc renderer.
6
+ `getStaticPaths` enumerates every doc URL at build time and
7
+ `voltro build` pre-renders them all — the result is a static site
8
+ you can deploy anywhere.
9
+
10
+ ```bash
11
+ pnpm install
12
+ pnpm --filter @{{projectName}}/{{appName}} dev
13
+ # → http://localhost:5173
14
+ # → http://localhost:5173/docs/intro/getting-started
15
+ ```
16
+
17
+ The starter ships a tiny in-file `DOCS` array. Replace it with a
18
+ real loader (markdown reader, CMS query, database fetch) — the
19
+ component contract stays the same.
@@ -0,0 +1,25 @@
1
+ // `port` is allocated by `voltro create-project` / `voltro add-app` from
2
+ // the project's portRange (in project.json).
3
+ import { defineEnv, envVar } from '@voltro/env'
4
+
5
+ // Typed PUBLIC environment — public vars are validated + baked into the browser
6
+ // bundle at build time and read via `publicEnv` from '@voltro/env/public'
7
+ // (typed, autocompleted). NEVER put a secret here (it would ship to every
8
+ // visitor) — declare secrets on the api instead. Run `voltro env` for the manifest.
9
+ export const env = defineEnv({
10
+ VOLTRO_PUBLIC_APP_NAME: envVar.string({ access: 'public', default: '{{capProjectName}}' }),
11
+ })
12
+
13
+ export default {
14
+ type: 'web' as const,
15
+ name: '{{capProjectName}}{{capAppName}}',
16
+ port: {{port}},
17
+ // The shipped catalogs (Strategy B: URL-prefix i18n). `defaultLocale`
18
+ // lives at the bare path (`/docs/…`); every other locale is prefixed
19
+ // (`/de/docs/…`). `voltro build` pre-renders one HTML file per locale ×
20
+ // doc. Keep this in sync with SUPPORTED_LOCALES / DEFAULT_LOCALE in
21
+ // src/lib/locale.ts — that file drives the [locale] mirror routing.
22
+ locales: ['en', 'de'] as const,
23
+ defaultLocale: 'en' as const,
24
+ env,
25
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@{{projectName}}/{{appName}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "voltro dev .",
8
+ "build": "voltro build .",
9
+ "start": "voltro start .",
10
+ "typecheck": "tsc --noEmit",
11
+ "test": "voltro test"
12
+ },
13
+ "dependencies": {
14
+ "@voltro/cli": "0.1.0",
15
+ "@voltro/client": "0.1.0",
16
+ "@voltro/env": "0.1.0",
17
+ "@voltro/i18n": "0.1.0",
18
+ "@voltro/ui-shadcn": "0.1.0",
19
+ "@voltro/web": "0.1.0",
20
+ "react": "^19.0.0",
21
+ "react-dom": "^19.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/react": "^19.0.0",
25
+ "@types/react-dom": "^19.0.0",
26
+ "typescript": "^5.7.0",
27
+ "vitest": "^3.0.0"
28
+ }
29
+ }
@@ -0,0 +1,32 @@
1
+ /* Docs template — design tokens + Tailwind. `@voltro/ui-shadcn/tokens.css`
2
+ * pulls Tailwind + the shadcn palette + the @theme mapping. */
3
+
4
+ @import "@voltro/ui-shadcn/tokens.css";
5
+
6
+ /* Scan THIS app's source so utility classes used only here (not in
7
+ * the kit) get generated. The kit declares its own @source for its
8
+ * files; once an explicit @source is in play, Tailwind v4's vite
9
+ * auto-detect doesn't fire — every consumer needs to declare its
10
+ * own scan target. */
11
+ @source "./**/*.{tsx,ts,jsx,js}";
12
+
13
+ html, body { min-height: 100vh; }
14
+
15
+ /* Prose typography for rendered markdown. The DocShell composition
16
+ * already applies Tailwind's `prose prose-invert` to the <main>;
17
+ * this block tunes specifics for the docs catalogue. */
18
+ .docs-prose h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 1rem; color: var(--foreground); }
19
+ .docs-prose h2 { font-size: 1.4rem; font-weight: 600; margin: 2rem 0 0.75rem; color: var(--foreground); }
20
+ .docs-prose h3 { font-size: 1.1rem; font-weight: 600; margin: 1.5rem 0 0.5rem; color: var(--foreground); }
21
+ .docs-prose p { margin: 0.5rem 0; line-height: 1.6; color: var(--muted-foreground); }
22
+ .docs-prose a { color: var(--primary); text-decoration: underline; }
23
+ .docs-prose code { background: var(--muted); padding: 2px 4px; border-radius: 3px; font-size: 0.85em; }
24
+ .docs-prose pre { background: oklch(0.18 0.005 280); padding: 1rem; border-radius: 6px; overflow-x: auto; margin: 1rem 0; }
25
+ .docs-prose pre code { background: transparent; padding: 0; }
26
+ .docs-prose ul { margin: 0.5rem 0; padding-left: 1.5rem; }
27
+ .docs-prose li { margin: 0.25rem 0; color: var(--muted-foreground); }
28
+
29
+ .docs-prose h2 .anchor,
30
+ .docs-prose h3 .anchor { opacity: 0; margin-right: 0.5rem; color: var(--muted-foreground); text-decoration: none; }
31
+ .docs-prose h2:hover .anchor,
32
+ .docs-prose h3:hover .anchor { opacity: 1; }
@@ -0,0 +1,72 @@
1
+ // The URL-prefix i18n helpers — the load-bearing pure functions that drive the
2
+ // [locale] mirror routing + the language switcher. `useUrlLocale` (the one hook
3
+ // in this module) reads useLocation from @voltro/web; the rest are pure string
4
+ // functions we can exercise directly.
5
+
6
+ import { describe, expect, test } from 'vitest'
7
+ import {
8
+ SUPPORTED_LOCALES,
9
+ DEFAULT_LOCALE,
10
+ getCatalog,
11
+ localeFromPathname,
12
+ withLocalePrefix,
13
+ stripLocalePrefix,
14
+ } from './locale'
15
+
16
+ describe('locale constants', () => {
17
+ test('supports en + de with en as the default', () => {
18
+ expect(SUPPORTED_LOCALES).toEqual(['en', 'de'])
19
+ expect(DEFAULT_LOCALE).toBe('en')
20
+ })
21
+ })
22
+
23
+ describe('getCatalog', () => {
24
+ test('returns the matching catalog for a supported locale', () => {
25
+ expect(getCatalog('de')['nav.home']).toBe('Start')
26
+ expect(getCatalog('en')['nav.home']).toBe('Home')
27
+ })
28
+
29
+ test('falls back to the default catalog for an unsupported locale', () => {
30
+ expect(getCatalog('zz')['nav.home']).toBe('Home')
31
+ })
32
+ })
33
+
34
+ describe('localeFromPathname', () => {
35
+ test('extracts a prefixed locale', () => {
36
+ expect(localeFromPathname('/de')).toBe('de')
37
+ expect(localeFromPathname('/de/docs/intro/getting-started')).toBe('de')
38
+ })
39
+
40
+ test('defaults to en for the bare path or an unknown prefix', () => {
41
+ expect(localeFromPathname('/')).toBe('en')
42
+ expect(localeFromPathname('/docs/intro/getting-started')).toBe('en')
43
+ expect(localeFromPathname('/fr/docs/x')).toBe('en')
44
+ })
45
+ })
46
+
47
+ describe('withLocalePrefix', () => {
48
+ test('leaves default-locale paths bare', () => {
49
+ expect(withLocalePrefix('/docs/x', 'en')).toBe('/docs/x')
50
+ expect(withLocalePrefix('/', 'en')).toBe('/')
51
+ })
52
+
53
+ test('prefixes non-default locales, mapping / to /<locale>', () => {
54
+ expect(withLocalePrefix('/docs/x', 'de')).toBe('/de/docs/x')
55
+ expect(withLocalePrefix('/', 'de')).toBe('/de')
56
+ })
57
+ })
58
+
59
+ describe('stripLocalePrefix', () => {
60
+ test('removes a locale prefix, mapping /<locale> back to /', () => {
61
+ expect(stripLocalePrefix('/de/docs/x')).toBe('/docs/x')
62
+ expect(stripLocalePrefix('/de')).toBe('/')
63
+ })
64
+
65
+ test('leaves an unprefixed path unchanged', () => {
66
+ expect(stripLocalePrefix('/docs/x')).toBe('/docs/x')
67
+ })
68
+
69
+ test('round-trips with withLocalePrefix', () => {
70
+ expect(stripLocalePrefix(withLocalePrefix('/docs/x', 'de'))).toBe('/docs/x')
71
+ })
72
+ })