@voltro/cli 0.38.0 → 0.39.1

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 (173) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/THIRD-PARTY-NOTICES.md +80 -45
  3. package/dist/{addCommand-BNeoeSxe.js → addCommand-C05L9tZh.js} +2 -2
  4. package/dist/addCommand-C3MdJG-a.js +2 -0
  5. package/dist/{agentsMd-mhQMF1bx.js → agentsMd-7zI2h5l9.js} +3 -3
  6. package/dist/agentsMd-BFCXh2gl.js +2 -0
  7. package/dist/apiBuild-BmR_bIxN.js +2 -0
  8. package/dist/{apiBuild-CvacV4zA.js → apiBuild-D9FB13_2.js} +3 -3
  9. package/dist/baselineCommand-CXv680Dc.js +2 -0
  10. package/dist/{baselineCommand-C6NMt-oa.js → baselineCommand-Ck2Xm8M7.js} +18 -18
  11. package/dist/bin.js +1 -1
  12. package/dist/{build-_LoTC1s0.js → build-DORV5mLM.js} +107 -100
  13. package/dist/{capabilitiesCommand-nq_pz5xd.js → capabilitiesCommand-D5gucwYa.js} +8 -8
  14. package/dist/{checkCommand-Pjk5sBl2.js → checkCommand-Bf6oMao4.js} +35 -35
  15. package/dist/{checkCommand-wibtQx-N.js → checkCommand-D9qK_gtA.js} +1 -1
  16. package/dist/{cloudCmd-NQSwe_Qk.js → cloudCmd-C42gaO8s.js} +16 -16
  17. package/dist/{clusterCmd-D5wsCmA_.js → clusterCmd-DrVFCzSj.js} +8 -4
  18. package/dist/{codegen-GYYcdpCg.js → codegen-CbpGCWLG.js} +1 -1
  19. package/dist/codegen-i8QGcHsi.js +2 -0
  20. package/dist/codegenCommand-CxOyKmc1.js +129 -0
  21. package/dist/{codemodRunner-CXgQ-ecJ.js → codemodRunner-D-jTyvWo.js} +622 -551
  22. package/dist/{commands-DaZVi9wi.js → commands-D6aW_6AR.js} +48 -48
  23. package/dist/{connectionConfig-UFlIEiys.js → connectionConfig-Bk9IC7D0.js} +1 -1
  24. package/dist/{dashboardCommand-Dxy_kmoW.js → dashboardCommand-CwTZh-XZ.js} +3 -3
  25. package/dist/{dataCommand-D6-Ha2lf.js → dataCommand-Cc9RiLQZ.js} +14 -11
  26. package/dist/{dbCommand-C4UW8cVN.js → dbCommand-DSwGv9wS.js} +50 -49
  27. package/dist/dbCommand-DcqEyxju.js +2 -0
  28. package/dist/{dev-E7Eo5GHc.js → dev-3mgc8c-H.js} +2260 -2184
  29. package/dist/dev-CjJAasDs.js +3 -0
  30. package/dist/{dialectDriver-CgXnDfec.js → dialectDriver-czCHYpeH.js} +2 -1
  31. package/dist/doctorCommand-Cghssndo.js +2 -0
  32. package/dist/{doctorCommand-gmDyALFL.js → doctorCommand-oLuzc-aC.js} +261 -244
  33. package/dist/{dormancyCommand-CE6wG8lj.js → dormancyCommand-Bxe4WtHU.js} +1 -1
  34. package/dist/{e2eCmd-BRabZww-.js → e2eCmd-uFHig1hV.js} +8 -2
  35. package/dist/{embeddingsCommand-C3uAuf6N.js → embeddingsCommand-CyNQkFIc.js} +6 -6
  36. package/dist/{envCommand-DzuWh8ya.js → envCommand-CAkSgBbh.js} +19 -19
  37. package/dist/{evolveCommand-DPLqcYb2.js → evolveCommand-CWhBoe_P.js} +6 -8
  38. package/dist/frameworkTableAssembly-DgylYh9_.js +2 -0
  39. package/dist/{generateCommand-DbgcUpGw.js → generateCommand-CcyvH2ve.js} +1 -1
  40. package/dist/index.js +1 -1
  41. package/dist/{infoCommand-CmczGj_l.js → infoCommand-CTo8Jnhq.js} +7 -7
  42. package/dist/inspect-B7U7Cl_Z.js +1192 -0
  43. package/dist/inspect-DUze25t0.js +2 -0
  44. package/dist/{inspectCmd-EHFZ9yYu.js → inspectCmd-niF97fAq.js} +5 -5
  45. package/dist/inspectGateHint-BjnFubmH.js +7 -0
  46. package/dist/{logFileSink-C_D2wRN1.js → logFileSink-B4uP8pvf.js} +1 -1
  47. package/dist/{logsCmd-D36xK7Zu.js → logsCmd-B6oNsfaZ.js} +10 -7
  48. package/dist/{manifestBuild-hpPLaGxV.js → manifestBuild-BK42hu0k.js} +1 -1
  49. package/dist/manifestBuild-j0n109tt.js +2 -0
  50. package/dist/{metaCommands-CIoQNlaQ.js → metaCommands-DUYR--Ts.js} +1 -1
  51. package/dist/{migrate-RwgUWXfc.js → migrate-BnPw2zC8.js} +7 -4
  52. package/dist/{packageCommand-Cug_3Ogl.js → packageCommand-9SVyvsSo.js} +3 -2
  53. package/dist/{probeCommand-BPEpwT32.js → probeCommand-C9gazU0H.js} +35 -24
  54. package/dist/{projectScaffold-CxgtJvlb.js → projectScaffold-BEhhHjPr.js} +1 -1
  55. package/dist/{projectScaffold-DDgWbNLe.js → projectScaffold-BvhLOrLq.js} +17 -15
  56. package/dist/{runtimeTrace-6jfznSzr.js → runtimeTrace-gNXeLf6H.js} +1 -1
  57. package/dist/{scheduleManifestCmd-D2x0CTTY.js → scheduleManifestCmd-kmWzrO_w.js} +6 -9
  58. package/dist/{sdkgen-CEJZZQUA.js → sdkgen-C8zz10-X.js} +4 -4
  59. package/dist/{seedRunner-ZmLSqNe2.js → seedRunner-IdHEprqf.js} +1 -4
  60. package/dist/serveCommand-BpK8-m1N.js +1770 -0
  61. package/dist/serveCommand-CW-goXvh.js +2 -0
  62. package/dist/serveEntry.js +2 -2
  63. package/dist/{serverlessCommand-CfJZy6dS.js → serverlessCommand-DbJ7Plg9.js} +3 -3
  64. package/dist/{start-CidwCcjl.js → start-BNuTWdRd.js} +1 -1
  65. package/dist/{start-RCh6qKFe.js → start-ft_KzFTd.js} +257 -254
  66. package/dist/startEntry.js +1 -1
  67. package/dist/{test-DIQ0jlkQ.js → test-CLYXrZ2F.js} +1 -1
  68. package/dist/{tracesCmd-DStmCJPi.js → tracesCmd-DgtgOUdi.js} +7 -4
  69. package/dist/{typecheckCommand-BlsWiCNq.js → typecheckCommand-BuCtT92o.js} +7 -7
  70. package/dist/updateCommand-6FMU2klq.js +2 -0
  71. package/dist/{updateCommand-CmksX7m_.js → updateCommand-CHBmCB17.js} +5 -3
  72. package/dist/{webDev-BKdD7c_a.js → webDev-CTpSY-e_.js} +813 -775
  73. package/dist/webDev-id3I5PvG.js +2 -0
  74. package/dist/{webhookDiscovery-D7VaeMlz.js → webhookDiscovery-CphsQe59.js} +4 -6
  75. package/dist/{webhookDiscovery-CrGAfhIG.js → webhookDiscovery-il9ti-HE.js} +1 -1
  76. package/dist/{webhooksCommand-BHeaF1ZJ.js → webhooksCommand-EccPZQZ4.js} +1 -1
  77. package/package.json +27 -21
  78. package/templates/AGENTS.md +2 -2
  79. package/templates/agent-docs/_index.md +2 -2
  80. package/templates/agent-docs/_manifest.json +2 -2
  81. package/templates/agent-docs/authentication.md +43 -4
  82. package/templates/agent-docs/cli.md +17 -13
  83. package/templates/agent-docs/data.md +44 -1
  84. package/templates/agent-docs/database/migrations.md +2 -2
  85. package/templates/agent-docs/database/seedsdialects.md +2 -2
  86. package/templates/agent-docs/deployment.md +21 -7
  87. package/templates/agent-docs/internationalization.md +10 -3
  88. package/templates/agent-docs/local-first-mobile.md +141 -20
  89. package/templates/agent-docs/plugins/mail.md +1 -1
  90. package/templates/agent-docs/plugins/ratelimit.md +1 -1
  91. package/templates/agent-docs/plugins.md +3 -1
  92. package/templates/agent-docs/releases.md +130 -1
  93. package/templates/agent-docs/routing.md +34 -2
  94. package/templates/agent-docs/templates/apibackends.md +1 -1
  95. package/templates/agent-docs/templates/mobile.md +1 -1
  96. package/templates/agent-docs/whats-new.md +26 -66
  97. package/templates/apps/api-ai/package.json +7 -7
  98. package/templates/apps/api-auth/package.json +8 -8
  99. package/templates/apps/api-backend/package.json +7 -7
  100. package/templates/apps/api-backend-deactivation/package.json +7 -7
  101. package/templates/apps/api-backend-mail/package.json +8 -8
  102. package/templates/apps/api-backend-mariadb/package.json +9 -9
  103. package/templates/apps/api-backend-sqlite/package.json +8 -8
  104. package/templates/apps/api-backend-storage/package.json +8 -8
  105. package/templates/apps/api-cms/package.json +10 -10
  106. package/templates/apps/api-collab/package.json +8 -8
  107. package/templates/apps/api-data-advanced/package.json +8 -8
  108. package/templates/apps/api-durable/package.json +8 -8
  109. package/templates/apps/api-durable/startup/warm.startup.tsx +16 -2
  110. package/templates/apps/api-feature-flags/package.json +9 -9
  111. package/templates/apps/api-governance/package.json +8 -8
  112. package/templates/apps/api-kv/package.json +8 -8
  113. package/templates/apps/api-moderation/package.json +8 -8
  114. package/templates/apps/api-observability/package.json +8 -8
  115. package/templates/apps/api-ratelimit/package.json +8 -8
  116. package/templates/apps/api-rbac/authz.ts +16 -1
  117. package/templates/apps/api-rbac/package.json +8 -8
  118. package/templates/apps/api-rest/package.json +7 -7
  119. package/templates/apps/api-saas/package.json +11 -11
  120. package/templates/apps/api-saas-starter/package.json +10 -10
  121. package/templates/apps/api-search/package.json +8 -8
  122. package/templates/apps/api-status/package.json +8 -8
  123. package/templates/apps/api-versioning/package.json +8 -8
  124. package/templates/apps/api-webhooks/package.json +9 -9
  125. package/templates/apps/changelog/package.json +6 -6
  126. package/templates/apps/edge-functions/package.json +2 -2
  127. package/templates/apps/frontend-admin/package.json +8 -8
  128. package/templates/apps/frontend-app/package.json +9 -9
  129. package/templates/apps/frontend-auth/package.json +8 -8
  130. package/templates/apps/frontend-blank/package.json +7 -7
  131. package/templates/apps/frontend-cms/package.json +9 -9
  132. package/templates/apps/frontend-collab/package.json +10 -10
  133. package/templates/apps/frontend-contact/package.json +7 -7
  134. package/templates/apps/frontend-dashboard/package.json +7 -7
  135. package/templates/apps/frontend-docs/package.json +7 -7
  136. package/templates/apps/frontend-i18n/package.json +6 -6
  137. package/templates/apps/frontend-landing/package.json +7 -7
  138. package/templates/apps/frontend-portal/package.json +8 -8
  139. package/templates/apps/frontend-saas/package.json +8 -8
  140. package/templates/apps/frontend-spa/package.json +7 -7
  141. package/templates/apps/frontend-ssr/package.json +7 -7
  142. package/templates/apps/frontend-ssr-api/package.json +8 -8
  143. package/templates/apps/frontend-static-blog/package.json +6 -6
  144. package/templates/apps/frontend-status/package.json +8 -8
  145. package/templates/apps/mobile-app/README.md +41 -17
  146. package/templates/apps/mobile-app/app.config.ts +1 -1
  147. package/templates/apps/mobile-app/package.json +15 -11
  148. package/templates/apps/mobile-app/src/app/_layout.tsx +44 -13
  149. package/templates/apps/mobile-app/src/app/index.tsx +1 -1
  150. package/templates/apps/mobile-app/src/app/settings.tsx +4 -1
  151. package/templates/apps/mobile-app/src/client.ts +74 -57
  152. package/templates/apps/mobile-app/src/lib/api.ts +4 -4
  153. package/templates/apps/mobile-app/src/lib/deeplinks.ts +6 -6
  154. package/templates/apps/mobile-app/src/persistence.ts +24 -3
  155. package/templates/apps/mobile-app/tsconfig.json +17 -3
  156. package/dist/addCommand-aXSQveak.js +0 -2
  157. package/dist/agentsMd-BTchIZku.js +0 -2
  158. package/dist/apiBuild-ttSDDOGp.js +0 -2
  159. package/dist/baselineCommand-Cfw2Afwm.js +0 -2
  160. package/dist/codegen-uYrrDzQv.js +0 -2
  161. package/dist/codegenCommand-C60m_LCp.js +0 -30
  162. package/dist/dbCommand-CC-qNzpz.js +0 -2
  163. package/dist/dev-CAOoXOkc.js +0 -3
  164. package/dist/doctorCommand-Cjl8Yii8.js +0 -2
  165. package/dist/frameworkTableAssembly-YyVe32Cb.js +0 -2
  166. package/dist/inspect-CjTYzAs_.js +0 -1190
  167. package/dist/inspect-P4pxoMaV.js +0 -2
  168. package/dist/inspectGateHint-BF6608UT.js +0 -4
  169. package/dist/manifestBuild-COkJoyAr.js +0 -2
  170. package/dist/serveCommand-DNRF2nDI.js +0 -2
  171. package/dist/serveCommand-DnY4VS3D.js +0 -1767
  172. package/dist/updateCommand-B0J_T9Vs.js +0 -2
  173. package/dist/webDev-CcJfdSjl2.js +0 -2
