@nativescript/vite 8.0.0-alpha.9 → 8.0.0-dev.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 (554) hide show
  1. package/README.md +89 -14
  2. package/bin/cli.cjs +8 -14
  3. package/configuration/angular.d.ts +34 -1
  4. package/configuration/angular.js +196 -217
  5. package/configuration/angular.js.map +1 -1
  6. package/configuration/base.js +152 -104
  7. package/configuration/base.js.map +1 -1
  8. package/configuration/javascript.js +14 -93
  9. package/configuration/javascript.js.map +1 -1
  10. package/configuration/react.js +41 -73
  11. package/configuration/react.js.map +1 -1
  12. package/configuration/solid.js +51 -6
  13. package/configuration/solid.js.map +1 -1
  14. package/configuration/typescript.js +11 -92
  15. package/configuration/typescript.js.map +1 -1
  16. package/framework.d.ts +22 -0
  17. package/framework.js +18 -0
  18. package/framework.js.map +1 -0
  19. package/helpers/app-components.d.ts +2 -1
  20. package/helpers/app-components.js.map +1 -1
  21. package/helpers/app-css-refresh.d.ts +31 -0
  22. package/helpers/app-css-refresh.js +43 -0
  23. package/helpers/app-css-refresh.js.map +1 -0
  24. package/helpers/app-css-state.d.ts +17 -0
  25. package/helpers/app-css-state.js +51 -0
  26. package/helpers/app-css-state.js.map +1 -0
  27. package/helpers/bundler-context.d.ts +11 -0
  28. package/helpers/bundler-context.js +71 -0
  29. package/helpers/bundler-context.js.map +1 -0
  30. package/helpers/cli-flags.d.ts +12 -0
  31. package/helpers/cli-flags.js +34 -0
  32. package/helpers/cli-flags.js.map +1 -1
  33. package/helpers/css-platform-plugin.d.ts +14 -0
  34. package/helpers/css-platform-plugin.js +43 -25
  35. package/helpers/css-platform-plugin.js.map +1 -1
  36. package/helpers/dev-host.d.ts +360 -0
  37. package/helpers/dev-host.js +694 -0
  38. package/helpers/dev-host.js.map +1 -0
  39. package/helpers/dynamic-import-plugin.d.ts +2 -1
  40. package/helpers/dynamic-import-plugin.js +59 -53
  41. package/helpers/dynamic-import-plugin.js.map +1 -1
  42. package/helpers/esbuild-platform-resolver.js +4 -1
  43. package/helpers/esbuild-platform-resolver.js.map +1 -1
  44. package/helpers/external-configs.d.ts +10 -12
  45. package/helpers/external-configs.js +58 -35
  46. package/helpers/external-configs.js.map +1 -1
  47. package/helpers/flavor.d.ts +31 -0
  48. package/helpers/flavor.js +53 -2
  49. package/helpers/flavor.js.map +1 -1
  50. package/helpers/global-defines.d.ts +100 -33
  51. package/helpers/global-defines.js +192 -66
  52. package/helpers/global-defines.js.map +1 -1
  53. package/helpers/hmr-scope.d.ts +26 -0
  54. package/helpers/hmr-scope.js +67 -0
  55. package/helpers/hmr-scope.js.map +1 -0
  56. package/helpers/init.js +24 -26
  57. package/helpers/init.js.map +1 -1
  58. package/helpers/logging.d.ts +11 -1
  59. package/helpers/logging.js +45 -2
  60. package/helpers/logging.js.map +1 -1
  61. package/helpers/main-entry.d.ts +4 -1
  62. package/helpers/main-entry.js +293 -40
  63. package/helpers/main-entry.js.map +1 -1
  64. package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
  65. package/helpers/nativeclass-esbuild-plugin.js +6 -1
  66. package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
  67. package/helpers/nativeclass-transform.d.ts +13 -0
  68. package/helpers/nativeclass-transform.js +37 -7
  69. package/helpers/nativeclass-transform.js.map +1 -1
  70. package/helpers/nativeclass-transformer-plugin.js +8 -3
  71. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  72. package/helpers/nativescript-package-resolver.js +10 -62
  73. package/helpers/nativescript-package-resolver.js.map +1 -1
  74. package/helpers/normalize-id.d.ts +42 -0
  75. package/helpers/normalize-id.js +60 -0
  76. package/helpers/normalize-id.js.map +1 -0
  77. package/helpers/ns-core-external-urls.d.ts +32 -0
  78. package/helpers/ns-core-external-urls.js +107 -0
  79. package/helpers/ns-core-external-urls.js.map +1 -0
  80. package/helpers/ns-core-url.d.ts +26 -3
  81. package/helpers/ns-core-url.js +66 -8
  82. package/helpers/ns-core-url.js.map +1 -1
  83. package/helpers/optimize-deps.d.ts +16 -0
  84. package/helpers/optimize-deps.js +17 -0
  85. package/helpers/optimize-deps.js.map +1 -0
  86. package/helpers/package-platform-aliases.js +34 -49
  87. package/helpers/package-platform-aliases.js.map +1 -1
  88. package/helpers/platform-types.d.ts +2 -0
  89. package/helpers/platform-types.js +2 -0
  90. package/helpers/platform-types.js.map +1 -0
  91. package/helpers/postcss-platform-config.d.ts +17 -1
  92. package/helpers/postcss-platform-config.js +20 -37
  93. package/helpers/postcss-platform-config.js.map +1 -1
  94. package/helpers/resolve-main-field-platform.d.ts +20 -0
  95. package/helpers/resolve-main-field-platform.js +49 -0
  96. package/helpers/resolve-main-field-platform.js.map +1 -0
  97. package/helpers/resolver.js +17 -2
  98. package/helpers/resolver.js.map +1 -1
  99. package/helpers/theme-core-plugins.js +1 -1
  100. package/helpers/theme-core-plugins.js.map +1 -1
  101. package/helpers/ts-config-paths.d.ts +32 -0
  102. package/helpers/ts-config-paths.js +143 -62
  103. package/helpers/ts-config-paths.js.map +1 -1
  104. package/helpers/typescript-check.d.ts +3 -3
  105. package/helpers/typescript-check.js +4 -4
  106. package/helpers/typescript-check.js.map +1 -1
  107. package/helpers/ui-registration.d.ts +21 -0
  108. package/helpers/ui-registration.js +156 -0
  109. package/helpers/ui-registration.js.map +1 -0
  110. package/helpers/utils.d.ts +9 -0
  111. package/helpers/utils.js +22 -2
  112. package/helpers/utils.js.map +1 -1
  113. package/helpers/vite-package-version.d.ts +7 -0
  114. package/helpers/vite-package-version.js +44 -0
  115. package/helpers/vite-package-version.js.map +1 -0
  116. package/helpers/workers.d.ts +33 -0
  117. package/helpers/workers.js +237 -10
  118. package/helpers/workers.js.map +1 -1
  119. package/hmr/client/css-handler.d.ts +2 -1
  120. package/hmr/client/css-handler.js +63 -32
  121. package/hmr/client/css-handler.js.map +1 -1
  122. package/hmr/client/css-update-overlay.d.ts +18 -0
  123. package/hmr/client/css-update-overlay.js +27 -0
  124. package/hmr/client/css-update-overlay.js.map +1 -0
  125. package/hmr/client/framework-client-strategy.d.ts +117 -0
  126. package/hmr/client/framework-client-strategy.js +18 -0
  127. package/hmr/client/framework-client-strategy.js.map +1 -0
  128. package/hmr/client/framework.d.ts +31 -0
  129. package/hmr/client/framework.js +17 -0
  130. package/hmr/client/framework.js.map +1 -0
  131. package/hmr/client/hmr-pending-overlay.d.ts +0 -14
  132. package/hmr/client/hmr-pending-overlay.js +2 -11
  133. package/hmr/client/hmr-pending-overlay.js.map +1 -1
  134. package/hmr/client/hot-context.d.ts +89 -0
  135. package/hmr/client/hot-context.js +404 -0
  136. package/hmr/client/hot-context.js.map +1 -0
  137. package/hmr/client/index.d.ts +9 -1
  138. package/hmr/client/index.js +70 -1970
  139. package/hmr/client/index.js.map +1 -1
  140. package/hmr/client/overlay-driver.d.ts +10 -0
  141. package/hmr/client/overlay-driver.js +33 -0
  142. package/hmr/client/overlay-driver.js.map +1 -0
  143. package/hmr/client/protocol-dispatch.d.ts +8 -0
  144. package/hmr/client/protocol-dispatch.js +308 -0
  145. package/hmr/client/protocol-dispatch.js.map +1 -0
  146. package/hmr/client/root-reset.d.ts +15 -0
  147. package/hmr/client/root-reset.js +358 -0
  148. package/hmr/client/root-reset.js.map +1 -0
  149. package/hmr/client/strategy-loader.d.ts +24 -0
  150. package/hmr/client/strategy-loader.js +136 -0
  151. package/hmr/client/strategy-loader.js.map +1 -0
  152. package/hmr/client/update-pipeline.d.ts +27 -0
  153. package/hmr/client/update-pipeline.js +489 -0
  154. package/hmr/client/update-pipeline.js.map +1 -0
  155. package/hmr/client/utils.d.ts +9 -1
  156. package/hmr/client/utils.js +117 -97
  157. package/hmr/client/utils.js.map +1 -1
  158. package/hmr/client/ws-transport.d.ts +21 -0
  159. package/hmr/client/ws-transport.js +323 -0
  160. package/hmr/client/ws-transport.js.map +1 -0
  161. package/hmr/entry-runtime.d.ts +2 -1
  162. package/hmr/entry-runtime.js +279 -44
  163. package/hmr/entry-runtime.js.map +1 -1
  164. package/hmr/framework-flavors.d.ts +59 -0
  165. package/hmr/framework-flavors.js +108 -0
  166. package/hmr/framework-flavors.js.map +1 -0
  167. package/hmr/frameworks/angular/build/angular-linker.d.ts +12 -0
  168. package/hmr/frameworks/angular/build/angular-linker.js +113 -0
  169. package/hmr/frameworks/angular/build/angular-linker.js.map +1 -0
  170. package/{helpers/angular → hmr/frameworks/angular/build}/inject-component-hmr-registration.js +2 -70
  171. package/hmr/frameworks/angular/build/inject-component-hmr-registration.js.map +1 -0
  172. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.d.ts +75 -0
  173. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js +221 -0
  174. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js.map +1 -0
  175. package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.js +1 -170
  176. package/hmr/frameworks/angular/build/inline-decorator-component-templates.js.map +1 -0
  177. package/hmr/frameworks/angular/build/js-lexer.d.ts +4 -0
  178. package/{helpers/angular/synthesize-decorator-ctor-parameters.js → hmr/frameworks/angular/build/js-lexer.js} +22 -96
  179. package/hmr/frameworks/angular/build/js-lexer.js.map +1 -0
  180. package/hmr/frameworks/angular/build/linker-stats.d.ts +18 -0
  181. package/hmr/frameworks/angular/build/linker-stats.js +29 -0
  182. package/hmr/frameworks/angular/build/linker-stats.js.map +1 -0
  183. package/hmr/frameworks/angular/build/shared-linker.d.ts +39 -0
  184. package/hmr/frameworks/angular/build/shared-linker.js +128 -0
  185. package/hmr/frameworks/angular/build/shared-linker.js.map +1 -0
  186. package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js +88 -0
  187. package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js.map +1 -0
  188. package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.js +1 -174
  189. package/hmr/frameworks/angular/build/synthesize-injectable-factories.js.map +1 -0
  190. package/hmr/frameworks/angular/build/ts-fallback-transform.d.ts +5 -0
  191. package/hmr/frameworks/angular/build/ts-fallback-transform.js +138 -0
  192. package/hmr/frameworks/angular/build/ts-fallback-transform.js.map +1 -0
  193. package/hmr/frameworks/angular/build/util.js.map +1 -0
  194. package/hmr/frameworks/angular/build/worker-url-preserve.d.ts +5 -0
  195. package/hmr/frameworks/angular/build/worker-url-preserve.js +140 -0
  196. package/hmr/frameworks/angular/build/worker-url-preserve.js.map +1 -0
  197. package/hmr/frameworks/angular/client/index.d.ts +0 -1
  198. package/hmr/frameworks/angular/client/index.js +360 -194
  199. package/hmr/frameworks/angular/client/index.js.map +1 -1
  200. package/hmr/frameworks/angular/client/strategy.d.ts +9 -0
  201. package/hmr/frameworks/angular/client/strategy.js +19 -0
  202. package/hmr/frameworks/angular/client/strategy.js.map +1 -0
  203. package/hmr/frameworks/angular/server/angular-root-component.d.ts +79 -0
  204. package/hmr/frameworks/angular/server/angular-root-component.js +149 -0
  205. package/hmr/frameworks/angular/server/angular-root-component.js.map +1 -0
  206. package/hmr/frameworks/angular/server/ng-component-route.d.ts +43 -0
  207. package/hmr/frameworks/angular/server/ng-component-route.js +113 -0
  208. package/hmr/frameworks/angular/server/ng-component-route.js.map +1 -0
  209. package/hmr/frameworks/angular/server/strategy.js +668 -13
  210. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  211. package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.js +2 -2
  212. package/hmr/frameworks/angular/server/websocket-angular-entry.js.map +1 -0
  213. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.d.ts +27 -11
  214. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.js +179 -107
  215. package/hmr/frameworks/angular/server/websocket-angular-hot-update.js.map +1 -0
  216. package/hmr/frameworks/react/client/strategy.d.ts +12 -0
  217. package/hmr/frameworks/react/client/strategy.js +27 -0
  218. package/hmr/frameworks/react/client/strategy.js.map +1 -0
  219. package/hmr/frameworks/react/server/strategy.d.ts +2 -0
  220. package/hmr/frameworks/react/server/strategy.js +230 -0
  221. package/hmr/frameworks/react/server/strategy.js.map +1 -0
  222. package/hmr/frameworks/solid/build/solid-jsx-deps.d.ts +15 -0
  223. package/hmr/frameworks/solid/build/solid-jsx-deps.js +178 -0
  224. package/hmr/frameworks/solid/build/solid-jsx-deps.js.map +1 -0
  225. package/hmr/frameworks/solid/client/app-runtime.d.ts +68 -0
  226. package/hmr/frameworks/solid/client/app-runtime.js +252 -0
  227. package/hmr/frameworks/solid/client/app-runtime.js.map +1 -0
  228. package/hmr/frameworks/solid/client/strategy.d.ts +7 -0
  229. package/hmr/frameworks/solid/client/strategy.js +391 -0
  230. package/hmr/frameworks/solid/client/strategy.js.map +1 -0
  231. package/hmr/frameworks/solid/server/strategy.js +293 -16
  232. package/hmr/frameworks/solid/server/strategy.js.map +1 -1
  233. package/hmr/frameworks/typescript/client/strategy.d.ts +7 -0
  234. package/hmr/frameworks/typescript/client/strategy.js +418 -0
  235. package/hmr/frameworks/typescript/client/strategy.js.map +1 -0
  236. package/hmr/frameworks/typescript/server/strategy.js +40 -14
  237. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  238. package/hmr/frameworks/vue/client/dep-propagation.d.ts +44 -0
  239. package/hmr/frameworks/vue/client/dep-propagation.js +148 -0
  240. package/hmr/frameworks/vue/client/dep-propagation.js.map +1 -0
  241. package/hmr/frameworks/vue/client/index.d.ts +10 -1
  242. package/hmr/frameworks/vue/client/index.js +270 -521
  243. package/hmr/frameworks/vue/client/index.js.map +1 -1
  244. package/hmr/frameworks/vue/client/navigate-app.d.ts +3 -0
  245. package/hmr/frameworks/vue/client/navigate-app.js +178 -0
  246. package/hmr/frameworks/vue/client/navigate-app.js.map +1 -0
  247. package/hmr/frameworks/vue/client/strategy.d.ts +33 -0
  248. package/hmr/frameworks/vue/client/strategy.js +152 -0
  249. package/hmr/frameworks/vue/client/strategy.js.map +1 -0
  250. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.d.ts +49 -0
  251. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js +124 -0
  252. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js.map +1 -0
  253. package/hmr/frameworks/vue/server/compiler.d.ts +3 -1
  254. package/hmr/frameworks/vue/server/compiler.js +3 -1
  255. package/hmr/frameworks/vue/server/compiler.js.map +1 -1
  256. package/hmr/frameworks/vue/server/sfc-route-assemble.d.ts +7 -0
  257. package/hmr/frameworks/vue/server/sfc-route-assemble.js +823 -0
  258. package/hmr/frameworks/vue/server/sfc-route-assemble.js.map +1 -0
  259. package/hmr/frameworks/vue/server/sfc-route-meta.d.ts +7 -0
  260. package/hmr/frameworks/vue/server/sfc-route-meta.js +80 -0
  261. package/hmr/frameworks/vue/server/sfc-route-meta.js.map +1 -0
  262. package/hmr/frameworks/vue/server/sfc-route-serve.d.ts +8 -0
  263. package/hmr/frameworks/vue/server/sfc-route-serve.js +462 -0
  264. package/hmr/frameworks/vue/server/sfc-route-serve.js.map +1 -0
  265. package/hmr/frameworks/vue/server/sfc-route-shared.d.ts +45 -0
  266. package/hmr/frameworks/vue/server/sfc-route-shared.js +105 -0
  267. package/hmr/frameworks/vue/server/sfc-route-shared.js.map +1 -0
  268. package/hmr/frameworks/vue/server/strategy.d.ts +35 -0
  269. package/hmr/frameworks/vue/server/strategy.js +291 -7
  270. package/hmr/frameworks/vue/server/strategy.js.map +1 -1
  271. package/hmr/frameworks/vue/server/websocket-sfc.d.ts +15 -0
  272. package/hmr/frameworks/vue/server/websocket-sfc.js +20 -0
  273. package/hmr/frameworks/vue/server/websocket-sfc.js.map +1 -0
  274. package/hmr/helpers/ast-normalizer.d.ts +3 -1
  275. package/hmr/helpers/ast-normalizer.js +109 -14
  276. package/hmr/helpers/ast-normalizer.js.map +1 -1
  277. package/hmr/helpers/package-exports.d.ts +16 -0
  278. package/hmr/helpers/package-exports.js +396 -0
  279. package/hmr/helpers/package-exports.js.map +1 -0
  280. package/hmr/helpers/vendor-rewrite.d.ts +1 -1
  281. package/hmr/helpers/vendor-rewrite.js +5 -3
  282. package/hmr/helpers/vendor-rewrite.js.map +1 -1
  283. package/hmr/server/boot-recording.d.ts +51 -0
  284. package/hmr/server/boot-recording.js +214 -0
  285. package/hmr/server/boot-recording.js.map +1 -0
  286. package/hmr/server/constants.js +7 -1
  287. package/hmr/server/constants.js.map +1 -1
  288. package/hmr/server/content-css-update.d.ts +54 -0
  289. package/hmr/server/content-css-update.js +78 -0
  290. package/hmr/server/content-css-update.js.map +1 -0
  291. package/hmr/server/core-bundle.d.ts +140 -0
  292. package/hmr/server/core-bundle.js +614 -0
  293. package/hmr/server/core-bundle.js.map +1 -0
  294. package/hmr/server/core-sanitize.d.ts +86 -7
  295. package/hmr/server/core-sanitize.js +155 -37
  296. package/hmr/server/core-sanitize.js.map +1 -1
  297. package/hmr/server/css-connect-sync.d.ts +28 -0
  298. package/hmr/server/css-connect-sync.js +59 -0
  299. package/hmr/server/css-connect-sync.js.map +1 -0
  300. package/hmr/server/css-device-module.d.ts +28 -0
  301. package/hmr/server/css-device-module.js +44 -0
  302. package/hmr/server/css-device-module.js.map +1 -0
  303. package/hmr/server/css-update-message.d.ts +23 -0
  304. package/hmr/server/css-update-message.js +41 -0
  305. package/hmr/server/css-update-message.js.map +1 -0
  306. package/hmr/server/deps-bundle.d.ts +233 -0
  307. package/hmr/server/deps-bundle.js +1022 -0
  308. package/hmr/server/deps-bundle.js.map +1 -0
  309. package/hmr/server/device-transform-helpers.d.ts +24 -0
  310. package/hmr/server/device-transform-helpers.js +408 -0
  311. package/hmr/server/device-transform-helpers.js.map +1 -0
  312. package/hmr/server/framework-strategy.d.ts +182 -11
  313. package/hmr/server/hmr-module-graph.d.ts +37 -0
  314. package/hmr/server/hmr-module-graph.js +215 -0
  315. package/hmr/server/hmr-module-graph.js.map +1 -0
  316. package/hmr/server/import-map.d.ts +57 -23
  317. package/hmr/server/import-map.js +142 -70
  318. package/hmr/server/import-map.js.map +1 -1
  319. package/hmr/server/index.js +7 -16
  320. package/hmr/server/index.js.map +1 -1
  321. package/hmr/server/node-builtins-route.d.ts +12 -0
  322. package/hmr/server/node-builtins-route.js +86 -0
  323. package/hmr/server/node-builtins-route.js.map +1 -0
  324. package/hmr/server/ns-m-response-memo.d.ts +10 -0
  325. package/hmr/server/ns-m-response-memo.js +33 -0
  326. package/hmr/server/ns-m-response-memo.js.map +1 -0
  327. package/hmr/server/ns-rt-bridge.d.ts +51 -0
  328. package/hmr/server/ns-rt-bridge.js +131 -0
  329. package/hmr/server/ns-rt-bridge.js.map +1 -0
  330. package/hmr/server/ns-rt-route.d.ts +5 -0
  331. package/hmr/server/ns-rt-route.js +39 -0
  332. package/hmr/server/ns-rt-route.js.map +1 -0
  333. package/hmr/server/perf-instrumentation.d.ts +1 -1
  334. package/hmr/server/perf-instrumentation.js +3 -1
  335. package/hmr/server/perf-instrumentation.js.map +1 -1
  336. package/hmr/server/process-code-for-device.d.ts +54 -0
  337. package/hmr/server/process-code-for-device.js +832 -0
  338. package/hmr/server/process-code-for-device.js.map +1 -0
  339. package/hmr/server/require-guard.d.ts +1 -0
  340. package/hmr/server/require-guard.js +12 -0
  341. package/hmr/server/require-guard.js.map +1 -0
  342. package/hmr/server/rewrite-imports.d.ts +2 -0
  343. package/hmr/server/rewrite-imports.js +631 -0
  344. package/hmr/server/rewrite-imports.js.map +1 -0
  345. package/hmr/server/route-helpers.d.ts +7 -0
  346. package/hmr/server/route-helpers.js +13 -0
  347. package/hmr/server/route-helpers.js.map +1 -0
  348. package/hmr/server/runtime-graph-filter.js +8 -1
  349. package/hmr/server/runtime-graph-filter.js.map +1 -1
  350. package/hmr/server/server-origin.d.ts +2 -0
  351. package/hmr/server/server-origin.js +88 -0
  352. package/hmr/server/server-origin.js.map +1 -0
  353. package/hmr/server/shared-transform-request.js +1 -2
  354. package/hmr/server/shared-transform-request.js.map +1 -1
  355. package/hmr/server/socket-utils.d.ts +10 -0
  356. package/hmr/server/socket-utils.js +14 -0
  357. package/hmr/server/socket-utils.js.map +1 -0
  358. package/hmr/server/transform-cache-invalidation.d.ts +37 -0
  359. package/hmr/server/transform-cache-invalidation.js +156 -0
  360. package/hmr/server/transform-cache-invalidation.js.map +1 -0
  361. package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
  362. package/hmr/server/vendor-bare-module-shims.js +80 -0
  363. package/hmr/server/vendor-bare-module-shims.js.map +1 -0
  364. package/hmr/server/vite-plugin.d.ts +1 -0
  365. package/hmr/server/vite-plugin.js +211 -53
  366. package/hmr/server/vite-plugin.js.map +1 -1
  367. package/hmr/server/websocket-core-bridge.d.ts +51 -4
  368. package/hmr/server/websocket-core-bridge.js +62 -49
  369. package/hmr/server/websocket-core-bridge.js.map +1 -1
  370. package/hmr/server/websocket-device-transform.d.ts +3 -0
  371. package/hmr/server/websocket-device-transform.js +7 -0
  372. package/hmr/server/websocket-device-transform.js.map +1 -0
  373. package/hmr/server/websocket-hmr-pending.d.ts +2 -16
  374. package/hmr/server/websocket-hmr-pending.js +0 -22
  375. package/hmr/server/websocket-hmr-pending.js.map +1 -1
  376. package/hmr/server/websocket-hot-update.d.ts +80 -0
  377. package/hmr/server/websocket-hot-update.js +299 -0
  378. package/hmr/server/websocket-hot-update.js.map +1 -0
  379. package/hmr/server/websocket-import-map-route.d.ts +15 -0
  380. package/hmr/server/websocket-import-map-route.js +51 -0
  381. package/hmr/server/websocket-import-map-route.js.map +1 -0
  382. package/hmr/server/websocket-module-bindings.d.ts +15 -0
  383. package/hmr/server/websocket-module-bindings.js +36 -3
  384. package/hmr/server/websocket-module-bindings.js.map +1 -1
  385. package/hmr/server/websocket-module-specifiers.d.ts +2 -5
  386. package/hmr/server/websocket-module-specifiers.js +42 -30
  387. package/hmr/server/websocket-module-specifiers.js.map +1 -1
  388. package/hmr/server/websocket-ns-core.d.ts +34 -0
  389. package/hmr/server/websocket-ns-core.js +414 -0
  390. package/hmr/server/websocket-ns-core.js.map +1 -0
  391. package/hmr/server/websocket-ns-entry.d.ts +21 -0
  392. package/hmr/server/websocket-ns-entry.js +163 -0
  393. package/hmr/server/websocket-ns-entry.js.map +1 -0
  394. package/hmr/server/websocket-ns-m-paths.d.ts +19 -3
  395. package/hmr/server/websocket-ns-m-paths.js +98 -75
  396. package/hmr/server/websocket-ns-m-paths.js.map +1 -1
  397. package/hmr/server/websocket-ns-m-request.d.ts +2 -1
  398. package/hmr/server/websocket-ns-m-request.js +3 -2
  399. package/hmr/server/websocket-ns-m-request.js.map +1 -1
  400. package/hmr/server/websocket-ns-m.d.ts +52 -0
  401. package/hmr/server/websocket-ns-m.js +592 -0
  402. package/hmr/server/websocket-ns-m.js.map +1 -0
  403. package/hmr/server/websocket-served-module-helpers.d.ts +65 -3
  404. package/hmr/server/websocket-served-module-helpers.js +457 -140
  405. package/hmr/server/websocket-served-module-helpers.js.map +1 -1
  406. package/hmr/server/websocket-txn.js +6 -9
  407. package/hmr/server/websocket-txn.js.map +1 -1
  408. package/hmr/server/websocket-vendor-unifier.d.ts +0 -1
  409. package/hmr/server/websocket-vendor-unifier.js +4 -9
  410. package/hmr/server/websocket-vendor-unifier.js.map +1 -1
  411. package/hmr/server/websocket.d.ts +6 -40
  412. package/hmr/server/websocket.js +661 -6751
  413. package/hmr/server/websocket.js.map +1 -1
  414. package/hmr/shared/ns-globals.d.ts +108 -0
  415. package/hmr/shared/ns-globals.js +29 -0
  416. package/hmr/shared/ns-globals.js.map +1 -0
  417. package/hmr/shared/protocol.d.ts +157 -0
  418. package/hmr/shared/protocol.js +28 -0
  419. package/hmr/shared/protocol.js.map +1 -0
  420. package/hmr/shared/runtime/boot-complete.d.ts +14 -0
  421. package/hmr/shared/runtime/boot-complete.js +32 -0
  422. package/hmr/shared/runtime/boot-complete.js.map +1 -0
  423. package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
  424. package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
  425. package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
  426. package/hmr/shared/runtime/boot-progress.d.ts +44 -0
  427. package/hmr/shared/runtime/boot-progress.js +134 -0
  428. package/hmr/shared/runtime/boot-progress.js.map +1 -0
  429. package/hmr/shared/runtime/boot-timeline.d.ts +1 -1
  430. package/hmr/shared/runtime/boot-timeline.js +8 -19
  431. package/hmr/shared/runtime/boot-timeline.js.map +1 -1
  432. package/hmr/shared/runtime/browser-runtime-contract.d.ts +58 -25
  433. package/hmr/shared/runtime/browser-runtime-contract.js +21 -9
  434. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -1
  435. package/hmr/shared/runtime/dev-overlay-ios.d.ts +87 -0
  436. package/hmr/shared/runtime/dev-overlay-ios.js +521 -0
  437. package/hmr/shared/runtime/dev-overlay-ios.js.map +1 -0
  438. package/hmr/shared/runtime/dev-overlay-shared.d.ts +58 -0
  439. package/hmr/shared/runtime/dev-overlay-shared.js +116 -0
  440. package/hmr/shared/runtime/dev-overlay-shared.js.map +1 -0
  441. package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
  442. package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
  443. package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
  444. package/hmr/shared/runtime/dev-overlay-tree.d.ts +59 -0
  445. package/hmr/shared/runtime/dev-overlay-tree.js +712 -0
  446. package/hmr/shared/runtime/dev-overlay-tree.js.map +1 -0
  447. package/hmr/shared/runtime/dev-overlay.d.ts +23 -69
  448. package/hmr/shared/runtime/dev-overlay.js +67 -1011
  449. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  450. package/hmr/shared/runtime/global-scope.d.ts +18 -0
  451. package/hmr/shared/runtime/global-scope.js +21 -0
  452. package/hmr/shared/runtime/global-scope.js.map +1 -0
  453. package/hmr/shared/runtime/hooks.js +2 -1
  454. package/hmr/shared/runtime/hooks.js.map +1 -1
  455. package/hmr/shared/runtime/launch-bridge.d.ts +9 -0
  456. package/hmr/shared/runtime/launch-bridge.js +98 -0
  457. package/hmr/shared/runtime/launch-bridge.js.map +1 -0
  458. package/hmr/shared/runtime/module-provenance.js +3 -2
  459. package/hmr/shared/runtime/module-provenance.js.map +1 -1
  460. package/hmr/shared/runtime/ns-runtime-test-double.d.ts +21 -0
  461. package/hmr/shared/runtime/ns-runtime-test-double.js +20 -0
  462. package/hmr/shared/runtime/ns-runtime-test-double.js.map +1 -0
  463. package/hmr/shared/runtime/overlay-flag.d.ts +9 -0
  464. package/hmr/shared/runtime/overlay-flag.js +34 -0
  465. package/hmr/shared/runtime/overlay-flag.js.map +1 -0
  466. package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
  467. package/hmr/shared/runtime/root-placeholder-view.js +311 -0
  468. package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
  469. package/hmr/shared/runtime/root-placeholder.js +382 -157
  470. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  471. package/hmr/shared/runtime/session-bootstrap.js +209 -54
  472. package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
  473. package/hmr/shared/runtime/vendor-bootstrap.js +2 -1
  474. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  475. package/hmr/shared/runtime/vendor-resolve.d.ts +22 -0
  476. package/hmr/shared/runtime/vendor-resolve.js +45 -0
  477. package/hmr/shared/runtime/vendor-resolve.js.map +1 -0
  478. package/hmr/shared/runtime/worker-tracking.d.ts +28 -0
  479. package/hmr/shared/runtime/worker-tracking.js +114 -0
  480. package/hmr/shared/runtime/worker-tracking.js.map +1 -0
  481. package/hmr/shared/vendor/manifest-collect.d.ts +4 -0
  482. package/hmr/shared/vendor/manifest-collect.js +909 -0
  483. package/hmr/shared/vendor/manifest-collect.js.map +1 -0
  484. package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
  485. package/hmr/shared/vendor/manifest-loader.js +5 -3
  486. package/hmr/shared/vendor/manifest-loader.js.map +1 -1
  487. package/hmr/shared/vendor/manifest.d.ts +10 -35
  488. package/hmr/shared/vendor/manifest.js +154 -978
  489. package/hmr/shared/vendor/manifest.js.map +1 -1
  490. package/hmr/shared/vendor/registry.d.ts +2 -0
  491. package/hmr/shared/vendor/registry.js +14 -0
  492. package/hmr/shared/vendor/registry.js.map +1 -1
  493. package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
  494. package/hmr/shared/vendor/vendor-device-shim.js +208 -0
  495. package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
  496. package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +107 -0
  497. package/hmr/shared/vendor/vendor-esbuild-plugins.js +540 -0
  498. package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
  499. package/package.json +70 -13
  500. package/runtime/core-aliases-early.js +11 -16
  501. package/runtime/core-aliases-early.js.map +1 -1
  502. package/shims/react-jsx-runtime.d.ts +4 -0
  503. package/shims/react-jsx-runtime.js +61 -0
  504. package/shims/react-jsx-runtime.js.map +1 -0
  505. package/helpers/angular/angular-linker.d.ts +0 -13
  506. package/helpers/angular/angular-linker.js +0 -185
  507. package/helpers/angular/angular-linker.js.map +0 -1
  508. package/helpers/angular/inject-component-hmr-registration.js.map +0 -1
  509. package/helpers/angular/inline-decorator-component-templates.js.map +0 -1
  510. package/helpers/angular/shared-linker.d.ts +0 -11
  511. package/helpers/angular/shared-linker.js +0 -75
  512. package/helpers/angular/shared-linker.js.map +0 -1
  513. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +0 -1
  514. package/helpers/angular/synthesize-injectable-factories.js.map +0 -1
  515. package/helpers/angular/util.js.map +0 -1
  516. package/helpers/module-runner-patch.d.ts +0 -3
  517. package/helpers/module-runner-patch.js +0 -63
  518. package/helpers/module-runner-patch.js.map +0 -1
  519. package/helpers/prelink-angular.d.ts +0 -2
  520. package/helpers/prelink-angular.js +0 -114
  521. package/helpers/prelink-angular.js.map +0 -1
  522. package/hmr/server/websocket-angular-entry.js.map +0 -1
  523. package/hmr/server/websocket-angular-hot-update.js.map +0 -1
  524. package/hmr/server/websocket-ns-m-finalize.d.ts +0 -22
  525. package/hmr/server/websocket-ns-m-finalize.js +0 -88
  526. package/hmr/server/websocket-ns-m-finalize.js.map +0 -1
  527. package/hmr/server/websocket-runtime-compat.d.ts +0 -19
  528. package/hmr/server/websocket-runtime-compat.js +0 -287
  529. package/hmr/server/websocket-runtime-compat.js.map +0 -1
  530. package/hmr/server/websocket-vue-sfc.d.ts +0 -27
  531. package/hmr/server/websocket-vue-sfc.js +0 -1069
  532. package/hmr/server/websocket-vue-sfc.js.map +0 -1
  533. package/hmr/shared/runtime/http-only-boot.d.ts +0 -2
  534. package/hmr/shared/runtime/http-only-boot.js +0 -171
  535. package/hmr/shared/runtime/http-only-boot.js.map +0 -1
  536. package/hmr/vendor-bootstrap.d.ts +0 -3
  537. package/hmr/vendor-bootstrap.js +0 -32
  538. package/hmr/vendor-bootstrap.js.map +0 -1
  539. package/shims/react-reconciler-constants.d.ts +0 -14
  540. package/shims/react-reconciler-constants.js +0 -21
  541. package/shims/react-reconciler-constants.js.map +0 -1
  542. package/shims/react-reconciler.d.ts +0 -8
  543. package/shims/react-reconciler.js +0 -15
  544. package/shims/react-reconciler.js.map +0 -1
  545. package/transformers/NativeClass/index.d.ts +0 -2
  546. package/transformers/NativeClass/index.js +0 -222
  547. package/transformers/NativeClass/index.js.map +0 -1
  548. /package/{helpers/angular → hmr/frameworks/angular/build}/inject-component-hmr-registration.d.ts +0 -0
  549. /package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.d.ts +0 -0
  550. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-decorator-ctor-parameters.d.ts +0 -0
  551. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.d.ts +0 -0
  552. /package/{helpers/angular → hmr/frameworks/angular/build}/util.d.ts +0 -0
  553. /package/{helpers/angular → hmr/frameworks/angular/build}/util.js +0 -0
  554. /package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.d.ts +0 -0
