@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
@@ -1,74 +1,91 @@
1
1
  // The Voltro client for React Native.
2
2
  //
3
- // The transport keystone now EXISTS: `@voltro/client`'s `buildApiRuntime` builds
4
- // the runtime + subscription cache + rpc client over a WebSocket, and it takes
5
- // the WebSocket constructor as an INJECTED dependency — so React Native passes
6
- // its own `globalThis.WebSocket` (which RN provides) and gets the SAME client
7
- // stack the web app uses, without pulling in `@voltro/web`. See
8
- // plans/open/mobile/00-overview.md (M0).
3
+ // Three pieces, all of them SHARED with the web client rather than
4
+ // re-implemented for mobile:
9
5
  //
10
- // ┌─ THE ONE REMAINING SEAM ─────────────────────────────────────────────────┐
11
- // `buildApiHandle` below is functional. What it still needs is the api's rpc │
12
- // GROUP + descriptor map on web these come from codegen's generated entry. │
13
- // A `voltro codegen` mobile target that emits them for this app is the next │
14
- // M-step (plans/open/mobile/01). Until it lands, `buildApiHandles()` returns
15
- // an empty map (the screens show their loading state) rather than faking it. │
16
- // └──────────────────────────────────────────────────────────────────────────┘
6
+ // · `mobileApis` the generated binding (`.framework/mobileApis.generated.ts`,
7
+ // written by `voltro codegen` from `voltro.mobile.ts`). It carries the api's
8
+ // rpc group and descriptors, so the hooks are typed end to end from the
9
+ // api's own schema.
10
+ // · `startMobileApis` connect + reconnect, over the SAME supervisor
11
+ // `@voltro/web` uses: exponential backoff, generation tracking, and the
12
+ // stale-seed gate that must not carry one subject's rows into the next.
13
+ // · `createAsyncStoragePersistence` — persisted stores over AsyncStorage,
14
+ // hydrated BEFORE the first render (a render cannot await).
15
+ //
16
+ // The ws URL is resolved at runtime, never baked in. `localhost` on a phone is
17
+ // the PHONE — the single most common reason a mobile dev loop silently never
18
+ // connects — so `resolveDevWsUrl` takes the LAN host Expo already knows.
17
19
 
18
- import { buildApiRuntime, type ApiHandle, type BuildApiRuntimeOptions } from '@voltro/client'
19
- import { offlineFirstDefaults } from '@voltro/react-native'
20
+ import Constants from 'expo-constants'
21
+ import NetInfo from '@react-native-community/netinfo'
22
+ import { setStoreStorage, type ResolvedClient } from '@voltro/client'
23
+ import {
24
+ createAsyncStoragePersistence,
25
+ netInfoOnlineSource,
26
+ offlineFirstDefaults,
27
+ resolveDevWsUrl,
28
+ startMobileApis,
29
+ toApiHandles,
30
+ } from '@voltro/react-native'
31
+ import { mobileApis } from '../.framework/mobileApis.generated'
32
+ import { storeStorage } from './persistence'
20
33
 
21
- /** The api's rpc group type sourced from @voltro/client so the template needs
22
- * no direct @effect/rpc dependency. Codegen produces the concrete value. */
23
- type ApiRpcGroup = BuildApiRuntimeOptions['group']
34
+ /** The api's port, as `voltro dev` allocates it. Override per environment. */
35
+ const API_PORT = Number(process.env.EXPO_PUBLIC_API_PORT ?? 4000)
24
36
 
25
- /** The api's base URL. On a simulator/device this must be your machine's LAN
26
- * address (not `localhost`), e.g. `http://192.168.1.20:4000`. */
27
- export const API_URL = process.env.EXPO_PUBLIC_API_URL ?? 'http://localhost:4000'
37
+ /**
38
+ * The api's WebSocket URL.
39
+ *
40
+ * In development this is derived from the host running Metro, so a real device
41
+ * on the same wifi reaches your machine. In production set
42
+ * `EXPO_PUBLIC_API_WS_URL` to the deployed api.
43
+ */
44
+ export const apiWsUrl = (): string =>
45
+ process.env.EXPO_PUBLIC_API_WS_URL
46
+ ?? resolveDevWsUrl(Constants.expoConfig?.hostUri, API_PORT)
28
47
 
29
- /** The offline-first posture spread into the app's client config. */
48
+ /** The offline-first posture (local-first on, optimistic writes, sync status
49
+ * surfaced). Spread into a client config, or read for UI decisions. */
30
50
  export const clientPosture = offlineFirstDefaults
31
51
 