@@ -12,16 +12,16 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@voltro/cli": "0.38.0",
16
- "@voltro/client": "0.38.0",
17
- "@voltro/env": "0.38.0",
18
- "@voltro/i18n": "0.38.0",
19
- "@voltro/web": "0.38.0",
15
+ "@voltro/cli": "0.39.1",
16
+ "@voltro/client": "0.39.1",
17
+ "@voltro/env": "0.39.1",
18
+ "@voltro/i18n": "0.39.1",
19
+ "@voltro/web": "0.39.1",
20
20
  "react": "^19.0.0",
21
21
  "react-dom": "^19.0.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@voltro/devtools": "0.38.0",
24
+ "@voltro/devtools": "0.39.1",
25
25
  "@types/react": "^19.0.0",
26
26
  "@types/react-dom": "^19.0.0",
27
27
  "jsdom": "^30.0.0",
@@ -12,17 +12,17 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@voltro/cli": "0.38.0",
16
- "@voltro/client": "0.38.0",
17
- "@voltro/env": "0.38.0",
18
- "@voltro/i18n": "0.38.0",
19
- "@voltro/ui-shadcn": "0.38.0",
20
- "@voltro/web": "0.38.0",
15
+ "@voltro/cli": "0.39.1",
16
+ "@voltro/client": "0.39.1",
17
+ "@voltro/env": "0.39.1",
18
+ "@voltro/i18n": "0.39.1",
19
+ "@voltro/ui-shadcn": "0.39.1",
20
+ "@voltro/web": "0.39.1",
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/devtools": "0.38.0",
25
+ "@voltro/devtools": "0.39.1",
26
26
  "@types/react": "^19.0.0",