@@ -1,1998 +1,101 @@
1
1
  /**
2
- * Robust HMR client for NativeScript.
2
+ * HMR client entry for NativeScript devices.
3
3
  *
4
4
  * Avoid importing from '@nativescript/core' and other framework modules here to prevent creating a second module realm via HTTP ESM.
5
5
  * Always resolve core classes and Application from the vendor realm or globalThis at runtime.
6
6
  * The HMR client is evaluated via HTTP ESM on device; static imports would create secondary instances.
7
+ *
8
+ * This entry owns boot-time side effects (core aliases, launch-notification
9
+ * bridge, CSS register) and wires the seams together:
10
+ * - `ws-transport.ts` — socket connect/reconnect + connection overlay
11
+ * - `protocol-dispatch.ts` — routes parsed wire messages
12
+ * - `update-pipeline.ts` — graph state + evict-then-reimport queue
13
+ * - `root-reset.ts` — root-view replacement
14
+ * - `strategy-loader.ts` — flavor detection + framework strategy loading
7
15
  */
8
- import { setHMRWsUrl, getHMRWsUrl, pendingModuleFetches, deriveHttpOrigin, setHttpOriginForVite, moduleFetchCache, requestModuleFromServer, getHttpOriginForVite, normalizeSpec, hmrMetrics, graph, setGraphVersion, getGraphVersion, getCurrentApp, getRootFrame, setCurrentApp, setRootFrame, getCore, hasExplicitEviction, invalidateModulesByUrls, buildEvictionUrls, emitHmrModeBannerOnce } from './utils.js';
9
- import { handleCssUpdates } from './css-handler.js';
10
- const VERBOSE = typeof __NS_ENV_VERBOSE__ !== 'undefined' && __NS_ENV_VERBOSE__;
11
- function resolveTargetFlavor() {
12
- try {
13
- if (typeof __NS_TARGET_FLAVOR__ !== 'undefined' && __NS_TARGET_FLAVOR__) {
14
- return __NS_TARGET_FLAVOR__;
15
- }
16
- }
17
- catch { }
18
- try {
19
- const g = globalThis;
20
- if (typeof g.__NS_TARGET_FLAVOR__ === 'string' && g.__NS_TARGET_FLAVOR__) {
21
- return g.__NS_TARGET_FLAVOR__;
22
- }
23
- if (typeof g.__NS_HMR_BROWSER_RUNTIME_TARGET_FLAVOR__ === 'string' && g.__NS_HMR_BROWSER_RUNTIME_TARGET_FLAVOR__) {
24
- return g.__NS_HMR_BROWSER_RUNTIME_TARGET_FLAVOR__;
25
- }
26
- if (typeof g.__reboot_ng_modules__ === 'function') {
27
- return 'angular';
28
- }
29
- if (g.__VUE_HMR_RUNTIME__ || g.__NS_HMR_VUE_SFC_REGISTRY__) {
30
- return 'vue';
31
- }
32
- }
33
- catch { }
34
- return undefined;
35
- }
36
- const TARGET_FLAVOR = resolveTargetFlavor();
37
- try {
38
- if (TARGET_FLAVOR && !globalThis.__NS_TARGET_FLAVOR__) {
39
- globalThis.__NS_TARGET_FLAVOR__ = TARGET_FLAVOR;
40
- }
41
- }
42
- catch { }
43
- const APP_ROOT_VIRTUAL = typeof __NS_APP_ROOT_VIRTUAL__ === 'string' && __NS_APP_ROOT_VIRTUAL__ ? __NS_APP_ROOT_VIRTUAL__ : '/src';
44
- const APP_VIRTUAL_WITH_SLASH = APP_ROOT_VIRTUAL.endsWith('/') ? APP_ROOT_VIRTUAL : `${APP_ROOT_VIRTUAL}/`;
45
- const APP_MAIN_ENTRY_SPEC = `${APP_VIRTUAL_WITH_SLASH}app.ts`;
46
- // Policy: by default, let the app's own main entry mount initially; HMR client handles updates/remounts only.
47
- // Flip this to true via global __NS_HMR_ALLOW_INITIAL_MOUNT__ if you need the client to perform the first mount.
48
- const ALLOW_INITIAL_MOUNT = !!globalThis.__NS_HMR_ALLOW_INITIAL_MOUNT__;
49
- // Ensure core aliases are present on globalThis early so that /ns/rt exports resolve to functions
16
+ import { setHMRWsUrl, getHMRWsUrl, getCore, ENV_VERBOSE } from './utils.js';
17
+ import { applyCssText } from './css-handler.js';
18
+ import { getGlobalScope } from '../shared/runtime/global-scope.js';
19
+ import { installLaunchNotificationBridge } from '../shared/runtime/launch-bridge.js';
20
+ import { connectHmr, setHmrMessageHandler } from './ws-transport.js';
21
+ import { handleHmrMessage } from './protocol-dispatch.js';
22
+ import { ensureCoreAliasesOnGlobalThis, performResetRoot } from './root-reset.js';
23
+ import { CLIENT_STRATEGY_READY, getClientStrategy } from './strategy-loader.js';
24
+ const VERBOSE = ENV_VERBOSE;
25
+ // Apply once on module evaluation so that /ns/rt exports resolve to functions
50
26
  // before any SFCs are evaluated during HTTP-only dev boot.