32
- /** http(s)://host:port ws(s)://host:port/ws (the api's WebSocket endpoint). */
33
- const toWsUrl = (httpUrl: string): string =>
34
- `${httpUrl.replace(/^http/, 'ws').replace(/\/+$/, '')}/ws`
52
+ /** Reachability, from NetInfo. Module scope on purpose: an inline
53
+ * `netInfoOnlineSource(NetInfo)` is a new object every render, and the hook
54
+ * would resubscribe on each one. */
55
+ export const onlineSource = netInfoOnlineSource(NetInfo)
35
56
 
36
- /** React Native provides a global WebSocket; no tracking/reconnect wrapper here
37
- * yet (the RN reconnect supervisor is a later M-step — plans/open/mobile/03). */
38
- const rnWebSocket = (url: string, protocols?: string | ReadonlyArray<string>): globalThis.WebSocket =>
39
- new globalThis.WebSocket(url, protocols as string | string[] | undefined)
57
+ /** Persisted stores, backed by AsyncStorage NOT the Keychain. `persistence.ts`
58
+ * says why, and where a secret goes instead. */
59
+ export const persistence = createAsyncStoragePersistence({ storage: storeStorage })
40
60
 
41
61
  /**
42
- * Build one api's {@link ApiHandle} for the RN client provider. Fully functional
43
- * — hand it the codegen-produced `group` + `descriptors` for the api and it
44
- * returns a live handle. `descriptors` is `ClientDescriptor`-shaped
45
- * (see @voltro/client); pass the generated map.
62
+ * Load persisted state and install it as the backing store for every
63
+ * `defineStore({ persist })`.
64
+ *
65
+ * MUST be awaited before the first render. A store reads during render and a
66
+ * render cannot await, so an app that renders first shows empty state and then
67
+ * flickers into the saved one. The root layout holds the splash screen until
68
+ * this resolves.
46
69
  */
