one 1.16.8 → 1.16.10

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 (287) hide show
  1. package/dist/cjs/Root.cjs +7 -6
  2. package/dist/cjs/Root.native.js +7 -6
  3. package/dist/cjs/Root.native.js.map +1 -1
  4. package/dist/cjs/babel-plugins/one-router-metro.cjs +5 -0
  5. package/dist/cjs/babel-plugins/one-router-metro.native.js +6 -0
  6. package/dist/cjs/babel-plugins/one-router-metro.native.js.map +1 -1
  7. package/dist/cjs/babel-plugins/one-router-metro.test.cjs +20 -0
  8. package/dist/cjs/babel-plugins/one-router-metro.test.native.js +20 -0
  9. package/dist/cjs/babel-plugins/one-router-metro.test.native.js.map +1 -1
  10. package/dist/cjs/cli/build.cjs +16 -1
  11. package/dist/cjs/cli/build.native.js +16 -1
  12. package/dist/cjs/cli/build.native.js.map +1 -1
  13. package/dist/cjs/cli/dev.cjs +12 -2
  14. package/dist/cjs/cli/dev.native.js +12 -2
  15. package/dist/cjs/cli/dev.native.js.map +1 -1
  16. package/dist/cjs/cli/install-error-handlers.cjs +132 -0
  17. package/dist/cjs/cli/install-error-handlers.native.js +144 -0
  18. package/dist/cjs/cli/install-error-handlers.native.js.map +1 -0
  19. package/dist/cjs/createApp.cjs +3 -0
  20. package/dist/cjs/createApp.native.js +1 -0
  21. package/dist/cjs/createApp.native.js.map +1 -1
  22. package/dist/cjs/fork/extractPathFromURL.cjs +19 -0
  23. package/dist/cjs/fork/extractPathFromURL.native.js +25 -0
  24. package/dist/cjs/fork/extractPathFromURL.native.js.map +1 -1
  25. package/dist/cjs/fork/extractPathFromURL.test.cjs +37 -0
  26. package/dist/cjs/fork/extractPathFromURL.test.native.js +40 -0
  27. package/dist/cjs/fork/extractPathFromURL.test.native.js.map +1 -0
  28. package/dist/cjs/headless.cjs +1 -0
  29. package/dist/cjs/headless.native.js +1 -0
  30. package/dist/cjs/headless.native.js.map +1 -1
  31. package/dist/cjs/index.cjs +4 -0
  32. package/dist/cjs/index.native.js +4 -0
  33. package/dist/cjs/index.native.js.map +1 -1
  34. package/dist/cjs/link/getLinking.cjs +48 -0
  35. package/dist/cjs/link/getLinking.native.js +54 -0
  36. package/dist/cjs/link/getLinking.native.js.map +1 -0
  37. package/dist/cjs/link/linking.cjs +4 -0
  38. package/dist/cjs/link/linking.native.js +9 -0
  39. package/dist/cjs/link/linking.native.js.map +1 -1
  40. package/dist/cjs/metro-config/getViteMetroPluginOptions.cjs +2 -0
  41. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js +2 -0
  42. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  43. package/dist/cjs/router/Route.cjs +1 -1
  44. package/dist/cjs/router/Route.native.js +1 -1
  45. package/dist/cjs/router/Route.native.js.map +1 -1
  46. package/dist/cjs/router/getLinkingConfig.cjs +13 -2
  47. package/dist/cjs/router/getLinkingConfig.native.js +14 -2
  48. package/dist/cjs/router/getLinkingConfig.native.js.map +1 -1
  49. package/dist/cjs/router/getLinkingConfig.test.cjs +41 -0
  50. package/dist/cjs/router/getLinkingConfig.test.native.js +44 -0
  51. package/dist/cjs/router/getLinkingConfig.test.native.js.map +1 -0
  52. package/dist/cjs/router/getRouteInfo.cjs +1 -1
  53. package/dist/cjs/router/getRouteInfo.native.js +2 -2
  54. package/dist/cjs/router/getRouteInfo.native.js.map +1 -1
  55. package/dist/cjs/router/linkingConfig.cjs +34 -9
  56. package/dist/cjs/router/linkingConfig.native.js +35 -9
  57. package/dist/cjs/router/linkingConfig.native.js.map +1 -1
  58. package/dist/cjs/router/router.cjs +6 -6
  59. package/dist/cjs/router/router.native.js +6 -6
  60. package/dist/cjs/router/router.native.js.map +1 -1
  61. package/dist/cjs/router/sitemap.cjs +65 -0
  62. package/dist/cjs/router/sitemap.native.js +75 -0
  63. package/dist/cjs/router/sitemap.native.js.map +1 -0
  64. package/dist/cjs/router/sitemap.test.cjs +34 -0
  65. package/dist/cjs/router/sitemap.test.native.js +37 -0
  66. package/dist/cjs/router/sitemap.test.native.js.map +1 -0
  67. package/dist/cjs/router/useInitializeOneRouter.cjs +5 -5
  68. package/dist/cjs/router/useInitializeOneRouter.native.js +5 -5
  69. package/dist/cjs/router/useInitializeOneRouter.native.js.map +1 -1
  70. package/dist/cjs/serve.cjs +14 -1
  71. package/dist/cjs/serve.native.js +14 -1
  72. package/dist/cjs/serve.native.js.map +1 -1
  73. package/dist/cjs/utils/isStatus.cjs +1 -1
  74. package/dist/cjs/utils/isStatus.native.js +1 -1
  75. package/dist/cjs/utils/isStatus.native.js.map +1 -1
  76. package/dist/cjs/views/Navigator.cjs +1 -1
  77. package/dist/cjs/views/Navigator.native.js +1 -1
  78. package/dist/cjs/views/Navigator.native.js.map +1 -1
  79. package/dist/cjs/vite/one.cjs +2 -0
  80. package/dist/cjs/vite/one.native.js +4 -2
  81. package/dist/cjs/vite/one.native.js.map +1 -1
  82. package/dist/cjs/vite/plugins/virtualEntryPlugin.cjs +4 -0
  83. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js +6 -0
  84. package/dist/cjs/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  85. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.cjs +13 -0
  86. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js +13 -0
  87. package/dist/cjs/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
  88. package/dist/esm/Root.mjs +8 -7
  89. package/dist/esm/Root.mjs.map +1 -1
  90. package/dist/esm/Root.native.js +8 -7
  91. package/dist/esm/Root.native.js.map +1 -1
  92. package/dist/esm/babel-plugins/one-router-metro.mjs +5 -0
  93. package/dist/esm/babel-plugins/one-router-metro.mjs.map +1 -1
  94. package/dist/esm/babel-plugins/one-router-metro.native.js +6 -0
  95. package/dist/esm/babel-plugins/one-router-metro.native.js.map +1 -1
  96. package/dist/esm/babel-plugins/one-router-metro.test.mjs +20 -0
  97. package/dist/esm/babel-plugins/one-router-metro.test.mjs.map +1 -1
  98. package/dist/esm/babel-plugins/one-router-metro.test.native.js +20 -0
  99. package/dist/esm/babel-plugins/one-router-metro.test.native.js.map +1 -1
  100. package/dist/esm/cli/build.mjs +16 -1
  101. package/dist/esm/cli/build.mjs.map +1 -1
  102. package/dist/esm/cli/build.native.js +16 -1
  103. package/dist/esm/cli/build.native.js.map +1 -1
  104. package/dist/esm/cli/dev.mjs +12 -2
  105. package/dist/esm/cli/dev.mjs.map +1 -1
  106. package/dist/esm/cli/dev.native.js +12 -2
  107. package/dist/esm/cli/dev.native.js.map +1 -1
  108. package/dist/esm/cli/install-error-handlers.mjs +105 -0
  109. package/dist/esm/cli/install-error-handlers.mjs.map +1 -0
  110. package/dist/esm/cli/install-error-handlers.native.js +114 -0
  111. package/dist/esm/cli/install-error-handlers.native.js.map +1 -0
  112. package/dist/esm/createApp.mjs +3 -0
  113. package/dist/esm/createApp.mjs.map +1 -1
  114. package/dist/esm/createApp.native.js +1 -0
  115. package/dist/esm/createApp.native.js.map +1 -1
  116. package/dist/esm/fork/extractPathFromURL.mjs +19 -0
  117. package/dist/esm/fork/extractPathFromURL.mjs.map +1 -1
  118. package/dist/esm/fork/extractPathFromURL.native.js +25 -0
  119. package/dist/esm/fork/extractPathFromURL.native.js.map +1 -1
  120. package/dist/esm/fork/extractPathFromURL.test.mjs +38 -0
  121. package/dist/esm/fork/extractPathFromURL.test.mjs.map +1 -0
  122. package/dist/esm/fork/extractPathFromURL.test.native.js +38 -0
  123. package/dist/esm/fork/extractPathFromURL.test.native.js.map +1 -0
  124. package/dist/esm/headless.mjs +1 -0
  125. package/dist/esm/headless.mjs.map +1 -1
  126. package/dist/esm/headless.native.js +1 -0
  127. package/dist/esm/headless.native.js.map +1 -1
  128. package/dist/esm/index.js +3 -1
  129. package/dist/esm/index.js.map +1 -1
  130. package/dist/esm/index.mjs +3 -1
  131. package/dist/esm/index.mjs.map +1 -1
  132. package/dist/esm/index.native.js +3 -1
  133. package/dist/esm/index.native.js.map +1 -1
  134. package/dist/esm/link/getLinking.mjs +22 -0
  135. package/dist/esm/link/getLinking.mjs.map +1 -0
  136. package/dist/esm/link/getLinking.native.js +25 -0
  137. package/dist/esm/link/getLinking.native.js.map +1 -0
  138. package/dist/esm/link/linking.mjs +4 -1
  139. package/dist/esm/link/linking.mjs.map +1 -1
  140. package/dist/esm/link/linking.native.js +9 -1
  141. package/dist/esm/link/linking.native.js.map +1 -1
  142. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs +2 -0
  143. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs.map +1 -1
  144. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js +2 -0
  145. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  146. package/dist/esm/router/Route.mjs +2 -2
  147. package/dist/esm/router/Route.mjs.map +1 -1
  148. package/dist/esm/router/Route.native.js +2 -2
  149. package/dist/esm/router/Route.native.js.map +1 -1
  150. package/dist/esm/router/getLinkingConfig.mjs +14 -4
  151. package/dist/esm/router/getLinkingConfig.mjs.map +1 -1
  152. package/dist/esm/router/getLinkingConfig.native.js +15 -4
  153. package/dist/esm/router/getLinkingConfig.native.js.map +1 -1
  154. package/dist/esm/router/getLinkingConfig.test.mjs +42 -0
  155. package/dist/esm/router/getLinkingConfig.test.mjs.map +1 -0
  156. package/dist/esm/router/getLinkingConfig.test.native.js +42 -0
  157. package/dist/esm/router/getLinkingConfig.test.native.js.map +1 -0
  158. package/dist/esm/router/getRouteInfo.mjs +2 -2
  159. package/dist/esm/router/getRouteInfo.mjs.map +1 -1
  160. package/dist/esm/router/getRouteInfo.native.js +3 -3
  161. package/dist/esm/router/getRouteInfo.native.js.map +1 -1
  162. package/dist/esm/router/linkingConfig.mjs +35 -10
  163. package/dist/esm/router/linkingConfig.mjs.map +1 -1
  164. package/dist/esm/router/linkingConfig.native.js +36 -10
  165. package/dist/esm/router/linkingConfig.native.js.map +1 -1
  166. package/dist/esm/router/router.mjs +7 -7
  167. package/dist/esm/router/router.mjs.map +1 -1
  168. package/dist/esm/router/router.native.js +7 -7
  169. package/dist/esm/router/router.native.js.map +1 -1
  170. package/dist/esm/router/sitemap.mjs +39 -0
  171. package/dist/esm/router/sitemap.mjs.map +1 -0
  172. package/dist/esm/router/sitemap.native.js +46 -0
  173. package/dist/esm/router/sitemap.native.js.map +1 -0
  174. package/dist/esm/router/sitemap.test.mjs +35 -0
  175. package/dist/esm/router/sitemap.test.mjs.map +1 -0
  176. package/dist/esm/router/sitemap.test.native.js +35 -0
  177. package/dist/esm/router/sitemap.test.native.js.map +1 -0
  178. package/dist/esm/router/useInitializeOneRouter.mjs +5 -5
  179. package/dist/esm/router/useInitializeOneRouter.mjs.map +1 -1
  180. package/dist/esm/router/useInitializeOneRouter.native.js +5 -5
  181. package/dist/esm/router/useInitializeOneRouter.native.js.map +1 -1
  182. package/dist/esm/serve.mjs +14 -1
  183. package/dist/esm/serve.mjs.map +1 -1
  184. package/dist/esm/serve.native.js +14 -1
  185. package/dist/esm/serve.native.js.map +1 -1
  186. package/dist/esm/utils/isStatus.mjs +1 -1
  187. package/dist/esm/utils/isStatus.mjs.map +1 -1
  188. package/dist/esm/utils/isStatus.native.js +1 -1
  189. package/dist/esm/utils/isStatus.native.js.map +1 -1
  190. package/dist/esm/views/Navigator.mjs +2 -2
  191. package/dist/esm/views/Navigator.mjs.map +1 -1
  192. package/dist/esm/views/Navigator.native.js +2 -2
  193. package/dist/esm/views/Navigator.native.js.map +1 -1
  194. package/dist/esm/vite/one.mjs +2 -0
  195. package/dist/esm/vite/one.mjs.map +1 -1
  196. package/dist/esm/vite/one.native.js +4 -2
  197. package/dist/esm/vite/one.native.js.map +1 -1
  198. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs +4 -0
  199. package/dist/esm/vite/plugins/virtualEntryPlugin.mjs.map +1 -1
  200. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js +6 -0
  201. package/dist/esm/vite/plugins/virtualEntryPlugin.native.js.map +1 -1
  202. package/dist/esm/vite/plugins/virtualEntryPlugin.test.mjs +13 -0
  203. package/dist/esm/vite/plugins/virtualEntryPlugin.test.mjs.map +1 -1
  204. package/dist/esm/vite/plugins/virtualEntryPlugin.test.native.js +13 -0
  205. package/dist/esm/vite/plugins/virtualEntryPlugin.test.native.js.map +1 -1
  206. package/metro-entry.js +3 -0
  207. package/package.json +9 -9
  208. package/src/Root.tsx +15 -6
  209. package/src/babel-plugins/one-router-metro.test.ts +33 -0
  210. package/src/babel-plugins/one-router-metro.ts +9 -0
  211. package/src/cli/build.ts +25 -1
  212. package/src/cli/dev.ts +16 -5
  213. package/src/cli/install-error-handlers.ts +172 -0
  214. package/src/createApp.native.tsx +1 -0
  215. package/src/createApp.tsx +5 -0
  216. package/src/fork/extractPathFromURL.test.ts +80 -0
  217. package/src/fork/extractPathFromURL.ts +28 -0
  218. package/src/headless.tsx +3 -0
  219. package/src/index.ts +2 -0
  220. package/src/link/getLinking.ts +56 -0
  221. package/src/link/linking.native.ts +9 -0
  222. package/src/link/linking.ts +4 -0
  223. package/src/metro-config/getViteMetroPluginOptions.ts +3 -0
  224. package/src/router/Route.tsx +2 -2
  225. package/src/router/getLinkingConfig.test.ts +57 -0
  226. package/src/router/getLinkingConfig.ts +21 -3
  227. package/src/router/getRouteInfo.ts +2 -2
  228. package/src/router/linkingConfig.ts +52 -8
  229. package/src/router/router.ts +9 -7
  230. package/src/router/sitemap.test.ts +50 -0
  231. package/src/router/sitemap.ts +66 -0
  232. package/src/router/useInitializeOneRouter.ts +7 -5
  233. package/src/serve.ts +22 -1
  234. package/src/utils/isStatus.ts +11 -2
  235. package/src/views/Navigator.tsx +4 -8
  236. package/src/vite/one.ts +2 -0
  237. package/src/vite/plugins/virtualEntryPlugin.test.ts +17 -0
  238. package/src/vite/plugins/virtualEntryPlugin.ts +8 -0
  239. package/src/vite/types.ts +23 -0
  240. package/types/Root.d.ts +2 -0
  241. package/types/Root.d.ts.map +1 -1
  242. package/types/babel-plugins/one-router-metro.d.ts +1 -0
  243. package/types/babel-plugins/one-router-metro.d.ts.map +1 -1
  244. package/types/cli/build.d.ts.map +1 -1
  245. package/types/cli/dev.d.ts.map +1 -1
  246. package/types/cli/install-error-handlers.d.ts +4 -0
  247. package/types/cli/install-error-handlers.d.ts.map +1 -0
  248. package/types/createApp.d.ts +2 -0
  249. package/types/createApp.d.ts.map +1 -1
  250. package/types/createApp.native.d.ts.map +1 -1
  251. package/types/fork/extractPathFromURL.d.ts.map +1 -1
  252. package/types/fork/extractPathFromURL.test.d.ts +2 -0
  253. package/types/fork/extractPathFromURL.test.d.ts.map +1 -0
  254. package/types/headless.d.ts +2 -0
  255. package/types/headless.d.ts.map +1 -1
  256. package/types/index.d.ts +2 -0
  257. package/types/index.d.ts.map +1 -1
  258. package/types/link/getLinking.d.ts +22 -0
  259. package/types/link/getLinking.d.ts.map +1 -0
  260. package/types/link/linking.d.ts +1 -0
  261. package/types/link/linking.d.ts.map +1 -1
  262. package/types/link/linking.native.d.ts +1 -0
  263. package/types/link/linking.native.d.ts.map +1 -1
  264. package/types/metro-config/getViteMetroPluginOptions.d.ts +2 -1
  265. package/types/metro-config/getViteMetroPluginOptions.d.ts.map +1 -1
  266. package/types/router/getLinkingConfig.d.ts +3 -1
  267. package/types/router/getLinkingConfig.d.ts.map +1 -1
  268. package/types/router/getLinkingConfig.test.d.ts +2 -0
  269. package/types/router/getLinkingConfig.test.d.ts.map +1 -0
  270. package/types/router/linkingConfig.d.ts +5 -4
  271. package/types/router/linkingConfig.d.ts.map +1 -1
  272. package/types/router/router.d.ts +2 -1
  273. package/types/router/router.d.ts.map +1 -1
  274. package/types/router/sitemap.d.ts +14 -0
  275. package/types/router/sitemap.d.ts.map +1 -0
  276. package/types/router/sitemap.test.d.ts +2 -0
  277. package/types/router/sitemap.test.d.ts.map +1 -0
  278. package/types/router/useInitializeOneRouter.d.ts +2 -1
  279. package/types/router/useInitializeOneRouter.d.ts.map +1 -1
  280. package/types/serve.d.ts.map +1 -1
  281. package/types/utils/isStatus.d.ts +2 -1
  282. package/types/utils/isStatus.d.ts.map +1 -1
  283. package/types/views/Navigator.d.ts.map +1 -1
  284. package/types/vite/one.d.ts.map +1 -1
  285. package/types/vite/plugins/virtualEntryPlugin.d.ts.map +1 -1
  286. package/types/vite/types.d.ts +23 -0
  287. package/types/vite/types.d.ts.map +1 -1
