@voltro/cli 0.27.0 → 0.29.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 (284) hide show
  1. package/CHANGELOG.md +513 -0
  2. package/THIRD-PARTY-NOTICES.md +88 -2
  3. package/dist/{apiBuild-D22_EpoR.js → apiBuild-BESZbTjA.js} +4 -4
  4. package/dist/apiBuild-C8d74T6g.js +2 -0
  5. package/dist/bin.js +3 -3
  6. package/dist/checkCommand-BPAtyWs8.js +2420 -0
  7. package/dist/checkCommand-DBvZvCh1.js +2 -0
  8. package/dist/cliRuntime-Oh517vCV.js +96 -0
  9. package/dist/{commands-jBX8no1I.js → commands-82BDEktg.js} +6476 -7672
  10. package/dist/dbCommand-CaIVTp-a.js +2 -0
  11. package/dist/{dbCommand-uuNCrFAb.js → dbCommand-bCBbk6tz.js} +3 -3
  12. package/dist/{dev-DcbIJrWg.js → dev-Cg4BKLmi.js} +3034 -2619
  13. package/dist/dev-DeEJj5T4.js +3 -0
  14. package/dist/fileConventions-Cof68_BL.js +33 -0
  15. package/dist/{frameworkTableAssembly-BwHU9Euq.js → frameworkTableAssembly-4Db40V23.js} +2 -2
  16. package/dist/frameworkTableAssembly-BTNirAAk.js +2 -0
  17. package/dist/index.js +1 -1
  18. package/dist/{inspect-CUCCzw2I.js → inspect-BMvQpwqy.js} +211 -190
  19. package/dist/inspect-DHeaMZak.js +2 -0
  20. package/dist/{inspectMetrics-BU90mvJN.js → inspectMetrics-DHYygE4s.js} +999 -961
  21. package/dist/{manifestBuild-BnzAxp2O.js → manifestBuild-C4R1EdHn.js} +1 -1
  22. package/dist/manifestBuild-Ck_90gZy.js +2 -0
  23. package/dist/sdkgen-CW5NbYF0.js +582 -0
  24. package/dist/{seedRunner-D6eu-u5U.js → seedRunner-Bqxgp7HZ.js} +60 -59
  25. package/dist/serveCommand-BXl8mhZD.js +1489 -0
  26. package/dist/serveEntry.js +3 -3
  27. package/dist/{start-BGXIf6zT.js → start-CsCIaW4-.js} +282 -269
  28. package/dist/startEntry.js +2 -2
  29. package/package.json +17 -17
  30. package/templates/AGENTS.md +2 -1
  31. package/templates/agent-docs/_index.md +2 -1
  32. package/templates/agent-docs/_manifest.json +10 -1
  33. package/templates/agent-docs/ai.md +135 -0
  34. package/templates/agent-docs/cli.md +124 -6
  35. package/templates/agent-docs/configuration.md +32 -0
  36. package/templates/agent-docs/data.md +282 -0
  37. package/templates/agent-docs/database/migrations.md +47 -0
  38. package/templates/agent-docs/database/misc.md +57 -0
  39. package/templates/agent-docs/database/schema.md +3 -1
  40. package/templates/agent-docs/deployment.md +56 -0
  41. package/templates/agent-docs/internationalization.md +161 -1
  42. package/templates/agent-docs/local-first-mobile.md +414 -0
  43. package/templates/agent-docs/routing.md +93 -2
  44. package/templates/agent-docs/schema-driven-ui.md +12 -0
  45. package/templates/agent-docs/templates/apibackends.md +1 -1
  46. package/templates/agent-docs/testing.md +42 -0
  47. package/templates/agent-docs/whats-new.md +165 -131
  48. package/templates/agent-docs/workflows.md +11 -0
  49. package/templates/apps/api-ai/package.json +7 -7
  50. package/templates/apps/api-auth/package.json +8 -8
  51. package/templates/apps/api-backend/package.json +7 -7
  52. package/templates/apps/api-backend-deactivation/package.json +7 -7
  53. package/templates/apps/api-backend-mail/package.json +8 -8
  54. package/templates/apps/api-backend-mariadb/package.json +9 -9
  55. package/templates/apps/api-backend-sqlite/.env.example +19 -0
  56. package/templates/apps/api-backend-sqlite/README.md +38 -0
  57. package/templates/apps/api-backend-sqlite/app.config.ts +35 -0
  58. package/templates/apps/api-backend-sqlite/database/schema.ts +54 -0
  59. package/templates/apps/api-backend-sqlite/mutations/notes.create.mutation.server.ts +19 -0
  60. package/templates/apps/api-backend-sqlite/mutations/notes.create.mutation.ts +37 -0
  61. package/templates/apps/api-backend-sqlite/package.json +30 -0
  62. package/templates/apps/api-backend-sqlite/queries/notes.query.server.ts +14 -0
  63. package/templates/apps/api-backend-sqlite/queries/notes.query.ts +20 -0
  64. package/templates/apps/api-backend-sqlite/template.json +6 -0
  65. package/templates/apps/api-backend-sqlite/tests/notes.create.test.ts +50 -0
  66. package/templates/apps/api-backend-sqlite/tsconfig.json +5 -0
  67. package/templates/apps/api-backend-storage/package.json +8 -8
  68. package/templates/apps/api-cms/README.md +104 -0
  69. package/templates/apps/api-cms/actions/content.get.action.server.ts +27 -0
  70. package/templates/apps/api-cms/actions/content.get.action.ts +19 -0
  71. package/templates/apps/api-cms/actions/content.types.action.server.ts +26 -0
  72. package/templates/apps/api-cms/actions/content.types.action.ts +40 -0
  73. package/templates/apps/api-cms/actions/me.action.server.ts +18 -0
  74. package/templates/apps/api-cms/actions/me.action.ts +16 -0
  75. package/templates/apps/api-cms/app.config.ts +61 -0
  76. package/templates/apps/api-cms/content/blogPost.contentType.ts +39 -0
  77. package/templates/apps/api-cms/content/index.ts +18 -0
  78. package/templates/apps/api-cms/content/page.contentType.ts +24 -0
  79. package/templates/apps/api-cms/database/schema.ts +64 -0
  80. package/templates/apps/api-cms/mutations/content.publish.mutation.server.ts +19 -0
  81. package/templates/apps/api-cms/mutations/content.publish.mutation.ts +15 -0
  82. package/templates/apps/api-cms/mutations/content.saveDraft.mutation.server.ts +36 -0
  83. package/templates/apps/api-cms/mutations/content.saveDraft.mutation.ts +32 -0
  84. package/templates/apps/api-cms/mutations/content.unpublish.mutation.server.ts +19 -0
  85. package/templates/apps/api-cms/mutations/content.unpublish.mutation.ts +11 -0
  86. package/templates/apps/api-cms/package.json +32 -0
  87. package/templates/apps/api-cms/queries/content.list.query.server.ts +0 -0
  88. package/templates/apps/api-cms/queries/content.list.query.ts +27 -0
  89. package/templates/apps/api-cms/template.json +6 -0
  90. package/templates/apps/api-cms/tests/content.descriptors.test.ts +64 -0
  91. package/templates/apps/api-cms/tests/content.write.test.ts +85 -0
  92. package/templates/apps/api-cms/tsconfig.json +5 -0
  93. package/templates/apps/api-data-advanced/package.json +8 -8
  94. package/templates/apps/api-durable/package.json +8 -8
  95. package/templates/apps/api-feature-flags/package.json +9 -9
  96. package/templates/apps/api-governance/package.json +8 -8
  97. package/templates/apps/api-kv/package.json +8 -8
  98. package/templates/apps/api-moderation/package.json +8 -8
  99. package/templates/apps/api-observability/package.json +8 -8
  100. package/templates/apps/api-ratelimit/package.json +8 -8
  101. package/templates/apps/api-rbac/package.json +8 -8
  102. package/templates/apps/api-rest/package.json +7 -7
  103. package/templates/apps/api-saas/package.json +11 -11
  104. package/templates/apps/api-saas-starter/README.md +103 -0
  105. package/templates/apps/api-saas-starter/actions/me.action.server.ts +18 -0
  106. package/templates/apps/api-saas-starter/actions/me.action.ts +20 -0
  107. package/templates/apps/api-saas-starter/app.config.ts +87 -0
  108. package/templates/apps/api-saas-starter/database/schema.ts +57 -0
  109. package/templates/apps/api-saas-starter/mutations/invites.create.mutation.server.ts +26 -0
  110. package/templates/apps/api-saas-starter/mutations/invites.create.mutation.ts +18 -0
  111. package/templates/apps/api-saas-starter/mutations/projects.create.mutation.server.ts +29 -0
  112. package/templates/apps/api-saas-starter/mutations/projects.create.mutation.ts +18 -0
  113. package/templates/apps/api-saas-starter/package.json +32 -0
  114. package/templates/apps/api-saas-starter/queries/invites.list.query.server.ts +14 -0
  115. package/templates/apps/api-saas-starter/queries/invites.list.query.ts +17 -0
  116. package/templates/apps/api-saas-starter/queries/projects.list.query.server.ts +14 -0
  117. package/templates/apps/api-saas-starter/queries/projects.list.query.ts +18 -0
  118. package/templates/apps/api-saas-starter/template.json +6 -0
  119. package/templates/apps/api-saas-starter/tests/projects.create.test.ts +62 -0
  120. package/templates/apps/api-saas-starter/tests/session.test.ts +33 -0
  121. package/templates/apps/api-saas-starter/tsconfig.json +5 -0
  122. package/templates/apps/api-search/package.json +8 -8
  123. package/templates/apps/api-status/README.md +88 -0
  124. package/templates/apps/api-status/app.config.ts +36 -0
  125. package/templates/apps/api-status/authz.ts +33 -0
  126. package/templates/apps/api-status/database/schema.ts +70 -0
  127. package/templates/apps/api-status/mutations/components.create.mutation.server.ts +19 -0
  128. package/templates/apps/api-status/mutations/components.create.mutation.ts +16 -0
  129. package/templates/apps/api-status/mutations/incidents.create.mutation.server.ts +25 -0
  130. package/templates/apps/api-status/mutations/incidents.create.mutation.ts +22 -0
  131. package/templates/apps/api-status/mutations/incidents.resolve.mutation.server.ts +24 -0
  132. package/templates/apps/api-status/mutations/incidents.resolve.mutation.ts +19 -0
  133. package/templates/apps/api-status/mutations/incidents.update.mutation.server.ts +26 -0
  134. package/templates/apps/api-status/mutations/incidents.update.mutation.ts +21 -0
  135. package/templates/apps/api-status/package.json +30 -0
  136. package/templates/apps/api-status/queries/components.list.query.server.ts +14 -0
  137. package/templates/apps/api-status/queries/components.list.query.ts +13 -0
  138. package/templates/apps/api-status/queries/incidents.live.query.server.ts +14 -0
  139. package/templates/apps/api-status/queries/incidents.live.query.ts +20 -0
  140. package/templates/apps/api-status/queries/updates.list.query.server.ts +14 -0
  141. package/templates/apps/api-status/queries/updates.list.query.ts +17 -0
  142. package/templates/apps/api-status/template.json +6 -0
  143. package/templates/apps/api-status/tests/status.test.ts +70 -0
  144. package/templates/apps/api-status/tsconfig.json +5 -0
  145. package/templates/apps/api-versioning/package.json +8 -8
  146. package/templates/apps/api-webhooks/package.json +9 -9
  147. package/templates/apps/changelog/package.json +6 -6
  148. package/templates/apps/edge-functions/package.json +2 -2
  149. package/templates/apps/frontend-admin/package.json +8 -8
  150. package/templates/apps/frontend-app/package.json +8 -8
  151. package/templates/apps/frontend-auth/README.md +78 -0
  152. package/templates/apps/frontend-auth/app.config.ts +34 -0
  153. package/templates/apps/frontend-auth/package.json +32 -0
  154. package/templates/apps/frontend-auth/src/components/AuthShell.tsx +35 -0
  155. package/templates/apps/frontend-auth/src/components/PasswordStrength.tsx +33 -0
  156. package/templates/apps/frontend-auth/src/config.ts +11 -0
  157. package/templates/apps/frontend-auth/src/globals.css +105 -0
  158. package/templates/apps/frontend-auth/src/globals.d.ts +6 -0
  159. package/templates/apps/frontend-auth/src/lib/auth.ts +34 -0
  160. package/templates/apps/frontend-auth/src/lib/redirect.test.ts +24 -0
  161. package/templates/apps/frontend-auth/src/lib/redirect.ts +29 -0
  162. package/templates/apps/frontend-auth/src/locales/de.ts +66 -0
  163. package/templates/apps/frontend-auth/src/locales/en.ts +76 -0
  164. package/templates/apps/frontend-auth/src/locales/index.ts +14 -0
  165. package/templates/apps/frontend-auth/src/pages/forgot/page.tsx +51 -0
  166. package/templates/apps/frontend-auth/src/pages/layout.tsx +12 -0
  167. package/templates/apps/frontend-auth/src/pages/login/page.test.tsx +53 -0
  168. package/templates/apps/frontend-auth/src/pages/login/page.tsx +67 -0
  169. package/templates/apps/frontend-auth/src/pages/logout/page.tsx +28 -0
  170. package/templates/apps/frontend-auth/src/pages/magic/page.tsx +51 -0
  171. package/templates/apps/frontend-auth/src/pages/page.tsx +26 -0
  172. package/templates/apps/frontend-auth/src/pages/reset/page.test.tsx +51 -0
  173. package/templates/apps/frontend-auth/src/pages/reset/page.tsx +63 -0
  174. package/templates/apps/frontend-auth/src/pages/signup/page.tsx +60 -0
  175. package/templates/apps/frontend-auth/src/pages/verify/page.tsx +50 -0
  176. package/templates/apps/frontend-auth/template.json +6 -0
  177. package/templates/apps/frontend-auth/tsconfig.json +5 -0
  178. package/templates/apps/frontend-blank/package.json +7 -7
  179. package/templates/apps/frontend-cms/README.md +47 -0
  180. package/templates/apps/frontend-cms/app.config.ts +37 -0
  181. package/templates/apps/frontend-cms/package.json +33 -0
  182. package/templates/apps/frontend-cms/src/config.ts +8 -0
  183. package/templates/apps/frontend-cms/src/globals.css +105 -0
  184. package/templates/apps/frontend-cms/src/globals.d.ts +6 -0
  185. package/templates/apps/frontend-cms/src/lib/api.ts +58 -0
  186. package/templates/apps/frontend-cms/src/locales/de.ts +50 -0
  187. package/templates/apps/frontend-cms/src/locales/en.ts +55 -0
  188. package/templates/apps/frontend-cms/src/locales/index.ts +14 -0
  189. package/templates/apps/frontend-cms/src/pages/(app)/error.tsx +18 -0
  190. package/templates/apps/frontend-cms/src/pages/(app)/layout.test.tsx +31 -0
  191. package/templates/apps/frontend-cms/src/pages/(app)/layout.tsx +62 -0
  192. package/templates/apps/frontend-cms/src/pages/(app)/not-found.tsx +14 -0
  193. package/templates/apps/frontend-cms/src/pages/(app)/page.test.tsx +110 -0
  194. package/templates/apps/frontend-cms/src/pages/(app)/page.tsx +159 -0
  195. package/templates/apps/frontend-cms/src/pages/layout.tsx +12 -0
  196. package/templates/apps/frontend-cms/src/pages/login/page.test.tsx +58 -0
  197. package/templates/apps/frontend-cms/src/pages/login/page.tsx +93 -0
  198. package/templates/apps/frontend-cms/template.json +6 -0
  199. package/templates/apps/frontend-cms/tsconfig.json +5 -0
  200. package/templates/apps/frontend-contact/package.json +7 -7
  201. package/templates/apps/frontend-dashboard/package.json +7 -7
  202. package/templates/apps/frontend-docs/package.json +7 -7
  203. package/templates/apps/frontend-i18n/package.json +6 -6
  204. package/templates/apps/frontend-landing/package.json +7 -7
  205. package/templates/apps/frontend-portal/README.md +71 -0
  206. package/templates/apps/frontend-portal/app.config.ts +37 -0
  207. package/templates/apps/frontend-portal/package.json +32 -0
  208. package/templates/apps/frontend-portal/src/config.ts +8 -0
  209. package/templates/apps/frontend-portal/src/globals.css +93 -0
  210. package/templates/apps/frontend-portal/src/globals.d.ts +6 -0
  211. package/templates/apps/frontend-portal/src/lib/api.ts +62 -0
  212. package/templates/apps/frontend-portal/src/locales/de.ts +86 -0
  213. package/templates/apps/frontend-portal/src/locales/en.ts +93 -0
  214. package/templates/apps/frontend-portal/src/locales/index.ts +14 -0
  215. package/templates/apps/frontend-portal/src/pages/(portal)/api-keys/page.test.tsx +71 -0
  216. package/templates/apps/frontend-portal/src/pages/(portal)/api-keys/page.tsx +124 -0
  217. package/templates/apps/frontend-portal/src/pages/(portal)/billing/page.test.tsx +86 -0
  218. package/templates/apps/frontend-portal/src/pages/(portal)/billing/page.tsx +97 -0
  219. package/templates/apps/frontend-portal/src/pages/(portal)/error.tsx +19 -0
  220. package/templates/apps/frontend-portal/src/pages/(portal)/invoices/page.tsx +45 -0
  221. package/templates/apps/frontend-portal/src/pages/(portal)/layout.test.tsx +31 -0
  222. package/templates/apps/frontend-portal/src/pages/(portal)/layout.tsx +63 -0
  223. package/templates/apps/frontend-portal/src/pages/(portal)/not-found.tsx +15 -0
  224. package/templates/apps/frontend-portal/src/pages/(portal)/page.tsx +39 -0
  225. package/templates/apps/frontend-portal/src/pages/(portal)/profile/page.tsx +79 -0
  226. package/templates/apps/frontend-portal/src/pages/layout.tsx +12 -0
  227. package/templates/apps/frontend-portal/src/pages/login/page.test.tsx +58 -0
  228. package/templates/apps/frontend-portal/src/pages/login/page.tsx +96 -0
  229. package/templates/apps/frontend-portal/template.json +6 -0
  230. package/templates/apps/frontend-portal/tsconfig.json +5 -0
  231. package/templates/apps/frontend-saas/README.md +73 -0
  232. package/templates/apps/frontend-saas/app.config.ts +46 -0
  233. package/templates/apps/frontend-saas/package.json +32 -0
  234. package/templates/apps/frontend-saas/src/config.ts +8 -0
  235. package/templates/apps/frontend-saas/src/globals.css +85 -0
  236. package/templates/apps/frontend-saas/src/globals.d.ts +6 -0
  237. package/templates/apps/frontend-saas/src/lib/api.ts +47 -0
  238. package/templates/apps/frontend-saas/src/locales/de.ts +72 -0
  239. package/templates/apps/frontend-saas/src/locales/en.ts +81 -0
  240. package/templates/apps/frontend-saas/src/locales/index.ts +14 -0
  241. package/templates/apps/frontend-saas/src/pages/(marketing)/layout.tsx +30 -0
  242. package/templates/apps/frontend-saas/src/pages/(marketing)/login/page.test.tsx +58 -0
  243. package/templates/apps/frontend-saas/src/pages/(marketing)/login/page.tsx +96 -0
  244. package/templates/apps/frontend-saas/src/pages/(marketing)/page.tsx +27 -0
  245. package/templates/apps/frontend-saas/src/pages/dashboard/billing/page.tsx +72 -0
  246. package/templates/apps/frontend-saas/src/pages/dashboard/error.tsx +20 -0
  247. package/templates/apps/frontend-saas/src/pages/dashboard/layout.test.tsx +32 -0
  248. package/templates/apps/frontend-saas/src/pages/dashboard/layout.tsx +69 -0
  249. package/templates/apps/frontend-saas/src/pages/dashboard/not-found.tsx +17 -0
  250. package/templates/apps/frontend-saas/src/pages/dashboard/page.test.tsx +113 -0
  251. package/templates/apps/frontend-saas/src/pages/dashboard/page.tsx +76 -0
  252. package/templates/apps/frontend-saas/src/pages/dashboard/team/page.tsx +73 -0
  253. package/templates/apps/frontend-saas/src/pages/layout.tsx +12 -0
  254. package/templates/apps/frontend-saas/template.json +6 -0
  255. package/templates/apps/frontend-saas/tsconfig.json +5 -0
  256. package/templates/apps/frontend-spa/package.json +7 -7
  257. package/templates/apps/frontend-ssr/package.json +7 -7
  258. package/templates/apps/frontend-ssr-api/package.json +8 -8
  259. package/templates/apps/frontend-static-blog/package.json +6 -6
  260. package/templates/apps/frontend-status/README.md +51 -0
  261. package/templates/apps/frontend-status/app.config.ts +39 -0
  262. package/templates/apps/frontend-status/package.json +32 -0
  263. package/templates/apps/frontend-status/src/config.ts +7 -0
  264. package/templates/apps/frontend-status/src/globals.css +70 -0
  265. package/templates/apps/frontend-status/src/globals.d.ts +6 -0
  266. package/templates/apps/frontend-status/src/lib/status.ts +81 -0
  267. package/templates/apps/frontend-status/src/locales/de.ts +41 -0
  268. package/templates/apps/frontend-status/src/locales/en.ts +45 -0
  269. package/templates/apps/frontend-status/src/locales/index.ts +13 -0
  270. package/templates/apps/frontend-status/src/pages/layout.tsx +27 -0
  271. package/templates/apps/frontend-status/src/pages/page.test.tsx +123 -0
  272. package/templates/apps/frontend-status/src/pages/page.tsx +136 -0
  273. package/templates/apps/frontend-status/template.json +6 -0
  274. package/templates/apps/frontend-status/tsconfig.json +11 -0
  275. package/templates/baselines/compose/docker-compose.prod.yml +15 -0
  276. package/templates/baselines/compose-mariadb/docker-compose.prod.yml +15 -0
  277. package/dist/apiBuild-BrjrVJJh.js +0 -2
  278. package/dist/dbCommand-DrzXimKf.js +0 -2
  279. package/dist/dev-DNkso403.js +0 -3
  280. package/dist/fileConventions-3bffWssN.js +0 -30
  281. package/dist/frameworkTableAssembly-lrjZtk0G.js +0 -2
  282. package/dist/inspect-gt8bq-Tz.js +0 -2
  283. package/dist/manifestBuild-ifczArzr.js +0 -2
  284. package/dist/serveCommand-DfkisVWP.js +0 -1310