47
- export const buildApiHandle = async (
48
- name: string,
49
- group: ApiRpcGroup,
50
- descriptors: ApiHandle['descriptors'],
51
- ): Promise<ApiHandle> => {
52
- const wsUrl = toWsUrl(API_URL)
53
- const built = await buildApiRuntime({ name, wsUrl, group, webSocketConstructor: rnWebSocket })
54
- return {
55
- runtime: built.runtime,
56
- cache: built.cache,
57
- client: built.client as ApiHandle['client'],
58
- descriptors,
59
- inspectBaseUrl: API_URL.replace(/\/+$/, ''),
60
- errorBus: built.errorBus,
61
- }
70
+ export const preparePersistence = async (): Promise<void> => {
71
+ await persistence.hydrate()
72
+ setStoreStorage(persistence.provider)
62
73
  }
63
74
 
75
+ /** Every api this app talks to, bound to the resolved ws URL. */
76
+ export const apis = mobileApis(() => apiWsUrl())
77
+
64
78
  /**
65
- * Build the `apis` map `FrameworkRuntimesProvider` needs. Returns an empty map
66
- * until codegen emits this app's rpc group (the seam above) — then map each
67
- * configured api through {@link buildApiHandle}.
79
+ * Connect the apis and keep them connected.
80
+ *
81
+ * `onChange` fires on the first connect, on every reconnect swap, and on
82
+ * teardown. Dispose the returned handle when the tree unmounts; call
83
+ * `reconnect()` after a sign-in so the connection re-resolves who it is.
68
84
  */
69
- export const buildApiHandles = async (): Promise<ReadonlyMap<string, ApiHandle>> => {
70
- // Once codegen targets mobile:
71
- // const { rpcGroup, descriptors } = await import('./rpcGroup.generated')
72
- // return new Map([['app', await buildApiHandle('app', rpcGroup, descriptors)]])
73
- return new Map<string, ApiHandle>()
74
- }
85
+ export const connectApis = (
86
+ onChange: (clients: ReadonlyMap<string, ResolvedClient>, initialized: boolean) => void,
87
+ ) => startMobileApis({ apis, onChange })
88
+
89
+ /** Map the live clients into the `apis` prop the client provider takes. */
90
+ export const handlesFor = (clients: ReadonlyMap<string, ResolvedClient>) =>
91
+ toApiHandles(apis, clients)
@@ -21,10 +21,10 @@
21
21
  // that reason; scaffold the pair (`create-project --api=api-backend --mobile`),
22
22
  // which is what this template's README already assumes.
23
23
  //
24
- // RUNTIME NOTE: the hooks are typed today and live once the mobile codegen
25
- // target lands `buildApiHandles()` in ../client.ts still returns an empty map
26
- // (see the seam documented there), so screens render their loading state until
27
- // then. The TYPES are real either way; they come from the api's own descriptors.
24
+ // RUNTIME: live. `voltro codegen` writes this app's api binding into
25
+ // `.framework/mobileApis.generated.ts` (from `voltro.mobile.ts`), and
26
+ // `../client.ts` connects it through the same supervisor the web client uses.
27
+ // The start scripts run codegen, so `pnpm ios` needs no separate step.
28
28
  import { createHooks } from '@voltro/client'
29
29
  import type { AppProcedures } from '@{{projectName}}/api/rpcGroup'
30
30
 
@@ -6,12 +6,12 @@
6
6
  // come from `@voltro/react-native`; this module is browser/RN-safe (no Metro, no
7
7
  // screens), which is exactly why it is unit-testable without a simulator.
8
8
  //
9
- // Declaration order wins in `matchFirstDeepLink`, so list more-specific patterns
9
+ // Declaration order wins in `dispatchDeepLink`, so list more-specific patterns
10
10
  // FIRST. The `navigate` callback is injected (the screen layer passes
11
11
  // expo-router's `router.push`), keeping this table pure + testable.
12
12
  import {
13
13
  defineDeepLink,
14
- matchFirstDeepLink,
14
+ dispatchDeepLink,
15
15
  type DeepLinkDescriptor,
16
16
  } from '@voltro/react-native'
17
17
 
@@ -32,8 +32,8 @@ export const handleDeepLink = (
32
32
  links: ReadonlyArray<DeepLinkDescriptor>,
33
33
  url: string,
34
34
  ): boolean => {
35
- const hit = matchFirstDeepLink(links, url)
36
- if (hit === null) return false
37
- hit.descriptor.handler(hit.params)
38
- return true
35
+ // `dispatchDeepLink` matches AND runs. Doing it in two steps here does not
36
+ // typecheck: the descriptors are a heterogeneous array, so the handler that
37
+ // comes back declares params the match that produced it cannot satisfy.
38
+ return dispatchDeepLink(links, url) !== null
39
39
  }
@@ -8,9 +8,15 @@
8
8
  // Putting a session token in AsyncStorage is a security bug; secure-store is its
9
9
  // home.
10
10
  //
11
- // This is a generic async KV. M0 adapts it to whichever persistence CONTRACT it
12
- // wires (the client cache and/or `@voltro/local-first`'s `PersistenceAdapter`)
13
- // it does not itself claim to satisfy a framework interface that would drift.
11
+ // Two exports, and the split between them is the point:
12
+ // - `kv` is the APP's own store for things it manages itself, tokens included.
13
+ // - `storeStorage` backs `defineStore({ persist })` and is AsyncStorage ONLY.
14
+ //
15
+ // A persisted store is app STATE — a draft, a filter, a wizard step — and none of
16
+ // that belongs in the Keychain, which cannot be enumerated and which the OS may
17
+ // gate behind a biometric prompt. A secret does not belong in a persisted store
18
+ // either; put it through `kv` with `secretKey()`. Routing store keys by prefix
19
+ // would blur a rule worth keeping sharp.
14
20
  import AsyncStorage from '@react-native-async-storage/async-storage'
15
21
  import * as SecureStore from 'expo-secure-store'
16
22
 
@@ -36,3 +42,18 @@ export const kv = {
36
42
 
37
43
  /** Prefix a key so it lands in secure storage. */
38
44
  export const secretKey = (name: string): string => `${SECRET_PREFIX}${name}`
45
+
46
+ /**
47
+ * The backing store for `defineStore({ persist })`, handed to
48
+ * `createAsyncStoragePersistence()` in `src/client.ts`.
49
+ *
50
+ * Deliberately AsyncStorage alone — see the header. `getAllKeys` is what lets
51
+ * the adapter hydrate without being told which keys exist; SecureStore has no
52
+ * equivalent, which is the second reason secrets do not live here.
53
+ */
54
+ export const storeStorage = {
55
+ getItem: (key: string): Promise<string | null> => AsyncStorage.getItem(key),
56
+ setItem: (key: string, value: string): Promise<void> => AsyncStorage.setItem(key, value),
57
+ removeItem: (key: string): Promise<void> => AsyncStorage.removeItem(key),
58
+ getAllKeys: async (): Promise<ReadonlyArray<string>> => AsyncStorage.getAllKeys(),
59
+ }
@@ -3,8 +3,22 @@
3
3
  "compilerOptions": {
4
4
  "strict": true,
5
5
  "paths": {
6
- "@/*": ["./src/*"]
7
- }
6
+ "@/*": [
7
+ "./src/*"
8
+ ]
9
+ },
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "types": [
13
+ "node",
14
+ "react"
15
+ ]
8
16
  },
9
- "include": ["src", "app.config.ts", "tests", ".expo/types/**/*.ts", "expo-env.d.ts"]
17
+ "include": [
18
+ "src",
19
+ "app.config.ts",
20
+ "tests",
21
+ ".expo/types/**/*.ts",
22
+ "expo-env.d.ts"
23
+ ]
10
24
  }
