one 1.15.10 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/dist/cjs/cli/build.cjs +98 -58
  2. package/dist/cjs/cli/build.native.js +106 -63
  3. package/dist/cjs/cli/build.native.js.map +1 -1
  4. package/dist/cjs/cli/buildPage.cjs +3 -3
  5. package/dist/cjs/cli/buildPage.native.js +3 -3
  6. package/dist/cjs/cli/buildPage.native.js.map +1 -1
  7. package/dist/cjs/constants.cjs +2 -0
  8. package/dist/cjs/constants.native.js +2 -0
  9. package/dist/cjs/constants.native.js.map +1 -1
  10. package/dist/cjs/createAPIRoute.native.js.map +1 -1
  11. package/dist/cjs/createApp.cjs +2 -6
  12. package/dist/cjs/createHandleRequest.cjs +2 -2
  13. package/dist/cjs/createHandleRequest.native.js +2 -2
  14. package/dist/cjs/createHandleRequest.native.js.map +1 -1
  15. package/dist/cjs/hooks.cjs +5 -1
  16. package/dist/cjs/hooks.native.js +7 -1
  17. package/dist/cjs/hooks.native.js.map +1 -1
  18. package/dist/cjs/index.native.js.map +1 -1
  19. package/dist/cjs/metro-config/getViteMetroPluginOptions.cjs +10 -7
  20. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js +13 -10
  21. package/dist/cjs/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  22. package/dist/cjs/metro-config/getViteMetroPluginOptions.test.cjs +23 -0
  23. package/dist/cjs/metro-config/getViteMetroPluginOptions.test.native.js +26 -0
  24. package/dist/cjs/metro-config/getViteMetroPluginOptions.test.native.js.map +1 -0
  25. package/dist/cjs/router/Route.cjs +21 -1
  26. package/dist/cjs/router/Route.native.js +22 -1
  27. package/dist/cjs/router/Route.native.js.map +1 -1
  28. package/dist/cjs/router/interceptRoutes.cjs +6 -6
  29. package/dist/cjs/router/interceptRoutes.native.js +6 -6
  30. package/dist/cjs/router/interceptRoutes.native.js.map +1 -1
  31. package/dist/cjs/router/params.cjs +46 -0
  32. package/dist/cjs/router/params.native.js +70 -0
  33. package/dist/cjs/router/params.native.js.map +1 -0
  34. package/dist/cjs/router/useScreens.cjs +3 -0
  35. package/dist/cjs/router/useScreens.native.js +2 -0
  36. package/dist/cjs/router/useScreens.native.js.map +1 -1
  37. package/dist/cjs/serve-worker.native.js.map +1 -1
  38. package/dist/cjs/server/getServerManifest.cjs +6 -6
  39. package/dist/cjs/server/getServerManifest.native.js +6 -6
  40. package/dist/cjs/server/getServerManifest.native.js.map +1 -1
  41. package/dist/cjs/server/oneServe.cjs +9 -5
  42. package/dist/cjs/server/oneServe.native.js +9 -5
  43. package/dist/cjs/server/oneServe.native.js.map +1 -1
  44. package/dist/cjs/server/workerHandler.cjs +2 -2
  45. package/dist/cjs/server/workerHandler.native.js +2 -2
  46. package/dist/cjs/server/workerHandler.native.js.map +1 -1
  47. package/dist/cjs/skewProtection.cjs +48 -7
  48. package/dist/cjs/skewProtection.native.js +48 -7
  49. package/dist/cjs/skewProtection.native.js.map +1 -1
  50. package/dist/cjs/useLoader.cjs +67 -69
  51. package/dist/cjs/useLoader.native.js +113 -117
  52. package/dist/cjs/useLoader.native.js.map +1 -1
  53. package/dist/cjs/utils/dynamicImport.cjs +3 -1
  54. package/dist/cjs/utils/dynamicImport.native.js +22 -1
  55. package/dist/cjs/utils/dynamicImport.native.js.map +1 -1
  56. package/dist/cjs/utils/toAbsolute.cjs +5 -2
  57. package/dist/cjs/utils/toAbsolute.native.js +6 -1
  58. package/dist/cjs/utils/toAbsolute.native.js.map +1 -1
  59. package/dist/cjs/utils/workerImport.cjs +1 -1
  60. package/dist/cjs/utils/workerImport.native.js +1 -1
  61. package/dist/cjs/utils/workerImport.native.js.map +1 -1
  62. package/dist/cjs/views/RootErrorBoundary.cjs +114 -117
  63. package/dist/cjs/views/RootErrorBoundary.native.js +126 -146
  64. package/dist/cjs/views/RootErrorBoundary.native.js.map +1 -1
  65. package/dist/cjs/views/Try.cjs +17 -18
  66. package/dist/cjs/views/Try.native.js +28 -42
  67. package/dist/cjs/views/Try.native.js.map +1 -1
  68. package/dist/cjs/vite/plugins/criticalCSSPlugin.cjs +2 -1
  69. package/dist/cjs/vite/plugins/criticalCSSPlugin.native.js +2 -1
  70. package/dist/cjs/vite/plugins/criticalCSSPlugin.native.js.map +1 -1
  71. package/dist/cjs/vite/plugins/criticalCSSPlugin.test.cjs +26 -20
  72. package/dist/cjs/vite/plugins/criticalCSSPlugin.test.native.js +28 -20
  73. package/dist/cjs/vite/plugins/criticalCSSPlugin.test.native.js.map +1 -1
  74. package/dist/cjs/vite/plugins/imageDataPlugin.cjs +3 -2
  75. package/dist/cjs/vite/plugins/imageDataPlugin.native.js +3 -2
  76. package/dist/cjs/vite/plugins/imageDataPlugin.native.js.map +1 -1
  77. package/dist/cjs/vite/plugins/imageDataPlugin.test.cjs +34 -69
  78. package/dist/cjs/vite/plugins/imageDataPlugin.test.native.js +34 -69
  79. package/dist/cjs/vite/plugins/imageDataPlugin.test.native.js.map +1 -1
  80. package/dist/cjs/vite/plugins/sourceInspectorPlugin.cjs +20 -2
  81. package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js +23 -2
  82. package/dist/cjs/vite/plugins/sourceInspectorPlugin.native.js.map +1 -1
  83. package/dist/cjs/vite/plugins/sourceInspectorPlugin.test.cjs +21 -0
  84. package/dist/cjs/vite/plugins/sourceInspectorPlugin.test.native.js +28 -0
  85. package/dist/cjs/vite/plugins/sourceInspectorPlugin.test.native.js.map +1 -0
  86. package/dist/cjs/vite/resolveResponse.cjs +7 -2
  87. package/dist/cjs/vite/resolveResponse.native.js +7 -2
  88. package/dist/cjs/vite/resolveResponse.native.js.map +1 -1
  89. package/dist/esm/cli/build.mjs +100 -60
  90. package/dist/esm/cli/build.mjs.map +1 -1
  91. package/dist/esm/cli/build.native.js +108 -65
  92. package/dist/esm/cli/build.native.js.map +1 -1
  93. package/dist/esm/cli/buildPage.mjs +4 -4
  94. package/dist/esm/cli/buildPage.mjs.map +1 -1
  95. package/dist/esm/cli/buildPage.native.js +4 -4
  96. package/dist/esm/cli/buildPage.native.js.map +1 -1
  97. package/dist/esm/constants.mjs +2 -1
  98. package/dist/esm/constants.mjs.map +1 -1
  99. package/dist/esm/constants.native.js +2 -1
  100. package/dist/esm/constants.native.js.map +1 -1
  101. package/dist/esm/createAPIRoute.mjs.map +1 -1
  102. package/dist/esm/createAPIRoute.native.js.map +1 -1
  103. package/dist/esm/createApp.mjs +2 -6
  104. package/dist/esm/createApp.mjs.map +1 -1
  105. package/dist/esm/createHandleRequest.mjs +2 -2
  106. package/dist/esm/createHandleRequest.mjs.map +1 -1
  107. package/dist/esm/createHandleRequest.native.js +2 -2
  108. package/dist/esm/createHandleRequest.native.js.map +1 -1
  109. package/dist/esm/hooks.mjs +5 -1
  110. package/dist/esm/hooks.mjs.map +1 -1
  111. package/dist/esm/hooks.native.js +7 -1
  112. package/dist/esm/hooks.native.js.map +1 -1
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/index.mjs.map +1 -1
  115. package/dist/esm/index.native.js.map +1 -1
  116. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs +9 -7
  117. package/dist/esm/metro-config/getViteMetroPluginOptions.mjs.map +1 -1
  118. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js +12 -10
  119. package/dist/esm/metro-config/getViteMetroPluginOptions.native.js.map +1 -1
  120. package/dist/esm/metro-config/getViteMetroPluginOptions.test.mjs +24 -0
  121. package/dist/esm/metro-config/getViteMetroPluginOptions.test.mjs.map +1 -0
  122. package/dist/esm/metro-config/getViteMetroPluginOptions.test.native.js +24 -0
  123. package/dist/esm/metro-config/getViteMetroPluginOptions.test.native.js.map +1 -0
  124. package/dist/esm/router/Route.mjs +21 -1
  125. package/dist/esm/router/Route.mjs.map +1 -1
  126. package/dist/esm/router/Route.native.js +22 -1
  127. package/dist/esm/router/Route.native.js.map +1 -1
  128. package/dist/esm/router/interceptRoutes.mjs +7 -7
  129. package/dist/esm/router/interceptRoutes.mjs.map +1 -1
  130. package/dist/esm/router/interceptRoutes.native.js +7 -7
  131. package/dist/esm/router/interceptRoutes.native.js.map +1 -1
  132. package/dist/esm/router/params.mjs +21 -0
  133. package/dist/esm/router/params.mjs.map +1 -0
  134. package/dist/esm/router/params.native.js +42 -0
  135. package/dist/esm/router/params.native.js.map +1 -0
  136. package/dist/esm/router/useScreens.mjs +3 -0
  137. package/dist/esm/router/useScreens.mjs.map +1 -1
  138. package/dist/esm/router/useScreens.native.js +2 -0
  139. package/dist/esm/router/useScreens.native.js.map +1 -1
  140. package/dist/esm/serve-worker.mjs.map +1 -1
  141. package/dist/esm/serve-worker.native.js.map +1 -1
  142. package/dist/esm/server/getServerManifest.mjs +6 -6
  143. package/dist/esm/server/getServerManifest.mjs.map +1 -1
  144. package/dist/esm/server/getServerManifest.native.js +6 -6
  145. package/dist/esm/server/getServerManifest.native.js.map +1 -1
  146. package/dist/esm/server/oneServe.mjs +11 -7
  147. package/dist/esm/server/oneServe.mjs.map +1 -1
  148. package/dist/esm/server/oneServe.native.js +11 -7
  149. package/dist/esm/server/oneServe.native.js.map +1 -1
  150. package/dist/esm/server/workerHandler.mjs +2 -2
  151. package/dist/esm/server/workerHandler.mjs.map +1 -1
  152. package/dist/esm/server/workerHandler.native.js +2 -2
  153. package/dist/esm/server/workerHandler.native.js.map +1 -1
  154. package/dist/esm/skewProtection.mjs +48 -8
  155. package/dist/esm/skewProtection.mjs.map +1 -1
  156. package/dist/esm/skewProtection.native.js +48 -8
  157. package/dist/esm/skewProtection.native.js.map +1 -1
  158. package/dist/esm/useLoader.mjs +64 -66
  159. package/dist/esm/useLoader.mjs.map +1 -1
  160. package/dist/esm/useLoader.native.js +112 -116
  161. package/dist/esm/useLoader.native.js.map +1 -1
  162. package/dist/esm/utils/dynamicImport.mjs +1 -1
  163. package/dist/esm/utils/dynamicImport.mjs.map +1 -1
  164. package/dist/esm/utils/dynamicImport.native.js +20 -1
  165. package/dist/esm/utils/dynamicImport.native.js.map +1 -1
  166. package/dist/esm/utils/toAbsolute.mjs +3 -1
  167. package/dist/esm/utils/toAbsolute.mjs.map +1 -1
  168. package/dist/esm/utils/toAbsolute.native.js +5 -1
  169. package/dist/esm/utils/toAbsolute.native.js.map +1 -1
  170. package/dist/esm/utils/workerImport.mjs +2 -2
  171. package/dist/esm/utils/workerImport.mjs.map +1 -1
  172. package/dist/esm/utils/workerImport.native.js +2 -2
  173. package/dist/esm/utils/workerImport.native.js.map +1 -1
  174. package/dist/esm/views/RootErrorBoundary.mjs +114 -117
  175. package/dist/esm/views/RootErrorBoundary.mjs.map +1 -1
  176. package/dist/esm/views/RootErrorBoundary.native.js +126 -146
  177. package/dist/esm/views/RootErrorBoundary.native.js.map +1 -1
  178. package/dist/esm/views/Try.mjs +17 -18
  179. package/dist/esm/views/Try.mjs.map +1 -1
  180. package/dist/esm/views/Try.native.js +28 -42
  181. package/dist/esm/views/Try.native.js.map +1 -1
  182. package/dist/esm/vite/plugins/criticalCSSPlugin.mjs +2 -1
  183. package/dist/esm/vite/plugins/criticalCSSPlugin.mjs.map +1 -1
  184. package/dist/esm/vite/plugins/criticalCSSPlugin.native.js +2 -1
  185. package/dist/esm/vite/plugins/criticalCSSPlugin.native.js.map +1 -1
  186. package/dist/esm/vite/plugins/criticalCSSPlugin.test.mjs +26 -20
  187. package/dist/esm/vite/plugins/criticalCSSPlugin.test.mjs.map +1 -1
  188. package/dist/esm/vite/plugins/criticalCSSPlugin.test.native.js +28 -20
  189. package/dist/esm/vite/plugins/criticalCSSPlugin.test.native.js.map +1 -1
  190. package/dist/esm/vite/plugins/imageDataPlugin.mjs +4 -3
  191. package/dist/esm/vite/plugins/imageDataPlugin.mjs.map +1 -1
  192. package/dist/esm/vite/plugins/imageDataPlugin.native.js +4 -3
  193. package/dist/esm/vite/plugins/imageDataPlugin.native.js.map +1 -1
  194. package/dist/esm/vite/plugins/imageDataPlugin.test.mjs +34 -69
  195. package/dist/esm/vite/plugins/imageDataPlugin.test.mjs.map +1 -1
  196. package/dist/esm/vite/plugins/imageDataPlugin.test.native.js +34 -69
  197. package/dist/esm/vite/plugins/imageDataPlugin.test.native.js.map +1 -1
  198. package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs +19 -3
  199. package/dist/esm/vite/plugins/sourceInspectorPlugin.mjs.map +1 -1
  200. package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js +22 -3
  201. package/dist/esm/vite/plugins/sourceInspectorPlugin.native.js.map +1 -1
  202. package/dist/esm/vite/plugins/sourceInspectorPlugin.test.mjs +22 -0
  203. package/dist/esm/vite/plugins/sourceInspectorPlugin.test.mjs.map +1 -0
  204. package/dist/esm/vite/plugins/sourceInspectorPlugin.test.native.js +26 -0
  205. package/dist/esm/vite/plugins/sourceInspectorPlugin.test.native.js.map +1 -0
  206. package/dist/esm/vite/resolveResponse.mjs +7 -2
  207. package/dist/esm/vite/resolveResponse.mjs.map +1 -1
  208. package/dist/esm/vite/resolveResponse.native.js +7 -2
  209. package/dist/esm/vite/resolveResponse.native.js.map +1 -1
  210. package/expo-plugin.cjs +1 -0
  211. package/package.json +15 -10
  212. package/react-native-commands.cjs +1 -0
  213. package/src/cli/build.ts +156 -99
  214. package/src/cli/buildPage.ts +4 -4
  215. package/src/constants.ts +15 -0
  216. package/src/createAPIRoute.ts +35 -2
  217. package/src/createApp.tsx +2 -6
  218. package/src/createHandleRequest.ts +6 -2
  219. package/src/hooks.tsx +9 -1
  220. package/src/index.ts +8 -1
  221. package/src/metro-config/getViteMetroPluginOptions.test.ts +34 -0
  222. package/src/metro-config/getViteMetroPluginOptions.ts +14 -11
  223. package/src/router/Route.tsx +52 -2
  224. package/src/router/interceptRoutes.ts +7 -7
  225. package/src/router/params.ts +32 -0
  226. package/src/router/useScreens.tsx +18 -0
  227. package/src/serve-worker.ts +4 -2
  228. package/src/server/getServerManifest.ts +11 -7
  229. package/src/server/oneServe.ts +12 -14
  230. package/src/server/workerHandler.ts +13 -2
  231. package/src/skewProtection.ts +45 -5
  232. package/src/useLoader.ts +6 -4
  233. package/src/utils/dynamicImport.ts +2 -2
  234. package/src/utils/toAbsolute.ts +5 -0
  235. package/src/utils/workerImport.ts +2 -2
  236. package/src/views/RootErrorBoundary.tsx +18 -0
  237. package/src/views/Try.tsx +18 -0
  238. package/src/vite/plugins/criticalCSSPlugin.test.ts +34 -24
  239. package/src/vite/plugins/criticalCSSPlugin.ts +3 -2
  240. package/src/vite/plugins/imageDataPlugin.test.ts +39 -83
  241. package/src/vite/plugins/imageDataPlugin.ts +5 -4
  242. package/src/vite/plugins/sourceInspectorPlugin.test.ts +40 -0
  243. package/src/vite/plugins/sourceInspectorPlugin.ts +30 -2
  244. package/src/vite/resolveResponse.ts +6 -2
  245. package/types/cli/build.d.ts.map +1 -1
  246. package/types/constants.d.ts +9 -0
  247. package/types/constants.d.ts.map +1 -1
  248. package/types/createAPIRoute.d.ts +28 -3
  249. package/types/createAPIRoute.d.ts.map +1 -1
  250. package/types/createApp.d.ts.map +1 -1
  251. package/types/createHandleRequest.d.ts +1 -1
  252. package/types/createHandleRequest.d.ts.map +1 -1
  253. package/types/headless-server.d.ts +1 -1
  254. package/types/hooks.d.ts.map +1 -1
  255. package/types/index.d.ts +1 -1
  256. package/types/index.d.ts.map +1 -1
  257. package/types/metro-config/getViteMetroPluginOptions.d.ts +5 -0
  258. package/types/metro-config/getViteMetroPluginOptions.d.ts.map +1 -1
  259. package/types/metro-config/getViteMetroPluginOptions.test.d.ts +2 -0
  260. package/types/metro-config/getViteMetroPluginOptions.test.d.ts.map +1 -0
  261. package/types/router/Route.d.ts +1 -0
  262. package/types/router/Route.d.ts.map +1 -1
  263. package/types/router/params.d.ts +3 -0
  264. package/types/router/params.d.ts.map +1 -0
  265. package/types/router/useScreens.d.ts.map +1 -1
  266. package/types/serve-worker.d.ts +5 -3
  267. package/types/serve-worker.d.ts.map +1 -1
  268. package/types/server/getServerManifest.d.ts.map +1 -1
  269. package/types/server/oneServe.d.ts.map +1 -1
  270. package/types/server/workerHandler.d.ts +1 -1
  271. package/types/server/workerHandler.d.ts.map +1 -1
  272. package/types/skewProtection.d.ts +1 -0
  273. package/types/skewProtection.d.ts.map +1 -1
  274. package/types/useLoader.d.ts.map +1 -1
  275. package/types/utils/dynamicImport.d.ts +2 -0
  276. package/types/utils/dynamicImport.d.ts.map +1 -1
  277. package/types/utils/toAbsolute.d.ts +3 -0
  278. package/types/utils/toAbsolute.d.ts.map +1 -1
  279. package/types/views/RootErrorBoundary.d.ts.map +1 -1
  280. package/types/views/Try.d.ts.map +1 -1
  281. package/types/vite/plugins/criticalCSSPlugin.d.ts.map +1 -1
  282. package/types/vite/plugins/imageDataPlugin.d.ts.map +1 -1
  283. package/types/vite/plugins/sourceInspectorPlugin.d.ts +2 -0
  284. package/types/vite/plugins/sourceInspectorPlugin.d.ts.map +1 -1
  285. package/types/vite/plugins/sourceInspectorPlugin.test.d.ts +2 -0
  286. package/types/vite/plugins/sourceInspectorPlugin.test.d.ts.map +1 -0
  287. package/types/vite/resolveResponse.d.ts +1 -1
  288. package/types/vite/resolveResponse.d.ts.map +1 -1