@@ -0,0 +1,136 @@
1
+ // `/` — the public status page. `renderMode: 'ssr'`, fed by the sibling api:
2
+ // the loader bakes the current incidents + components + updates into the first
3
+ // paint (crawlable), then the component upgrades each to live with
4
+ // `useSubscription`, so a newly-declared or resolved incident lands on every
5
+ // open page within seconds — no polling.
6
+ import type { ReactNode } from 'react'
7
+ import { useLoaderData, type LoaderFn, type PageMeta } from '@voltro/web'
8
+ import { useSubscription } from '@voltro/client'
9
+ import { T } from '@voltro/i18n'
10
+ import { getCatalog } from '../locales'
11
+ import {
12
+ deriveOverall, uptimeGrid, uptimePercent,
13
+ type Incident, type Component, type Update,
14
+ } from '../lib/status'
15
+
16
+ interface PageData {
17
+ readonly incidents: ReadonlyArray<Incident>
18
+ readonly components: ReadonlyArray<Component>
19
+ readonly updates: ReadonlyArray<Update>
20
+ }
21
+
22
+ export const renderMode = 'ssr' as const
23
+
24
+ // `query` is present ONLY server-side. It invokes the api's rpc over POST /rpc;
25
+ // a streaming query is drained to its first snapshot. On a client navigation
26
+ // `query` is undefined and we start empty — the subscriptions fill in.
27
+ export const loader: LoaderFn<PageData> = async ({ query }) => ({
28
+ incidents: query ? await query<ReadonlyArray<Incident>>('incidents.live', {}) : [],
29
+ components: query ? await query<ReadonlyArray<Component>>('components.list', {}) : [],
30
+ updates: query ? await query<ReadonlyArray<Update>>('updates.list', {}) : [],
31
+ })
32
+
33
+ export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
34
+ title: getCatalog(locale)['meta.title'],
35
+ description: getCatalog(locale)['meta.description'],
36
+ })
37
+
38
+ const fmtDate = (v: string | Date | null): string =>
39
+ v == null ? '' : new Date(v).toLocaleString()
40
+
41
+ export default function StatusPage(): ReactNode {
42
+ const initial = useLoaderData<PageData>()
43
+ const { data: iLive } = useSubscription<ReadonlyArray<Incident>>('app', 'incidents.live')
44
+ const { data: cLive } = useSubscription<ReadonlyArray<Component>>('app', 'components.list')
45
+ const { data: uLive } = useSubscription<ReadonlyArray<Update>>('app', 'updates.list')
46
+
47
+ const incidents = iLive ?? initial.incidents
48
+ const components = cLive ?? initial.components
49
+ const updates = uLive ?? initial.updates
50
+
51
+ const overall = deriveOverall(incidents, components)
52
+ const grid = uptimeGrid(incidents)
53
+ const pct = uptimePercent(grid)
54
+
55
+ const updatesFor = (incidentId: string): ReadonlyArray<Update> =>
56
+ updates
57
+ .filter((u) => u.incidentId === incidentId)
58
+ .slice()
59
+ .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())
60
+
61
+ return (
62
+ <main>
63
+ {/* Overall banner */}
64
+ <div className={`banner banner--${overall}`} role="status">
65
+ <span className="dot" aria-hidden="true" />
66
+ <strong><T id={`overall.${overall}`} /></strong>
67
+ </div>
68
+
69
+ {/* Uptime */}
70
+ <section>
71
+ <h2><T id="uptime.heading" values={{ days: String(grid.length) }} /></h2>
72
+ <div className="uptime" aria-hidden="true">
73
+ {grid.map((up, idx) => (
74
+ <span key={idx} className={up ? 'day up' : 'day down'} />
75
+ ))}
76
+ </div>
77
+ <p className="muted"><T id="uptime.percent" values={{ percent: String(pct) }} /></p>
78
+ </section>
79
+
80
+ {/* Components */}
81
+ <section>
82
+ <h2><T id="components.heading" /></h2>
83
+ {components.length === 0 ? (
84
+ <p className="muted"><T id="components.empty" /></p>
85
+ ) : (
86
+ <ul className="components">
87
+ {components.map((c) => (
88
+ <li key={c.id}>
89
+ <span>{c.name}</span>
90
+ <span className={`pill pill--${c.status}`}><T id={`comp.status.${c.status}`} /></span>
91
+ </li>
92
+ ))}
93
+ </ul>
94
+ )}
95
+ </section>
96
+
97
+ {/* Incidents */}
98
+ <section>
99
+ <h2><T id="incidents.heading" /></h2>
100
+ {incidents.length === 0 ? (
101
+ <p className="muted"><T id="incidents.none" /></p>
102
+ ) : (
103
+ <ul className="incidents">
104
+ {incidents.map((inc) => (
105
+ <li key={inc.id} className={`incident impact--${inc.impact}`}>
106
+ <div className="incident-head">
107
+ <strong>{inc.title}</strong>
108
+ <span className="pill"><T id={`impact.${inc.impact}`} /></span>
109
+ <span className="pill"><T id={`status.${inc.status}`} /></span>
110
+ </div>
111
+ <p className="muted">
112
+ <T id="incident.started" values={{ when: fmtDate(inc.startedAt) }} />
113
+ {' · '}
114
+ {inc.resolvedAt == null
115
+ ? <T id="incident.ongoing" />
116
+ : <T id="incident.resolved" values={{ when: fmtDate(inc.resolvedAt) }} />}
117
+ </p>
118
+ {updatesFor(inc.id).length > 0 ? (
119
+ <ul className="timeline">
120
+ {updatesFor(inc.id).map((u) => (
121
+ <li key={u.id}>
122
+ <span className="ts">{fmtDate(u.createdAt)}</span>
123
+ <span className="pill"><T id={`status.${u.status}`} /></span>
124
+ <span>{u.body}</span>
125
+ </li>
126
+ ))}
127
+ </ul>
128
+ ) : null}
129
+ </li>
130
+ ))}
131
+ </ul>
132
+ )}
133
+ </section>
134
+ </main>
135
+ )
136
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "frontend-status",
3
+ "kind": "web",
4
+ "summary": "A public status page — a clean live-useSubscription showcase. An SSR shell bakes the current incidents + components into the first paint (crawlable), then upgrades to live: the banner, 90-day uptime grid and incident timeline update within seconds when an operator posts, with no polling. Pairs with the api-status backend. Bilingual (en/de), no auth (it must stay up when the product is down).",
5
+ "tags": ["web", "frontend", "status-page", "live", "useSubscription", "ssr", "uptime"]
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
+ }
@@ -59,6 +59,21 @@ services:
59
59
  NODE_ENV: production