27
27
  "@types/react-dom": "^19.0.0",
28
28
  "jsdom": "^30.0.0",
@@ -12,18 +12,18 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@{{projectName}}/api": "0.38.0",
16
- "@voltro/cli": "0.38.0",
17
- "@voltro/client": "0.38.0",
18
- "@voltro/env": "0.38.0",
19
- "@voltro/i18n": "0.38.0",
20
- "@voltro/ui-shadcn": "0.38.0",
21
- "@voltro/web": "0.38.0",
15
+ "@{{projectName}}/api": "0.39.1",
16
+ "@voltro/cli": "0.39.1",
17
+ "@voltro/client": "0.39.1",
18
+ "@voltro/env": "0.39.1",
19
+ "@voltro/i18n": "0.39.1",
20
+ "@voltro/ui-shadcn": "0.39.1",
21
+ "@voltro/web": "0.39.1",
22
22
  "react": "^19.0.0",
23
23
  "react-dom": "^19.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/devtools": "0.38.0",
26
+ "@voltro/devtools": "0.39.1",
27
27
  "@types/react": "^19.0.0",
28
28
  "@types/react-dom": "^19.0.0",
29
29
  "jsdom": "^30.0.0",
@@ -12,18 +12,18 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@{{projectName}}/api": "0.38.0",
16
- "@voltro/cli": "0.38.0",
17
- "@voltro/client": "0.38.0",
18
- "@voltro/env": "0.38.0",
19
- "@voltro/i18n": "0.38.0",
20
- "@voltro/ui-shadcn": "0.38.0",
21
- "@voltro/web": "0.38.0",
15
+ "@{{projectName}}/api": "0.39.1",
16
+ "@voltro/cli": "0.39.1",
17
+ "@voltro/client": "0.39.1",
18
+ "@voltro/env": "0.39.1",
19
+ "@voltro/i18n": "0.39.1",
20
+ "@voltro/ui-shadcn": "0.39.1",
21
+ "@voltro/web": "0.39.1",
22
22
  "react": "^19.0.0",