51
- function ensureCoreAliasesOnGlobalThis() {
52
- const g = globalThis;
53
- try {
54
- const F = getCore('Frame') || g.Frame;
55
- const A = getCore('Application') || g.Application;
56
- const P = getCore('Page') || g.Page;
57
- // Publish to globalThis if missing
58
- try {
59
- if (F && !g.Frame)
60
- g.Frame = F;
61
- }
62
- catch { }
63
- try {
64
- if (A && (!g.Application || typeof g.Application.run !== 'function' || typeof g.Application.on !== 'function' || typeof g.Application.resetRootView !== 'function')) {
65
- g.Application = A;
66
- }
67
- }
68
- catch { }
69
- try {
70
- if (P && !g.Page)
71
- g.Page = P;
72
- }
73
- catch { }
74
- }
75
- catch { }
76
- }
77
- // Apply once on module evaluation
78
27
  ensureCoreAliasesOnGlobalThis();
79
- function getHmrOverlayApi() {
80
- try {
81
- return globalThis.__NS_HMR_DEV_OVERLAY__ || null;
82
- }
83
- catch { }
84
- return null;
85
- }
86
- function setConnectionOverlayStage(stage, detail) {
87
- try {
88
- const api = getHmrOverlayApi();
89
- if (api && typeof api.setConnectionStage === 'function') {
90
- api.setConnectionStage(stage, { detail });
91
- }
92
- }
93
- catch { }
94
- }
95
- function hideConnectionOverlay() {
96
- try {
97
- const api = getHmrOverlayApi();
98
- if (api && typeof api.hide === 'function') {
99
- api.hide('healthy');
100
- }
101
- }
102
- catch { }
103
- }
104
- // Eagerly drive the HMR-applying overlay's 'received' frame as soon
105
- // as the server emits `ns:hmr-pending`, BEFORE the framework-specific
106
- // (`ns:angular-update` / `ns:css-updates`) payload arrives. The
107
- // flavor-specific handler later walks through 'evicting' →
108
- // 'reimporting' → 'rebooting' → 'complete'. Calling 'received' twice
109
- // in the same cycle is safe: the overlay preserves
110
- // `updateCycleStartedAt` when a 'received' frame replaces an existing
111
- // 'received' frame so the minimum-visible window is still timed
112
- // against the FIRST frame.
28
+ // Late-registration bridge for one-shot iOS launch notifications
29
+ // (see shared/runtime/launch-bridge.ts).
113
30
  //