@@ -1,2 +0,0 @@
1
- import { r as e } from "./addCommand-BNeoeSxe.js";
2
- export { e as runAddCommand };
@@ -1,2 +0,0 @@
1
- import { a as e } from "./agentsMd-mhQMF1bx.js";
2
- export { e as runAgentsMd };
@@ -1,2 +0,0 @@
1
- import { c as e, l as t } from "./apiBuild-CvacV4zA.js";
2
- export { e as runApiBuild, t as runServeBundleBuild };
@@ -1,2 +0,0 @@
1
- import { o as e } from "./baselineCommand-C6NMt-oa.js";
2
- export { e as runBaselineCommand };
@@ -1,2 +0,0 @@
1
- import { t as e } from "./codegen-GYYcdpCg.js";
2
- export { e as checkRpcGroupFreshness };
@@ -1,30 +0,0 @@
1
- import { l as e, z as t } from "./dev-E7Eo5GHc.js";
2
- import { r as n } from "./codegen-GYYcdpCg.js";
3
- import { basename as r, relative as i, resolve as a } from "node:path";
4
- //#region src/codegenCommand.ts
5
- var o = async (i) => {
6
- let { config: a, present: o, error: s } = await e(i);
7
- if (o && a === null) return {
8
- kind: "refused",
9
- reason: "app.config.ts exists but could not be loaded" + (s === void 0 ? "" : ` — ${s instanceof Error ? s.message : String(s)}`)
10
- };
11
- let c = a?.plugins ?? [], { pluginContributions: l, pluginErrorImports: u, pluginRpcImports: d } = await t(c, a?.name ?? r(i), i), f = await n({
12
- root: i,
13
- ...l.length > 0 ? { pluginContributions: l } : {},
14
- ...u.length > 0 ? { pluginErrorImports: u } : {},
15
- ...d.length > 0 ? { pluginRpcImports: d } : {},
16
- ...a?.name === void 0 ? {} : { apiName: a.name }
17
- });
18
- return f ? {
19
- kind: "wrote",
20
- file: f,
21
- plugins: c.length,
22
- errorSchemas: u.length,
23
- routes: d.length
24
- } : { kind: "nothing-to-write" };
25
- }, s = async (e) => {
26
- let t = a(e.find((e) => !e.startsWith("-")) ?? process.cwd()), n = await o(t);
27
- return n.kind === "refused" ? (console.error(`voltro codegen: ${n.reason} — refusing to write.`), console.error(" The generated file would omit every plugin's error union and client routes, and would typecheck, so the omission would only surface as a missing error tag at runtime."), 1) : n.kind === "nothing-to-write" ? (console.log("voltro codegen: no rpc primitives found — nothing to write."), 0) : (console.log(`voltro codegen: wrote ${i(t, n.file)} (plugins ${n.plugins}, error schemas ${n.errorSchemas}, plugin routes ${n.routes})`), n.plugins > 0 && n.errorSchemas === 0 && console.log(" note: no plugin contributed a cross-cutting error schema, so the wire error union carries only each procedure's own `error:`. Expected if none of your plugins declare `errorSchemas` — but `guards:` needs @voltro/plugin-rbac for its ScopeError to decode typed."), 0);
28
- };
29
- //#endregion
30
- export { o as regenerateRpcGroup, s as runCodegenCommand };
@@ -1,2 +0,0 @@
1
- import { s as e } from "./dbCommand-C4UW8cVN.js";
2
- export { e as runDbCommand };
@@ -1,3 +0,0 @@
1
- import { c as e, d as t, f as n, i as r, u as i } from "./dev-E7Eo5GHc.js";
2
- import "./dialectDriver-CgXnDfec.js";
3
- export { r as buildStore, e as loadApiConfig, i as loadDiscovered, t as runDev, n as walk };
@@ -1,2 +0,0 @@
1
- import { v as e, y as t } from "./doctorCommand-gmDyALFL.js";
2
- export { e as runDoctorCommand, t as runServePreflight };
@@ -1,2 +0,0 @@
1
- import { n as e } from "./frameworkTableAssembly-oMPBKqlE.js";
2
- export { e as assembleFrameworkTables };