23
23
  "react-dom": "^19.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/devtools": "0.38.0",
26
+ "@voltro/devtools": "0.39.1",
27
27
  "@types/react": "^19.0.0",
28
28
  "@types/react-dom": "^19.0.0",
29
29
  "jsdom": "^30.0.0",
@@ -12,17 +12,17 @@
12
12
  "typecheck": "tsc --noEmit"
13
13
  },
14
14
  "dependencies": {
15
- "@voltro/cli": "0.38.0",
16
- "@voltro/client": "0.38.0",
17
- "@voltro/env": "0.38.0",
18
- "@voltro/i18n": "0.38.0",
19
- "@voltro/ui-shadcn": "0.38.0",
20
- "@voltro/web": "0.38.0",
15
+ "@voltro/cli": "0.39.1",
16
+ "@voltro/client": "0.39.1",
17
+ "@voltro/env": "0.39.1",
18
+ "@voltro/i18n": "0.39.1",
19
+ "@voltro/ui-shadcn": "0.39.1",
20
+ "@voltro/web": "0.39.1",
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/devtools": "0.38.0",
25
+ "@voltro/devtools": "0.39.1",
26
26
  "@types/react": "^19.0.0",
27
27
  "@types/react-dom": "^19.0.0",
28
28
  "jsdom": "^30.0.0",
@@ -12,17 +12,17 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@voltro/cli": "0.38.0",
16
- "@voltro/client": "0.38.0",
17
- "@voltro/env": "0.38.0",
18
- "@voltro/i18n": "0.38.0",
19
- "@voltro/ui-shadcn": "0.38.0",
20
- "@voltro/web": "0.38.0",
15
+ "@voltro/cli": "0.39.1",
16
+ "@voltro/client": "0.39.1",
17
+ "@voltro/env": "0.39.1",
18
+ "@voltro/i18n": "0.39.1",
19
+ "@voltro/ui-shadcn": "0.39.1",
20
+ "@voltro/web": "0.39.1",
21
21
  "react": "^19.0.0",
22
22
  "react-dom": "^19.0.0"
23
23
  },