@@ -8,6 +8,14 @@ import {
8
8
  ROUTE_NATIVE_EXCLUSION_GLOB_PATTERNS,
9
9
  } from '../router/glob-patterns'
10
10
 
11
+ /**
12
+ * On Windows, micromatch.makeRe() produces regex patterns with `[\\/]` or `[^\\/]`
13
+ * instead of `\/` and `[^/]`. Normalize them so the startsWith check works.
14
+ */
15
+ export function normalizeReSource(source: string): string {
16
+ return source.replace(/\[\\\\\/\]/g, '\\/').replace(/\[\^\\\\\/\]/g, '[^/]')
17
+ }
18
+
11
19
  export function getViteMetroPluginOptions({
12
20
  projectRoot,
13
21
  relativeRouterRoot,
@@ -56,7 +64,7 @@ export function getViteMetroPluginOptions({
56
64
  * ^(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\+api\.(ts|tsx))$
57
65
  * ```
58
66
  */
59
- const reSource = re.source
67
+ const reSource = normalizeReSource(re.source)
60
68
 
61
69
  if (
62
70
  !(
@@ -112,13 +120,7 @@ export function getViteMetroPluginOptions({
112
120
  // .filter((i): i is NonNullable<typeof i> => !!i)
113
121
  // ),
114
122
  },
115
- nodeModulesPaths: tsconfigPathsConfigLoadResult.absoluteBaseUrl
116
- ? [
117
- // "vite-tsconfig-paths" for Metro
118
- tsconfigPathsConfigLoadResult.absoluteBaseUrl,
119
- ...(defaultConfig?.resolver?.nodeModulesPaths || []),
120
- ]
121
- : defaultConfig?.resolver?.nodeModulesPaths,
123
+ nodeModulesPaths: defaultConfig?.resolver?.nodeModulesPaths,
122
124
  resolveRequest: (context, moduleName, platform) => {
123
125
  if (moduleName.endsWith('.css')) {
124
126
  return {
@@ -153,12 +155,13 @@ export function getViteMetroPluginOptions({
153
155
  const defaultResolveRequest =
154
156
  defaultConfig?.resolver?.resolveRequest || context.resolveRequest
155
157
  const res = defaultResolveRequest(context, moduleName, platform)
156
- if (res && 'filePath' in res && res.filePath.includes('/src/index.ts')) {
158
+ const svgSrcSuffix = `${path.sep}src${path.sep}index.ts`
159
+ if (res && 'filePath' in res && res.filePath.includes(svgSrcSuffix)) {
157
160
  return {
158
161
  ...res,
159
162
  filePath: res.filePath.replace(
160
- '/src/index.ts',
161
- '/lib/commonjs/index.js'
163
+ svgSrcSuffix,
164
+ `${path.sep}lib${path.sep}commonjs${path.sep}index.js`
162
165
  ),
163
166
  }
164
167
  }
@@ -1,9 +1,13 @@
1
1
  import React, { createContext, type ReactNode, useContext } from 'react'
2
+ import { findFocusedRoute } from '../fork/findFocusedRoute'
2
3
  import type { ErrorBoundaryProps } from '../views/Try'
3
4
  import type { LoaderProps } from '../types'
4
5
  import type { One } from '../vite/types'
5
6
  import type { ParamValidator, RouteValidationFn } from '../validateParams'
7
+ import { getLinking } from './linkingConfig'
6
8
  import { getContextKey } from './matchers'
9
+ import { mergeDynamicParams } from './params'
10
+ import { routeInfo } from './router'
7
11
  import { RouteInfoContextProvider } from './RouteInfoContext'
8
12
 
9
13
  export type DynamicConvention = {
@@ -136,6 +140,34 @@ export function useContextKey(): string {
136
140
  return getContextKey(node.contextKey)
137
141
  }
138
142
 
143
+ /**
144
+ * Resolve path params from the current URL using the same linking
145
+ * config (getStateFromPath) that the router uses for navigation.
146
+ * Returns `undefined` if linking isn't set up yet (SSR, pre-init) or
147
+ * the URL doesn't produce a focused route with params.
148
+ *
149
+ * Reuses the router's existing URL-parsing rather than re-implementing
150
+ * segment matching, so group/catch-all/index semantics stay consistent.
151
+ */
152
+ function getParamsFromCurrentUrl(route?: {
153
+ path?: string
154
+ params?: Record<string, string | undefined>
155
+ }): Record<string, any> | undefined {
156
+ const linking = getLinking()
157
+ if (!linking?.getStateFromPath) return undefined
158
+ const path =
159
+ routeInfo?.unstable_globalHref ||
160
+ route?.path ||
161
+ (typeof window !== 'undefined' && window.location
162
+ ? window.location.pathname + window.location.search
163
+ : undefined)
164
+ if (!path) return undefined
165
+ const state = linking.getStateFromPath(path, linking.config)
166
+ if (!state) return undefined
167
+ const focused = findFocusedRoute(state)
168
+ return focused?.params as Record<string, any> | undefined
169
+ }
170
+
139
171
  /** Provides the matching routes and filename to the children. */
140
172
  export function Route({
141
173
  children,
@@ -144,10 +176,28 @@ export function Route({
144
176
  }: {
145
177
  children: ReactNode
146
178
  node: RouteNode
147
- route?: { params?: Record<string, string | undefined> }
179
+ route?: {
180
+ path?: string
181
+ params?: Record<string, string | undefined>
182
+ }
148
183
  }) {
184
+ // url is the source of truth for path params. react navigation can provide
185
+ // a `route` whose `params` are missing or stale for the dynamic segments
186
+ // this node expects (observed in spa-shell mode under strictmode, and when
187
+ // navigating between sibling dynamic routes under the same layout).
188
+ //
189
+ // to keep useParams() aligned with the current route, recover dynamic
190
+ // segment params by re-parsing the router path through the linking config.
191
+ // non-dynamic params keep flowing from React Navigation.
192
+ const resolvedParams = React.useMemo(() => {
193
+ const rp = route?.params
194
+ if (!node.dynamic?.length) return rp
195
+ const fromUrl = getParamsFromCurrentUrl(route)
196
+ return mergeDynamicParams(rp, node.dynamic, fromUrl)
197
+ }, [node, route, routeInfo?.unstable_globalHref])
198
+
149
199
  return (
150
- <RouteParamsContext.Provider value={route?.params}>
200
+ <RouteParamsContext.Provider value={resolvedParams}>
151
201
  <CurrentRouteContext.Provider value={node}>
152
202
  <RouteInfoContextProvider>{children}</RouteInfoContextProvider>
153
203
  </CurrentRouteContext.Provider>
@@ -4,7 +4,7 @@ import {
4
4
  matchRoutePattern,
5
5
  stripGroupSegmentsFromPath,
6
6
  } from './matchers'
7
- import { isNative } from '../constants'
7
+ import { hasWebHistory, isNative } from '../constants'
8
8
 
9
9
  // ============================================
10
10
  // Navigation Type Tracking
@@ -333,7 +333,7 @@ let preInterceptUrl: string | null = null
333
333
  * Used when activating an intercept route to show the target URL.
334
334
  */
335
335
  export function updateURLWithoutNavigation(href: string) {
336
- if (typeof window !== 'undefined') {
336
+ if (hasWebHistory) {
337
337
  // Store the URL before we change it
338
338
  preInterceptUrl = window.location.pathname + window.location.search
339
339
 
@@ -361,7 +361,7 @@ export function registerClearSlotStates(callback: () => void) {
361
361
  * This should be called from modal close handlers instead of router.back().
362
362
  */
363
363
  export function closeIntercept(): boolean {
364
- if (typeof window === 'undefined') return false
364
+ if (!hasWebHistory) return false
365
365
 
366
366
  const state = window.history.state
367
367
  if (!state?.__intercepted) {
@@ -385,7 +385,7 @@ export function closeIntercept(): boolean {
385
385
  * Check if the current navigation state is from an interception
386
386
  */
387
387
  export function isInterceptedNavigation(): boolean {
388
- if (typeof window === 'undefined') return false
388
+ if (!hasWebHistory) return false
389
389
  return window.history.state?.__intercepted === true
390
390
  }
391
391
 
@@ -393,7 +393,7 @@ export function isInterceptedNavigation(): boolean {
393
393
  * Get the actual path from an intercepted navigation
394
394
  */
395
395
  export function getInterceptedActualPath(): string | null {
396
- if (typeof window === 'undefined') return null
396
+ if (!hasWebHistory) return null
397
397
  return window.history.state?.__actualPath ?? null
398
398
  }
399
399
 
@@ -401,7 +401,7 @@ export function getInterceptedActualPath(): string | null {
401
401
  * Get the URL from before the interception
402
402
  */
403
403
  export function getPreInterceptUrl(): string | null {
404
- if (typeof window === 'undefined') return null
404
+ if (!hasWebHistory) return null
405
405
  return window.history.state?.__preInterceptUrl ?? preInterceptUrl
406
406
  }
407
407
 
@@ -456,7 +456,7 @@ export function storeInterceptState(
456
456
  * Returns true if an intercept was restored, false otherwise.
457
457
  */
458
458
  export function restoreInterceptFromHistory(): boolean {
459
- if (typeof window === 'undefined') return false
459
+ if (!hasWebHistory) return false
460
460
 
461
461
  const state = window.history.state
462
462
  if (!state?.__intercepted) {
@@ -0,0 +1,32 @@
1
+ import type { DynamicConvention } from './Route'
2
+
3
+ function paramValueEqual(a: unknown, b: unknown) {
4
+ if (Array.isArray(a) || Array.isArray(b)) {
5
+ return (
6
+ Array.isArray(a) &&
7
+ Array.isArray(b) &&
8
+ a.length === b.length &&
9
+ a.every((value, index) => value === b[index])
10
+ )
11
+ }
12
+ return a === b
13
+ }
14
+
15
+ export function mergeDynamicParams<TParams extends Record<string, any> | undefined>(
16
+ params: TParams,
17
+ dynamic: DynamicConvention[] | null | undefined,
18
+ source: Record<string, any> | undefined
19
+ ): TParams {
20
+ if (!dynamic?.length || !source) return params
21
+
22
+ let next: Record<string, any> | undefined
23
+
24
+ for (const segment of dynamic) {
25
+ const value = source[segment.name]
26
+ if (value == null || paramValueEqual(params?.[segment.name], value)) continue
27
+ next ??= { ...params }
28
+ next[segment.name] = value
29
+ }
30
+
31
+ return (next ?? params) as TParams
32
+ }
@@ -13,6 +13,8 @@ import { ServerContextScript } from '../server/ServerContextScript'
13
13
  import { getPageExport } from '../utils/getPageExport'
14
14
  import { EmptyRoute } from '../views/EmptyRoute'
15
15
  import { Try } from '../views/Try'
16
+ import { checkSkewAndReload } from '../skewProtection'
17
+ import { handleSkewError, isChunkLoadError } from '../utils/dynamicImport'
16
18
  import { DevHead } from '../vite/DevHead'
17
19
  import { useServerContext } from '../vite/one-server-only'
18
20
  import { filterRootHTML } from './filterRootHTML'
@@ -626,6 +628,22 @@ class RouteErrorBoundary extends React.Component<
626
628
  }\n\n${error.stack}\n\nComponent Stack:\n${errorInfo.componentStack}`
627
629
  )
628
630
  this.setState({ errorInfo })
631
+
632
+ // skew protection: chunk-load errors at the route level are unambiguous,
633
+ // reload immediately. for any other render error, do a one-shot version
634
+ // check and only reload if the deployed build actually changed. genuine
635
+ // bugs fall through to the route error UI.
636
+ if (
637
+ process.env.TAMAGUI_TARGET !== 'native' &&
638
+ process.env.NODE_ENV === 'production' &&
639
+ process.env.ONE_SKEW_PROTECTION !== 'false'
640
+ ) {
641
+ if (isChunkLoadError(error)) {
642
+ handleSkewError()
643
+ } else {
644
+ checkSkewAndReload()
645
+ }
646
+ }
629
647
  }
630
648
 
631
649
  clearError() {
@@ -14,8 +14,10 @@ export type { LazyRoutes }
14
14
  * Creates a fetch handler for edge/worker environments (Cloudflare Workers, service workers, etc.)
15
15
  * No Hono dependency — routes are matched dynamically via compiled regexes against a mutable table.
16
16
  *
17
- * @returns `{ fetch, updateRoutes }` — call `fetch(request)` to handle requests,
18
- * `updateRoutes(newBuildInfo, newLazyRoutes?)` to hot-swap the route table.
17
+ * @returns `{ fetch, updateRoutes }` — call `fetch(request, env?, ctx?)` to handle requests
18
+ * (`env` and `ctx` are forwarded from the worker's fetch handler and surfaced on
19
+ * API route handler contexts as `{ env, executionCtx }`).
20
+ * Call `updateRoutes(newBuildInfo, newLazyRoutes?)` to hot-swap the route table.
19
21
  */
20
22
  export async function serve(buildInfo: One.BuildInfo, lazyRoutes?: LazyRoutes) {
21
23
  setupBuildInfo(buildInfo)
@@ -150,13 +150,10 @@ export function getServerManifest(route: RouteNode): OneRouterServerManifestV1 {
150
150
  const addedMiddlewares: Record<string, boolean> = {}
151
151
 
152
152
  for (const [path, node] of flat) {
153
- if (node.type === 'api') {
154
- const route = getGeneratedNamedRouteRegex(path, node)
155
- apiRoutes.push(route)
156
- allRoutes.push(route)
157
- continue
158
- }
159
-
153
+ // collect middlewares for every route type, not just pages. a middleware
154
+ // nested under api/ (e.g. app/api/admin/_middleware.ts) must still end up
155
+ // in middlewareRoutes so the build pipeline compiles it — otherwise the
156
+ // compiled file never exists and runtime lookups return undefined.
160
157
  if (node.middlewares?.length) {
161
158
  for (const middleware of node.middlewares) {
162
159
  if (!addedMiddlewares[middleware.contextKey]) {
@@ -166,6 +163,13 @@ export function getServerManifest(route: RouteNode): OneRouterServerManifestV1 {
166
163
  }
167
164
  }
168
165
 
166
+ if (node.type === 'api') {
167
+ const route = getGeneratedNamedRouteRegex(path, node)
168
+ apiRoutes.push(route)
169
+ allRoutes.push(route)
170
+ continue
171
+ }
172
+
169
173
  const route = getGeneratedNamedRouteRegex(path, node)
170
174
  pageRoutes.push(route)
171
175
  allRoutes.push(route)
@@ -1,7 +1,7 @@
1
1
  import type { Hono, MiddlewareHandler } from 'hono'
2
2
  import type { BlankEnv } from 'hono/types'
3
3
  import { readFile } from 'node:fs/promises'
4
- import { join, resolve } from 'node:path'
4
+ import { join } from 'node:path'
5
5
  import {
6
6
  CSS_PRELOAD_JS_POSTFIX,
7
7
  LOADER_JS_POSTFIX_UNCACHED,
@@ -16,7 +16,7 @@ import {
16
16
  } from '../createHandleRequest'
17
17
  import type { RenderAppProps } from '../types'
18
18
  import { getPathFromLoaderPath } from '../utils/cleanUrl'
19
- import { toAbsolute } from '../utils/toAbsolute'
19
+ import { toAbsoluteUrl } from '../utils/toAbsolute'
20
20
  import type { One } from '../vite/types'
21
21
  import type { RouteInfoCompiled } from './createRoutesManifest'
22
22
  import { setSSRLoaderData } from './ssrLoaderData'
@@ -175,8 +175,8 @@ export async function oneServe(
175
175
  routeExported = lazyKey
176
176
  ? options?.lazyRoutes?.pages?.[lazyKey]
177
177
  ? await options.lazyRoutes.pages[lazyKey]()
178
- : await import(toAbsolute(resolvedPath))
179
- : await import(toAbsolute(serverPath!))
178
+ : await import(toAbsoluteUrl(resolvedPath))
179
+ : await import(toAbsoluteUrl(serverPath!))
180
180
  moduleImportCache.set(cacheKey, routeExported)
181
181
  }
182
182
 
@@ -279,8 +279,7 @@ export async function oneServe(
279
279
  const entry = options?.lazyRoutes?.serverEntry
280
280
  ? await options.lazyRoutes.serverEntry()
281
281
  : await import(
282
- resolve(
283
- process.cwd(),
282
+ toAbsoluteUrl(
284
283
  `${serverOptions.root}/${outDir}/server/_virtual_one-entry.${typeof oneOptions.build?.server === 'object' && oneOptions.build.server.outputFormat === 'cjs' ? 'c' : ''}js`
285
284
  )
286
285
  )
@@ -315,13 +314,8 @@ export async function oneServe(
315
314
  }
316
315
  // both vite and rolldown-vite replace brackets with underscores in output filenames
317
316
  const fileName = route.page.slice(1).replace(/\[/g, '_').replace(/\]/g, '_')
318
- const apiFile = join(
319
- process.cwd(),
320
- outDir,
321
- 'api',
322
- fileName + (apiCJS ? '.cjs' : '.js')
323
- )
324
- return await import(apiFile)
317
+ const apiFile = join(outDir, 'api', fileName + (apiCJS ? '.cjs' : '.js'))
318
+ return await import(toAbsoluteUrl(apiFile))
325
319
  },
326
320
 
327
321
  async loadMiddleware(route) {
@@ -329,7 +323,7 @@ export async function oneServe(
329
323
  if (options?.lazyRoutes?.middlewares?.[route.contextKey]) {
330
324
  return await options.lazyRoutes.middlewares[route.contextKey]()
331
325
  }
332
- return await import(toAbsolute(route.contextKey))
326
+ return await import(toAbsoluteUrl(route.contextKey))
333
327
  },
334
328
 
335
329
  async handleLoader({ route, loaderProps }) {
@@ -916,17 +910,21 @@ url: ${url}`)
916
910
 
917
911
  for (const route of compiledManifest.apiRoutes) {
918
912
  app.get(route.urlPath, createHonoHandler(route))
913
+ app.on('HEAD', route.urlPath, createHonoHandler(route))
919
914
  app.put(route.urlPath, createHonoHandler(route))
920
915
  app.post(route.urlPath, createHonoHandler(route))
921
916
  app.delete(route.urlPath, createHonoHandler(route))
922
917
  app.patch(route.urlPath, createHonoHandler(route))
918
+ app.options(route.urlPath, createHonoHandler(route))
923
919
 
924
920
  if (route.urlPath !== route.urlCleanPath) {
925
921
  app.get(route.urlCleanPath, createHonoHandler(route))
922
+ app.on('HEAD', route.urlCleanPath, createHonoHandler(route))
926
923
  app.put(route.urlCleanPath, createHonoHandler(route))
927
924
  app.post(route.urlCleanPath, createHonoHandler(route))
928
925
  app.delete(route.urlCleanPath, createHonoHandler(route))
929
926
  app.patch(route.urlCleanPath, createHonoHandler(route))
927
+ app.options(route.urlCleanPath, createHonoHandler(route))
930
928
  }
931
929
  }
932
930
 
@@ -566,7 +566,11 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
566
566
  }
567
567
 
568
568
  // the main fetch handler - matches request to route and dispatches
569
- async function handleRequest(request: Request): Promise<Response | null> {
569
+ async function handleRequest(
570
+ request: Request,
571
+ env?: unknown,
572
+ executionCtx?: unknown
573
+ ): Promise<Response | null> {
570
574
  const url = getURLfromRequestURL(request)
571
575
  const pathname = url.pathname
572
576
  const method = request.method
@@ -683,7 +687,14 @@ export function createWorkerHandler(options: WorkerHandlerOptions) {
683
687
  if (route.compiledRegex.test(pathname)) {
684
688
  if (debugRouter)
685
689
  console.info(`[one] ⚡ ${pathname} → matched API route: ${route.page}`)
686
- const response = await resolveAPIRoute(requestHandlers, request, url, route)
690
+ const response = await resolveAPIRoute(
691
+ requestHandlers,
692
+ request,
693
+ url,
694
+ route,
695
+ env,
696
+ executionCtx
697
+ )
687
698
  if (response && isResponse(response)) {
688
699
  return setCacheHeaders(response, route, true)
689
700
  }
@@ -1,8 +1,10 @@
1
1
  import { CACHE_KEY } from './constants'
2
2
  import { getURL } from './getURL'
3
+ import { handleSkewError } from './utils/dynamicImport'
3
4
 
4
5
  let stale = false
5
6
  let polling: ReturnType<typeof setTimeout> | null = null
7
+ let inFlightCheck: Promise<boolean> | null = null
6
8
 
7
9
  export function isVersionStale() {
8
10
  if (stale) return true
@@ -11,6 +13,48 @@ export function isVersionStale() {
11
13
  return false
12
14
  }
13
15
 
16
+ function markStale(version?: string) {
17
+ stale = true
18
+ if (typeof window !== 'undefined') {
19
+ ;(window as any).__oneVersionStale = true
20
+ window.dispatchEvent(new CustomEvent('one-version-update', { detail: { version } }))
21
+ }
22
+ }
23
+
24
+ // one-shot version check for use when something already looks wrong
25
+ // (e.g. an error reached the root boundary). reloads if the deployed
26
+ // version no longer matches our build, otherwise leaves the error UI alone.
27
+ // dedupes concurrent calls so a render-loop crash only fetches once.
28
+ export function checkSkewAndReload(): Promise<boolean> {
29
+ if (typeof window === 'undefined') return Promise.resolve(false)
30
+ if (process.env.ONE_SKEW_PROTECTION === 'false') return Promise.resolve(false)
31
+ if (isVersionStale()) {
32
+ handleSkewError()
33
+ return Promise.resolve(true)
34
+ }
35
+ if (inFlightCheck) return inFlightCheck
36
+ inFlightCheck = (async () => {
37
+ try {
38
+ const res = await fetch(`${getURL()}/version.json`, {
39
+ headers: { 'cache-control': 'no-cache', pragma: 'no-cache' },
40
+ })
41
+ if (!res.ok) return false
42
+ const data = await res.json()
43
+ if (data.version && data.version !== CACHE_KEY) {
44
+ markStale(data.version)
45
+ handleSkewError()
46
+ return true
47
+ }
48
+ return false
49
+ } catch {
50
+ return false
51
+ } finally {
52
+ inFlightCheck = null
53
+ }
54
+ })()
55
+ return inFlightCheck
56
+ }
57
+
14
58
  export function setupSkewProtection() {
15
59
  if (typeof window === 'undefined') return
16
60
  if (process.env.NODE_ENV === 'development') return
@@ -31,11 +75,7 @@ export function setupSkewProtection() {
31
75
  }
32
76
  const data = await res.json()
33
77
  if (data.version !== CACHE_KEY) {
34
- stale = true
35
- ;(window as any).__oneVersionStale = true
36
- window.dispatchEvent(
37
- new CustomEvent('one-version-update', { detail: { version: data.version } })
38
- )
78
+ markStale(data.version)
39
79
  // stop polling once stale detected
40
80
  return
41
81
  }
package/src/useLoader.ts CHANGED
@@ -517,10 +517,12 @@ export function useLoaderState<
517
517
  } finally {
518
518
  clearTimeout(timeoutId)
519
519
  }
520
- // biome-ignore lint/security/noGlobalEval: we need eval for native
521
- const result = eval(
522
- `() => { var exports = {}; ${loaderJsCode}; return exports; }`
523
- )()
520
+ // use Function constructor instead of direct eval. hermes treats
521
+ // direct eval as indirect (no lexical scope) and rolldown warns
522
+ // about it; new Function is predictable across both engines and
523
+ // explicitly threads the exports object through as a parameter.
524
+ const result: { loader?: () => any } = {}
525
+ new Function('exports', loaderJsCode)(result)
524
526
  const moduleLoadTime = performance.now() - moduleLoadStart
525
527
 
526
528
  if (typeof result.loader !== 'function') {
@@ -28,12 +28,12 @@ const CHUNK_ERROR_PATTERNS = [
28
28
  'Importing a module script failed', // safari
29
29
  ]
30
30
 
31
- function isChunkLoadError(err: unknown): boolean {
31
+ export function isChunkLoadError(err: unknown): boolean {
32
32
  const msg = err instanceof Error ? err.message : String(err)
33
33
  return CHUNK_ERROR_PATTERNS.some((p) => msg.includes(p))
34
34
  }
35
35
 
36
- function handleSkewError() {
36
+ export function handleSkewError() {
37
37
  if (typeof window === 'undefined') return
38
38
  const key = '__one_skew_reload'
39
39
  const last = sessionStorage.getItem(key)
@@ -1,3 +1,8 @@
1
1
  import { resolve } from 'node:path'
2
+ import { pathToFileURL } from 'node:url'
2
3
 
4
+ /** Resolve to native filesystem path — for fs operations (readFile, writeFile, join). */
3
5
  export const toAbsolute = (p: string) => resolve(process.cwd(), p)
6
+
7
+ /** Resolve to file:// URL — for dynamic import() which requires URLs on Windows. */
8
+ export const toAbsoluteUrl = (p: string) => pathToFileURL(resolve(process.cwd(), p)).href
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Usage: Pass the caller's import.meta.url to resolve relative paths correctly.
6
6
  */
7
- import { fileURLToPath } from 'node:url'
7
+ import { fileURLToPath, pathToFileURL } from 'node:url'
8
8
  import { dirname, resolve } from 'node:path'
9
9
 
10
10
  type ModuleCache = Map<string, any>
@@ -33,7 +33,7 @@ export async function workerImport<T = any>(
33
33
  const mjsPath = absolutePath.endsWith('.mjs') ? absolutePath : `${absolutePath}.mjs`
34
34
 
35
35
  // @ts-ignore - runtime needs .mjs extension for proper ESM resolution
36
- const mod = await import(mjsPath)
36
+ const mod = await import(pathToFileURL(mjsPath).href)
37
37
  cache.set(cacheKey, mod)
38
38
  return mod
39
39
  }
@@ -1,5 +1,7 @@
1
1
  import React from 'react'
2
2
  import { Platform, Text, View } from 'react-native'
3
+ import { checkSkewAndReload } from '../skewProtection'
4
+ import { handleSkewError, isChunkLoadError } from '../utils/dynamicImport'
3
5
 
4
6
  type RootErrorBoundaryState = {
5
7
  hasError: boolean
@@ -28,6 +30,22 @@ export class RootErrorBoundary extends React.Component<
28
30
  `[One] Root error boundary caught error:\n${printError(error)}\n${info.componentStack}`
29
31
  )
30
32
 
33
+ // skew protection: chunk-load errors are unambiguous → reload immediately.
34
+ // for any other render error, do a one-shot version check and only reload
35
+ // if the deployed build actually changed. genuine bugs fall through to the
36
+ // fallback UI below.
37
+ if (
38
+ process.env.TAMAGUI_TARGET !== 'native' &&
39
+ process.env.NODE_ENV === 'production' &&
40
+ process.env.ONE_SKEW_PROTECTION !== 'false'
41
+ ) {
42
+ if (isChunkLoadError(error)) {
43
+ handleSkewError()
44
+ } else {
45
+ checkSkewAndReload()
46
+ }
47
+ }
48
+
31
49
  // Dispatch error event for devtools (web only - CustomEvent doesn't exist on native)
32
50
  if (typeof window !== 'undefined' && typeof CustomEvent !== 'undefined') {
33
51
  window.dispatchEvent(
package/src/views/Try.tsx CHANGED
@@ -1,4 +1,6 @@
1
1
  import React from 'react'
2
+ import { checkSkewAndReload } from '../skewProtection'
3
+ import { handleSkewError, isChunkLoadError } from '../utils/dynamicImport'
2
4
 
3
5
  /**
4
6
  * Route context information passed to error boundaries.
@@ -65,6 +67,22 @@ export class Try extends React.Component<TryProps, TryState> {
65
67
  )
66
68
  }
67
69
 
70
+ // skew protection: chunk-load errors at the route level are unambiguous,
71
+ // reload immediately. for any other render error, do a one-shot version
72
+ // check and only reload if the deployed build actually changed. genuine
73
+ // bugs fall through to the route's own ErrorBoundary UI below.
74
+ if (
75
+ process.env.TAMAGUI_TARGET !== 'native' &&
76
+ process.env.NODE_ENV === 'production' &&
77
+ process.env.ONE_SKEW_PROTECTION !== 'false'
78
+ ) {
79
+ if (isChunkLoadError(error)) {
80
+ handleSkewError()
81
+ } else {
82
+ checkSkewAndReload()
83
+ }
84
+ }
85
+
68
86
  // Dispatch error event for devtools integration (web only - CustomEvent doesn't exist on native)
69
87
  if (typeof window !== 'undefined' && typeof CustomEvent !== 'undefined') {
70
88
  window.dispatchEvent(