@@ -129,6 +129,11 @@ function fromDeepLink(url: string): string {
129
129
  }
130
130
 
131
131
  export function extractExpoPathFromURL(_prefixes: string[], url = '') {
132
+ const pathFromPrefix = extractPathFromPrefix(_prefixes, url)
133
+ if (pathFromPrefix !== undefined) {
134
+ return pathFromPrefix.replace(/^\//, '')
135
+ }
136
+
132
137
  return (
133
138
  extractExactPathFromURL(url)
134
139
  // TODO: We should get rid of this, dropping specificities is not good
@@ -136,6 +141,29 @@ export function extractExpoPathFromURL(_prefixes: string[], url = '') {
136
141
  )
137
142
  }
138
143
 
144
+ function extractPathFromPrefix(prefixes: string[] = [], url: string) {
145
+ const prefix = getMatchingPrefix(prefixes, url)
146
+ if (!prefix) return undefined
147
+
148
+ return url.slice(prefix.length)
149
+ }
150
+
151
+ const PREFIX_BOUNDARY_CHARS = ['/', '?', '#']
152
+
153
+ function getMatchingPrefix(prefixes: string[], url: string) {
154
+ return prefixes
155
+ .filter((prefix) => matchesPrefix(prefix, url))
156
+ .sort((a, b) => b.length - a.length)[0]
157
+ }
158
+
159
+ function matchesPrefix(prefix: string, url: string) {
160
+ if (!url.startsWith(prefix)) return false
161
+ if (url.length === prefix.length) return true
162
+ // a prefix already ending in '/' has consumed its boundary
163
+ if (prefix.endsWith('/')) return true
164
+ return PREFIX_BOUNDARY_CHARS.includes(url[prefix.length])
165
+ }
166
+
139
167
  export function adjustPathname(url: { hostname?: string | null; pathname: string }) {
140
168
  if (url.hostname === 'exp.host' || url.hostname === 'u.expo.dev') {
141
169
  // drop the first two segments from pathname:
package/src/headless.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import './setup'
2
2
 
3
+ import type { OneLinkingConfig } from './link/getLinking'
3
4
  import { Root } from './Root'
4
5
  import { resolveClientLoader } from './clientLoaderResolver'
5
6
  import { render } from './render'
@@ -13,6 +14,7 @@ export type CreateHeadlessAppProps = {
13
14
  routerRoot: string
14
15
  path?: string
15
16
  flags?: One.Flags
17
+ linking?: OneLinkingConfig
16
18
  getSetupPromise?: () => Promise<unknown>
17
19
  }
18
20
 
@@ -34,6 +36,7 @@ export function createApp(options: CreateHeadlessAppProps) {
34
36
  flags={options.flags}
35
37
  routes={options.routes}
36
38
  routerRoot={options.routerRoot}
39
+ linking={options.linking}
37
40
  path={
38
41
  options.path || (typeof window !== 'undefined' ? window.location.href : '/')
39
42
  }
package/src/index.ts CHANGED
@@ -77,7 +77,9 @@ export {
77
77
  useSegments,
78
78
  useUnstableGlobalHref,
79
79
  } from './hooks'
80
+ export { useSitemap, type SitemapType } from './router/sitemap'
80
81
  export { href } from './href'
82
+ export { getLinking, type OneLinkingConfig } from './link/getLinking'
81
83
  // components
82
84
  export { Stack } from './layouts/Stack'
83
85
  export { Tabs } from './layouts/Tabs'
@@ -0,0 +1,56 @@
1
+ export type OneLinkingConfig = {
2
+ /**
3
+ * Custom app scheme or schemes. Each scheme is expanded to double- and
4
+ * triple-slashed URL prefixes.
5
+ */
6
+ scheme?: string | string[]
7
+ /**
8
+ * Fully qualified URL prefixes to strip before matching routes.
9
+ *
10
+ * For host-bearing custom scheme URLs, include the host:
11
+ * `myapp://app`.
12
+ */
13
+ prefixes?: string[]
14
+ filter?: (url: string) => boolean
15
+ }
16
+
17
+ export type NormalizedOneLinkingConfig = {
18
+ prefixes: string[]
19
+ filter?: (url: string) => boolean
20
+ }
21
+
22
+ export function getLinking(config: OneLinkingConfig = {}): OneLinkingConfig {
23
+ return config
24
+ }
25
+
26
+ export function normalizeLinkingConfig(
27
+ config: OneLinkingConfig | undefined,
28
+ defaultPrefixes: string[] = []
29
+ ): NormalizedOneLinkingConfig {
30
+ // merge: defaults from the native manifest combine with whatever the user
31
+ // provides via scheme/prefixes, so URLs from any registered scheme are
32
+ // recognized even when the user only mentions a subset
33
+ const merged = [
34
+ ...defaultPrefixes,
35
+ ...getSchemePrefixes(config?.scheme),
36
+ ...(config?.prefixes ?? []),
37
+ ]
38
+
39
+ return {
40
+ prefixes: dedupe(merged),
41
+ filter: config?.filter,
42
+ }
43
+ }
44
+
45
+ function getSchemePrefixes(scheme: string | string[] | undefined): string[] {
46
+ const schemes = Array.isArray(scheme) ? scheme : scheme ? [scheme] : []
47
+
48
+ return schemes.flatMap((value) => {
49
+ const normalized = value.replace(/:\/+$/, '')
50
+ return [`${normalized}://`, `${normalized}:///`]
51
+ })
52
+ }
53
+
54
+ function dedupe(values: string[]): string[] {
55
+ return [...new Set(values.filter(Boolean))]
56
+ }
@@ -62,6 +62,15 @@ export function getRootURL(): string {
62
62
  return _rootURL
63
63
  }
64
64
 
65
+ export function getDefaultLinkingPrefixes(): string[] {
66
+ return (
67
+ Linking.collectManifestSchemes?.().flatMap((scheme) => {
68
+ const normalized = scheme.replace(/:\/+$/, '')
69
+ return [`${normalized}://`, `${normalized}:///`]
70
+ }) ?? []
71
+ )
72
+ }
73
+
65
74
  export function addEventListener(listener: (url: string) => void) {
66
75
  let callback: (({ url }: { url: string }) => void) | undefined
67
76
 
@@ -12,6 +12,10 @@ export function getRootURL(): string {
12
12
  return '/'
13
13
  }
14
14
 
15
+ export function getDefaultLinkingPrefixes(): string[] {
16
+ return []
17
+ }
18
+
15
19
  export function addEventListener(listener: (url: string) => void) {
16
20
  if (typeof window === 'undefined') {
17
21
  return () => {}
@@ -20,12 +20,14 @@ export function getViteMetroPluginOptions({
20
20
  projectRoot,
21
21
  relativeRouterRoot,
22
22
  ignoredRouteFiles,
23
+ linking,
23
24
  userDefaultConfigOverrides,
24
25
  setupFile,
25
26
  }: {
26
27
  projectRoot: string
27
28
  relativeRouterRoot: string
28
29
  ignoredRouteFiles?: Array<`**/*${string}`>
30
+ linking?: unknown
29
31
  userDefaultConfigOverrides?: NonNullable<
30
32
  Parameters<typeof metroPlugin>[0]
31
33
  >['defaultConfigOverrides']
@@ -236,6 +238,7 @@ export function getViteMetroPluginOptions({
236
238
  ),
237
239
  ONE_ROUTER_ROOT_FOLDER_NAME: relativeRouterRoot,
238
240
  ONE_ROUTER_REQUIRE_CONTEXT_REGEX_STRING: routerRequireContextRegexString,
241
+ ONE_ROUTER_LINKING_CONFIG: linking,
239
242
  ONE_SETUP_FILE_NATIVE: (() => {
240
243
  if (!setupFile) return undefined
241
244
  // Extract native setup file path
@@ -4,7 +4,7 @@ import type { ErrorBoundaryProps } from '../views/Try'
4
4
  import type { LoaderProps } from '../types'
5
5
  import type { One } from '../vite/types'
6
6
  import type { ParamValidator, RouteValidationFn } from '../validateParams'
7
- import { getLinking } from './linkingConfig'
7
+ import { getResolvedLinking } from './linkingConfig'
8
8
  import { getContextKey } from './matchers'
9
9
  import { mergeDynamicParams } from './params'
10
10
  import { routeInfo } from './router'
@@ -153,7 +153,7 @@ function getParamsFromCurrentUrl(route?: {
153
153
  path?: string
154
154
  params?: Record<string, string | undefined>
155
155
  }): Record<string, any> | undefined {
156
- const linking = getLinking()
156
+ const linking = getResolvedLinking()
157
157
  if (!linking?.getStateFromPath) return undefined
158
158
  const path =
159
159
  routeInfo?.unstable_globalHref ||
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { normalizeLinkingConfig } from '../link/getLinking'
3
+ import { getRoutes } from './getRoutes'
4
+ import { getLinkingConfig } from './getLinkingConfig'
5
+ import { getMockContext } from '../testing-utils'
6
+
7
+ describe('getLinkingConfig', () => {
8
+ it('expands configured schemes into prefixes', () => {
9
+ const routes = getRoutes(getMockContext(['_layout.tsx', 'index.tsx']))!
10
+ const linking = getLinkingConfig(routes, true, {
11
+ scheme: 'threepunchconvo',
12
+ })
13
+
14
+ expect(linking.prefixes).toEqual(['threepunchconvo://', 'threepunchconvo:///'])
15
+ })
16
+
17
+ it('merges explicit prefixes with scheme-derived prefixes', () => {
18
+ const routes = getRoutes(getMockContext(['_layout.tsx', 'index.tsx']))!
19
+ const linking = getLinkingConfig(routes, true, {
20
+ scheme: 'threepunchconvo',
21
+ prefixes: ['threepunchconvo://app'],
22
+ })
23
+
24
+ expect(linking.prefixes).toEqual([
25
+ 'threepunchconvo://',
26
+ 'threepunchconvo:///',
27
+ 'threepunchconvo://app',
28
+ ])
29
+ })
30
+ })
31
+
32
+ describe('normalizeLinkingConfig', () => {
33
+ it('merges manifest-default prefixes with user-supplied scheme/prefixes', () => {
34
+ const result = normalizeLinkingConfig(
35
+ { scheme: 'foo', prefixes: ['https://example.test/app'] },
36
+ ['bar://', 'bar:///']
37
+ )
38
+
39
+ expect(result.prefixes).toEqual([
40
+ 'bar://',
41
+ 'bar:///',
42
+ 'foo://',
43
+ 'foo:///',
44
+ 'https://example.test/app',
45
+ ])
46
+ })
47
+
48
+ it('falls back to manifest-default prefixes when nothing is configured', () => {
49
+ const result = normalizeLinkingConfig(undefined, ['bar://', 'bar:///'])
50
+ expect(result.prefixes).toEqual(['bar://', 'bar:///'])
51
+ })
52
+
53
+ it('dedupes overlapping defaults and configured prefixes', () => {
54
+ const result = normalizeLinkingConfig({ scheme: 'foo' }, ['foo://', 'foo:///'])
55
+ expect(result.prefixes).toEqual(['foo://', 'foo:///'])
56
+ })
57
+ })
@@ -3,10 +3,13 @@ import type { State } from '../fork/getPathFromState'
3
3
  import { getReactNavigationConfig, type Screen } from '../getReactNavigationConfig'
4
4
  import {
5
5
  addEventListener,
6
+ getDefaultLinkingPrefixes,
6
7
  getInitialURL,
7
8
  getPathFromState,
8
9
  getStateFromPath,
9
10
  } from '../link/linking'
11
+ import { normalizeLinkingConfig, type OneLinkingConfig } from '../link/getLinking'
12
+ import { evictOldest } from '../utils/evictOldest'
10
13
  import type { RouteNode } from './Route'
11
14
 
12
15
  export function getNavigationConfig(
@@ -23,10 +26,16 @@ export type OneLinkingOptions = LinkingOptions<object> & {
23
26
  getPathFromState?: typeof getPathFromState
24
27
  }
25
28
 
26
- export function getLinkingConfig(routes: RouteNode, metaOnly = true): OneLinkingOptions {
29
+ export function getLinkingConfig(
30
+ routes: RouteNode,
31
+ metaOnly = true,
32
+ linking?: OneLinkingConfig
33
+ ): OneLinkingOptions {
27
34
  const config = getNavigationConfig(routes, metaOnly)
35
+ const resolvedLinking = normalizeLinkingConfig(linking, getDefaultLinkingPrefixes())
28
36
  return {
29
- prefixes: [],
37
+ prefixes: resolvedLinking.prefixes,
38
+ filter: resolvedLinking.filter,
30
39
  // @ts-expect-error
31
40
  config,
32
41
  // A custom getInitialURL is used on native to ensure the app always starts at
@@ -53,7 +62,15 @@ export function getLinkingConfig(routes: RouteNode, metaOnly = true): OneLinking
53
62
 
54
63
  export const stateCache = new Map<string, any>()
55
64
 
56
- /** We can reduce work by memoizing the state by the pathname. This only works because the options (linking config) theoretically never change. */
65
+ const STATE_CACHE_THRESHOLD = 5000
66
+ const STATE_CACHE_EVICTION = 1000
67
+
68
+ export function clearStateCache() {
69
+ stateCache.clear()
70
+ }
71
+
72
+ /** memoize getStateFromPath by pathname. cache is cleared when the route tree
73
+ * or linking config changes (see ensureBaseLinkingConfig in linkingConfig.ts). */
57
74
  function getStateFromPathMemoized(
58
75
  path: string,
59
76
  options: Parameters<typeof getStateFromPath>[1]
@@ -63,6 +80,7 @@ function getStateFromPathMemoized(
63
80
  return cached
64
81
  }
65
82
  const result = getStateFromPath(path, options)
83
+ evictOldest(stateCache, STATE_CACHE_THRESHOLD, STATE_CACHE_EVICTION)
66
84
  stateCache.set(path, result)
67
85
  return result
68
86
  }
@@ -4,14 +4,14 @@ import { stripBaseUrl } from '../fork/getStateFromPath-mods'
4
4
  import type { OneRouter } from '../interfaces/router'
5
5
  import { getNormalizedStatePath, type UrlObject } from './getNormalizedStatePath'
6
6
  import { isIndexPath } from './isIndexPath'
7
- import { getLinking } from './linkingConfig'
7
+ import { getResolvedLinking } from './linkingConfig'
8
8
 
9
9
  export function getRouteInfo(state: OneRouter.ResultState) {
10
10
  return getRouteInfoFromState(
11
11
  (state: Parameters<typeof originalGetPathFromState>[0], asPath: boolean) => {
12
12
  return getPathDataFromState(state, {
13
13
  screens: [],
14
- ...getLinking()?.config,
14
+ ...getResolvedLinking()?.config,
15
15
  preserveDynamicRoutes: asPath,
16
16
  preserveGroups: asPath,
17
17
  })
@@ -1,7 +1,9 @@
1
1
  import { isWebClient } from '../constants'
2
2
  import type { OneRouter } from '../interfaces/router'
3
+ import type { OneLinkingConfig } from '../link/getLinking'
3
4
  import { evictOldest } from '../utils/evictOldest'
4
5
  import {
6
+ clearStateCache,
5
7
  getLinkingConfig as createLinkingConfig,
6
8
  type OneLinkingOptions,
7
9
  } from './getLinkingConfig'
@@ -12,12 +14,13 @@ let linkingConfig: OneLinkingOptions | undefined
12
14
  // cache the base linking config (route-tree dependent, not URL-dependent)
13
15
  let cachedBaseLinkingConfig: OneLinkingOptions | undefined
14
16
  let cachedRouteNodeForLinking: RouteNode | null = null
17
+ let cachedLinkingConfigKey = ''
15
18
 
16
19
  // cache getStateFromPath results by path for SSR performance
17
20
  // same path always produces the same navigation state (route tree is static in prod)
18
21
  const ssrStateCache = new Map<string, OneRouter.ResultState | undefined>()
19
22
 
20
- export function getLinking() {
23
+ export function getResolvedLinking() {
21
24
  return linkingConfig
22
25
  }
23
26
 
@@ -33,13 +36,25 @@ export function resetLinking() {
33
36
  * Ensure the base linking config is initialized for a given route tree.
34
37
  * Does not set any per-request state.
35
38
  */
36
- export function ensureBaseLinkingConfig(routeNode: RouteNode | null) {
39
+ export function ensureBaseLinkingConfig(
40
+ routeNode: RouteNode | null,
41
+ linking?: OneLinkingConfig
42
+ ) {
43
+ const linkingConfigKey = getLinkingConfigKey(linking)
37
44
  if (
38
45
  routeNode &&
39
- (routeNode !== cachedRouteNodeForLinking || !cachedBaseLinkingConfig)
46
+ (routeNode !== cachedRouteNodeForLinking ||
47
+ linkingConfigKey !== cachedLinkingConfigKey ||
48
+ !cachedBaseLinkingConfig)
40
49
  ) {
41
- cachedBaseLinkingConfig = createLinkingConfig(routeNode)
50
+ // route tree or linking config changed — drop memoized navigation states
51
+ // so getStateFromPathMemoized doesn't return entries computed against
52
+ // the previous configuration
53
+ clearStateCache()
54
+ ssrStateCache.clear()
55
+ cachedBaseLinkingConfig = createLinkingConfig(routeNode, true, linking)
42
56
  cachedRouteNodeForLinking = routeNode
57
+ cachedLinkingConfigKey = linkingConfigKey
43
58
  }
44
59
  }
45
60
 
@@ -49,11 +64,12 @@ export function ensureBaseLinkingConfig(routeNode: RouteNode | null) {
49
64
  */
50
65
  export function getSSRInitialState(
51
66
  routeNode: RouteNode | null,
52
- initialLocation: URL
67
+ initialLocation: URL,
68
+ linking?: OneLinkingConfig
53
69
  ): OneRouter.ResultState | undefined {
54
70
  if (!routeNode) return undefined
55
71
 
56
- ensureBaseLinkingConfig(routeNode)
72
+ ensureBaseLinkingConfig(routeNode, linking)
57
73
  if (!cachedBaseLinkingConfig) return undefined
58
74
 
59
75
  const path = initialLocation.pathname + (initialLocation.search || '')
@@ -70,13 +86,14 @@ export function getSSRInitialState(
70
86
 
71
87
  export function setupLinking(
72
88
  routeNode: RouteNode | null,
73
- initialLocation?: URL
89
+ initialLocation?: URL,
90
+ linking?: OneLinkingConfig
74
91
  ): OneRouter.ResultState | undefined {
75
92
  let initialState: OneRouter.ResultState | undefined
76
93
 
77
94
  if (routeNode) {
78
95
  // reuse ensureBaseLinkingConfig to avoid duplicating cache logic
79
- ensureBaseLinkingConfig(routeNode)
96
+ ensureBaseLinkingConfig(routeNode, linking)
80
97
 
81
98
  // shallow copy so per-request mutations (getInitialURL) don't affect cache
82
99
  linkingConfig = { ...cachedBaseLinkingConfig! }
@@ -101,3 +118,30 @@ export function setupLinking(
101
118
 
102
119
  return initialState
103
120
  }
121
+
122
+ // each unique filter function gets a stable id so reference-equal filters
123
+ // share a cache key while distinct filters invalidate it
124
+ const filterIds = new WeakMap<NonNullable<OneLinkingConfig['filter']>, number>()
125
+ let filterIdCounter = 0
126
+ function getFilterId(filter: OneLinkingConfig['filter']) {
127
+ if (!filter) return 0
128
+ let id = filterIds.get(filter)
129
+ if (id === undefined) {
130
+ id = ++filterIdCounter
131
+ filterIds.set(filter, id)
132
+ }
133
+ return id
134
+ }
135
+
136
+ function getLinkingConfigKey(linking: OneLinkingConfig | undefined) {
137
+ // sort prefixes/schemes so ordering doesn't cause spurious cache misses
138
+ const schemes = Array.isArray(linking?.scheme)
139
+ ? [...linking.scheme].sort()
140
+ : (linking?.scheme ?? null)
141
+ const prefixes = linking?.prefixes ? [...linking.prefixes].sort() : null
142
+ return JSON.stringify({
143
+ scheme: schemes,
144
+ prefixes,
145
+ filterId: getFilterId(linking?.filter),
146
+ })
147
+ }
@@ -20,6 +20,7 @@ import { Platform } from 'react-native'
20
20
  import { devtoolsRegistry } from '../devtools/registry'
21
21
  import type { OneRouter } from '../interfaces/router'
22
22
  import { resolveHref } from '../link/href'
23
+ import type { OneLinkingConfig } from '../link/getLinking'
23
24
  import { openExternalURL } from '../link/openExternalURL'
24
25
  import { resolve } from '../link/path'
25
26
  import { checkBlocker } from '../useBlocker'
@@ -45,7 +46,7 @@ import type { UrlObject } from './getNormalizedStatePath'
45
46
  import { getRouteInfo } from './getRouteInfo'
46
47
  import { getRoutes } from './getRoutes'
47
48
  import { setLastAction } from './lastAction'
48
- import { getLinking, resetLinking, setupLinking } from './linkingConfig'
49
+ import { getResolvedLinking, resetLinking, setupLinking } from './linkingConfig'
49
50
  import type { RouteNode } from './Route'
50
51
  import { sortRoutes } from './sortRoutes'
51
52
  import { getQualifiedRouteComponent } from './useScreens'
@@ -214,7 +215,8 @@ let cachedContext: One.RouteContext | null = null
214
215
  export function initialize(
215
216
  context: One.RouteContext,
216
217
  ref: NavigationContainerRefWithCurrent<ReactNavigation.RootParamList>,
217
- initialLocation?: URL
218
+ initialLocation?: URL,
219
+ linking?: OneLinkingConfig
218
220
  ) {
219
221
  cleanUpState()
220
222
 
@@ -281,7 +283,7 @@ export function initialize(
281
283
  }
282
284
 
283
285
  navigationRef = ref as unknown as OneRouter.NavigationRef
284
- setupLinkingAndRouteInfo(initialLocation)
286
+ setupLinkingAndRouteInfo(initialLocation, linking)
285
287
  subscribeToNavigationChanges()
286
288
  }
287
289
 
@@ -297,8 +299,8 @@ function cleanUpState() {
297
299
  storeSubscribers.clear()
298
300
  }
299
301
 
300
- function setupLinkingAndRouteInfo(initialLocation?: URL) {
301
- initialState = setupLinking(routeNode, initialLocation)
302
+ function setupLinkingAndRouteInfo(initialLocation?: URL, linking?: OneLinkingConfig) {
303
+ initialState = setupLinking(routeNode, initialLocation, linking)
302
304
 
303
305
  // capture the original pathname before React Navigation's linking can modify it
304
306
  initialPathname =
@@ -557,7 +559,7 @@ function getSnapshot() {
557
559
  linkTo,
558
560
  routeNode,
559
561
  rootComponent,
560
- linking: getLinking(),
562
+ linking: getResolvedLinking(),
561
563
  hasAttemptedToHideSplash,
562
564
  initialState,
563
565
  rootState,
@@ -1059,7 +1061,7 @@ export async function linkTo(
1059
1061
  )
1060
1062
  }
1061
1063
 
1062
- const linking = getLinking()
1064
+ const linking = getResolvedLinking()
1063
1065
 
1064
1066
  if (!linking) {
1065
1067
  throw new Error('Attempted to link to route when no routes are present')
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { getRoutes } from './getRoutes'
3
+ import { getSitemap } from './sitemap'
4
+ import { getMockContext } from '../testing-utils'
5
+
6
+ describe('getSitemap', () => {
7
+ it('maps the route tree to a public sitemap shape', () => {
8
+ const routes = getRoutes(
9
+ getMockContext([
10
+ '_layout.tsx',
11
+ 'index.tsx',
12
+ '(app)/_layout.tsx',
13
+ '(app)/thread/[id].tsx',
14
+ 'docs/[...slug].tsx',
15
+ ])
16
+ )!
17
+ const sitemap = getSitemap(routes)!
18
+
19
+ expect(sitemap).toMatchObject({
20
+ contextKey: './_layout.tsx',
21
+ href: '/',
22
+ isInternal: false,
23
+ isGenerated: false,
24
+ children: expect.arrayContaining([
25
+ expect.objectContaining({
26
+ contextKey: './index.tsx',
27
+ filename: 'index',
28
+ href: '/',
29
+ }),
30
+ expect.objectContaining({
31
+ contextKey: './(app)/_layout.tsx',
32
+ filename: '(app)/_layout',
33
+ href: '/(app)',
34
+ children: expect.arrayContaining([
35
+ expect.objectContaining({
36
+ contextKey: './(app)/thread/[id].tsx',
37
+ filename: 'thread/[id]',
38
+ href: '/(app)/thread/[id]',
39
+ }),
40
+ ]),
41
+ }),
42
+ expect.objectContaining({
43
+ contextKey: './docs/[...slug].tsx',
44
+ filename: 'docs/[...slug]',
45
+ href: '/docs/[...slug]',
46
+ }),
47
+ ]),
48
+ })
49
+ })
50
+ })
@@ -0,0 +1,66 @@
1
+ import { useMemo } from 'react'
2
+ import type { OneRouter } from '../interfaces/router'
3
+ import type { RouteNode } from './Route'
4
+ import { removeSupportedExtensions } from './matchers'
5
+ import { routeNode } from './router'
6
+ import { sortRoutes } from './sortRoutes'
7
+
8
+ export type SitemapType = {
9
+ contextKey: string
10
+ filename: string
11
+ href: string | OneRouter.Href
12
+ isInitial: boolean
13
+ isInternal: boolean
14
+ isGenerated: boolean
15
+ children: SitemapType[]
16
+ }
17
+
18
+ export function useSitemap(): SitemapType | null {
19
+ return useMemo(() => getSitemap(routeNode), [routeNode])
20
+ }
21
+
22
+ export function getSitemap(root: RouteNode | null): SitemapType | null {
23
+ return root ? mapRouteToSitemap(root, []) : null
24
+ }
25
+
26
+ function mapRouteToSitemap(route: RouteNode, parents: string[]): SitemapType {
27
+ return {
28
+ contextKey: route.contextKey,
29
+ filename: getRouteFilename(route),
30
+ href: getRouteHref(route, parents),
31
+ isInitial: route.initialRouteName === route.route,
32
+ isInternal: route.internal ?? false,
33
+ isGenerated: route.generated ?? false,
34
+ children: [...route.children]
35
+ .sort(sortRoutes)
36
+ .map((child) => mapRouteToSitemap(child, getRouteSegments(route, parents))),
37
+ }
38
+ }
39
+
40
+ function getRouteSegments(route: RouteNode, parents: string[]) {
41
+ return [...parents, ...route.route.split('/')]
42
+ }
43
+
44
+ // the sitemap exposes route patterns rather than concrete sample URLs:
45
+ // dynamic segments stay as `[id]` / `[...slug]`, and `index` collapses to '/'.
46
+ // callers wanting clickable links should fill in their own params.
47
+ function getRouteHref(route: RouteNode, parents: string[]) {
48
+ const path = getRouteSegments(route, parents)
49
+ .map((segment) => (segment === 'index' ? '' : segment))
50
+ .filter(Boolean)
51
+ .join('/')
52
+
53
+ return `/${path}`
54
+ }
55
+
56
+ function getRouteFilename(route: RouteNode) {
57
+ const contextKey = removeSupportedExtensions(route.contextKey)
58
+ const segments = contextKey.split('/')
59
+
60
+ if (route.contextKey.match(/_layout\.[jt]sx?$/)) {
61
+ return segments.slice(-2).join('/')
62
+ }
63
+
64
+ const routeSegmentsCount = route.route.split('/').length
65
+ return segments.slice(-routeSegmentsCount).join('/')
66
+ }
@@ -1,6 +1,7 @@
1
1
  import { useNavigationContainerRef } from '@react-navigation/native'
2
2
  import { resetLoaderState } from '../useLoader'
3
3
  import type { One } from '../vite/types'
4
+ import type { OneLinkingConfig } from '../link/getLinking'
4
5
  import * as routerStore from './router'
5
6
  import { initialize } from './router'
6
7
  import { getSSRInitialState, ensureBaseLinkingConfig } from './linkingConfig'
@@ -15,7 +16,8 @@ let ssrRouteTreeInitialized = false
15
16
 
16
17
  export function useInitializeOneRouter(
17
18
  context: One.RouteContext,
18
- initialLocation: URL | undefined
19
+ initialLocation: URL | undefined,
20
+ linking?: OneLinkingConfig
19
21
  ) {
20
22
  const navigationRef = useNavigationContainerRef()
21
23
 
@@ -23,15 +25,15 @@ export function useInitializeOneRouter(
23
25
  if (typeof window === 'undefined') {
24
26
  if (!ssrRouteTreeInitialized) {
25
27
  // first SSR request: full initialization to set up route tree, root component, etc.
26
- initialize(context, navigationRef, initialLocation)
28
+ initialize(context, navigationRef, initialLocation, linking)
27
29
  ssrRouteTreeInitialized = true
28
30
  // also ensure linking config base is cached
29
- ensureBaseLinkingConfig(routerStore.routeNode)
31
+ ensureBaseLinkingConfig(routerStore.routeNode, linking)
30
32
  }
31
33
 
32
34
  // per-request: compute initialState from URL (cached by path)
33
35
  const initialState = initialLocation
34
- ? getSSRInitialState(routerStore.routeNode, initialLocation)
36
+ ? getSSRInitialState(routerStore.routeNode, initialLocation, linking)
35
37
  : routerStore.initialState
36
38
 
37
39
  // return per-request snapshot to prevent concurrent request trampling
@@ -48,7 +50,7 @@ export function useInitializeOneRouter(
48
50
  const contexts = '__react_navigation__elements_contexts'
49
51
  globalThis[contexts] = new Map<string, React.Context<any>>()
50
52
 
51
- initialize(context, navigationRef, initialLocation)
53
+ initialize(context, navigationRef, initialLocation, linking)
52
54
  lastInitVersion = initVersion
53
55
  }
54
56