24
24
  "devDependencies": {
25
- "@voltro/devtools": "0.38.0",
25
+ "@voltro/devtools": "0.39.1",
26
26
  "@types/react": "^19.0.0",
27
27
  "@types/react-dom": "^19.0.0",
28
28
  "jsdom": "^30.0.0",
@@ -12,18 +12,18 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@{{projectName}}/api": "0.38.0",
16
- "@voltro/cli": "0.38.0",
17
- "@voltro/client": "0.38.0",
18
- "@voltro/env": "0.38.0",
19
- "@voltro/i18n": "0.38.0",
20
- "@voltro/ui-shadcn": "0.38.0",
21
- "@voltro/web": "0.38.0",
15
+ "@{{projectName}}/api": "0.39.1",
16
+ "@voltro/cli": "0.39.1",
17
+ "@voltro/client": "0.39.1",
18
+ "@voltro/env": "0.39.1",
19
+ "@voltro/i18n": "0.39.1",
20
+ "@voltro/ui-shadcn": "0.39.1",
21
+ "@voltro/web": "0.39.1",
22
22
  "react": "^19.0.0",
23
23
  "react-dom": "^19.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/devtools": "0.38.0",
26
+ "@voltro/devtools": "0.39.1",
27
27
  "@types/react": "^19.0.0",
28
28
  "@types/react-dom": "^19.0.0",
29
29
  "jsdom": "^30.0.0",
@@ -12,16 +12,16 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@voltro/cli": "0.38.0",
16
- "@voltro/client": "0.38.0",
17
- "@voltro/env": "0.38.0",
18
- "@voltro/i18n": "0.38.0",
19
- "@voltro/web": "0.38.0",
15
+ "@voltro/cli": "0.39.1",
16
+ "@voltro/client": "0.39.1",
17
+ "@voltro/env": "0.39.1",
18
+ "@voltro/i18n": "0.39.1",
19
+ "@voltro/web": "0.39.1",
20
20
  "react": "^19.0.0",
21
21
  "react-dom": "^19.0.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@voltro/devtools": "0.38.0",
24
+ "@voltro/devtools": "0.39.1",
25
25
  "@types/react": "^19.0.0",
26
26
  "@types/react-dom": "^19.0.0",
27
27
  "jsdom": "^30.0.0",
@@ -12,18 +12,18 @@
12
12
  "test": "voltro test"
13
13
  },
