@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,56 @@
1
+ // The single source of truth for this app's locales + the URL-prefix
2
+ // helpers. `app.config.ts` lists the same codes for the build pipeline;
3
+ // the [locale] mirror pages + the layout's <I18nProvider> read THIS file.
4
+ //
5
+ // Keep SUPPORTED_LOCALES / DEFAULT_LOCALE in sync with `locales` /
6
+ // `defaultLocale` in app.config.ts.
7
+
8
+ import { useLocation } from '@voltro/web'
9
+ import en from '../locales/en'
10
+ import de from '../locales/de'
11
+
12
+ export const SUPPORTED_LOCALES = ['en', 'de'] as const
13
+ export const DEFAULT_LOCALE = 'en'
14
+
15
+ export type Locale = (typeof SUPPORTED_LOCALES)[number]
16
+
17
+ // The catalogs, keyed by code. The layout picks one to feed the inner
18
+ // <I18nProvider>; `meta` (build-time, per locale) reads one via getCatalog.
19
+ export const CATALOGS = { en, de } as const
20
+
21
+ // Every catalog mirrors `en`'s keys (defineLocale enforces it), so a
22
+ // plain string-record over en's keys is the common type both satisfy —
23
+ // what `meta` reads at build time (`c['meta.home.title']` → string), and
24
+ // what the docs table's title/body keys are typed against.
25
+ export type Messages = Record<keyof typeof en, string>
26
+
27
+ const isSupported = (v: string): v is Locale =>
28
+ (SUPPORTED_LOCALES as ReadonlyArray<string>).includes(v)
29
+
30
+ export const getCatalog = (locale: string): Messages =>
31
+ isSupported(locale) ? CATALOGS[locale] : CATALOGS[DEFAULT_LOCALE]
32
+
33
+ // `/de/docs/x` → 'de'; `/docs/x` → 'en' (default lives at the bare path).
34
+ export const localeFromPathname = (pathname: string): Locale => {
35
+ const match = /^\/([a-z]{2})(?:\/|$)/.exec(pathname)
36
+ return match && isSupported(match[1]!) ? (match[1] as Locale) : DEFAULT_LOCALE
37
+ }
38
+
39
+ // Reactive: useLocation re-renders on client-side nav, so the layout's
40
+ // provider swaps catalogs when you move between /docs/x and /de/docs/x
41
+ // without a full reload.
42
+ export const useUrlLocale = (): Locale => localeFromPathname(useLocation())
43
+
44
+ // '/docs/x' + 'de' → '/de/docs/x'; the default locale stays bare.
45
+ export const withLocalePrefix = (path: string, locale: string): string => {
46
+ if (locale === DEFAULT_LOCALE) return path
47
+ const p = path.startsWith('/') ? path : `/${path}`
48
+ return p === '/' ? `/${locale}` : `/${locale}${p}`
49
+ }
50
+
51
+ // '/de/docs/x' → '/docs/x'; '/docs/x' → '/docs/x'. The inverse of the
52
+ // above, used to keep the active path when switching language.
53
+ export const stripLocalePrefix = (pathname: string): string => {
54
+ const match = /^\/([a-z]{2})(\/.*|$)/.exec(pathname)
55
+ return match && isSupported(match[1]!) ? match[2] || '/' : pathname
56
+ }
@@ -0,0 +1,24 @@
1
+ // German catalog. MUST mirror en.ts key-for-key — `defineLocale<typeof en>()`
2
+ // returns a curried function that fails `tsc --noEmit` on a missing or extra
3
+ // key, so translations can never silently drift out of sync.
4
+ import { defineLocale } from '@voltro/i18n'
5
+ import en from './en'
6
+
7
+ export default defineLocale<typeof en>()({
8
+ 'nav.home': 'Start',
9
+ 'nav.language': 'Sprache',
10
+
11
+ 'home.title': '{project} Dokumentation',
12
+
13
+ 'docs.getting-started.title': 'Erste Schritte',
14
+ 'docs.getting-started.body': 'Willkommen in der {{capProjectName}}-Dokumentation.',
15
+ 'docs.first-page.title': 'Deine erste Seite',
16
+ 'docs.first-page.body': 'Lege eine `*.tsx`-Datei in src/pages/ ab.',
17
+
18
+ 'docs.notFound.title': 'Nicht gefunden',
19
+ 'docs.notFound.body': 'Kein Dokument unter <code>{slug}</code>.',
20
+
21
+ 'meta.home.title': 'Dokumentation',
22
+ 'meta.home.description': 'Eine zweisprachige Dokumentationsseite mit Voltro — Englisch am bloßen Pfad, Deutsch unter /de.',
23
+ 'meta.docs.description': 'Referenzdokumentation, pro Sprache als statisches HTML vorgerendert.',
24
+ })
@@ -0,0 +1,28 @@
1
+ // Base catalog — the source of truth. Every other locale (de.ts) mirrors
2
+ // these keys EXACTLY; `defineLocale<typeof en>()` enforces that at `tsc`.
3
+ //
4
+ // The doc pages are keyed by SLUG (stable across locales — the URL structure
5
+ // is the same, only the /de prefix differs); the per-locale title + body come
6
+ // from these `docs.*` entries. Keep ICU placeholders (`{project}`, `{slug}`)
7
+ // + rich-text tags (`<code>`) identical across locales.
8
+ import { defineCatalog } from '@voltro/i18n'
9
+
10
+ export default defineCatalog({
11
+ 'nav.home': 'Home',
12
+ 'nav.language': 'Language',
13
+
14
+ // `{project}` is the scaffold-substituted app name, passed as a <T> value.
15
+ 'home.title': '{project} docs',
16
+
17
+ 'docs.getting-started.title': 'Getting started',
18
+ 'docs.getting-started.body': 'Welcome to the {{capProjectName}} docs.',
19
+ 'docs.first-page.title': 'Your first page',
20
+ 'docs.first-page.body': 'Drop a `*.tsx` file into src/pages/.',
21
+
22
+ 'docs.notFound.title': 'Not found',
23
+ 'docs.notFound.body': 'No doc at <code>{slug}</code>.',
24
+
25
+ 'meta.home.title': 'Documentation',
26
+ 'meta.home.description': 'A bilingual documentation site built with Voltro — English at the bare path, German under /de.',
27
+ 'meta.docs.description': 'Reference documentation, pre-rendered per locale as static HTML.',
28
+ } as const)
@@ -0,0 +1,18 @@
1
+ // Locale mirror of the catch-all docs route → renders `/de/docs/<slug>`.
2
+ // Re-exports the bare `[...slug]` page (the component + its per-locale meta
3
+ // read locale + slug from the URL / params). This is a DYNAMIC route mirrored
4
+ // under a DYNAMIC locale segment, so `getStaticPaths` must emit the
5
+ // CROSS-PRODUCT of every non-default locale × every doc slug — otherwise the
6
+ // German docs URLs are never enumerated for pre-render.
7
+ import { SUPPORTED_LOCALES, DEFAULT_LOCALE } from '../../../lib/locale'
8
+ import { DOCS } from '../../docs/[...slug]'
9
+
10
+ export { default } from '../../docs/[...slug]'
11
+ export { renderMode, interactive, meta } from '../../docs/[...slug]'
12
+
13
+ export const getStaticPaths = async (): Promise<
14
+ Array<{ params: { locale: string; slug: string } }>
15
+ > =>
16
+ SUPPORTED_LOCALES
17
+ .filter((l) => l !== DEFAULT_LOCALE)
18
+ .flatMap((locale) => DOCS.map((d) => ({ params: { locale, slug: d.slug } })))
@@ -0,0 +1,13 @@
1
+ // Locale mirror of `/` → renders `/de`. Re-exports the bare docs landing
2
+ // (the component reads its locale from the URL via the layout's provider);
3
+ // `getStaticPaths` tells `voltro build` which locale-prefixed paths to emit.
4
+ // The default locale is NOT listed here — it lives at the bare `/`.
5
+ import { SUPPORTED_LOCALES, DEFAULT_LOCALE } from '../../lib/locale'
6
+
7
+ export { default } from '../index'
8
+ export { renderMode, interactive, meta } from '../index'
9
+
10
+ export const getStaticPaths = async (): Promise<Array<{ params: { locale: string } }>> =>
11
+ SUPPORTED_LOCALES
12
+ .filter((l) => l !== DEFAULT_LOCALE)
13
+ .map((locale) => ({ params: { locale } }))
@@ -0,0 +1,67 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // The [locale] mirror pages re-export the bare pages and add getStaticPaths,
4
+ // which tells `voltro build` which locale-prefixed paths to emit. The default
5
+ // locale (en) is NOT listed — it lives at the bare path. The docs [...slug]
6
+ // mirror is the interesting case: a DYNAMIC route under a DYNAMIC locale
7
+ // segment, so its getStaticPaths must emit the CROSS-PRODUCT of every
8
+ // non-default locale × every doc slug.
9
+
10
+ import { describe, expect, test, vi } from 'vitest'
11
+
12
+ // The mirrors transitively import the base pages, which import @voltro/i18n
13
+ // and @voltro/web. Stub both so importing the modules doesn't require the
14
+ // real runtimes.
15
+ vi.mock('@voltro/web', () => ({
16
+ useLocation: () => '/',
17
+ useParams: () => ({ slug: '' }),
18
+ }))
19
+
20
+ vi.mock('@voltro/i18n', () => ({
21
+ // The locale catalogs call these at module top-level; identity mirrors the
22
+ // real (compile-time-only) implementations so importing them doesn't throw.
23
+ defineCatalog: <T,>(c: T): T => c,
24
+ defineLocale:
25
+ () =>
26
+ <T,>(c: T): T =>
27
+ c,
28
+ useLocale: () => 'en',
29
+ useTFn: () => (id: string) => id,
30
+ T: ({ id }: { id: string }) => id,
31
+ }))
32
+
33
+ const indexMirror = await import('./index')
34
+ const slugMirror = await import('./docs/[...slug]')
35
+
36
+ describe('home mirror — getStaticPaths', () => {
37
+ test('emits only non-default locales (just /de)', async () => {
38
+ const paths = await indexMirror.getStaticPaths()
39
+ expect(paths).toEqual([{ params: { locale: 'de' } }])
40
+ })
41
+
42
+ test('re-exports the base page component + its meta function', () => {
43
+ expect(typeof indexMirror.default).toBe('function')
44
+ expect(indexMirror.meta({ locale: 'de' }).title).toBe('Dokumentation')
45
+ expect(indexMirror.renderMode).toBe('static')
46
+ expect(indexMirror.interactive).toBe('none')
47
+ })
48
+ })
49
+
50
+ describe('docs [...slug] mirror — getStaticPaths (locale × slug cross-product)', () => {
51
+ test('emits every non-default locale paired with every doc slug', async () => {
52
+ const paths = await slugMirror.getStaticPaths()
53
+ expect(paths).toEqual([
54
+ { params: { locale: 'de', slug: 'intro/getting-started' } },
55
+ { params: { locale: 'de', slug: 'guides/first-page' } },
56
+ ])
57
+ })
58
+
59
+ test('re-exports the base page component + its per-locale meta function', () => {
60
+ expect(typeof slugMirror.default).toBe('function')
61
+ expect(
62
+ slugMirror.meta({ locale: 'de', params: { slug: 'guides/first-page' } }).title,
63
+ ).toBe('Deine erste Seite')
64
+ expect(slugMirror.renderMode).toBe('static')
65
+ expect(slugMirror.interactive).toBe('none')
66
+ })
67
+ })
@@ -0,0 +1,115 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/docs/[...slug]` catch-all — its `getStaticPaths` export (enumerates the
4
+ // pre-rendered doc slugs) and the localized page render for a matched vs.
5
+ // unknown slug. The page reads the captured slug via `useParams` (mocked to
6
+ // drive the slug) and its per-locale prose via @voltro/i18n (mocked to resolve
7
+ // against the real catalogs for a controllable "current locale").
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 en from '../../locales/en'
13
+ import de from '../../locales/de'
14
+
15
+ const params = vi.fn<() => Record<string, string>>()
16
+ vi.mock('@voltro/web', () => ({ useParams: () => params() }))
17
+
18
+ const catalogs: Record<string, Record<string, string>> = { en, de }
19
+ let currentLocale = 'en'
20
+
21
+ const fill = (msg: string, values?: Record<string, unknown>): string =>
22
+ values ? msg.replace(/\{(\w+)\}/g, (_, k: string) => String(values[k] ?? `{${k}}`)) : msg
23
+
24
+ vi.mock('@voltro/i18n', () => ({
25
+ // The locale catalogs call these at module top-level; identity mirrors the
26
+ // real (compile-time-only) implementations so importing them doesn't throw.
27
+ defineCatalog: <T,>(c: T): T => c,
28
+ defineLocale:
29
+ () =>
30
+ <T,>(c: T): T =>
31
+ c,
32
+ useTFn:
33
+ () =>
34
+ (id: string, values?: Record<string, unknown>) =>
35
+ fill(catalogs[currentLocale]?.[id] ?? id, values),
36
+ T: ({ id, values }: { id: string; values?: Record<string, unknown> }) =>
37
+ fill(catalogs[currentLocale]?.[id] ?? id, values),
38
+ }))
39
+
40
+ const { default: DocPage, getStaticPaths, meta, renderMode, interactive } = await import('./[...slug]')
41
+
42
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
43
+
44
+ let container: HTMLDivElement
45
+ let root: Root
46
+
47
+ const render = (node: ReactNode): void => {
48
+ container = document.createElement('div')
49
+ document.body.appendChild(container)
50
+ act(() => {
51
+ root = createRoot(container)
52
+ root.render(node)
53
+ })
54
+ }
55
+
56
+ beforeEach(() => params.mockReset())
57
+
58
+ afterEach(() => {
59
+ currentLocale = 'en'
60
+ if (root) act(() => root.unmount())
61
+ container?.remove()
62
+ document.body.innerHTML = ''
63
+ })
64
+
65
+ describe('docs [...slug] — config + getStaticPaths', () => {
66
+ test('is a static page with no client JS', () => {
67
+ expect(renderMode).toBe('static')
68
+ expect(interactive).toBe('none')
69
+ })
70
+
71
+ test('enumerates every doc slug as a single `/`-joined string', async () => {
72
+ const paths = await getStaticPaths()
73
+ expect(paths.map((p) => p.params.slug)).toEqual([
74
+ 'intro/getting-started',
75
+ 'guides/first-page',
76
+ ])
77
+ })
78
+ })
79
+
80
+ describe('docs [...slug] — localized meta', () => {
81
+ test('reads the per-doc title from the catalog, per locale', () => {
82
+ expect(meta({ locale: 'en', params: { slug: 'guides/first-page' } }).title).toBe('Your first page')
83
+ expect(meta({ locale: 'de', params: { slug: 'guides/first-page' } }).title).toBe('Deine erste Seite')
84
+ })
85
+
86
+ test('falls back to the not-found title for an unknown slug', () => {
87
+ expect(meta({ locale: 'en', params: { slug: 'does/not-exist' } }).title).toBe('Not found')
88
+ })
89
+ })
90
+
91
+ describe('docs [...slug] — localized render', () => {
92
+ test('renders the matched doc title + body (English) for a known slug', () => {
93
+ currentLocale = 'en'
94
+ params.mockReturnValue({ slug: 'guides/first-page' })
95
+ render(createElement(DocPage))
96
+ expect(container.querySelector('h1')?.textContent).toBe('Your first page')
97
+ expect(container.textContent).toContain('Drop a')
98
+ })
99
+
100
+ test('renders the matched doc title + body (German) for a known slug', () => {
101
+ currentLocale = 'de'
102
+ params.mockReturnValue({ slug: 'guides/first-page' })
103
+ render(createElement(DocPage))
104
+ expect(container.querySelector('h1')?.textContent).toBe('Deine erste Seite')
105
+ expect(container.textContent).toContain('Lege eine')
106
+ })
107
+
108
+ test('renders the localized not-found fallback for an unknown slug', () => {
109
+ currentLocale = 'en'
110
+ params.mockReturnValue({ slug: 'does/not-exist' })
111
+ render(createElement(DocPage))
112
+ expect(container.querySelector('h1')?.textContent).toBe('Not found')
113
+ expect(container.textContent).toContain('does/not-exist')
114
+ })
115
+ })
@@ -0,0 +1,82 @@
1
+ // Catch-all docs router. Renders the localized content for any
2
+ // `/docs/<path>` URL (and its `/de/docs/<path>` mirror). `getStaticPaths`
3
+ // enumerates the doc tree at build time so every page is pre-rendered.
4
+ //
5
+ // Bilingual (Strategy B): the doc SLUG is stable across locales — only the
6
+ // /de URL prefix differs — so each entry carries a `titleKey` / `bodyKey`
7
+ // into the message catalog rather than literal, one-language strings. The
8
+ // [locale] mirror (src/pages/[locale]/docs/[...slug].tsx) re-exports this
9
+ // page and emits the cross-product of non-default locales × these slugs.
10
+
11
+ import type { ReactNode } from 'react'
12
+ import type { PageMeta } from '@voltro/web'
13
+ import { useParams } from '@voltro/web'
14
+ import { T, useTFn } from '@voltro/i18n'
15
+ import { getCatalog, type Messages } from '../../lib/locale'
16
+
17
+ export const renderMode = 'static' as const
18
+ export const interactive = 'none' as const
19
+
20
+ interface DocEntry {
21
+ readonly slug: string
22
+ readonly titleKey: keyof Messages
23
+ readonly bodyKey: keyof Messages
24
+ }
25
+
26
+ // The doc tree — slugs stay identical across locales; the per-locale prose
27
+ // lives in the catalogs. Replace with a loader over a markdown folder / CMS
28
+ // / database query; the shape stays the same.
29
+ export const DOCS: ReadonlyArray<DocEntry> = [
30
+ { slug: 'intro/getting-started', titleKey: 'docs.getting-started.title', bodyKey: 'docs.getting-started.body' },
31
+ { slug: 'guides/first-page', titleKey: 'docs.first-page.title', bodyKey: 'docs.first-page.body' },
32
+ ]
33
+
34
+ // getStaticPaths returns `{ params: { slug: '<path>' } }` entries — the
35
+ // framework substitutes each into `/docs/[...slug]` to enumerate the URLs
36
+ // to pre-render. The captured slug is the raw `/`-joined path (NOT a string
37
+ // array) so a single deep slug like 'intro/getting-started' renders one file.
38
+ export const getStaticPaths = async (): Promise<Array<{ params: { slug: string } }>> =>
39
+ DOCS.map((d) => ({ params: { slug: d.slug } }))
40
+
41
+ // Per-locale, per-doc <title>: reads the active locale + the captured slug
42
+ // (both threaded in at SSG time) so each variant's head is localised.
43
+ export const meta = ({
44
+ locale,
45
+ params,
46
+ }: {
47
+ locale: string
48
+ params: Readonly<Record<string, string>>
49
+ }): PageMeta => {
50
+ const c = getCatalog(locale)
51
+ const doc = DOCS.find((d) => d.slug === params.slug)
52
+ return {
53
+ title: doc ? c[doc.titleKey] : c['docs.notFound.title'],
54
+ description: c['meta.docs.description'],
55
+ }
56
+ }
57
+
58
+ const code = (chunks: ReactNode): ReactNode => <code>{chunks}</code>
59
+
60
+ export default function DocPage(): ReactNode {
61
+ const { slug } = useParams<{ slug: string }>()
62
+ const t = useTFn()
63
+ const doc = DOCS.find((d) => d.slug === slug)
64
+ if (!doc) {
65
+ return (
66
+ <article>
67
+ <h1>
68
+ <T id="docs.notFound.title" />
69
+ </h1>
70
+ <p>
71
+ <T id="docs.notFound.body" values={{ slug, code }} />
72
+ </p>
73
+ </article>
74
+ )
75
+ }
76
+ return (
77
+ <article>
78
+ <h1>{t(doc.titleKey)}</h1>
79
+ <p>{t(doc.bodyKey)}</p>
80
+ </article>
81
+ )
82
+ }
@@ -0,0 +1,90 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // `/` docs landing — a bilingual static page (Strategy B). Its links are
4
+ // locale-prefixed off the active locale via `withLocalePrefix`, so /de's
5
+ // landing points at the /de docs. We assert the render-mode config, the
6
+ // localized meta, and that the links resolve to the right locale's URLs.
7
+ // The heading carries a `{{capProjectName}}` scaffold placeholder threaded in
8
+ // as a <T> value, so we assert the localized suffix, not the substituted name.
9
+
10
+ import { afterEach, describe, expect, test, vi } from 'vitest'
11
+ import { act, createElement, type ReactNode } from 'react'
12
+ import { createRoot, type Root } from 'react-dom/client'
13
+ import en from '../locales/en'
14
+ import de from '../locales/de'
15
+
16
+ const catalogs: Record<string, Record<string, string>> = { en, de }
17
+ let currentLocale = 'en'
18
+
19
+ const fill = (msg: string, values?: Record<string, unknown>): string =>
20
+ values ? msg.replace(/\{(\w+)\}/g, (_, k: string) => String(values[k] ?? `{${k}}`)) : msg
21
+
22
+ vi.mock('@voltro/i18n', () => ({
23
+ // The locale catalogs call these at module top-level; identity mirrors the
24
+ // real (compile-time-only) implementations so importing them doesn't throw.
25
+ defineCatalog: <T,>(c: T): T => c,
26
+ defineLocale:
27
+ () =>
28
+ <T,>(c: T): T =>
29
+ c,
30
+ useLocale: () => currentLocale,
31
+ T: ({ id, values }: { id: string; values?: Record<string, unknown> }) =>
32
+ fill(catalogs[currentLocale]?.[id] ?? id, values),
33
+ }))
34
+
35
+ const { default: Index, meta, renderMode, interactive } = await import('./index')
36
+
37
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
38
+
39
+ let container: HTMLDivElement
40
+ let root: Root
41
+
42
+ const render = (node: ReactNode): void => {
43
+ container = document.createElement('div')
44
+ document.body.appendChild(container)
45
+ act(() => {
46
+ root = createRoot(container)
47
+ root.render(node)
48
+ })
49
+ }
50
+
51
+ const hrefs = (): Array<string | null> =>
52
+ Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
53
+
54
+ afterEach(() => {
55
+ currentLocale = 'en'
56
+ if (root) act(() => root.unmount())
57
+ container?.remove()
58
+ document.body.innerHTML = ''
59
+ })
60
+
61
+ describe('index — config + localized meta', () => {
62
+ test('is a static page with no client JS', () => {
63
+ expect(renderMode).toBe('static')
64
+ expect(interactive).toBe('none')
65
+ })
66
+
67
+ test('meta() is localized per locale', () => {
68
+ expect(meta({ locale: 'en' }).title).toBe('Documentation')
69
+ expect(meta({ locale: 'de' }).title).toBe('Dokumentation')
70
+ expect(meta({ locale: 'zz' }).title).toBe('Documentation')
71
+ })
72
+ })
73
+
74
+ describe('index — localized render', () => {
75
+ test('links to both doc pages with bare (en) URLs and English titles', () => {
76
+ currentLocale = 'en'
77
+ render(createElement(Index))
78
+ expect(hrefs()).toEqual(['/docs/intro/getting-started', '/docs/guides/first-page'])
79
+ expect(container.textContent).toContain('Getting started')
80
+ expect(container.textContent).toContain('Your first page')
81
+ })
82
+
83
+ test('prefixes the doc links with /de and shows German titles for locale de', () => {
84
+ currentLocale = 'de'
85
+ render(createElement(Index))
86
+ expect(hrefs()).toEqual(['/de/docs/intro/getting-started', '/de/docs/guides/first-page'])
87
+ expect(container.textContent).toContain('Erste Schritte')
88
+ expect(container.textContent).toContain('Deine erste Seite')
89
+ })
90
+ })
@@ -0,0 +1,45 @@
1
+ // Docs landing — link to the available doc pages. Keep this thin; the docs
2
+ // themselves live under `src/pages/docs/[...slug].tsx`.
3
+ //
4
+ // Bilingual (Strategy B): mounted at `/` (default locale) and mirrored at
5
+ // `/de` by src/pages/[locale]/index.tsx. The links are locale-prefixed off
6
+ // the active locale so /de's landing points at the /de docs.
7
+
8
+ import type { ReactNode } from 'react'
9
+ import type { PageMeta } from '@voltro/web'
10
+ import { T, useLocale } from '@voltro/i18n'
11
+ import { getCatalog, withLocalePrefix } from '../lib/locale'
12
+
13
+ export const renderMode = 'static' as const
14
+ export const interactive = 'none' as const
15
+
16
+ export const meta = ({ locale }: { locale: string }): PageMeta => {
17
+ const c = getCatalog(locale)
18
+ return {
19
+ title: c['meta.home.title'],
20
+ description: c['meta.home.description'],
21
+ }
22
+ }
23
+
24
+ export default function Index(): ReactNode {
25
+ const locale = useLocale()
26
+ return (
27
+ <main>
28
+ <h1>
29
+ <T id="home.title" values={{ project: '{{capProjectName}}' }} />
30
+ </h1>
31
+ <ul>
32
+ <li>
33
+ <a href={withLocalePrefix('/docs/intro/getting-started', locale)}>
34
+ <T id="docs.getting-started.title" />
35
+ </a>
36
+ </li>
37
+ <li>
38
+ <a href={withLocalePrefix('/docs/guides/first-page', locale)}>
39
+ <T id="docs.first-page.title" />
40
+ </a>
41
+ </li>
42
+ </ul>
43
+ </main>
44
+ )
45
+ }
@@ -0,0 +1,84 @@
1
+ // @vitest-environment jsdom
2
+ //
3
+ // Root layout — renders the top nav whose Home link + language switcher are
4
+ // locale-prefixed off the CURRENT url (useUrlLocale → useLocation). We mock
5
+ // useLocation (@voltro/web) to drive the active locale, and mock @voltro/i18n so
6
+ // <I18nProvider> is a pass-through and <T> resolves against the real catalogs.
7
+
8
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
9
+ import { act, createElement, type ReactNode } from 'react'
10
+ import { createRoot, type Root } from 'react-dom/client'
11
+ import en from '../locales/en'
12
+ import de from '../locales/de'
13
+
14
+ const location = vi.fn<() => string>()
15
+ vi.mock('@voltro/web', () => ({ useLocation: () => location() }))
16
+
17
+ const catalogs: Record<string, Record<string, string>> = { en, de }
18
+ const localeFor = (path: string): string => (/^\/de(?:\/|$)/.test(path) ? 'de' : 'en')
19
+
20
+ vi.mock('@voltro/i18n', () => ({
21
+ // The locale catalogs call these at module top-level; identity mirrors the
22
+ // real (compile-time-only) implementations so importing them doesn't throw.
23
+ defineCatalog: <T,>(c: T): T => c,
24
+ defineLocale:
25
+ () =>
26
+ <T,>(c: T): T =>
27
+ c,
28
+ I18nProvider: ({ children }: { children?: ReactNode }) => children,
29
+ // The nav uses <T> for link labels; resolve against the catalog of the
30
+ // locale implied by the current path (matches what useUrlLocale computes).
31
+ T: ({ id }: { id: string }) => catalogs[localeFor(location())]?.[id] ?? id,
32
+ }))
33
+
34
+ const { default: Layout } = await import('./layout')
35
+
36
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
37
+
38
+ let container: HTMLDivElement
39
+ let root: Root
40
+
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(node)
47
+ })
48
+ }
49
+
50
+ const hrefs = (): Array<string | null> =>
51
+ Array.from(container.querySelectorAll('a')).map((a) => a.getAttribute('href'))
52
+
53
+ beforeEach(() => location.mockReset())
54
+
55
+ afterEach(() => {
56
+ if (root) act(() => root.unmount())
57
+ container?.remove()
58
+ document.body.innerHTML = ''
59
+ })
60
+
61
+ describe('docs layout — English (bare path)', () => {
62
+ test('renders a bare Home link, an English nav label and the DE switcher target', () => {
63
+ location.mockReturnValue('/docs/intro/getting-started')
64
+ render(createElement(Layout, { children: createElement('p', null, 'page') }))
65
+ const h = hrefs()
66
+ expect(h).toContain('/')
67
+ // the language switcher keeps you on the same doc, re-prefixed per locale
68
+ expect(h).toContain('/de/docs/intro/getting-started')
69
+ expect(container.textContent).toContain('Home')
70
+ expect(container.textContent).toContain('page')
71
+ })
72
+ })
73
+
74
+ describe('docs layout — German (/de prefix)', () => {
75
+ test('prefixes the home link with /de and renders German labels', () => {
76
+ location.mockReturnValue('/de/docs/intro/getting-started')
77
+ render(createElement(Layout, { children: null }))
78
+ const h = hrefs()
79
+ expect(h).toContain('/de')
80
+ // switching back to en strips the prefix
81
+ expect(h).toContain('/docs/intro/getting-started')
82
+ expect(container.textContent).toContain('Start')
83
+ })
84
+ })