60
60
  DB_URL: postgres://{{projectNameSnake}}:${POSTGRES_PASSWORD:-change-me-in-prod}@postgres:5432/{{projectNameSnake}}
61
61
  VOLTRO_SESSION_SECRET: ${VOLTRO_SESSION_SECRET:?must be set for prod compose}
62
+ # Only needed once an app turns on a plugin that encrypts columns at rest
63
+ # (`governance` with `fieldEncryption`, or any `.encrypted()` column). It
64
+ # is commented out because a generated file cannot know which plugins you
65
+ # will enable — and left here, named, because the alternative is finding
66
+ # out at `onActivate` in a container:
67
+ #
68
+ # governance: fieldEncryption is enabled but secret
69
+ # "VOLTRO_FIELD_ENCRYPTION_KEY" did not resolve
70
+ #
71
+ # Mint it with `voltro secret generate field-encryption` — same shape as
72
+ # `openssl rand -hex 32`, but it is the documented path and it cannot
73
+ # produce the wrong length. LOSE THE KEY, LOSE THE DATA: there is no
74
+ # recovery for a column encrypted under a key you no longer have, so back
75
+ # it up wherever you keep the session secret.
76
+ # VOLTRO_FIELD_ENCRYPTION_KEY: ${VOLTRO_FIELD_ENCRYPTION_KEY:?must be set once fieldEncryption is on}
62
77
  ports:
63
78
  - "4000:4000"
64
79
  depends_on:
@@ -83,6 +83,21 @@ services:
83
83
  S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY:-minioadmin}
84
84
  S3_FORCE_PATH_STYLE: "1"
85
85
  VOLTRO_SESSION_SECRET: ${VOLTRO_SESSION_SECRET:?must be set for prod compose}
86
+ # Only needed once an app turns on a plugin that encrypts columns at rest
87
+ # (`governance` with `fieldEncryption`, or any `.encrypted()` column). It
88
+ # is commented out because a generated file cannot know which plugins you
89
+ # will enable — and left here, named, because the alternative is finding
90
+ # out at `onActivate` in a container:
91
+ #
92
+ # governance: fieldEncryption is enabled but secret
93
+ # "VOLTRO_FIELD_ENCRYPTION_KEY" did not resolve
94
+ #
95
+ # Mint it with `voltro secret generate field-encryption` — same shape as
96
+ # `openssl rand -hex 32`, but it is the documented path and it cannot
97
+ # produce the wrong length. LOSE THE KEY, LOSE THE DATA: there is no
98
+ # recovery for a column encrypted under a key you no longer have, so back
99
+ # it up wherever you keep the session secret.
100
+ # VOLTRO_FIELD_ENCRYPTION_KEY: ${VOLTRO_FIELD_ENCRYPTION_KEY:?must be set once fieldEncryption is on}
86
101
  ports:
87
102
  - "4000:4000"
88
103
  depends_on:
@@ -1,2 +0,0 @@
1
- import { c as e, l as t } from "./apiBuild-D22_EpoR.js";
2
- export { e as runApiBuild, t as runServeBundleBuild };
@@ -1,2 +0,0 @@
1
- import { s as e } from "./dbCommand-uuNCrFAb.js";
2
- export { e as runDbCommand };
@@ -1,3 +0,0 @@
1
- import "./seedRunner-D6eu-u5U.js";
2
- import { c as e, h as t, u as n } from "./dev-DcbIJrWg.js";
3
- export { e as loadApiConfig, n as loadDiscovered, t as walk };
@@ -1,30 +0,0 @@
1
- //#region src/fileConventions.ts
2
- var e = /\.(query|mutation|action|stream)\.ts$/, t = /\.(query|mutation|action|stream)\.server\.ts$/, n = /\.event\.ts$/, r = /\.workflow\.tsx$/, i = /\.workflow\.server\.tsx$/, a = /\.workflow\.tsx?$/, o = /\.trigger\.tsx?$/, s = /\.cron\.tsx?$/, c = /\.webhook\.tsx?$/, l = /\.outbox\.tsx?$/, u = /\.subscribe\.tsx?$/, d = /\.reaction\.tsx?$/, f = /\.aggregate\.tsx?$/, p = /\.startup\.tsx?$/, m = /\.seed\.ts$/, h = /\.relations\.ts$/, g = /\.entity\.ts$|\.schema\.ts$|^schema\.ts$/, _ = (e) => a.test(e) && !r.test(e) && !i.test(e), v = /(?:^|\/)page\.tsx$/, y = /\.island\.tsx?$/, b = /\.component\.tsx$/, x = /\.component\.ui\.tsx$/, S = /\.hook\.tsx?$/, C = /\.internal\.tsx?$/, w = /\.types\.tsx?$/, T = /\.fixture\.tsx?$/, E = /\.tracking\.tsx?$/, D = /\.store\.tsx?$/, O = /\.client\.tsx?$/, k = /\.(test|spec)\.tsx?$/, A = [
3
- e,
4
- t,
5
- a,
6
- i,
7
- o,
8
- s,
9
- c,
10
- l,
11
- u,
12
- d,
13
- f,
14
- p,
15
- m,
16
- h,
17
- g,
18
- /\.route\.tsx?$/,
19
- n,
20
- D,
21
- O,
22
- /\.(agent|tool|email|connection|serverless|server|config|generated)\.tsx?$/
23
- ], j = (e) => A.some((t) => t.test(e)), M = /* @__PURE__ */ new Set([
24
- "layout.tsx",
25
- "error.tsx",
26
- "loading.tsx",
27
- "not-found.tsx"
28
- ]);
29
- //#endregion
30
- export { j as A, E as C, r as D, c as E, a as O, k as S, w as T, g as _, n as a, D as b, C as c, v as d, M as f, h as g, d as h, s as i, _ as j, i as k, y as l, t as m, b as n, T as o, e as p, x as r, S as s, f as t, l as u, m as v, o as w, u as x, p as y };
@@ -1,2 +0,0 @@
1
- import { t as e } from "./frameworkTableAssembly-BwHU9Euq.js";
2
- export { e as assembleFrameworkTables };
@@ -1,2 +0,0 @@
1
- import { r as e } from "./inspect-CUCCzw2I.js";
2
- export { e as buildCapabilityManifest };
@@ -1,2 +0,0 @@
1
- import { t as e } from "./manifestBuild-BnzAxp2O.js";
2
- export { e as buildRpcEntry };