14
14
  "dependencies": {
15
- "@{{projectName}}/api": "0.38.0",
16
- "@voltro/cli": "0.38.0",
17
- "@voltro/client": "0.38.0",
18
- "@voltro/env": "0.38.0",
19
- "@voltro/i18n": "0.38.0",
20
- "@voltro/ui-shadcn": "0.38.0",
21
- "@voltro/web": "0.38.0",
15
+ "@{{projectName}}/api": "0.39.1",
16
+ "@voltro/cli": "0.39.1",
17
+ "@voltro/client": "0.39.1",
18
+ "@voltro/env": "0.39.1",
19
+ "@voltro/i18n": "0.39.1",
20
+ "@voltro/ui-shadcn": "0.39.1",
21
+ "@voltro/web": "0.39.1",
22
22
  "react": "^19.0.0",
23
23
  "react-dom": "^19.0.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@voltro/devtools": "0.38.0",
26
+ "@voltro/devtools": "0.39.1",
27
27
  "@types/react": "^19.0.0",
28
28
  "@types/react-dom": "^19.0.0",
29
29
  "jsdom": "^30.0.0",
@@ -15,12 +15,14 @@ registration for push.
15
15
  # 1. In one shell — the api (scaffold it with --api=api-backend):
16
16
  voltro dev
17
17
 
18
- # 2. Point this app at the api. On a simulator/device use your machine's LAN
19
- # address, NOT localhost:
20
- export EXPO_PUBLIC_API_URL="http://192.168.x.x:4000"
21
-
22
- # 3. In another shell — the app:
18
+ # 2. In another shell the app. `pnpm ios` runs `voltro codegen` first, which
19
+ # writes this app's api binding from voltro.mobile.ts.
23
20
  pnpm ios # or: pnpm android · pnpm start (Expo Go)
21
+
22
+ # The ws URL is derived from the host running Metro, so a device on the same
23
+ # wifi reaches your machine. Override it for a deployed api:
24
+ # export EXPO_PUBLIC_API_WS_URL="wss://api.example.com/ws"
25
+ # export EXPO_PUBLIC_API_PORT=4000 # if your api is not on 4000
24
26
  ```
25
27
 
26
28
  ## What's here
@@ -31,25 +33,32 @@ pnpm ios # or: pnpm android · pnpm start (Expo Go)
31
33
  | `src/lib/deeplinks.ts` | the typed deep-link table + pure resolver (**tested**) |
32
34
  | `src/lib/sync.ts` | the background-sync decision layer (**tested**) |
33
35
  | `src/lib/notifications.ts` | build a `_voltro_devices` row from a push token (**tested**) |
34
- | `src/client.ts` | the Voltro client + the **M0 seam** (read its header) |
36
+ | `src/client.ts` | the Voltro client: generated api binding + supervisor + persistence |
35
37
  | `src/persistence.ts` | RN key-value with the secure/plain split |
36
38
  | `src/app/*` | Expo Router screens (list, detail, settings) |
37
39
  | `voltro.mobile.ts` | which api(s) this app consumes |
38
40
 
39
41
  ## Honest status (read before you expect the loop to work on a device)
40
42
 
41
- The **pure logic** in `src/lib/*` is real and unit-tested (`pnpm test`). The
42
- **client wiring** building the runtime + subscription cache + rpc client that
43
- the hooks read is **not yet implemented for React Native**: on the web it lives
44
- in `@voltro/web`'s web-coupled boot. Wiring an RN-safe equivalent is Phase **M0**
45
- in the framework's mobile plan (`plans/open/mobile/`). Until it lands,
46
- `buildApiHandles()` in `src/client.ts` returns an empty map and the screens show
47
- their loading state deliberately, not a crash. `src/client.ts`'s header spells
48
- out exactly what M0 must build.
43
+ The client is wired: `voltro codegen` writes this app's api binding from
44
+ `voltro.mobile.ts`, and `src/client.ts` connects it through the SAME reconnect
45
+ supervisor the web client uses, with persisted stores hydrated before the first
46
+ render. The start scripts run codegen, so `pnpm ios` needs no separate step.
47
+
48
+ What is NOT verified in this repository is the one thing only a device can tell
49
+ you: that the loop runs under Metro on a simulator or a phone. There is no
50
+ iOS/Android toolchain in the framework's sandbox, so booting the app is your
51
+ Expo/EAS CI step. The unit tests here run without one and deliberately do not
52
+ pretend otherwise.
53
+
54
+ Two things to check first if a device shows loading forever:
49
55
 
50
- The tests here run without a simulator. Booting the app on a device (`expo
51
- run:ios`) is your Expo/EAS CI step there is no iOS/Android toolchain in the
52
- framework repo's sandbox.
56
+ - **`localhost` on a phone is the phone.** The ws URL is derived from the host
57
+ running Metro (`resolveDevWsUrl`), which works on a device on the same wifi.
58
+ Set `EXPO_PUBLIC_API_WS_URL` to point somewhere else.
59
+ - **The api must be running.** `voltro dev` in the project root boots it; this
60
+ app is deliberately not part of that orchestration, because Expo owns its own
61
+ dev server.
53
62
 
54
63
  ## Tests
55
64
 
@@ -57,3 +66,18 @@ framework repo's sandbox.
57
66
  pnpm test # the pure lib — no simulator needed
58
67
  pnpm typecheck # tsc over the app (needs Expo/RN types installed)
59
68
  ```
69
+
70
+ ### Why this app's `tsconfig.json` overrides Expo's base
71
+
72
+ Three overrides, each for a reason that shows up as a hard error without it:
73
+
74
+ - **`moduleResolution: "bundler"`** — Expo's base sets `node` (node10), which
75
+ TypeScript 6 rejects outright. `bundler` is also the honest description of
76
+ Metro.
77
+ - **`types: ["node", "react"]`** — `process.env.EXPO_PUBLIC_*` is Expo's own
78
+ idiom for build-time config, and `process` needs a type. Listing the types
79
+ explicitly keeps everything else out.
80
+ - **`@types/node` as a devDependency** — the other half of the same line.
81
+
82
+ Run `pnpm typecheck` after `voltro codegen`, in that order: the generated api
83
+ binding is a real import and the app does not typecheck without it.
@@ -4,7 +4,7 @@
4
4
  // mobile app is not run by `voltro dev` — Expo owns Metro and the simulator
5
5
  // (`expo start` / `expo run:ios`). The sibling api this app consumes still runs
6
6
  // under `voltro dev`; the app connects to it over HTTP/WebSocket via
7
- // `EXPO_PUBLIC_API_URL` (see src/client.ts).
7
+ // `EXPO_PUBLIC_API_WS_URL` / `EXPO_PUBLIC_API_PORT` (see src/client.ts).
8
8
  //
9
9
  // `scheme` is the custom URL scheme that makes deep links open THIS app
10
10
  // (`{{appName}}://orders/42`). Keep it in sync with the deep-link table in
@@ -4,32 +4,36 @@
4
4
  "private": true,
5
5
  "main": "expo-router/entry",
6
6
  "scripts": {
7
- "start": "expo start",
8
- "ios": "expo run:ios",
9
- "android": "expo run:android",
10
- "web": "expo start --web",
7
+ "start": "voltro codegen . && expo start",
8
+ "ios": "voltro codegen . && expo run:ios",
9
+ "android": "voltro codegen . && expo run:android",
10
+ "web": "voltro codegen . && expo start --web",
11
11
  "test": "vitest run",
12
- "typecheck": "tsc --noEmit"
12
+ "typecheck": "tsc --noEmit",
13
+ "codegen": "voltro codegen ."
13
14
  },
14
15
  "dependencies": {
15
- "@voltro/client": "0.38.0",
16
- "@voltro/react-native": "0.38.0",
16
+ "@react-native-async-storage/async-storage": "1.23.1",
17
+ "@react-native-community/netinfo": "11.4.1",
18
+ "@voltro/client": "0.39.1",
19
+ "@voltro/react-native": "0.39.1",
20
+ "@{{projectName}}/api": "0.39.1",
17
21
  "expo": "^52.0.0",
18
22
  "expo-constants": "~17.0.0",
19
23
  "expo-linking": "~7.0.0",
20
24
  "expo-router": "~4.0.0",
21
25
  "expo-secure-store": "~14.0.0",
26
+ "expo-splash-screen": "~0.29.0",
22
27
  "expo-status-bar": "~2.0.0",
23
- "@react-native-async-storage/async-storage": "1.23.1",
24
- "@react-native-community/netinfo": "11.4.1",
25
28
  "react": "^19.0.0",
26
29
  "react-native": "0.76.5"
27
30
  },
28
31
  "devDependencies": {
29
- "@{{projectName}}/api": "0.38.0",
32
+ "@types/node": "^22.0.0",
30
33
  "@types/react": "^19.0.0",
31
- "typescript": "^6.0.3",
32
34
  "@vitest/coverage-v8": "^4.1.10",
35
+ "@voltro/cli": "0.39.1",
36
+ "typescript": "^6.0.3",
33
37
  "vitest": "^4.1.10"
34
38
  }
35
39
  }
@@ -1,21 +1,35 @@
1
- // Root layout — wires the Voltro client provider, deep-link routing, and a
2
- // connection banner around the whole app.
1
+ // Root layout — wires the Voltro client, deep-link routing, and a connection
2
+ // banner around the whole app.
3
3
  //
4
- // NOTE: `buildApiHandles()` is the M0 seam (see ../client.ts). Until the RN boot
5
- // helper lands it returns an empty map, so the hooks render their loading state
6
- // rather than live data — deliberately honest, not a crash.
4
+ // The boot ORDER here is load-bearing, and it is the one thing to preserve if
5
+ // you rewrite this file:
6
+ //
7
+ // 1. hydrate persisted stores, THEN install them as the backing store;
8
+ // 2. only then render the app.
9
+ //
10
+ // A store reads during render and a render cannot await, so rendering first
11
+ // shows empty state and flickers into the saved state a frame later. The splash
12
+ // screen stays up until step 1 finishes — that is what it is for.
13
+ //
14
+ // Connecting is deliberately NOT part of that gate. The app must open offline.
7
15
  import { useEffect, useState } from 'react'
8
16
  import { Stack, useRouter } from 'expo-router'
9
17
  import * as Linking from 'expo-linking'
18
+ import * as SplashScreen from 'expo-splash-screen'
10
19
  import { StatusBar } from 'expo-status-bar'
11
- import { FrameworkRuntimesProvider, type ApiHandle } from '@voltro/client'
20
+ import { FrameworkRuntimesProvider, type ApiHandle, type ResolvedClient } from '@voltro/client'
12
21
  import { useMobileConnectionStatus } from '@voltro/react-native'
13
22
  import { Text, View } from 'react-native'
14
- import { buildApiHandles } from '../client'
23
+ import { connectApis, handlesFor, onlineSource, preparePersistence } from '../client'
15
24
  import { handleDeepLink, makeDeepLinks } from '../lib/deeplinks'
16
25
 
26
+ void SplashScreen.preventAutoHideAsync()
27
+
17
28
  function ConnectionBanner() {
18
- const { status } = useMobileConnectionStatus()
29
+ // Reachability comes from NetInfo. The default source reads `navigator.onLine`,
30
+ // which React Native does not have — so on a device it would answer "online"
31
+ // forever, including in airplane mode.
32
+ const { status } = useMobileConnectionStatus({ onlineSource })
19
33
  if (status === 'connected') return null
20
34
  return (
21
35
  <View style={{ backgroundColor: status === 'offline' ? '#b91c1c' : '#b45309', padding: 8 }}>
@@ -27,16 +41,31 @@ function ConnectionBanner() {
27
41
  }
28
42
 
29
43
  export default function RootLayout() {
30
- // Build the api handle map once on mount (async — it opens the WebSocket via
31
- // @voltro/client's buildApiRuntime). Empty until it resolves; the hooks render
32
- // their loading state meanwhile.
44
+ const [ready, setReady] = useState(false)
33
45
  const [apis, setApis] = useState<ReadonlyMap<string, ApiHandle>>(() => new Map())
46
+ const router = useRouter()
47
+
48
+ // 1. Persisted state, before anything renders.
34
49
  useEffect(() => {
35
50
  let live = true
36
- void buildApiHandles().then((map) => { if (live) setApis(map) })
51
+ void preparePersistence()
52
+ .catch(() => { /* a device with no readable storage still gets an app */ })
53
+ .finally(() => {
54
+ if (!live) return
55
+ setReady(true)
56
+ void SplashScreen.hideAsync()
57
+ })
37
58
  return () => { live = false }