114
- // Soft-fails when the overlay isn't installed (production builds,
115
- // vitest, etc.) or when the user opted out via
116
- // `__NS_HMR_PROGRESS_OVERLAY_ENABLED__ === false`.
117
- import { applyHmrPendingFrame } from './hmr-pending-overlay.js';
118
- function setHmrPendingOverlay(filePath) {
119
- applyHmrPendingFrame(filePath, { getOverlay: getHmrOverlayApi });
120
- }
121
- let connectionOverlayTimer = null;
122
- let connectionOverlayVisible = false;
123
- let hasOpenedHmrSocket = false;
124
- let awaitingHealthyHmrMessage = false;
125
- let pendingConnectionOverlayStage = 'connecting';
126
- let pendingConnectionOverlayDetail = '';
127
- function clearConnectionOverlayTimer() {
128
- if (connectionOverlayTimer) {
129
- clearTimeout(connectionOverlayTimer);
130
- connectionOverlayTimer = null;
131
- }
132
- }
133
- function showConnectionOverlayNow(stage, detail) {
134
- pendingConnectionOverlayStage = stage;
135
- pendingConnectionOverlayDetail = detail || '';
136
- connectionOverlayVisible = true;
137
- setConnectionOverlayStage(stage, detail);
138
- }
139
- function scheduleConnectionOverlay(stage, detail, delayMs = 1200) {
140
- pendingConnectionOverlayStage = stage;
141
- pendingConnectionOverlayDetail = detail || '';
142
- clearConnectionOverlayTimer();
143
- connectionOverlayTimer = setTimeout(() => {
144
- showConnectionOverlayNow(pendingConnectionOverlayStage, pendingConnectionOverlayDetail);
145
- }, delayMs);
146
- }
147
- function updateConnectionOverlay(stage, detail) {
148
- pendingConnectionOverlayStage = stage;
149
- pendingConnectionOverlayDetail = detail || '';
150
- if (connectionOverlayVisible) {
151
- showConnectionOverlayNow(stage, detail);
152
- }
153
- }
154
- function markHmrConnectionHealthy() {
155
- awaitingHealthyHmrMessage = false;
156
- clearConnectionOverlayTimer();
157
- if (connectionOverlayVisible) {
158
- connectionOverlayVisible = false;
159
- hideConnectionOverlay();
160
- }
161
- }
162
- /**
163
- * Flavor hooks
164
- */
165
- import { installNsVueDevShims, ensureBackWrapperInstalled, getRootForVue, loadSfcComponent, ensureVueGlobals, ensurePiniaOnApp, addSfcMapping, recordVuePayloadChanges, handleVueSfcRegistry, handleVueSfcRegistryUpdate, sfcArtifactMap } from '../frameworks/vue/client/index.js';
166
- import { handleAngularHotUpdateMessage, installAngularHmrClientHooks } from '../frameworks/angular/client/index.js';
167
- switch (TARGET_FLAVOR) {
168
- case 'vue':
169
- installNsVueDevShims();
170
- break;
171
- case 'angular':
172
- installAngularHmrClientHooks();
173
- break;
174
- }
175
- // Track whether we've mounted an initial app root yet in HTTP-only boot
176
- let initialMounted = !!globalThis.__NS_HMR_BOOT_COMPLETE__;
177
- // Prevent duplicate initial-mount scheduling across rapid full-graph broadcasts and re-evaluations
178
- let initialMounting = !!globalThis.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__;
179
- // Track whether the first full-graph has been received. Before the full-graph,
180
- // delta messages are just the server discovering modules during initial boot —
181
- // NOT actual code changes. Re-imports must be gated behind this flag.
182
- let hasReceivedFullGraph = false;
183
- // TypeScript flavor: track registry modules and inferred main id
184
- let tsModuleSet = null;
185
- let tsMainId = null;
186
- const changedQueue = [];
187
- let processingQueue = false;
188
- let processingPromise = null;
189
- // Detect whether the early placeholder root is still active on screen
190
- function isPlaceholderActive() {
191
- try {
192
- const g = globalThis;
193
- if (g.__NS_DEV_PLACEHOLDER_ROOT_VIEW__)
194
- return true;
195
- if (g.__NS_DEV_PLACEHOLDER_ROOT_EARLY__)
196
- return true;
197
- }
198
- catch { }
199
- return false;
200
- }
201
- // Navigation queue removed: we navigate immediately or throw with a clear error
202
- // Robust navigation fallback: create a sub-app and mount it on a new Page, then navigate there.
203
- // __nsNavigateWithSubApp removed: no navigation fallbacks are used
204
- function applyFullGraph(payload) {
205
- if (typeof payload.version !== 'number' || !Array.isArray(payload.modules))
206
- return;
207
- graph.clear();
208
- payload.modules.forEach((m) => {
209
- if (m && m.id)
210
- graph.set(m.id, { id: m.id, deps: m.deps || [], hash: m.hash || '' });
211
- });
212
- setGraphVersion(payload.version);
213
- if (VERBOSE)
214
- console.log('[hmr][graph] full graph applied version', getGraphVersion(), 'modules=', graph.size);
215
- // Guarded initial mount rescue: if app hasn't replaced the placeholder shortly after graph arrives,
216
- // perform a one-time mount. This waits briefly to let the app's main entry start() run first to avoid double mounts.
217
- // TypeScript flavor: skip the rescue entirely. The HTTP boot will load main.ts which
218
- // calls Application.run() (patched to resetRootView) — the rescue is redundant and
219
- // causes a double-mount race (rescue fires at 450ms, then main.ts fires ~1s later,
220
- // causing a visual flash and leaving the app in an inconsistent state).
221
- try {
222
- const g = globalThis;
223
- const bootDone = !!g.__NS_HMR_BOOT_COMPLETE__;
224
- if (!bootDone && !initialMounted && !initialMounting && !g.__NS_HMR_RESCUE_SCHEDULED__ && TARGET_FLAVOR !== 'typescript') {
225
- // simple snapshot helpers
226
- const getTopmost = () => {
227
- try {
228
- const F = getCore('Frame') || g.Frame;
229
- return F?.topmost?.() || null;
230
- }
231
- catch {
232
- return null;
233
- }
234
- };
235
- const isPlaceholderView = (v) => {
236
- try {
237
- if (!v)
238
- return false;
239
- if (v === (g.__NS_DEV_PLACEHOLDER_ROOT_VIEW__ || null))
240
- return true;
241
- return !!v.__ns_dev_placeholder;
242
- }
243
- catch {
244
- return false;
245
- }
246
- };
247
- const hasRealRoot = () => {
248
- try {
249
- const fr = getTopmost();
250
- if (!fr)
251
- return false;
252
- if (isPlaceholderView(fr))
253
- return false;
254
- const pg = fr.currentPage || fr._currentEntry?.resolvedPage;
255
- if (!pg)
256
- return false;
257
- if (isPlaceholderView(pg))
258
- return false;
259
- return true;
260
- }
261
- catch {
262
- return false;
263
- }
264
- };
265
- try {
266
- g.__NS_HMR_RESCUE_SCHEDULED__ = true;
267
- }
268
- catch { }
269
- setTimeout(() => {
270
- try {
271
- if (g.__NS_HMR_BOOT_COMPLETE__)
272
- return; // app already mounted
273
- if (hasRealRoot()) {
274
- try {
275
- g.__NS_HMR_BOOT_COMPLETE__ = true;
276
- }
277
- catch { }
278
- if (VERBOSE)
279
- console.log('[hmr][init] detected real root after delay; skipping client initial mount');
280
- // Detach placeholder handler if still present
281
- try {
282
- const restore = g.__NS_DEV_RESTORE_PLACEHOLDER__;
283
- if (typeof restore === 'function')
284
- restore();
285
- }
286
- catch { }
287
- return;
288
- }
289
- // If placeholder still active and no real root, try a one-time gentle initial mount.
290
- // Vue: prefer SFCs; TypeScript: import the app main TS module and let performResetRoot handle it once.
291
- const placeholderActive = isPlaceholderActive();
292
- if (!placeholderActive)
293
- return;
294
- if (VERBOSE)
295
- console.log('[hmr][init] placeholder persists after delay; evaluating rescue policy');
296
- // Flavor-specific rescue handling
297
- if (TARGET_FLAVOR === 'typescript') {
298
- // For TS apps, perform a one-time resetRootView to the conventional
299
- // app root module. This mimics what Application.run would do and
300
- // replaces the placeholder with the real UI without trying to
301
- // treat app.ts as a component.
302
- try {
303
- const App = getCore('Application') || g.Application;
304
- if (App && typeof App.resetRootView === 'function') {
305
- if (VERBOSE)
306
- console.log('[hmr][init] TS flavor: performing rescue resetRootView to moduleName=app-root');
307
- initialMounting = true;
308
- try {
309
- g.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = true;
310
- }
311
- catch { }
312
- App.resetRootView({ moduleName: 'app-root' });
313
- initialMounted = true;
314
- try {
315
- g.__NS_HMR_BOOT_COMPLETE__ = true;
316
- }
317
- catch { }
318
- if (VERBOSE)
319
- console.log('[hmr][init] TS rescue resetRootView complete');
320
- }
321
- else if (VERBOSE) {
322
- console.warn('[hmr][init] TS flavor: Application.resetRootView unavailable; cannot perform rescue');
323
- }
324
- }
325
- catch (e) {
326
- console.warn('[hmr][init] TS rescue resetRootView failed', e);
327
- }
328
- finally {
329
- initialMounting = false;
330
- try {
331
- g.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = false;
332
- }
333
- catch { }
334
- }
335
- return;
336
- }
337
- let candidate = null;
338
- switch (TARGET_FLAVOR) {
339
- case 'vue': {
340
- const appEntry = graph.get(APP_MAIN_ENTRY_SPEC);
341
- if (appEntry && Array.isArray(appEntry.deps)) {
342
- const vueDep = appEntry.deps.find((d) => typeof d === 'string' && /\.vue$/i.test(d));
343
- if (vueDep)
344
- candidate = vueDep;
345
- }
346
- if (!candidate) {
347
- for (const id of graph.keys()) {
348
- if (/\.vue$/i.test(id)) {
349
- candidate = id;
350
- break;
351
- }
352
- }
353
- }
354
- // Fallback: when the module graph is empty (Vite 7+ may not populate it
355
- // before the first full-graph broadcast), check the SFC artifact registry
356
- // which is populated from the ns:vue-sfc-registry message.
357
- if (!candidate && sfcArtifactMap.size > 0) {
358
- for (const id of sfcArtifactMap.keys()) {
359
- if (/\.vue$/i.test(id)) {
360
- candidate = id;
361
- if (VERBOSE)
362
- console.log('[hmr][init] rescue candidate from SFC registry:', id);
363
- break;
364
- }
365
- }
366
- }
367
- break;
368
- }
369
- }
370
- if (!candidate)
371
- return;
372
- initialMounting = true;
373
- try {
374
- g.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = true;
375
- }
376
- catch { }
377
- (async () => {
378
- try {
379
- let comp = null;
380
- switch (TARGET_FLAVOR) {
381
- case 'vue':
382
- comp = await loadSfcComponent(candidate, 'initial_mount_rescue');
383
- break;
384
- }
385
- if (!comp)
386
- return;
387
- const ok = await performResetRoot(comp);
388
- if (ok) {
389
- initialMounted = true;
390
- try {
391
- g.__NS_HMR_BOOT_COMPLETE__ = true;
392
- }
393
- catch { }
394
- if (VERBOSE)
395
- console.log('[hmr][init] initial mount (rescue) complete');
396
- }
397
- }
398
- catch (e) {
399
- console.warn('[hmr][init] initial mount (rescue) error', e);
400
- }
401
- finally {
402
- initialMounting = false;
403
- try {
404
- g.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = false;
405
- }
406
- catch { }
407
- }
408
- })();
409
- }
410
- catch { }
411
- }, 450);
412
- }
413
- }
414
- catch { }
415
- // On first full graph, if we have not mounted yet, attempt an initial mount
416
- // by choosing a likely root component for the active flavor and performing a resetRootView with it.
417
- try {
418
- // Short-circuit if boot is complete or an initial mount is already underway (across realms/evals)
419
- const bootDone = !!globalThis.__NS_HMR_BOOT_COMPLETE__;
420
- const bootInProgress = !!globalThis.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ || initialMounting;
421
- // Only allow initial mount when explicitly enabled. Rely on the app's own main entry start() for the first mount
422
- // to avoid double-mount races that can cause duplicate navigation logs.
423
- if (ALLOW_INITIAL_MOUNT && !initialMounted && !bootDone && !bootInProgress && !getCurrentApp() && !getRootFrame()) {
424
- let candidate = null;
425
- switch (TARGET_FLAVOR) {
426
- case 'vue': {
427
- const appEntry = graph.get(APP_MAIN_ENTRY_SPEC);
428
- if (appEntry && Array.isArray(appEntry.deps)) {
429
- const vueDep = appEntry.deps.find((d) => typeof d === 'string' && /\.vue$/i.test(d));
430
- if (vueDep)
431
- candidate = vueDep;
432
- }
433
- if (!candidate) {
434
- for (const id of graph.keys()) {
435
- if (/\.vue$/i.test(id)) {
436
- candidate = id;
437
- break;
438
- }
439
- }
440
- }
441
- // Fallback: SFC registry (same as rescue mount above)
442
- if (!candidate && sfcArtifactMap.size > 0) {
443
- for (const id of sfcArtifactMap.keys()) {
444
- if (/\.vue$/i.test(id)) {
445
- candidate = id;
446
- if (VERBOSE)
447
- console.log('[hmr][init] initial mount candidate from SFC registry:', id);
448
- break;
449
- }
450
- }
451
- }
452
- break;
453
- }
454
- case 'typescript': {
455
- // For TS flavor, do not perform client-driven initial mount; rely on Application.run.
456
- return;
457
- }
458
- }
459
- if (candidate) {
460
- // Mark initial-mount in progress (both module-local and global) BEFORE scheduling async work
461
- initialMounting = true;
462
- try {
463
- globalThis.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = true;
464
- }
465
- catch { }
466
- (async () => {
467
- try {
468
- if (VERBOSE)
469
- console.log('[hmr][init] mounting initial root from', candidate, 'flavor=', TARGET_FLAVOR);
470
- // Android-only: avoid racing entry-runtime reset and Activity bring-up
471
- try {
472
- const g = globalThis;
473
- const App = getCore('Application') || g.Application;
474
- const isAndroid = !!(App && App.android !== undefined);
475
- if (isAndroid) {
476
- const ready = async (ms = 8000, step = 60) => {
477
- const start = Date.now();
478
- const ok = () => {
479
- try {
480
- const a = App.android;
481
- const act = a && (a.foregroundActivity || a.startActivity);
482
- const inProg = !!g.__NS_DEV_RESET_IN_PROGRESS__;
483
- return !!act && !inProg;
484
- }
485
- catch {
486
- return false;
487
- }
488
- };
489
- while (Date.now() - start < ms) {
490
- if (ok())
491
- return true;
492
- await new Promise((r) => setTimeout(r, step));
493
- }
494
- return ok();
495
- };
496
- const ok = await ready(8000, 60);
497
- if (!ok && VERBOSE)
498
- console.warn('[hmr][init] proceeding without explicit boot-ready signal (timeout)');
499
- }
500
- }
501
- catch { }
502
- let comp = null;
503
- switch (TARGET_FLAVOR) {
504
- case 'vue':
505
- comp = await loadSfcComponent(candidate, 'initial_mount');
506
- break;
507
- case 'typescript':
508
- try {
509
- const url = await requestModuleFromServer(candidate);
510
- const mod = await import(/* @vite-ignore */ url);
511
- comp = mod && (mod.default || mod);
512
- }
513
- catch (e) {
514
- if (VERBOSE)
515
- console.warn('[hmr][init] TS initial mount failed to import', candidate, e);
516
- }
517
- break;
518
- }
519
- if (comp) {
520
- const ok = await performResetRoot(comp);
521
- if (ok) {
522
- initialMounted = true;
523
- try {
524
- globalThis.__NS_HMR_BOOT_COMPLETE__ = true;
525
- }
526
- catch { }
527
- if (VERBOSE)
528
- console.log('[hmr][init] initial mount complete');
529
- }
530
- else if (VERBOSE) {
531
- console.warn('[hmr][init] initial mount did not verify; will rely on subsequent retries');
532
- }
533
- }
534
- else if (VERBOSE) {
535
- console.warn('[hmr][init] failed to load initial component from', candidate);
536
- }
537
- }
538
- catch (e) {
539
- console.warn('[hmr][init] initial mount error', e);
540
- }
541
- finally {
542
- // Clear in-progress flag regardless of outcome to allow future retries if needed
543
- initialMounting = false;
544
- try {
545
- globalThis.__NS_HMR_INITIAL_MOUNT_IN_PROGRESS__ = false;
546
- }
547
- catch { }
548
- }
549
- })();
550
- }
551
- else if (VERBOSE) {
552
- console.warn('[hmr][init] no component found in graph to mount initially for flavor', TARGET_FLAVOR);
553
- }
554
- }
555
- }
556
- catch { }
557
- }
558
- function applyDelta(payload) {
559
- // If versions are out of sync, request a full graph resync, but still
560
- // opportunistically queue the changed ids so the client can react once
561
- // the resync arrives. This is especially important for simple TS flavors
562
- // where we only need a signal that "something changed" to trigger a
563
- // resetRootView-driven hot update.
564
- const currentVersion = getGraphVersion();
565
- const versionMatches = payload.baseVersion === currentVersion;
566
- if (!versionMatches) {
567
- if (VERBOSE)
568
- console.warn('[hmr][graph] version mismatch requesting resync', payload.baseVersion, currentVersion);
569
- try {
570
- hmrSocket?.send(JSON.stringify({ type: 'ns:hmr-resync-request' }));
571
- }
572
- catch { }
573
- }
574
- if (versionMatches) {
575
- setGraphVersion(payload.newVersion);
576
- }
577
- const changed = payload.changed || [];
578
- switch (TARGET_FLAVOR) {
579
- case 'vue':
580
- recordVuePayloadChanges(changed, getGraphVersion());
581
- break;
582
- }
583
- (payload.changed || []).forEach((m) => {
584
- if (!m || !m.id)
585
- return;
586
- // Always update the local graph view with the announced module metadata
587
- graph.set(m.id, { id: m.id, deps: m.deps || [], hash: m.hash || '' });
588
- });
589
- (payload.removed || []).forEach((r) => {
590
- graph.delete(r);
591
- });
592
- if (VERBOSE)
593
- console.log('[hmr][graph] delta applied newVersion', getGraphVersion(), 'changed=', (payload.changed || []).length, 'removed=', (payload.removed || []).length, 'baseVersion=', payload.baseVersion);
594
- // Queue evaluation of changed modules (placeholder pipeline)
595
- if (payload.changed?.length) {
596
- // Gate: Before the first full-graph is received, delta messages are the server
597
- // discovering modules during initial boot — NOT actual code changes. The entry-runtime
598
- // already loaded all modules; re-importing them would cause duplicate Application.run(),
599
- // router initialization, and modal conflicts. Only queue re-imports after the first
600
- // full-graph confirms the graph is synced and subsequent deltas are real changes.
601
- if (!hasReceivedFullGraph) {
602
- if (VERBOSE)
603
- console.log('[hmr][delta] skipping re-import queue (initial graph build, no full-graph yet)');
604
- return;
605
- }
606
- // HARD SUPPRESS: the very first delta (baseVersion 0) commonly includes the app main entry which is already evaluated during bootstrap.
607
- // Importing it again with a cache-bust often produces a spurious module-not-found (timestamp param treated as distinct file).
608
- const isInitial = payload.baseVersion === 0;
609
- // Filter out virtual helper ids (e.g. '\0plugin-vue:export-helper') which we do not evaluate directly
610
- const realIds = payload.changed.map((c) => c.id).filter((id) => !/^\0|^\/\0|plugin-vue:export-helper/.test(id));
611
- // Proactively prefetch core/src deps for any changed .vue SFCs (before registry update triggers reset)
612
- try {
613
- for (const entry of payload.changed || []) {
614
- if (!entry || !/\.vue$/i.test(entry.id))
615
- continue;
616
- const deps = Array.isArray(entry.deps) ? entry.deps : [];
617
- const prefetchTargets = deps.filter((d) => /^\//.test(d) && !/node_modules/.test(d) && !/\.vue$/i.test(d));
618
- if (prefetchTargets.length && VERBOSE)
619
- console.log('[hmr][prefetch] SFC deps', entry.id, '->', prefetchTargets);
620
- for (const dep of prefetchTargets) {
621
- const norm = normalizeSpec(dep);
622
- // Skip if we already wrote it (basic heuristic: moduleFetchCache has it or path exists in Documents/_ns_hmr)
623
- if (moduleFetchCache.has(norm))
624
- continue;
625
- // Fire and forget; ensure rejection does not break HMR pipeline
626
- requestModuleFromServer(norm).catch(() => { });
627
- }
628
- }
629
- }
630
- catch (e) {
631
- if (VERBOSE)
632
- console.warn('[hmr][prefetch] failed', e);
633
- }
634
- const isAppMainEntryId = (value) => value.endsWith(APP_MAIN_ENTRY_SPEC);
635
- for (const id of realIds) {
636
- // We now rely on SFC registry update events to trigger root resets for .vue files directly
637
- if (/\.vue$/i.test(id)) {
638
- if (VERBOSE)
639
- console.log('[hmr][delta] skipping queue for .vue id; will handle on registry update', id);
640
- continue;
641
- }
642
- if (isInitial && isAppMainEntryId(id)) {
643
- if (VERBOSE)
644
- console.log(`[hmr][delta] suppressing initial ${APP_MAIN_ENTRY_SPEC} evaluation`);
645
- continue;
646
- }
647
- if (isAppMainEntryId(id)) {
648
- try {
649
- const exists = globalThis.require?.(id) || globalThis.__nsGetModuleExports?.(id);
650
- if (!exists && VERBOSE)
651
- console.log(`[hmr][delta] skipping unresolved ${APP_MAIN_ENTRY_SPEC} change`);
652
- if (!exists)
653
- continue;
654
- }
655
- catch {
656
- /* ignore */
657
- }
658
- }
659
- changedQueue.push(id);
660
- }
661
- if (changedQueue.length)
662
- processQueue();
663
- }
664
- }
665
- // Deterministic navigation using the current Vue app instance rather than vendor-held rootApp
666
- function __nsNavigateUsingApp(comp, opts = {}) {
667
- const g = globalThis;
668
- switch (TARGET_FLAVOR) {
669
- case 'vue':
670
- ensureVueGlobals();
671
- break;
672
- }
673
- const AppFactory = g.createApp;
674
- const RootCtor = g.NSVRoot;
675
- if (typeof AppFactory !== 'function' || typeof RootCtor !== 'function') {
676
- throw new Error('Vue runtime not initialized');
677
- }
31
+ // Under a webpack (or non-HMR vite) build the app bundle evaluates BEFORE
32
+ // `UIApplicationMain` finishes launching, so
33
+ // `Application.ios.addNotificationObserver(UIApplicationDidFinishLaunchingNotification, cb)`
34
+ // registers in time. Under the HTTP dev session UIKit is fully launched long
35
+ // before the app graph evaluates — those observers register AFTER the
36
+ // notification fired and are never called, so apps that gate SDK init (auth,
37
+ // Firebase, Sentry) behind didFinishLaunching silently never initialize. The
38
+ // bridge wraps `addNotificationObserver` so a post-launch registration for
39
+ // Did/WillFinishLaunching still registers normally AND has its callback
40
+ // invoked on the next macrotask with a synthesized NSNotification.
41
+ //
42
+ // The DETERMINISTIC install happens in the /__ns_dev__/client bootstrap
43
+ // wrapper, which runs before the app entry. This module-eval attempt and the
44
+ // global hook are belt-and-braces for exotic boot paths — this client
45
+ // evaluates async and can lose the race against the entry graph, so it must
46
+ // never be the only wrap.
47
+ function tryInstallLaunchNotificationBridge(attempts, explicitApplication) {
48
+ let wrappedAny = false;
678
49
  try {
679
- const top = (g.Frame && g.Frame.topmost && g.Frame.topmost()) || null;
680
- const ctor = top && top.constructor && top.constructor.name;
681
- if (VERBOSE)
682
- console.log('[app-nav] begin', {
683
- hmrRealm: g.__NS_HMR_REALM__ || 'unknown',
684
- rtRealm: g.__NS_RT_REALM__ || 'unknown',
685
- topCtor: ctor,
686
- hasTop: !!top,
687
- });
50
+ wrappedAny = installLaunchNotificationBridge(explicitApplication, [getCore('Application')]);
688
51
  }
689
52
  catch { }
690
- // Build a fresh Page each time the factory is invoked to avoid reusing a Page instance
691
- // across fragment recreations (Android) or multiple frame attachments.
692
- const buildTarget = () => {
693
- const existingApp = getCurrentApp();
694
- const baseProvides = (existingApp && existingApp._context && existingApp._context.provides) || {};
695
- const app = AppFactory(normalizeComponent(comp, comp && (comp.__name || comp.name)));
696
- switch (TARGET_FLAVOR) {
697
- case 'vue':
698
- ensurePiniaOnApp(app);
699
- break;
700
- }
701
- try {
702
- const registry = g.__nsVendorRegistry;
703
- const req = registry?.get ? g.__nsVendorRequire || g.__nsRequire || g.require : g.__nsRequire || g.require;
704
- let rh = null;
705
- if (registry && registry.has('nativescript-vue/dist/runtimeHelpers'))
706
- rh = registry.get('nativescript-vue/dist/runtimeHelpers');
707
- if (!rh && typeof req === 'function') {
708
- try {
709
- rh = req('nativescript-vue/dist/runtimeHelpers');
710
- }
711
- catch { }
712
- }
713
- const setRootApp = rh && (rh.setRootApp || rh.default?.setRootApp);
714
- if (typeof setRootApp === 'function')
715
- setRootApp(app);
716
- }
717
- catch { }
718
- try {
719
- const ctx = app?._context;
720
- if (ctx) {
721
- const prov = (ctx.provides || (ctx.provides = {}));
722
- Object.getOwnPropertyNames(baseProvides).forEach((k) => {
723
- if (!Object.prototype.hasOwnProperty.call(prov, k))
724
- prov[k] = baseProvides[k];
725
- });
726
- Object.getOwnPropertySymbols(baseProvides).forEach((s) => {
727
- if (!Object.prototype.hasOwnProperty.call(prov, s))
728
- prov[s] = baseProvides[s];
729
- });
730
- }
731
- }
732
- catch { }
733
- const root = new RootCtor();
734
- const vm = typeof app.runWithContext === 'function' ? app.runWithContext(() => app.mount(root)) : app.mount(root);
735
- setCurrentApp(app);
736
- const el = vm?.$el;
737
- const nativeView = el?.nativeView;
738
- if (!nativeView)
739
- throw new Error('navigation mount did not yield a nativeView');
740
- const P = getCore('Page');
741
- const ctorName = String(nativeView?.constructor?.name || '').replace(/^_+/, '');
742
- if (ctorName === 'Page' || /^Page(\$\d+)?$/.test(ctorName)) {
743
- return nativeView;
744
- }
745
- if (typeof P === 'function') {
746
- const pg = new P();
747
- pg.content = nativeView;
748
- // Hide default ActionBar for wrapped views to avoid double bars
749
- try {
750
- pg.actionBarHidden = true;
751
- }
752
- catch { }
753
- return pg;
754
- }
755
- return nativeView; // fallback
756
- };
757
- let frame = opts && opts.frame ? opts.frame : getRootFrame();
758
- if (!frame) {
759
- const F = getCore('Frame');
760
- frame = F && typeof F.topmost === 'function' ? F.topmost() : null;
53
+ if (!wrappedAny && attempts > 0) {
54
+ setTimeout(() => tryInstallLaunchNotificationBridge(attempts - 1, explicitApplication), 100);
761
55
  }
762
- if (!frame) {
763
- const GApp = getCore('Application') || g.Application;
764
- const F = getCore('Frame');
765
- if (typeof GApp?.resetRootView === 'function' && typeof F === 'function') {
766
- GApp.resetRootView({
767
- create: () => {
768
- const fr = new F();
769
- const navEntry = {
770
- create: () => buildTarget(),
771
- clearHistory: true,
772
- animated: false,
773
- };
774
- try {
775
- fr.navigate(navEntry);
776
- }
777
- catch { }
778
- setRootFrame(fr);
779
- return fr;
780
- },
781
- });
782
- return undefined;
783
- }
784
- throw new Error('Application.resetRootView unavailable');
785
- }
786
- const navEntry = { create: () => buildTarget(), ...(opts || {}) };
787
- frame.navigate(navEntry);
788
- return undefined;
789
56
  }
790
- // Expose deterministic app navigation globally so /ns/rt can guarantee single-path navigation
57
+ tryInstallLaunchNotificationBridge(100);
791
58
  try {
792
- globalThis.__nsNavigateUsingApp = __nsNavigateUsingApp;
59
+ globalThis.__NS_DEV_INSTALL_LAUNCH_BRIDGE__ = (explicitApplication) => tryInstallLaunchNotificationBridge(100, explicitApplication);
793
60
  }
794
61
  catch { }
795
- async function processQueue() {
796
- if (!globalThis.__NS_HMR_BOOT_COMPLETE__) {
797
- if (VERBOSE)
798
- console.log('[hmr][gate] deferring HMR eval until boot complete');
799
- setTimeout(() => {
800
- try {
801
- processQueue();
802
- }
803
- catch { }
804
- }, 150);
805
- return Promise.resolve();
806
- }
807
- if (processingQueue)
808
- return processingPromise || Promise.resolve();
809
- processingQueue = true;
810
- processingPromise = (async () => {
811
- try {
812
- // Simple deterministic drain of the queue. We currently focus on TS flavor
813
- // by re-importing changed modules (to refresh their HTTP ESM copies) and
814
- // then performing a root reset so the UI reflects the new code.
815
- const seen = new Set();
816
- const drained = [];
817
- while (changedQueue.length) {
818
- const id = changedQueue.shift();
819
- if (!id || typeof id !== 'string')
820
- continue;
821
- if (seen.has(id))
822
- continue;
823
- seen.add(id);
824
- drained.push(id);
825
- }
826
- if (!drained.length)
827
- return;
828
- if (VERBOSE)
829
- console.log('[hmr][queue] processing changed ids', drained);
830
- // Explicit eviction step.
831
- //
832
- // On modern runtimes the URL canonicalizer collapses any
833
- // `__ns_hmr__/<tag>/` segment back to a stable cache key, so
834
- // without explicit eviction the upcoming `import(url)` would
835
- // resolve via V8's `g_moduleRegistry` and return the cached
836
- // stale module — making the queue drain a silent no-op for
837
- // every save after the first.
838
- //
839
- // We hand the canonical eviction URLs to the runtime first;
840
- // `invalidateModulesByUrls` is a no-op on older runtimes and
841
- // `requestModuleFromServer` automatically falls back to the
842
- // legacy `/ns/m/__ns_hmr__/v<N>/` URL versioning path in that
843
- // case. node_modules and virtual specs are filtered out by
844
- // `buildEvictionUrls` so vendor modules stay hot.
845
- const evictUrls = buildEvictionUrls(drained);
846
- const evicted = invalidateModulesByUrls(evictUrls);
847
- if (VERBOSE)
848
- console.log(`[hmr][queue] eviction count=${evictUrls.length} ok=${evicted}`);
849
- // Evaluate changed modules best-effort; failures shouldn't completely break HMR.
850
- for (const id of drained) {
851
- try {
852
- const spec = normalizeSpec(id);
853
- const url = await requestModuleFromServer(spec);
854
- if (!url)
855
- continue;
856
- if (VERBOSE)
857
- console.log('[hmr][queue] re-import', { id, spec, url });
858
- const mod = await import(/* @vite-ignore */ url);
859
- }
860
- catch (e) {
861
- if (VERBOSE)
862
- console.warn('[hmr][queue] re-import failed for', id, e);
863
- }
864
- }
865
- // After evaluating the batch, perform flavor-specific UI refresh.
866
- switch (TARGET_FLAVOR) {
867
- case 'vue':
868
- // Vue SFCs are handled via the registry update path; nothing to do here.
869
- break;
870
- case 'solid': {
871
- // Solid .tsx components are self-accepting via solid-refresh's inline
872
- // patchRegistry — re-importing them is sufficient. For non-component
873
- // .ts utility modules, we must propagate up the import graph to find
874
- // the .tsx/.jsx component boundaries and re-import those so their
875
- // solid-refresh proxies pick up the new dependency values.
876
- try {
877
- // Build reverse index: dep id → list of importer ids
878
- const reverseIndex = new Map();
879
- for (const [id, mod] of graph) {
880
- for (const dep of mod.deps) {
881
- let arr = reverseIndex.get(dep);
882
- if (!arr) {
883
- arr = [];
884
- reverseIndex.set(dep, arr);
885
- }
886
- arr.push(id);
887
- }
888
- }
889
- // BFS from each non-tsx changed module up to tsx/jsx boundaries
890
- const boundaries = new Set();
891
- for (const id of drained) {
892
- if (/\.(tsx|jsx)$/i.test(id))
893
- continue; // already self-accepting
894
- const visited = new Set();
895
- const queue = [id];
896
- while (queue.length) {
897
- const cur = queue.shift();
898
- if (visited.has(cur))
899
- continue;
900
- visited.add(cur);
901
- const importers = reverseIndex.get(cur);
902
- if (!importers)
903
- continue;
904
- for (const imp of importers) {
905
- if (/\.(tsx|jsx)$/i.test(imp)) {
906
- boundaries.add(imp);
907
- }
908
- else {
909
- queue.push(imp);
910
- }
911
- }
912
- }
913
- }
914
- // Re-import each boundary so solid-refresh patchRegistry fires.
915
- // For route files (TanStack Router), capture the new Route export
916
- // and patch the router's existing route with the fresh loader.
917
- let routesPatchCount = 0;
918
- let discoveredRouter = null;
919
- // Discover router: try __ns_router global (set by createNativeScriptRouter),
920
- // then scan globalThis for any router-shaped object with routesById.
921
- const findRouter = () => {
922
- if (discoveredRouter)
923
- return discoveredRouter;
924
- const g = globalThis;
925
- if (g.__ns_router?.routesById)
926
- return (discoveredRouter = g.__ns_router);
927
- // Fallback: scan common global keys for router
928
- for (const key of ['__ns_router', 'router', '__router']) {
929
- if (g[key]?.routesById && g[key]?.invalidate)
930
- return (discoveredRouter = g[key]);
931
- }
932
- return null;
933
- };
934
- // Convert boundary file path to TanStack Router fullPath.
935
- // e.g. /src/routes/posts.$postId.tsx → /posts/$postId
936
- const boundaryToFullPath = (bid) => {
937
- const m = bid.match(/\/src\/routes\/(.+)\.(tsx|jsx|ts|js)$/i);
938
- if (!m)
939
- return null;
940
- let p = m[1];
941
- // Replace dots between segments with slashes (posts.$postId → posts/$postId)
942
- p = p.replace(/\./g, '/');
943
- // Handle index files
944
- if (p === 'index')
945
- return '/';
946
- if (p.endsWith('/index'))
947
- p = p.slice(0, -6);
948
- // Strip leading - (TanStack pathless layout convention)
949
- p = p.replace(/(^|\/)-([\w])/g, '$1$2');
950
- return '/' + p;
951
- };
952
- // Find existing route by fullPath (since new Route has no id yet)
953
- const findRouteByFullPath = (router, fp) => {
954
- if (!router?.routesById)
955
- return null;
956
- for (const rid of Object.keys(router.routesById)) {
957
- const r = router.routesById[rid];
958
- if (r?.fullPath === fp)
959
- return r;
960
- }
961
- return null;
962
- };
963
- // Evict the boundary set so re-importing each .tsx
964
- // component actually picks up the new transitive
965
- // dependency code; without this V8 returns the
966
- // cached boundary module unchanged.
967
- const boundaryIds = Array.from(boundaries);
968
- const solidEvictUrls = buildEvictionUrls(boundaryIds);
969
- const solidEvicted = invalidateModulesByUrls(solidEvictUrls);
970
- if (VERBOSE)
971
- console.log(`[hmr][solid] eviction count=${solidEvictUrls.length} ok=${solidEvicted}`);
972
- for (const id of boundaries) {
973
- if (seen.has(id))
974
- continue;
975
- try {
976
- const spec = normalizeSpec(id);
977
- const url = await requestModuleFromServer(spec);
978
- if (!url)
979
- continue;
980
- if (VERBOSE)
981
- console.log('[hmr][solid] propagated to boundary', { id, url });
982
- const mod = await import(/* @vite-ignore */ url);
983
- // Patch TanStack Router route loaders
984
- try {
985
- const newRoute = mod?.Route;
986
- if (newRoute?.options?.loader) {
987
- const router = findRouter();
988
- const fullPath = boundaryToFullPath(id);
989
- if (VERBOSE)
990
- console.log('[hmr][solid][diag] route patch attempt', { id, fullPath, hasRouter: !!router, routesByIdKeys: router?.routesById ? Object.keys(router.routesById) : 'none' });
991
- const existingRoute = fullPath && router ? findRouteByFullPath(router, fullPath) : null;
992
- if (existingRoute?.options) {
993
- existingRoute.options.loader = newRoute.options.loader;
994
- if (newRoute.options.component)
995
- existingRoute.options.component = newRoute.options.component;
996
- routesPatchCount++;
997
- if (VERBOSE)
998
- console.log('[hmr][solid] patched route loader', existingRoute.id, 'fullPath=', fullPath);
999
- }
1000
- else if (VERBOSE) {
1001
- console.log('[hmr][solid] no matching route for fullPath', fullPath);
1002
- }
1003
- }
1004
- }
1005
- catch (e) {
1006
- if (VERBOSE)
1007
- console.warn('[hmr][solid] route patch error', id, e);
1008
- }
1009
- }
1010
- catch (e) {
1011
- if (VERBOSE)
1012
- console.warn('[hmr][solid] boundary re-import failed', id, e);
1013
- }
1014
- }
1015
- // Route loaders were patched with fresh closures. The data is
1016
- // correct in router.state.matches[].loaderData (confirmed via
1017
- // diagnostics), but the currently visible page doesn't re-render
1018
- // because the NativeScriptRouterProvider's Solid store flush only
1019
- // fires through history.subscribe. TODO: find the right mechanism
1020
- // to trigger a Solid reactive update for the active match stores.
1021
- if (routesPatchCount > 0 && VERBOSE) {
1022
- console.log('[hmr][solid] patched', routesPatchCount, 'route loaders (data correct in match state, pending UI refresh mechanism)');
1023
- }
1024
- if (VERBOSE) {
1025
- if (boundaries.size)
1026
- console.log('[hmr][solid] propagated non-component change to', boundaries.size, 'boundaries', Array.from(boundaries));
1027
- console.log('[hmr][queue] Solid: modules re-imported, solid-refresh handles reactive update', drained);
1028
- }
1029
- }
1030
- catch (e) {
1031
- if (VERBOSE)
1032
- console.warn('[hmr][solid] propagation failed', e);
1033
- }
1034
- break;
1035
- }
1036
- case 'typescript': {
1037
- // For TS apps, always reset back to the conventional app root.
1038
- // This preserves the shell (Frame, ActionBar, etc.) that the app's
1039
- // own bootstrapping wires up via `Application.run`.
1040
- try {
1041
- const g = globalThis;
1042
- const App = getCore('Application') || g.Application;
1043
- if (!App || typeof App.resetRootView !== 'function') {
1044
- if (VERBOSE)
1045
- console.warn('[hmr][queue] TS flavor: Application.resetRootView unavailable; skipping UI refresh');
1046
- break;
1047
- }
1048
- // Re-fetch changed XML/CSS files and update the bundled module registry
1049
- // so Builder.createViewFromEntry picks up fresh content.
1050
- const rawAssetIds = drained.filter((id) => /\.(xml|css|scss|sass|less)$/i.test(id));
1051
- if (rawAssetIds.length && typeof g.registerModule === 'function') {
1052
- const origin = getHttpOriginForVite() || deriveHttpOrigin(getHMRWsUrl());
1053
- if (origin) {
1054
- for (const id of rawAssetIds) {
1055
- try {
1056
- const spec = normalizeSpec(id);
1057
- // Fetch the raw file content directly from Vite's dev server.
1058
- // Use the project-relative path which Vite serves as static files.
1059
- const fetchUrl = origin + (spec.startsWith('/') ? spec : '/' + spec);
1060
- if (VERBOSE)
1061
- console.log('[hmr][queue] fetching raw asset', { id, fetchUrl });
1062
- const resp = await fetch(fetchUrl);
1063
- if (resp.ok) {
1064
- const rawContent = await resp.text();
1065
- // Register under all nickname variants the module registry uses.
1066
- // The bundler context registers XML as e.g., './main-page.xml' and 'main-page.xml'
1067
- const appVirtual = APP_VIRTUAL_WITH_SLASH.replace(/^\//, '');
1068
- let relPath = spec.startsWith('/') ? spec.slice(1) : spec;
1069
- if (relPath.startsWith(appVirtual))
1070
- relPath = relPath.slice(appVirtual.length);
1071
- const nicknames = ['./' + relPath, relPath];
1072
- // Also add without extension for CSS
1073
- const extIdx = relPath.lastIndexOf('.');
1074
- if (extIdx > 0) {
1075
- const baseName = relPath.slice(0, extIdx);
1076
- if (!relPath.endsWith('.xml'))
1077
- nicknames.push(baseName, './' + baseName);
1078
- }
1079
- for (const name of nicknames) {
1080
- if (VERBOSE)
1081
- console.log('[hmr][queue] re-registering module', name);
1082
- g.registerModule(name, () => rawContent);
1083
- }
1084
- }
1085
- else if (VERBOSE) {
1086
- console.warn('[hmr][queue] raw asset fetch failed', id, resp.status);
1087
- }
1088
- }
1089
- catch (e) {
1090
- if (VERBOSE)
1091
- console.warn('[hmr][queue] raw asset refresh failed for', id, e);
1092
- }
1093
- }
1094
- }
1095
- }
1096
- // Determine if we can navigate in-place to a changed page
1097
- // instead of resetting all the way back to app-root.
1098
- // This keeps the user on the page they're editing for faster iteration.
1099
- const changedXmlPages = drained
1100
- .filter((id) => /\.xml$/i.test(id))
1101
- .map((id) => {
1102
- const spec = normalizeSpec(id);
1103
- const appVirtual = APP_VIRTUAL_WITH_SLASH.replace(/^\//, '');
1104
- let relPath = spec.startsWith('/') ? spec.slice(1) : spec;
1105
- if (relPath.startsWith(appVirtual))
1106
- relPath = relPath.slice(appVirtual.length);
1107
- // Strip .xml extension to get the moduleName (e.g., 'pages/status-bar')
1108
- return relPath.replace(/\.xml$/i, '');
1109
- })
1110
- .filter((m) => m && m !== 'app-root');
1111
- // Resolve the topmost Frame from the bundled realm.
1112
- // Frame.topmost() relies on an internal frameStack array, so we must
1113
- // call it on the bundled-realm class. Multiple strategies to find it:
1114
- const FrameClass = getCore('Frame') || g.Frame;
1115
- let topFrame = null;
1116
- // 1) Try the vendor-realm static topmost()
1117
- try {
1118
- topFrame = FrameClass?.topmost?.();
1119
- }
1120
- catch { }
1121
- // 2) Try getting the root view from Application — if it's a Frame, use it
1122
- if (!topFrame) {
1123
- try {
1124
- const rootView = App.getRootView?.() || App._rootView;
1125
- if (rootView) {
1126
- // rootView could be a Frame itself, or contain a Frame
1127
- const isFrame = rootView.constructor?.name === 'Frame' || rootView.navigate;
1128
- if (isFrame) {
1129
- topFrame = rootView;
1130
- }
1131
- else if (rootView.getChildAt) {
1132
- // Walk direct children looking for a Frame
1133
- for (let i = 0; i < (rootView.getChildrenCount?.() || 0); i++) {
1134
- const child = rootView.getChildAt(i);
1135
- if (child?.constructor?.name === 'Frame' || child?.navigate) {
1136
- topFrame = child;
1137
- break;
1138
- }
1139
- }
1140
- }
1141
- }
1142
- }
1143
- catch { }
1144
- }
1145
- if (VERBOSE)
1146
- console.log('[hmr][queue] TS: changedXmlPages=', changedXmlPages, 'topFrame=', !!topFrame);
1147
- if (changedXmlPages.length > 0 && topFrame) {
1148
- // Navigate the current frame to the changed page directly.
1149
- // Use the last changed XML page (most specific).
1150
- const moduleName = changedXmlPages[changedXmlPages.length - 1];
1151
- if (VERBOSE)
1152
- console.log('[hmr][queue] TS: navigating in-place to', moduleName);
1153
- try {
1154
- topFrame.navigate({ moduleName, clearHistory: false, animated: false });
1155
- }
1156
- catch (navErr) {
1157
- console.warn('[hmr][queue] TS flavor: in-place navigate failed, falling back to resetRootView', navErr);
1158
- App.resetRootView({ moduleName: 'app-root' });
1159
- }
1160
- }
1161
- else {
1162
- if (VERBOSE)
1163
- console.log('[hmr][queue] TS flavor: resetRootView(app-root) after changes');
1164
- App.resetRootView({ moduleName: 'app-root' });
1165
- }
1166
- }
1167
- catch (e) {
1168
- console.warn('[hmr][queue] TS flavor: resetRootView(app-root) failed', e);
1169
- }
1170
- break;
1171
- }
1172
- }
1173
- }
1174
- finally {
1175
- processingQueue = false;
1176
- processingPromise = null;
1177
- }
1178
- })();
1179
- return processingPromise;
1180
- }
1181
- let hmrSocket = null;
1182
- // Track server-announced batches for each version so we can import in-order client-side
1183
- const txnClientBatches = new Map();
1184
- // Public hook for NativeScript runtime to call from ImportModuleDynamicallyCallback later.
1185
- globalThis.__nsHmrRequestModule = async function (spec) {
1186
- let normalized = normalizeSpec(spec);
1187
- // Remove extension for transform lookup variants (server will try .ts/.js/.mjs)
1188
- normalized = normalized.replace(/\.(ts|js|tsx|jsx|mjs)$/i, '');
1189
- if (!normalized.startsWith('/'))
1190
- normalized = '/' + normalized;
1191
- if (normalized === '@') {
1192
- // Soft-handle instead of throwing to avoid breaking evaluation paths: return a safe empty module stub.
1193
- try {
1194
- const err = new Error('[hmr-fetch] anomalous @ spec');
1195
- const stack = err.stack || '';
1196
- hmrMetrics.invalidAtSpec = (hmrMetrics.invalidAtSpec || 0) + 1;
1197
- console.warn('[hmr-fetch] refusing to fetch bare @ spec; returning stub; original=', spec, 'stack=\n' + stack);
1198
- }
1199
- catch { }
1200
- return '/__invalid_at__.mjs';
1201
- }
1202
- const url = await requestModuleFromServer(normalized);
1203
- return url;
1204
- };
1205
- function connectHmr() {
1206
- if (hmrSocket?.readyState === WebSocket.OPEN)
1207
- return;
1208
- if (hmrSocket?.readyState === WebSocket.CONNECTING) {
1209
- if (__NS_ENV_VERBOSE__)
1210
- console.log('[hmr-client] Already connecting to HMR WebSocket, skipping');
62
+ // Install the device CSS applier. CSS-bearing modules (a Vue SFC `<style>` via
63
+ // `/ns/asm`, an imported `.css` via `/ns/m`) call `__NS_REGISTER_CSS__(tag, css)`,
64
+ // or queue in `__NS_PENDING_CSS__` if they ran first; the drain below covers that.
65
+ // Routes through the shared `applyCssText` (tagged remove+add + root restyle),
66
+ // the same path app.css and live `.css` edits use.
67
+ function installCssRegister() {
68
+ const g = getGlobalScope();
69
+ if (typeof g.__NS_REGISTER_CSS__ === 'function') {
1211
70
  return;
1212
71
  }
1213
- try {
1214
- globalThis.__NS_HMR_CLIENT_SOCKET_READY__ = false;
1215
- }
1216
- catch { }
1217
- const overlayStage = hasOpenedHmrSocket ? 'reconnecting' : 'connecting';
1218
- const baseUrl = getHMRWsUrl() || 'ws://localhost:5173/ns-hmr';
1219
- const buildCandidates = (url) => {
1220
- let candidates = [];
1221
- try {
1222
- const u = new URL(url);
1223
- const proto = u.protocol === 'wss:' ? ['wss'] : ['ws'];
1224
- const defaultPort = u.port || '5173';
1225
- // Build ordered host candidates with preference to the active HTTP origin
1226
- const orderedHosts = [];
1227
- try {
1228
- const g = globalThis;
1229
- const httpOrigin = g && typeof g.__NS_HTTP_ORIGIN__ === 'string' ? g.__NS_HTTP_ORIGIN__ : undefined;
1230
- if (httpOrigin) {
1231
- try {
1232
- const ho = new URL(httpOrigin);
1233
- orderedHosts.push({
1234
- host: ho.hostname,
1235
- port: ho.port || defaultPort,
1236
- });
1237
- }
1238
- catch { }
1239
- }
1240
- }
1241
- catch { }
1242
- // From provided URL
1243
- orderedHosts.push({ host: u.hostname, port: defaultPort });
1244
- // Explicit override
1245
- try {
1246
- const h = globalThis.__NS_HMR_HOST;
1247
- if (h)
1248
- orderedHosts.push({ host: String(h), port: defaultPort });
1249
- }
1250
- catch { }
1251
- // Common fallbacks
1252
- orderedHosts.push({ host: '10.0.2.2', port: defaultPort });
1253
- orderedHosts.push({ host: 'localhost', port: defaultPort });
1254
- const seen = new Set();
1255
- for (const p of proto) {
1256
- for (const { host, port } of orderedHosts) {
1257
- const key = `${host}:${port}`;
1258
- if (seen.has(key))
1259
- continue;
1260
- seen.add(key);
1261
- const cand = `${p}://${host}:${port}${u.pathname || '/ns-hmr'}${u.search || ''}`;
1262
- candidates.push(cand);
1263
- }
1264
- }
1265
- }
1266
- catch {
1267
- candidates.push(url);
1268
- }
1269
- // Deduplicate while preserving order
1270
- const seen = new Set();
1271
- return candidates.filter((c) => (seen.has(c) ? false : (seen.add(c), true)));
1272
- };
1273
- const candidates = buildCandidates(baseUrl);
1274
- let idx = 0;
1275
- const tryNext = () => {
1276
- if (idx >= candidates.length) {
1277
- showConnectionOverlayNow('offline', 'Waiting for the Vite websocket to come back.');
1278
- console.warn('[hmr-client] All WS candidates failed:', candidates.join(', '));
1279
- setTimeout(connectHmr, 1500);
72
+ const apply = (tag, cssText) => {
73
+ if (typeof cssText !== 'string' || !cssText.length) {
1280
74
  return;
1281
75
  }
1282
- const url = candidates[idx++];
1283
- const connectionDetail = `${overlayStage === 'reconnecting' ? 'Retrying' : 'Opening'} ${url}`;
1284
- if (connectionOverlayVisible) {
1285
- updateConnectionOverlay(overlayStage, connectionDetail);
1286
- }
1287
- else {
1288
- scheduleConnectionOverlay(overlayStage, connectionDetail);
1289
- }
1290
76
  try {
1291
- if (__NS_ENV_VERBOSE__)
1292
- console.log('[hmr-client] Connecting to HMR WebSocket:', url);
1293
- const sock = new WebSocket(url);
1294
- hmrSocket = sock;
1295
- setHttpOriginForVite(deriveHttpOrigin(url));
1296
- let opened = false;
1297
- const timeout = setTimeout(() => {
1298
- if (!opened && sock.readyState !== WebSocket.OPEN) {
1299
- try {
1300
- sock.close();
1301
- }
1302
- catch { }
1303
- if (VERBOSE)
1304
- console.warn('[hmr-client] WS connect timeout, trying next…');
1305
- tryNext();
1306
- }
1307
- }, 3500);
1308
- sock.onopen = () => {
1309
- opened = true;
1310
- clearTimeout(timeout);
1311
- clearConnectionOverlayTimer();
1312
- hasOpenedHmrSocket = true;
1313
- awaitingHealthyHmrMessage = true;
1314
- try {
1315
- globalThis.__NS_HMR_CLIENT_SOCKET_READY__ = true;
1316
- }
1317
- catch { }
1318
- if (connectionOverlayVisible) {
1319
- showConnectionOverlayNow('synchronizing', 'Connected. Synchronizing the HMR graph.');
1320
- }
1321
- VERBOSE && console.log('[hmr-client] Connected to HMR WebSocket');
1322
- // Print the active module reload mode once on first
1323
- // successful connect so the user can correlate HMR latency
1324
- // with runtime capability without grepping for protocol
1325
- // details. The banner is verbose-gated.
1326
- try {
1327
- emitHmrModeBannerOnce();
1328
- }
1329
- catch { }
1330
- };
1331
- sock.onmessage = handleHmrMessage;
1332
- sock.onerror = (error) => {
1333
- clearTimeout(timeout);
1334
- console.warn('[hmr-client] WebSocket error:', (error && (error.message || error)) || error);
1335
- };
1336
- sock.onclose = (ev) => {
1337
- clearTimeout(timeout);
1338
- try {
1339
- globalThis.__NS_HMR_CLIENT_SOCKET_READY__ = false;
1340
- }
1341
- catch { }
1342
- if (!opened) {
1343
- // immediate failure during connect → try another candidate
1344
- if (VERBOSE)
1345
- console.warn('[hmr-client] WS close before open (code', ev?.code, '), trying next…');
1346
- tryNext();
1347
- }
1348
- else {
1349
- if (VERBOSE)
1350
- console.log('[hmr-client] WebSocket closed (code', ev?.code, '), will reconnect…');
1351
- scheduleConnectionOverlay('reconnecting', 'The websocket closed. Waiting to reconnect.', 700);
1352
- // try to reconnect with full candidate list again
1353
- setTimeout(connectHmr, 1000);
1354
- }
1355
- };
77
+ applyCssText(cssText, tag);
1356
78
  }
1357
- catch (e) {
1358
- console.warn('[hmr-client] Failed to connect WebSocket', e);
1359
- tryNext();
79
+ catch (cssErr) {
80
+ if (VERBOSE)
81
+ console.warn('[ns-hmr] CSS register/apply failed for', tag, cssErr?.message || cssErr);
1360
82
  }
1361
83
  };
1362
- tryNext();
1363
- }
1364
- async function handleHmrMessage(ev) {
1365
- let msg;
1366
- try {
1367
- msg = JSON.parse(ev.data);
1368
- }
1369
- catch {
1370
- return;
1371
- }
1372
- if (awaitingHealthyHmrMessage && msg) {
1373
- markHmrConnectionHealthy();
1374
- }
1375
- if (VERBOSE && msg?.type) {
1376
- console.log('[hmr-client] received message', msg.type);
1377
- }
1378
- // Notify optional app-level hook after an HMR batch is applied.
1379
- function notifyAppHmrUpdate(kind, changedIds) {
1380
- try {
1381
- const hook = globalThis.__NS_HMR_ON_UPDATE__;
1382
- if (typeof hook === 'function') {
1383
- hook({ type: kind, version: getGraphVersion(), changedIds: changedIds || [], raw: msg });
1384
- }
1385
- }
1386
- catch { }
1387
- }
1388
- if (msg) {
1389
- // `ns:hmr-pending` is a fire-and-forget UX hint emitted by the
1390
- // server at the START of handleHotUpdate. We drive the
1391
- // HMR-applying overlay's 'received' frame here (synchronously),
1392
- // well before the authoritative payload (`ns:angular-update` /
1393
- // `ns:css-updates`) lands. Skip running any other handlers —
1394
- // the pending message has no module payload and intentionally
1395
- // does not bump the graph version.
1396
- if (msg.type === 'ns:hmr-pending' && typeof msg.path === 'string') {
1397
- setHmrPendingOverlay(msg.path);
1398
- return;
1399
- }
1400
- if (msg.type === 'ns:hmr-full-graph') {
1401
- // Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
1402
- try {
1403
- const g = globalThis;
1404
- g.__NS_HMR_IMPORT_NONCE__ = (typeof g.__NS_HMR_IMPORT_NONCE__ === 'number' ? g.__NS_HMR_IMPORT_NONCE__ : 0) + 1;
1405
- }
1406
- catch { }
1407
- // Capture previous graph snapshot so we can infer which modules changed.
1408
- const prevGraph = new Map(graph);
1409
- setGraphVersion(Number(msg.version || getGraphVersion() || 0));
1410
- applyFullGraph(msg);
1411
- hasReceivedFullGraph = true;
1412
- // Gate: On first boot, the entry-runtime handles all initial module loading
1413
- // (with the import map already configured). Don't re-import here — the graph
1414
- // is stored above for future HMR delta comparisons, but modules are already
1415
- // loaded correctly via the entry-runtime boot sequence.
1416
- //
1417
- // Two cases to catch:
1418
- // 1. Boot still in progress (__NS_HMR_BOOT_COMPLETE__ is false)
1419
- // 2. Boot already finished but this is the FIRST full-graph (prevGraph was
1420
- // empty). The WebSocket often connects after entry-runtime finishes, so
1421
- // boot is "complete" but we still shouldn't re-import — all modules were
1422
- // just loaded fresh. Only re-import on subsequent full-graphs (reconnect
1423
- // scenarios) where prevGraph already has entries.
1424
- if (!globalThis.__NS_HMR_BOOT_COMPLETE__) {
1425
- if (VERBOSE)
1426
- console.info('[hmr][full-graph] skipping initial re-import (boot in progress)');
1427
- const fullIds = Array.isArray(msg.modules) ? msg.modules.map((m) => m?.id).filter(Boolean) : [];
1428
- notifyAppHmrUpdate('full-graph', fullIds);
1429
- return;
1430
- }
1431
- if (prevGraph.size === 0) {
1432
- if (VERBOSE)
1433
- console.info('[hmr][full-graph] skipping re-import on first graph after boot (modules already fresh)');
1434
- const fullIds = Array.isArray(msg.modules) ? msg.modules.map((m) => m?.id).filter(Boolean) : [];
1435
- notifyAppHmrUpdate('full-graph', fullIds);
1436
- return;
1437
- }
1438
- // Reconnect / resync case — re-import changed modules as normal.
1439
- // In some cases (e.g. server chooses full-graph resync / page reload), we won't
1440
- // receive a delta queue to re-import changed TS modules. Without re-import,
1441
- // HTTP ESM caching means module bodies (and side effects) won't re-run.
1442
- try {
1443
- const inferredChanged = [];
1444
- try {
1445
- for (const [id, next] of graph.entries()) {
1446
- const prev = prevGraph.get(id);
1447
- if (!prev || prev.hash !== next.hash)
1448
- inferredChanged.push(id);
1449
- }
1450
- // Removed modules are also "changed" but we don't import them.
1451
- }
1452
- catch { }
1453
- // Best-effort: only re-import real source modules (avoid .vue registry pipeline and virtual ids)
1454
- const toReimport = inferredChanged.filter((id) => {
1455
- if (!id || typeof id !== 'string')
1456
- return false;
1457
- if (/^\0|^\/\0/.test(id))
1458
- return false;
1459
- if (/plugin-vue:export-helper/.test(id))
1460
- return false;
1461
- if (/\.vue$/i.test(id))
1462
- return false;
1463
- if (id.endsWith(APP_MAIN_ENTRY_SPEC))
1464
- return false;
1465
- return true;
1466
- });
1467
- if (toReimport.length && VERBOSE)
1468
- console.log('[hmr][full-graph] inferred changed modules; re-importing', toReimport);
1469
- // Evict the inferred changed set before re-importing.
1470
- // See `processQueue` for the architectural rationale; the
1471
- // full-graph code path is the resync fallback (server chose
1472
- // not to send a delta) and shares the same V8 cache pitfall.
1473
- const fgEvictUrls = buildEvictionUrls(toReimport);
1474
- const fgEvicted = invalidateModulesByUrls(fgEvictUrls);
1475
- if (VERBOSE)
1476
- console.log(`[hmr][full-graph] eviction count=${fgEvictUrls.length} ok=${fgEvicted}`);
1477
- for (const id of toReimport) {
1478
- try {
1479
- const spec = normalizeSpec(id);
1480
- const url = await requestModuleFromServer(spec);
1481
- if (!url)
1482
- continue;
1483
- if (VERBOSE)
1484
- console.log('[hmr][full-graph] re-import', { id, spec, url });
1485
- await import(/* @vite-ignore */ url);
1486
- }
1487
- catch (e) {
1488
- if (VERBOSE)
1489
- console.warn('[hmr][full-graph] re-import failed for', id, e);
1490
- }
1491
- }
1492
- }
1493
- catch { }
1494
- const fullIds = Array.isArray(msg.modules) ? msg.modules.map((m) => m?.id).filter(Boolean) : [];
1495
- notifyAppHmrUpdate('full-graph', fullIds);
1496
- return;
1497
- }
1498
- if (msg.type === 'ns:ts-module-registry') {
1499
- try {
1500
- const mods = Array.isArray(msg.modules) ? msg.modules.filter((m) => typeof m === 'string') : [];
1501
- if (mods.length) {
1502
- if (!tsModuleSet)
1503
- tsModuleSet = new Set();
1504
- mods.forEach((m) => tsModuleSet.add(m));
1505
- // Prefer explicit app main entry if present, else first module
1506
- if (mods.includes(APP_MAIN_ENTRY_SPEC)) {
1507
- tsMainId = APP_MAIN_ENTRY_SPEC;
1508
- }
1509
- else if (!tsMainId) {
1510
- tsMainId = mods[0];
1511
- }
1512
- if (VERBOSE)
1513
- console.log('[hmr-client][ts-registry] registered TS modules', {
1514
- count: tsModuleSet.size,
1515
- mainId: tsMainId,
1516
- });
1517
- }
1518
- }
1519
- catch (e) {
1520
- if (VERBOSE)
1521
- console.warn('[hmr-client][ts-registry] failed to record', e);
1522
- }
1523
- return;
1524
- }
1525
- if (msg.type === 'ns:hmr-delta') {
1526
- // Bump a monotonic nonce so HTTP ESM imports can always be cache-busted per update.
1527
- try {
1528
- const g = globalThis;
1529
- g.__NS_HMR_IMPORT_NONCE__ = (typeof g.__NS_HMR_IMPORT_NONCE__ === 'number' ? g.__NS_HMR_IMPORT_NONCE__ : 0) + 1;
1530
- }
1531
- catch { }
1532
- try {
1533
- const ids = Array.isArray(msg.changed) ? msg.changed.map((c) => c?.id).filter(Boolean) : [];
1534
- if (ids.length)
1535
- txnClientBatches.set(getGraphVersion(), ids);
1536
- }
1537
- catch { }
1538
- applyDelta(msg);
1539
- // Ensure queued module re-imports complete before notifying app hooks.
1540
- // Otherwise app-level handlers can run against stale module bodies due to HTTP ESM caching.
1541
- try {
1542
- await processQueue();
1543
- }
1544
- catch { }
1545
- const deltaIds = Array.isArray(msg.changed) ? msg.changed.map((c) => c?.id).filter(Boolean) : [];
1546
- notifyAppHmrUpdate('delta', deltaIds);
1547
- return;
1548
- }
1549
- else {
1550
- if (msg.type === 'ns:angular-update' && typeof msg.version === 'number') {
1551
- setGraphVersion(Number(msg.version || getGraphVersion() || 0));
1552
- }
1553
- if (await handleAngularHotUpdateMessage(msg, { getCore, verbose: VERBOSE })) {
1554
- return;
1555
- }
1556
- }
1557
- }
1558
- // On-demand module fetch response (Option A)
1559
- if (msg.type === 'ns:module-response' && typeof msg.requestId === 'number') {
1560
- const pending = pendingModuleFetches.get(msg.requestId);
1561
- if (pending) {
1562
- pendingModuleFetches.delete(msg.requestId);
1563
- if (msg.error) {
1564
- if (VERBOSE)
1565
- console.warn('[hmr-fetch] error', msg.error, 'spec=', pending.spec, 'id=', msg.requestId);
1566
- pending.reject(new Error(`[hmr-fetch] ${msg.error} for ${pending.spec}`));
1567
- }
1568
- else {
1569
- try {
1570
- const origin = getHttpOriginForVite() || deriveHttpOrigin(getHMRWsUrl());
1571
- if (!origin)
1572
- throw new Error('no-http-origin');
1573
- const url = origin + '/ns/m' + (String(pending.spec).startsWith('/') ? pending.spec : '/' + pending.spec);
1574
- moduleFetchCache.set(pending.spec, url);
1575
- if (VERBOSE)
1576
- console.log('[hmr-fetch] resolved via URL', pending.spec, '->', url, 'id=', msg.requestId);
1577
- pending.resolve(url);
1578
- }
1579
- catch (e) {
1580
- pending.reject(e);
1581
- }
1582
- }
1583
- }
1584
- return;
1585
- }
1586
- if (msg.type === 'ns:css-updates' && Array.isArray(msg.updates)) {
1587
- try {
1588
- const origin = msg.origin || getHttpOriginForVite() || deriveHttpOrigin(getHMRWsUrl());
1589
- await handleCssUpdates(msg.updates, origin);
1590
- return;
1591
- }
1592
- catch (e) {
1593
- console.warn('[hmr-client] CSS updates handling failed:', e);
1594
- return;
1595
- }
1596
- }
1597
- if (msg.type === 'ns:vue-sfc-registry') {
1598
- handleVueSfcRegistry(msg);
1599
- return;
1600
- }
1601
- if (msg.type === 'ns:vue-sfc-registry-update') {
1602
- if (typeof msg.version === 'number')
1603
- setGraphVersion(msg.version);
1604
- const comp = await handleVueSfcRegistryUpdate(msg, getGraphVersion());
1605
- if (comp) {
1606
- await performResetRoot(comp);
1607
- }
1608
- return;
1609
- }
1610
- }
1611
- function normalizeComponent(input, nameHint) {
84
+ g.__NS_REGISTER_CSS__ = apply;
1612
85
  try {
1613
- if (!input)
1614
- return null;
1615
- // Unwrap module namespace with default
1616
- if (input && typeof input === 'object' && 'default' in input) {
1617
- const d = input.default;
1618
- if (d)
1619
- return normalizeComponent(d, nameHint);
1620
- }
1621
- // If already a component-like object with render/setup/template, return as-is
1622
- if (typeof input === 'object' && (input.render || input.setup || input.template || input.__isVue)) {
1623
- return input;
1624
- }
1625
- // If provided a render function, wrap with defineComponent
1626
- if (typeof input === 'function') {
1627
- ensureVueGlobals();
1628
- const comp = globalThis.defineComponent
1629
- ? globalThis.defineComponent({
1630
- name: nameHint || input.name || 'AnonymousSFC',
1631
- render: input,
1632
- })
1633
- : { name: nameHint || input.name || 'AnonymousSFC', render: input };
1634
- return comp;
1635
- }
1636
- // If object has a render function property
1637
- if (input?.render && typeof input.render === 'function') {
1638
- ensureVueGlobals();
1639
- const comp = globalThis.defineComponent
1640
- ? globalThis.defineComponent({
1641
- name: nameHint || input.name || 'AnonymousSFC',
1642
- render: input.render,
1643
- })
1644
- : {
1645
- name: nameHint || input.name || 'AnonymousSFC',
1646
- render: input.render,
1647
- };
1648
- return comp;
1649
- }
1650
- }
1651
- catch { }
1652
- return input;
1653
- }
1654
- async function performResetRoot(newComponent) {
1655
- const tStart = Date.now();
1656
- // Guard against re-entrant or rapid successive resets
1657
- try {
1658
- globalThis.__NS_DEV_RESET_IN_PROGRESS__ = true;
1659
- }
1660
- catch { }
1661
- try {
1662
- ensureCoreAliasesOnGlobalThis();
1663
- }
1664
- catch { }
1665
- if (VERBOSE) {
1666
- console.log('[hmr-client] Single-path: replace current root Page');
1667
- console.log('[hmr-client] Component details:', {
1668
- componentName: newComponent?.__name,
1669
- componentFile: newComponent?.__file,
1670
- hasRender: !!newComponent?.render,
1671
- hasSetup: !!newComponent?.setup,
1672
- componentKeys: Object.keys(newComponent || {}),
1673
- });
1674
- }
1675
- function createRootFactory() {
1676
- let rootKind = 'page';
1677
- let cachedRoot = undefined;
1678
- const state = {
1679
- getRootKind: () => rootKind,
1680
- setRootKind: (k) => {
1681
- rootKind = k;
1682
- },
1683
- getCachedRoot: () => cachedRoot,
1684
- setCachedRoot: (r) => {
1685
- cachedRoot = r;
1686
- },
1687
- };
1688
- const factory = {
1689
- get kind() {
1690
- return rootKind;
1691
- },
1692
- create: () => {
1693
- if (cachedRoot)
1694
- return cachedRoot;
1695
- try {
1696
- switch (TARGET_FLAVOR) {
1697
- case 'vue':
1698
- cachedRoot = getRootForVue(newComponent, state);
1699
- break;
1700
- case 'typescript': {
1701
- // For TS flavor, treat the component as a factory or direct NS view.
1702
- let root = null;
1703
- try {
1704
- if (typeof newComponent === 'function') {
1705
- root = newComponent();
1706
- }
1707
- else {
1708
- root = newComponent;
1709
- }
1710
- }
1711
- catch (e) {
1712
- console.warn('[hmr-client][ts] root factory invocation failed', e);
1713
- }
1714
- cachedRoot = root || {};
1715
- // Heuristic: if the root "looks" like a Frame, prefer frame semantics
1716
- try {
1717
- const name = String(cachedRoot?.constructor?.name || '').replace(/^_+/, '');
1718
- if (/^Frame(\$\d+)?$/.test(name)) {
1719
- rootKind = 'frame';
1720
- }
1721
- }
1722
- catch { }
1723
- break;
1724
- }
1725
- }
1726
- return cachedRoot;
1727
- }
1728
- catch (e) {
1729
- console.warn('[hmr-client] createRootFactory failed', e);
1730
- if (VERBOSE)
1731
- console.warn('[hmr-client] [createRoot] stack', e?.stack);
1732
- const GPage = getCore('Page');
1733
- rootKind = 'page';
1734
- cachedRoot = GPage ? new GPage() : {};
1735
- return cachedRoot;
1736
- }
1737
- },
1738
- };
1739
- return factory;
1740
- }
1741
- // Android readiness before any root changes
1742
- const App = getCore('Application') || globalThis.Application;
1743
- const isAndroid = !!(App && App.android !== undefined);
1744
- if (isAndroid) {
1745
- const isReady = () => {
1746
- try {
1747
- const a = App.android;
1748
- const act = a && (a.foregroundActivity || a.startActivity);
1749
- return !!act;
1750
- }
1751
- catch {
1752
- return false;
1753
- }
1754
- };
1755
- const waitFor = async (pred, ms = 6000, step = 60) => {
1756
- const start = Date.now();
1757
- while (Date.now() - start < ms) {
1758
- if (pred())
1759
- return true;
1760
- await new Promise((r) => setTimeout(r, step));
86
+ const pending = g.__NS_PENDING_CSS__;
87
+ if (pending && typeof pending === 'object') {
88
+ for (const tag of Object.keys(pending)) {
89
+ apply(tag, pending[tag]);
1761
90
  }
1762
- return pred();
1763
- };
1764
- const withEvents = async (ms = 6000) => {
1765
- try {
1766
- const a = App.android;
1767
- if (!a || typeof a.on !== 'function' || typeof a.off !== 'function') {
1768
- if (VERBOSE)
1769
- console.log('[hmr-client] [android] events API not available; polling');
1770
- return await waitFor(isReady, ms, 60);
1771
- }
1772
- if (isReady()) {
1773
- if (VERBOSE)
1774
- console.log('[hmr-client] [android] activity already ready');
1775
- return true;
1776
- }
1777
- return await new Promise((resolve) => {
1778
- let done = false;
1779
- const tWait = Date.now();
1780
- const finish = (ok) => {
1781
- if (done)
1782
- return;
1783
- done = true;
1784
- try {
1785
- a.off(a.activityStartedEvent || 'activityStarted', onAny);
1786
- a.off(a.activityResumedEvent || 'activityResumed', onAny);
1787
- }
1788
- catch { }
1789
- if (VERBOSE)
1790
- console.log('[hmr-client] [android] readiness result', {
1791
- ok,
1792
- elapsedMs: Date.now() - tWait,
1793
- });
1794
- resolve(ok);
1795
- };
1796
- const onAny = (evt) => {
1797
- if (VERBOSE)
1798
- console.log('[hmr-client] [android] activity event', {
1799
- type: evt?.eventName || 'unknown',
1800
- });
1801
- if (isReady())
1802
- finish(true);
1803
- };
1804
- try {
1805
- a.on(a.activityStartedEvent || 'activityStarted', onAny);
1806
- a.on(a.activityResumedEvent || 'activityResumed', onAny);
1807
- if (VERBOSE)
1808
- console.log('[hmr-client] [android] waiting for activity events…');
1809
- }
1810
- catch {
1811
- return resolve(waitFor(isReady, ms, 60));
1812
- }
1813
- setTimeout(() => finish(isReady()), ms);
1814
- });
1815
- }
1816
- catch {
1817
- return await waitFor(isReady, ms, 60);
1818
- }
1819
- };
1820
- const ok = await withEvents(6000);
1821
- if (!ok && VERBOSE)
1822
- console.warn('[hmr-client] [android] activity not ready; proceeding with best-effort');
1823
- }
1824
- // Create the new root first to determine whether it is a Page or a Frame
1825
- const rootFactory = createRootFactory();
1826
- const preparedRoot = rootFactory.create();
1827
- const isFrameRoot = (() => {
1828
- try {
1829
- const name = String(preparedRoot?.constructor?.name || '').replace(/^_+/, '');
1830
- return /^Frame(\$\d+)?$/.test(name);
91
+ g.__NS_PENDING_CSS__ = null;
1831
92
  }
1832
- catch {
1833
- return false;
1834
- }
1835
- })();
1836
- // Prefer resetRootView on initial boot (placeholder present) or on iOS to avoid early createRootView races
1837
- let hadPlaceholder = false;
1838
- let isIOS = false;
1839
- try {
1840
- hadPlaceholder = !!globalThis.__NS_DEV_PLACEHOLDER_ROOT_EARLY__;
1841
93
  }
1842
94
  catch { }
1843
- try {
1844
- const AppAny = getCore('Application') || globalThis.Application;
1845
- isIOS = !!(AppAny && AppAny.ios !== undefined);
1846
- }
1847
- catch { }
1848
- // Preferred policy:
1849
- // - If this is the very first mount (placeholder present), or if the new root is a Frame,
1850
- // perform a full root replacement via resetRootView so we never couple with the placeholder.
1851
- // - Otherwise (subsequent HMR updates with an authoritative Frame already in place), re-use the
1852
- // current app Frame and navigate to the new Page. This avoids a brief flash that can occur
1853
- // when swapping the entire root view on Android. The placeholder is never involved here.
1854
- const gAnyForPolicy = globalThis;
1855
- const placeholderFrame = (() => {
1856
- try {
1857
- return gAnyForPolicy.__NS_DEV_PLACEHOLDER_ROOT_VIEW__ || null;
1858
- }
1859
- catch {
1860
- return null;
1861
- }
1862
- })();
1863
- let existingAppFrame = null;
1864
- try {
1865
- existingAppFrame = getRootFrame() || getCore('Frame')?.topmost?.() || null;
1866
- }
1867
- catch { }
1868
- const isAuthoritativeFrame = !!existingAppFrame && existingAppFrame !== placeholderFrame;
1869
- if (!hadPlaceholder && !isFrameRoot && isAuthoritativeFrame && typeof existingAppFrame.navigate === 'function') {
1870
- try {
1871
- const navEntry = {
1872
- create: () => preparedRoot,
1873
- clearHistory: true,
1874
- animated: false,
1875
- };
1876
- existingAppFrame.navigate(navEntry);
1877
- setRootFrame(existingAppFrame);
1878
- return true;
1879
- }
1880
- catch (e) {
1881
- console.warn('[hmr-client] authoritative navigate fallback to resetRootView due to error', e);
1882
- }
1883
- }
1884
- if (VERBOSE)
1885
- console.log('[hmr-client] full root replacement via resetRootView (placeholder will be discarded)', { isFrameRoot, isIOS, hadPlaceholder });
1886
- // Fallback or preferred path: resetRootView with a creator that builds a fresh Frame and navigates to the new Page
1887
- try {
1888
- const App2 = getCore('Application') || globalThis.Application;
1889
- if (!App2 || typeof App2.resetRootView !== 'function') {
1890
- console.warn('[hmr-client] Application.resetRootView unavailable');
1891
- return false;
1892
- }
1893
- // iOS-specific: if the cached window was left in an invalid state (boolean false), clear it so
1894
- // setWindowContent can recreate a proper UIWindow. This can occur in rare early-boot races.
1895
- try {
1896
- const isIos = !!(App2 && App2.ios !== undefined);
1897
- if (isIos) {
1898
- let win = undefined;
1899
- try {
1900
- win = App2.window;
1901
- }
1902
- catch { }
1903
- if (win === false) {
1904
- if (VERBOSE)
1905
- console.warn('[hmr-client] iOS Application.window is boolean false; attempting to clear cached window');
1906
- try {
1907
- const g = globalThis;
1908
- const reg = g.__nsVendorRegistry;
1909
- const req = reg?.get ? g.__nsVendorRequire || g.__nsRequire || g.require : g.__nsRequire || g.require;
1910
- let helpers = null;
1911
- // Try vendor registry first
1912
- if (reg && reg.has('@nativescript/core/application/helpers-common')) {
1913
- helpers = reg.get('@nativescript/core/application/helpers-common');
1914
- }
1915
- // Fallback to device require
1916
- if (!helpers && typeof req === 'function') {
1917
- try {
1918
- helpers = req('@nativescript/core/application/helpers-common');
1919
- }
1920
- catch { }
1921
- }
1922
- const setter = helpers && (helpers.setiOSWindow || helpers.default?.setiOSWindow);
1923
- if (typeof setter === 'function') {
1924
- try {
1925
- setter(undefined);
1926
- if (VERBOSE)
1927
- console.log('[hmr-client] cleared cached iOS window via helpers-common');
1928
- }
1929
- catch { }
1930
- }
1931
- }
1932
- catch { }
1933
- }
1934
- }
1935
- }
1936
- catch { }
1937
- // Use the previously created preparedRoot
1938
- const entry = {
1939
- create: () => {
1940
- if (!isFrameRoot) {
1941
- const F = getCore('Frame');
1942
- const fr = new F();
1943
- if (VERBOSE)
1944
- console.log('[hmr-client] resetRootView:create new Frame', {
1945
- type: fr?.constructor?.name,
1946
- });
1947
- const navEntry = {
1948
- create: () => preparedRoot,
1949
- clearHistory: true,
1950
- animated: false,
1951
- };
1952
- try {
1953
- fr.navigate(navEntry);
1954
- }
1955
- catch (e) {
1956
- console.warn('[hmr-client] resetRootView:create navigate failed', e);
1957
- }
1958
- setRootFrame(fr);
1959
- return fr;
1960
- }
1961
- else {
1962
- const fr = preparedRoot;
1963
- setRootFrame(fr);
1964
- return fr;
1965
- }
1966
- },
1967
- };
1968
- // Always use an entry with a create() function to avoid cross‑realm instanceof checks on Android.
1969
- App2.resetRootView(entry);
1970
- // After authoritative reset, it's safe to detach the early placeholder launch handler
1971
- try {
1972
- const restore = globalThis.__NS_DEV_RESTORE_PLACEHOLDER__;
1973
- if (typeof restore === 'function') {
1974
- restore();
1975
- }
1976
- }
1977
- catch { }
1978
- return true;
1979
- }
1980
- catch (e) {
1981
- console.warn('[hmr-client] resetRootView failed', e);
1982
- try {
1983
- if (VERBOSE)
1984
- console.warn('[hmr-client] resetRootView stack', e?.stack);
1985
- }
1986
- catch { }
1987
- return false;
1988
- }
1989
- finally {
1990
- try {
1991
- globalThis.__NS_DEV_RESET_IN_PROGRESS__ = false;
1992
- }
1993
- catch { }
1994
- }
1995
95
  }
96
+ installCssRegister();
97
+ // Route incoming socket messages through the protocol dispatcher.
98
+ setHmrMessageHandler(handleHmrMessage);
1996
99
  export function initHmrClient(opts) {
1997
100
  if (opts?.wsUrl) {
1998
101
  setHMRWsUrl(opts.wsUrl);
@@ -2029,12 +132,9 @@ export function initHmrClient(opts) {
2029
132
  console.log('[hmr-client] deferring WebSocket connection until boot completes');
2030
133
  setTimeout(waitForBoot, 100);
2031
134
  }
2032
- // Best-effort: install back wrapper even before first remount; original root may be captured later
2033
- switch (TARGET_FLAVOR) {
2034
- case 'vue':
2035
- ensureBackWrapperInstalled(performResetRoot, getCore);
2036
- break;
2037
- }
135
+ // Best-effort: install back wrapper even before first remount; original root may be captured later.
136
+ // Deferred until the dynamically-imported strategy resolves.
137
+ void CLIENT_STRATEGY_READY.then(() => getClientStrategy()?.installBackWrapper?.(performResetRoot, getCore));
2038
138
  }
2039
139
  export default function startViteHMR(opts) {
2040
140
  if (VERBOSE)