38
59
  }, [])
39
- const router = useRouter()
60
+
61
+ // 2. Connect, and keep connected. The supervisor re-dials with backoff; a
62
+ // dropped socket needs no handling here.
63
+ useEffect(() => {
64
+ const supervisor = connectApis((clients: ReadonlyMap<string, ResolvedClient>) => {
65
+ setApis(handlesFor(clients))
66
+ })
67
+ return () => supervisor.dispose()
68
+ }, [])
40
69
 
41
70
  // Route inbound URLs (universal links, custom scheme, push taps) through the
42
71
  // ONE typed link table — the same `matchFirstDeepLink` path push will use.
@@ -51,6 +80,8 @@ export default function RootLayout() {
51
80
  return () => sub.remove()
52
81
  }, [router])
53
82
 
83
+ if (!ready) return null
84
+
54
85
  return (
55
86
  <FrameworkRuntimesProvider apis={apis}>
56
87
  <StatusBar style="auto" />
@@ -3,7 +3,7 @@
3
3
  // The SAME hooks as the web frontend: `useSubscription('notes.list')` streams
4
4
  // the server-side query; `useMutation('notes.create')` writes it. When the
5
5
  // mutation lands, the server pushes a delta and this list re-renders — no
6
- // refetch, no polling. (Requires the M0 client boot; see ../client.ts.)
6
+ // refetch, no polling.
7
7
  //
8
8
  // Both come from `../lib/api`, which binds them ONCE to the api's generated
9
9
  // procedure map — so the tag autocompletes, a typo is a compile error, and the
@@ -3,9 +3,12 @@ import { useState } from 'react'
3
3
  import { Pressable, Text, View } from 'react-native'
4
4
  import { useMobileConnectionStatus } from '@voltro/react-native'
5
5
  import { buildDeviceRegistration } from '../lib/notifications'
6
+ import { onlineSource } from '../client'
6
7
 
7
8
  export default function Settings() {
8
- const { status, reportSuccess, reportFailure } = useMobileConnectionStatus()
9
+ // Same injected source as the banner in _layout: the default reads
10
+ // `navigator.onLine`, which React Native does not have.
11
+ const { status, reportSuccess, reportFailure } = useMobileConnectionStatus({ onlineSource })
9
12
  const [registered, setRegistered] = useState<string | null>(null)
10
13
 
11
14
  return (