@nativescript/vite 8.0.0-alpha.6 → 8.0.0-alpha.61

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 (465) hide show
  1. package/README.md +51 -11
  2. package/bin/cli.cjs +8 -14
  3. package/configuration/angular.d.ts +34 -1
  4. package/configuration/angular.js +390 -165
  5. package/configuration/angular.js.map +1 -1
  6. package/configuration/base.js +244 -53
  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 +12 -93
  15. package/configuration/typescript.js.map +1 -1
  16. package/helpers/app-components.d.ts +2 -1
  17. package/helpers/app-components.js.map +1 -1
  18. package/helpers/app-css-state.d.ts +8 -0
  19. package/helpers/app-css-state.js +8 -0
  20. package/helpers/app-css-state.js.map +1 -0
  21. package/helpers/bundler-context.d.ts +11 -0
  22. package/helpers/bundler-context.js +71 -0
  23. package/helpers/bundler-context.js.map +1 -0
  24. package/helpers/cli-flags.d.ts +12 -0
  25. package/helpers/cli-flags.js +34 -0
  26. package/helpers/cli-flags.js.map +1 -1
  27. package/helpers/css-platform-plugin.d.ts +14 -0
  28. package/helpers/css-platform-plugin.js +43 -25
  29. package/helpers/css-platform-plugin.js.map +1 -1
  30. package/helpers/dev-host.d.ts +360 -0
  31. package/helpers/dev-host.js +694 -0
  32. package/helpers/dev-host.js.map +1 -0
  33. package/helpers/dynamic-import-plugin.js +9 -4
  34. package/helpers/dynamic-import-plugin.js.map +1 -1
  35. package/helpers/esbuild-platform-resolver.js +4 -1
  36. package/helpers/esbuild-platform-resolver.js.map +1 -1
  37. package/helpers/external-configs.d.ts +10 -12
  38. package/helpers/external-configs.js +58 -35
  39. package/helpers/external-configs.js.map +1 -1
  40. package/helpers/global-defines.d.ts +100 -13
  41. package/helpers/global-defines.js +165 -28
  42. package/helpers/global-defines.js.map +1 -1
  43. package/helpers/hmr-scope.d.ts +26 -0
  44. package/helpers/hmr-scope.js +67 -0
  45. package/helpers/hmr-scope.js.map +1 -0
  46. package/helpers/init.js +0 -18
  47. package/helpers/init.js.map +1 -1
  48. package/helpers/logging.js +29 -1
  49. package/helpers/logging.js.map +1 -1
  50. package/helpers/main-entry.d.ts +4 -1
  51. package/helpers/main-entry.js +368 -53
  52. package/helpers/main-entry.js.map +1 -1
  53. package/helpers/nativeclass-esbuild-plugin.d.ts +2 -1
  54. package/helpers/nativeclass-esbuild-plugin.js +6 -1
  55. package/helpers/nativeclass-esbuild-plugin.js.map +1 -1
  56. package/helpers/nativeclass-transform.d.ts +13 -0
  57. package/helpers/nativeclass-transform.js +37 -7
  58. package/helpers/nativeclass-transform.js.map +1 -1
  59. package/helpers/nativeclass-transformer-plugin.d.ts +9 -2
  60. package/helpers/nativeclass-transformer-plugin.js +163 -15
  61. package/helpers/nativeclass-transformer-plugin.js.map +1 -1
  62. package/helpers/nativescript-package-resolver.js +10 -62
  63. package/helpers/nativescript-package-resolver.js.map +1 -1
  64. package/helpers/normalize-id.d.ts +42 -0
  65. package/helpers/normalize-id.js +60 -0
  66. package/helpers/normalize-id.js.map +1 -0
  67. package/helpers/ns-core-url.d.ts +29 -7
  68. package/helpers/ns-core-url.js +69 -12
  69. package/helpers/ns-core-url.js.map +1 -1
  70. package/helpers/optimize-deps.d.ts +16 -0
  71. package/helpers/optimize-deps.js +17 -0
  72. package/helpers/optimize-deps.js.map +1 -0
  73. package/helpers/package-platform-aliases.js +34 -49
  74. package/helpers/package-platform-aliases.js.map +1 -1
  75. package/helpers/platform-types.d.ts +2 -0
  76. package/helpers/platform-types.js +2 -0
  77. package/helpers/platform-types.js.map +1 -0
  78. package/helpers/postcss-platform-config.d.ts +17 -1
  79. package/helpers/postcss-platform-config.js +20 -37
  80. package/helpers/postcss-platform-config.js.map +1 -1
  81. package/helpers/project.d.ts +35 -0
  82. package/helpers/project.js +120 -2
  83. package/helpers/project.js.map +1 -1
  84. package/helpers/resolve-main-field-platform.d.ts +20 -0
  85. package/helpers/resolve-main-field-platform.js +49 -0
  86. package/helpers/resolve-main-field-platform.js.map +1 -0
  87. package/helpers/resolver.js +17 -2
  88. package/helpers/resolver.js.map +1 -1
  89. package/helpers/theme-core-plugins.js +1 -1
  90. package/helpers/theme-core-plugins.js.map +1 -1
  91. package/helpers/ts-config-paths.d.ts +32 -0
  92. package/helpers/ts-config-paths.js +156 -27
  93. package/helpers/ts-config-paths.js.map +1 -1
  94. package/helpers/typescript-check.d.ts +2 -1
  95. package/helpers/typescript-check.js +2 -2
  96. package/helpers/typescript-check.js.map +1 -1
  97. package/helpers/ui-registration.d.ts +21 -0
  98. package/helpers/ui-registration.js +156 -0
  99. package/helpers/ui-registration.js.map +1 -0
  100. package/helpers/utils.d.ts +9 -0
  101. package/helpers/utils.js +22 -2
  102. package/helpers/utils.js.map +1 -1
  103. package/helpers/vite-package-version.d.ts +7 -0
  104. package/helpers/vite-package-version.js +44 -0
  105. package/helpers/vite-package-version.js.map +1 -0
  106. package/helpers/workers.d.ts +48 -19
  107. package/helpers/workers.js +662 -13
  108. package/helpers/workers.js.map +1 -1
  109. package/hmr/client/css-handler.d.ts +2 -1
  110. package/hmr/client/css-handler.js +50 -26
  111. package/hmr/client/css-handler.js.map +1 -1
  112. package/hmr/client/css-update-overlay.d.ts +18 -0
  113. package/hmr/client/css-update-overlay.js +27 -0
  114. package/hmr/client/css-update-overlay.js.map +1 -0
  115. package/hmr/client/framework-client-strategy.d.ts +79 -0
  116. package/hmr/client/framework-client-strategy.js +19 -0
  117. package/hmr/client/framework-client-strategy.js.map +1 -0
  118. package/hmr/client/hmr-pending-overlay.d.ts +0 -14
  119. package/hmr/client/hmr-pending-overlay.js +14 -4
  120. package/hmr/client/hmr-pending-overlay.js.map +1 -1
  121. package/hmr/client/hot-context.d.ts +67 -0
  122. package/hmr/client/hot-context.js +284 -0
  123. package/hmr/client/hot-context.js.map +1 -0
  124. package/hmr/client/index.js +922 -273
  125. package/hmr/client/index.js.map +1 -1
  126. package/hmr/client/utils.d.ts +2 -1
  127. package/hmr/client/utils.js +111 -99
  128. package/hmr/client/utils.js.map +1 -1
  129. package/hmr/entry-runtime.d.ts +2 -1
  130. package/hmr/entry-runtime.js +279 -71
  131. package/hmr/entry-runtime.js.map +1 -1
  132. package/hmr/frameworks/angular/build/angular-linker.d.ts +12 -0
  133. package/hmr/frameworks/angular/build/angular-linker.js +109 -0
  134. package/hmr/frameworks/angular/build/angular-linker.js.map +1 -0
  135. package/hmr/frameworks/angular/build/inject-component-hmr-registration.d.ts +112 -0
  136. package/hmr/frameworks/angular/build/inject-component-hmr-registration.js +291 -0
  137. package/hmr/frameworks/angular/build/inject-component-hmr-registration.js.map +1 -0
  138. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.d.ts +75 -0
  139. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js +221 -0
  140. package/hmr/frameworks/angular/build/inject-hmr-vite-ignore.js.map +1 -0
  141. package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.js +1 -170
  142. package/hmr/frameworks/angular/build/inline-decorator-component-templates.js.map +1 -0
  143. package/hmr/frameworks/angular/build/js-lexer.d.ts +4 -0
  144. package/{helpers/angular/synthesize-decorator-ctor-parameters.js → hmr/frameworks/angular/build/js-lexer.js} +22 -96
  145. package/hmr/frameworks/angular/build/js-lexer.js.map +1 -0
  146. package/hmr/frameworks/angular/build/shared-linker.d.ts +39 -0
  147. package/hmr/frameworks/angular/build/shared-linker.js +128 -0
  148. package/hmr/frameworks/angular/build/shared-linker.js.map +1 -0
  149. package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js +88 -0
  150. package/hmr/frameworks/angular/build/synthesize-decorator-ctor-parameters.js.map +1 -0
  151. package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.js +1 -174
  152. package/hmr/frameworks/angular/build/synthesize-injectable-factories.js.map +1 -0
  153. package/{helpers/angular → hmr/frameworks/angular/build}/util.d.ts +1 -0
  154. package/hmr/frameworks/angular/build/util.js +155 -0
  155. package/hmr/frameworks/angular/build/util.js.map +1 -0
  156. package/hmr/frameworks/angular/client/index.js +542 -175
  157. package/hmr/frameworks/angular/client/index.js.map +1 -1
  158. package/hmr/frameworks/angular/client/strategy.d.ts +9 -0
  159. package/hmr/frameworks/angular/client/strategy.js +19 -0
  160. package/hmr/frameworks/angular/client/strategy.js.map +1 -0
  161. package/hmr/frameworks/angular/server/angular-root-component.d.ts +79 -0
  162. package/hmr/frameworks/angular/server/angular-root-component.js +149 -0
  163. package/hmr/frameworks/angular/server/angular-root-component.js.map +1 -0
  164. package/hmr/frameworks/angular/server/linker.js +1 -4
  165. package/hmr/frameworks/angular/server/linker.js.map +1 -1
  166. package/hmr/frameworks/angular/server/strategy.js +458 -12
  167. package/hmr/frameworks/angular/server/strategy.js.map +1 -1
  168. package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.js +2 -2
  169. package/hmr/frameworks/angular/server/websocket-angular-entry.js.map +1 -0
  170. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.d.ts +14 -11
  171. package/hmr/{server → frameworks/angular/server}/websocket-angular-hot-update.js +108 -111
  172. package/hmr/frameworks/angular/server/websocket-angular-hot-update.js.map +1 -0
  173. package/hmr/frameworks/react/server/strategy.d.ts +2 -0
  174. package/hmr/frameworks/react/server/strategy.js +230 -0
  175. package/hmr/frameworks/react/server/strategy.js.map +1 -0
  176. package/hmr/frameworks/solid/build/solid-jsx-deps.d.ts +15 -0
  177. package/hmr/frameworks/solid/build/solid-jsx-deps.js +178 -0
  178. package/hmr/frameworks/solid/build/solid-jsx-deps.js.map +1 -0
  179. package/hmr/frameworks/solid/client/app-runtime.d.ts +68 -0
  180. package/hmr/frameworks/solid/client/app-runtime.js +246 -0
  181. package/hmr/frameworks/solid/client/app-runtime.js.map +1 -0
  182. package/hmr/frameworks/solid/server/strategy.js +291 -16
  183. package/hmr/frameworks/solid/server/strategy.js.map +1 -1
  184. package/hmr/frameworks/typescript/server/strategy.js +38 -14
  185. package/hmr/frameworks/typescript/server/strategy.js.map +1 -1
  186. package/hmr/frameworks/vue/client/dep-propagation.d.ts +44 -0
  187. package/hmr/frameworks/vue/client/dep-propagation.js +148 -0
  188. package/hmr/frameworks/vue/client/dep-propagation.js.map +1 -0
  189. package/hmr/frameworks/vue/client/index.d.ts +9 -0
  190. package/hmr/frameworks/vue/client/index.js +251 -247
  191. package/hmr/frameworks/vue/client/index.js.map +1 -1
  192. package/hmr/frameworks/vue/client/strategy.d.ts +33 -0
  193. package/hmr/frameworks/vue/client/strategy.js +157 -0
  194. package/hmr/frameworks/vue/client/strategy.js.map +1 -0
  195. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.d.ts +49 -0
  196. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js +142 -0
  197. package/hmr/frameworks/vue/client/vue-sfc-update-overlay.js.map +1 -0
  198. package/hmr/frameworks/vue/server/compiler.d.ts +3 -1
  199. package/hmr/frameworks/vue/server/compiler.js +3 -1
  200. package/hmr/frameworks/vue/server/compiler.js.map +1 -1
  201. package/hmr/frameworks/vue/server/sfc-route-assemble.d.ts +7 -0
  202. package/hmr/frameworks/vue/server/sfc-route-assemble.js +823 -0
  203. package/hmr/frameworks/vue/server/sfc-route-assemble.js.map +1 -0
  204. package/hmr/frameworks/vue/server/sfc-route-meta.d.ts +7 -0
  205. package/hmr/frameworks/vue/server/sfc-route-meta.js +80 -0
  206. package/hmr/frameworks/vue/server/sfc-route-meta.js.map +1 -0
  207. package/hmr/frameworks/vue/server/sfc-route-serve.d.ts +8 -0
  208. package/hmr/frameworks/vue/server/sfc-route-serve.js +462 -0
  209. package/hmr/frameworks/vue/server/sfc-route-serve.js.map +1 -0
  210. package/hmr/frameworks/vue/server/sfc-route-shared.d.ts +45 -0
  211. package/hmr/frameworks/vue/server/sfc-route-shared.js +105 -0
  212. package/hmr/frameworks/vue/server/sfc-route-shared.js.map +1 -0
  213. package/hmr/frameworks/vue/server/strategy.d.ts +35 -0
  214. package/hmr/frameworks/vue/server/strategy.js +286 -7
  215. package/hmr/frameworks/vue/server/strategy.js.map +1 -1
  216. package/hmr/frameworks/vue/server/websocket-sfc.d.ts +15 -0
  217. package/hmr/frameworks/vue/server/websocket-sfc.js +20 -0
  218. package/hmr/frameworks/vue/server/websocket-sfc.js.map +1 -0
  219. package/hmr/helpers/ast-normalizer.d.ts +3 -1
  220. package/hmr/helpers/ast-normalizer.js +77 -10
  221. package/hmr/helpers/ast-normalizer.js.map +1 -1
  222. package/hmr/helpers/cjs-named-exports.d.ts +23 -0
  223. package/hmr/helpers/cjs-named-exports.js +152 -0
  224. package/hmr/helpers/cjs-named-exports.js.map +1 -0
  225. package/hmr/helpers/package-exports.d.ts +16 -0
  226. package/hmr/helpers/package-exports.js +396 -0
  227. package/hmr/helpers/package-exports.js.map +1 -0
  228. package/hmr/helpers/vendor-rewrite.d.ts +1 -1
  229. package/hmr/helpers/vendor-rewrite.js +5 -3
  230. package/hmr/helpers/vendor-rewrite.js.map +1 -1
  231. package/hmr/server/boot-archive-route.d.ts +40 -0
  232. package/hmr/server/boot-archive-route.js +154 -0
  233. package/hmr/server/boot-archive-route.js.map +1 -0
  234. package/hmr/server/boot-closure-route.d.ts +49 -0
  235. package/hmr/server/boot-closure-route.js +144 -0
  236. package/hmr/server/boot-closure-route.js.map +1 -0
  237. package/hmr/server/boot-recording.d.ts +58 -0
  238. package/hmr/server/boot-recording.js +228 -0
  239. package/hmr/server/boot-recording.js.map +1 -0
  240. package/hmr/server/constants.js +20 -5
  241. package/hmr/server/constants.js.map +1 -1
  242. package/hmr/server/core-bundle.d.ts +140 -0
  243. package/hmr/server/core-bundle.js +614 -0
  244. package/hmr/server/core-bundle.js.map +1 -0
  245. package/hmr/server/core-sanitize.d.ts +86 -7
  246. package/hmr/server/core-sanitize.js +170 -45
  247. package/hmr/server/core-sanitize.js.map +1 -1
  248. package/hmr/server/css-device-module.d.ts +28 -0
  249. package/hmr/server/css-device-module.js +44 -0
  250. package/hmr/server/css-device-module.js.map +1 -0
  251. package/hmr/server/deps-bundle.d.ts +218 -0
  252. package/hmr/server/deps-bundle.js +998 -0
  253. package/hmr/server/deps-bundle.js.map +1 -0
  254. package/hmr/server/device-transform-helpers.d.ts +24 -0
  255. package/hmr/server/device-transform-helpers.js +408 -0
  256. package/hmr/server/device-transform-helpers.js.map +1 -0
  257. package/hmr/server/framework-strategy.d.ts +113 -11
  258. package/hmr/server/hmr-module-graph.d.ts +37 -0
  259. package/hmr/server/hmr-module-graph.js +215 -0
  260. package/hmr/server/hmr-module-graph.js.map +1 -0
  261. package/hmr/server/import-map.d.ts +13 -4
  262. package/hmr/server/import-map.js +94 -47
  263. package/hmr/server/import-map.js.map +1 -1
  264. package/hmr/server/index.js +7 -16
  265. package/hmr/server/index.js.map +1 -1
  266. package/hmr/server/ns-core-cjs-shape.d.ts +2 -4
  267. package/hmr/server/ns-core-cjs-shape.js +4 -6
  268. package/hmr/server/ns-core-cjs-shape.js.map +1 -1
  269. package/hmr/server/ns-m-response-memo.d.ts +10 -0
  270. package/hmr/server/ns-m-response-memo.js +33 -0
  271. package/hmr/server/ns-m-response-memo.js.map +1 -0
  272. package/hmr/server/ns-rt-bridge.d.ts +51 -0
  273. package/hmr/server/ns-rt-bridge.js +131 -0
  274. package/hmr/server/ns-rt-bridge.js.map +1 -0
  275. package/hmr/server/ns-rt-route.d.ts +5 -0
  276. package/hmr/server/ns-rt-route.js +39 -0
  277. package/hmr/server/ns-rt-route.js.map +1 -0
  278. package/hmr/server/perf-instrumentation.d.ts +6 -10
  279. package/hmr/server/perf-instrumentation.js +5 -6
  280. package/hmr/server/perf-instrumentation.js.map +1 -1
  281. package/hmr/server/process-code-for-device.d.ts +30 -0
  282. package/hmr/server/process-code-for-device.js +791 -0
  283. package/hmr/server/process-code-for-device.js.map +1 -0
  284. package/hmr/server/require-guard.d.ts +1 -0
  285. package/hmr/server/require-guard.js +12 -0
  286. package/hmr/server/require-guard.js.map +1 -0
  287. package/hmr/server/rewrite-imports.d.ts +2 -0
  288. package/hmr/server/rewrite-imports.js +638 -0
  289. package/hmr/server/rewrite-imports.js.map +1 -0
  290. package/hmr/server/route-helpers.d.ts +7 -0
  291. package/hmr/server/route-helpers.js +13 -0
  292. package/hmr/server/route-helpers.js.map +1 -0
  293. package/hmr/server/server-origin.d.ts +2 -0
  294. package/hmr/server/server-origin.js +83 -0
  295. package/hmr/server/server-origin.js.map +1 -0
  296. package/hmr/server/shared-transform-request.js +1 -2
  297. package/hmr/server/shared-transform-request.js.map +1 -1
  298. package/hmr/server/transform-cache-invalidation.d.ts +37 -0
  299. package/hmr/server/transform-cache-invalidation.js +156 -0
  300. package/hmr/server/transform-cache-invalidation.js.map +1 -0
  301. package/hmr/server/vendor-bare-module-shims.d.ts +4 -0
  302. package/hmr/server/vendor-bare-module-shims.js +80 -0
  303. package/hmr/server/vendor-bare-module-shims.js.map +1 -0
  304. package/hmr/server/vite-plugin.d.ts +1 -0
  305. package/hmr/server/vite-plugin.js +180 -54
  306. package/hmr/server/vite-plugin.js.map +1 -1
  307. package/hmr/server/websocket-core-bridge.d.ts +51 -4
  308. package/hmr/server/websocket-core-bridge.js +62 -54
  309. package/hmr/server/websocket-core-bridge.js.map +1 -1
  310. package/hmr/server/websocket-css-hot-update.d.ts +33 -0
  311. package/hmr/server/websocket-css-hot-update.js +65 -0
  312. package/hmr/server/websocket-css-hot-update.js.map +1 -0
  313. package/hmr/server/websocket-device-transform.d.ts +3 -0
  314. package/hmr/server/websocket-device-transform.js +7 -0
  315. package/hmr/server/websocket-device-transform.js.map +1 -0
  316. package/hmr/server/websocket-hmr-pending.d.ts +3 -9
  317. package/hmr/server/websocket-hmr-pending.js +1 -1
  318. package/hmr/server/websocket-hmr-pending.js.map +1 -1
  319. package/hmr/server/websocket-hot-update.d.ts +77 -0
  320. package/hmr/server/websocket-hot-update.js +360 -0
  321. package/hmr/server/websocket-hot-update.js.map +1 -0
  322. package/hmr/server/websocket-import-map-route.d.ts +15 -0
  323. package/hmr/server/websocket-import-map-route.js +50 -0
  324. package/hmr/server/websocket-import-map-route.js.map +1 -0
  325. package/hmr/server/websocket-module-bindings.js +3 -3
  326. package/hmr/server/websocket-module-bindings.js.map +1 -1
  327. package/hmr/server/websocket-module-specifiers.d.ts +66 -2
  328. package/hmr/server/websocket-module-specifiers.js +191 -20
  329. package/hmr/server/websocket-module-specifiers.js.map +1 -1
  330. package/hmr/server/websocket-ns-core.d.ts +34 -0
  331. package/hmr/server/websocket-ns-core.js +414 -0
  332. package/hmr/server/websocket-ns-core.js.map +1 -0
  333. package/hmr/server/websocket-ns-entry.d.ts +21 -0
  334. package/hmr/server/websocket-ns-entry.js +164 -0
  335. package/hmr/server/websocket-ns-entry.js.map +1 -0
  336. package/hmr/server/websocket-ns-m-paths.d.ts +1 -3
  337. package/hmr/server/websocket-ns-m-paths.js +25 -82
  338. package/hmr/server/websocket-ns-m-paths.js.map +1 -1
  339. package/hmr/server/websocket-ns-m-request.d.ts +11 -1
  340. package/hmr/server/websocket-ns-m-request.js +17 -9
  341. package/hmr/server/websocket-ns-m-request.js.map +1 -1
  342. package/hmr/server/websocket-ns-m.d.ts +52 -0
  343. package/hmr/server/websocket-ns-m.js +835 -0
  344. package/hmr/server/websocket-ns-m.js.map +1 -0
  345. package/hmr/server/websocket-served-module-helpers.d.ts +50 -4
  346. package/hmr/server/websocket-served-module-helpers.js +384 -86
  347. package/hmr/server/websocket-served-module-helpers.js.map +1 -1
  348. package/hmr/server/websocket-txn.js +6 -9
  349. package/hmr/server/websocket-txn.js.map +1 -1
  350. package/hmr/server/websocket-vendor-unifier.d.ts +0 -1
  351. package/hmr/server/websocket-vendor-unifier.js +4 -9
  352. package/hmr/server/websocket-vendor-unifier.js.map +1 -1
  353. package/hmr/server/websocket.d.ts +7 -39
  354. package/hmr/server/websocket.js +643 -6716
  355. package/hmr/server/websocket.js.map +1 -1
  356. package/hmr/shared/ns-globals.d.ts +108 -0
  357. package/hmr/shared/ns-globals.js +28 -0
  358. package/hmr/shared/ns-globals.js.map +1 -0
  359. package/hmr/shared/protocol.d.ts +145 -0
  360. package/hmr/shared/protocol.js +28 -0
  361. package/hmr/shared/protocol.js.map +1 -0
  362. package/hmr/shared/runtime/boot-archive-format.d.ts +16 -0
  363. package/hmr/shared/runtime/boot-archive-format.js +31 -0
  364. package/hmr/shared/runtime/boot-archive-format.js.map +1 -0
  365. package/hmr/shared/runtime/boot-complete.d.ts +14 -0
  366. package/hmr/shared/runtime/boot-complete.js +32 -0
  367. package/hmr/shared/runtime/boot-complete.js.map +1 -0
  368. package/hmr/shared/runtime/boot-placeholder-ui.d.ts +69 -0
  369. package/hmr/shared/runtime/boot-placeholder-ui.js +101 -0
  370. package/hmr/shared/runtime/boot-placeholder-ui.js.map +1 -0
  371. package/hmr/shared/runtime/boot-progress.d.ts +44 -0
  372. package/hmr/shared/runtime/boot-progress.js +134 -0
  373. package/hmr/shared/runtime/boot-progress.js.map +1 -0
  374. package/hmr/shared/runtime/boot-timeline.d.ts +2 -1
  375. package/hmr/shared/runtime/boot-timeline.js +9 -22
  376. package/hmr/shared/runtime/boot-timeline.js.map +1 -1
  377. package/hmr/shared/runtime/browser-runtime-contract.d.ts +53 -22
  378. package/hmr/shared/runtime/browser-runtime-contract.js +6 -9
  379. package/hmr/shared/runtime/browser-runtime-contract.js.map +1 -1
  380. package/hmr/shared/runtime/dev-overlay-snapshots.d.ts +31 -0
  381. package/hmr/shared/runtime/dev-overlay-snapshots.js +324 -0
  382. package/hmr/shared/runtime/dev-overlay-snapshots.js.map +1 -0
  383. package/hmr/shared/runtime/dev-overlay.d.ts +76 -30
  384. package/hmr/shared/runtime/dev-overlay.js +767 -408
  385. package/hmr/shared/runtime/dev-overlay.js.map +1 -1
  386. package/hmr/shared/runtime/global-scope.d.ts +18 -0
  387. package/hmr/shared/runtime/global-scope.js +21 -0
  388. package/hmr/shared/runtime/global-scope.js.map +1 -0
  389. package/hmr/shared/runtime/hooks.js +2 -1
  390. package/hmr/shared/runtime/hooks.js.map +1 -1
  391. package/hmr/shared/runtime/http-only-boot.js +7 -6
  392. package/hmr/shared/runtime/http-only-boot.js.map +1 -1
  393. package/hmr/shared/runtime/module-provenance.js +4 -6
  394. package/hmr/shared/runtime/module-provenance.js.map +1 -1
  395. package/hmr/shared/runtime/root-placeholder-view.d.ts +19 -0
  396. package/hmr/shared/runtime/root-placeholder-view.js +311 -0
  397. package/hmr/shared/runtime/root-placeholder-view.js.map +1 -0
  398. package/hmr/shared/runtime/root-placeholder.js +398 -204
  399. package/hmr/shared/runtime/root-placeholder.js.map +1 -1
  400. package/hmr/shared/runtime/session-bootstrap.js +274 -55
  401. package/hmr/shared/runtime/session-bootstrap.js.map +1 -1
  402. package/hmr/shared/runtime/vendor-bootstrap.js +3 -10
  403. package/hmr/shared/runtime/vendor-bootstrap.js.map +1 -1
  404. package/hmr/shared/vendor/manifest-collect.d.ts +4 -0
  405. package/hmr/shared/vendor/manifest-collect.js +549 -0
  406. package/hmr/shared/vendor/manifest-collect.js.map +1 -0
  407. package/hmr/shared/vendor/manifest-loader.d.ts +2 -1
  408. package/hmr/shared/vendor/manifest-loader.js +5 -3
  409. package/hmr/shared/vendor/manifest-loader.js.map +1 -1
  410. package/hmr/shared/vendor/manifest.d.ts +1 -7
  411. package/hmr/shared/vendor/manifest.js +136 -825
  412. package/hmr/shared/vendor/manifest.js.map +1 -1
  413. package/hmr/shared/vendor/registry.d.ts +2 -0
  414. package/hmr/shared/vendor/registry.js +14 -0
  415. package/hmr/shared/vendor/registry.js.map +1 -1
  416. package/hmr/shared/vendor/vendor-device-shim.d.ts +1 -0
  417. package/hmr/shared/vendor/vendor-device-shim.js +208 -0
  418. package/hmr/shared/vendor/vendor-device-shim.js.map +1 -0
  419. package/hmr/shared/vendor/vendor-esbuild-plugins.d.ts +76 -0
  420. package/hmr/shared/vendor/vendor-esbuild-plugins.js +401 -0
  421. package/hmr/shared/vendor/vendor-esbuild-plugins.js.map +1 -0
  422. package/hmr/vendor-bootstrap.d.ts +1 -3
  423. package/hmr/vendor-bootstrap.js +4 -6
  424. package/hmr/vendor-bootstrap.js.map +1 -1
  425. package/index.d.ts +1 -0
  426. package/index.js +5 -0
  427. package/index.js.map +1 -1
  428. package/package.json +65 -11
  429. package/runtime/core-aliases-early.js +25 -55
  430. package/runtime/core-aliases-early.js.map +1 -1
  431. package/shims/react-jsx-runtime.d.ts +4 -0
  432. package/shims/react-jsx-runtime.js +61 -0
  433. package/shims/react-jsx-runtime.js.map +1 -0
  434. package/helpers/angular/angular-linker.d.ts +0 -13
  435. package/helpers/angular/angular-linker.js +0 -194
  436. package/helpers/angular/angular-linker.js.map +0 -1
  437. package/helpers/angular/inline-decorator-component-templates.js.map +0 -1
  438. package/helpers/angular/shared-linker.d.ts +0 -11
  439. package/helpers/angular/shared-linker.js +0 -75
  440. package/helpers/angular/shared-linker.js.map +0 -1
  441. package/helpers/angular/synthesize-decorator-ctor-parameters.js.map +0 -1
  442. package/helpers/angular/synthesize-injectable-factories.js.map +0 -1
  443. package/helpers/angular/util.js +0 -67
  444. package/helpers/angular/util.js.map +0 -1
  445. package/helpers/prelink-angular.d.ts +0 -2
  446. package/helpers/prelink-angular.js +0 -117
  447. package/helpers/prelink-angular.js.map +0 -1
  448. package/hmr/server/websocket-angular-entry.js.map +0 -1
  449. package/hmr/server/websocket-angular-hot-update.js.map +0 -1
  450. package/hmr/server/websocket-ns-m-finalize.d.ts +0 -22
  451. package/hmr/server/websocket-ns-m-finalize.js +0 -88
  452. package/hmr/server/websocket-ns-m-finalize.js.map +0 -1
  453. package/hmr/server/websocket-runtime-compat.d.ts +0 -19
  454. package/hmr/server/websocket-runtime-compat.js +0 -286
  455. package/hmr/server/websocket-runtime-compat.js.map +0 -1
  456. package/hmr/server/websocket-vue-sfc.d.ts +0 -27
  457. package/hmr/server/websocket-vue-sfc.js +0 -1114
  458. package/hmr/server/websocket-vue-sfc.js.map +0 -1
  459. package/transformers/NativeClass/index.d.ts +0 -2
  460. package/transformers/NativeClass/index.js +0 -222
  461. package/transformers/NativeClass/index.js.map +0 -1
  462. /package/{helpers/angular → hmr/frameworks/angular/build}/inline-decorator-component-templates.d.ts +0 -0
  463. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-decorator-ctor-parameters.d.ts +0 -0
  464. /package/{helpers/angular → hmr/frameworks/angular/build}/synthesize-injectable-factories.d.ts +0 -0
  465. /package/hmr/{server → frameworks/angular/server}/websocket-angular-entry.d.ts +0 -0
@@ -1,18 +1,42 @@
1
- const BOOT_TITLE = 'NativeScript Vite preparing dev session...';
2
- const DEFAULT_SNAPSHOT = {
3
- visible: false,
4
- mode: 'hidden',
5
- badge: 'HMR',
6
- title: BOOT_TITLE,
7
- phase: '',
8
- detail: '',
9
- progress: null,
10
- busy: false,
11
- blocking: false,
12
- tone: 'info',
13
- };
1
+ import { BOOT_PLACEHOLDER_MOTION, computeBootProgressFillScale, formatBootDetailLine, formatBootPrimaryLine } from './boot-placeholder-ui.js';
2
+ import { BOOT_TITLE, DEFAULT_SNAPSHOT, createBootOverlaySnapshot, createConnectionOverlaySnapshot, createUpdateOverlaySnapshot } from './dev-overlay-snapshots.js';
3
+ import { getGlobalScope } from './global-scope.js';
4
+ // Re-export the snapshot model so existing `./dev-overlay.js` importers keep working.
5
+ export { createBootOverlaySnapshot, createConnectionOverlaySnapshot, createUpdateOverlaySnapshot } from './dev-overlay-snapshots.js';
6
+ const DEFAULT_OVERLAY_POSITION = 'top';
14
7
  function getOverlayGlobal() {
15
- return globalThis;
8
+ return getGlobalScope();
9
+ }
10
+ /**
11
+ * Resolve the configured live-overlay position.
12
+ *
13
+ * Reads `globalThis.__NS_HMR_OVERLAY_POSITION__` so a project can
14
+ * override the default at boot time (e.g. inside `app.ts` before the
15
+ * Vite session bootstraps). Falls back to 'top' which gives the
16
+ * toast-style chip with a slide-in animation and safe-area padding.
17
+ */
18
+ export function getHmrDevOverlayPosition() {
19
+ const g = getOverlayGlobal();
20
+ const stored = g.__NS_HMR_OVERLAY_POSITION__;
21
+ if (stored === 'top' || stored === 'bottom' || stored === 'center') {
22
+ return stored;
23
+ }
24
+ return DEFAULT_OVERLAY_POSITION;
25
+ }
26
+ /**
27
+ * Imperative setter for the live-overlay position. Re-applies the
28
+ * current snapshot so the change is visible without waiting for the
29
+ * next HMR cycle. Useful during dev to A/B between top/bottom/center
30
+ * without restarting the app.
31
+ */
32
+ export function setHmrDevOverlayPosition(position) {
33
+ if (position !== 'top' && position !== 'bottom' && position !== 'center') {
34
+ return;
35
+ }
36
+ const g = getOverlayGlobal();
37
+ g.__NS_HMR_OVERLAY_POSITION__ = position;
38
+ const state = getRuntimeState();
39
+ applyRuntimeSnapshot(state.snapshot);
16
40
  }
17
41
  function getRuntimeState() {
18
42
  const g = getOverlayGlobal();
@@ -41,319 +65,6 @@ function getRuntimeState() {
41
65
  state.updateCycleStartedAt = 0;
42
66
  return state;
43
67
  }
44
- function describeAttempt(info) {
45
- const attempt = Number(info?.attempt || 0);
46
- const attempts = Number(info?.attempts || 0);
47
- if (!attempt || !attempts) {
48
- return '';
49
- }
50
- return `Attempt ${attempt}/${attempts}`;
51
- }
52
- export function createBootOverlaySnapshot(stage, info) {
53
- const attemptText = describeAttempt(info);
54
- const phaseInfo = {
55
- placeholder: {
56
- visible: true,
57
- mode: 'boot',
58
- badge: 'BOOT',
59
- title: BOOT_TITLE,
60
- phase: 'Preparing the HTTP HMR bootstrap',
61
- progress: 4,
62
- busy: true,
63
- blocking: true,
64
- tone: 'info',
65
- },
66
- 'probing-origin': {
67
- visible: true,
68
- mode: 'boot',
69
- badge: 'BOOT',
70
- title: BOOT_TITLE,
71
- phase: 'Contacting the Vite dev server',
72
- progress: 8,
73
- busy: true,
74
- blocking: true,
75
- tone: 'info',
76
- },
77
- 'loading-entry-runtime': {
78
- visible: true,
79
- mode: 'boot',
80
- badge: 'BOOT',
81
- title: BOOT_TITLE,
82
- phase: 'Loading the entry runtime bridge',
83
- progress: 16,
84
- busy: true,
85
- blocking: true,
86
- tone: 'info',
87
- },
88
- 'configuring-import-map': {
89
- visible: true,
90
- mode: 'boot',
91
- badge: 'BOOT',
92
- title: BOOT_TITLE,
93
- phase: 'Configuring the import map',
94
- progress: 26,
95
- busy: true,
96
- blocking: true,
97
- tone: 'info',
98
- },
99
- 'loading-runtime-bridge': {
100
- visible: true,
101
- mode: 'boot',
102
- badge: 'BOOT',
103
- title: BOOT_TITLE,
104
- phase: 'Loading the NativeScript runtime bridge',
105
- progress: 40,
106
- busy: true,
107
- blocking: true,
108
- tone: 'info',
109
- },
110
- 'loading-core-bridge': {
111
- visible: true,
112
- mode: 'boot',
113
- badge: 'BOOT',
114
- title: BOOT_TITLE,
115
- phase: 'Loading the unified core bridge',
116
- progress: 54,
117
- busy: true,
118
- blocking: true,
119
- tone: 'info',
120
- },
121
- 'preloading-style-scope': {
122
- visible: true,
123
- mode: 'boot',
124
- badge: 'BOOT',
125
- title: BOOT_TITLE,
126
- phase: 'Preparing the shared style scope',
127
- progress: 62,
128
- busy: true,
129
- blocking: true,
130
- tone: 'info',
131
- },
132
- 'installing-css': {
133
- visible: true,
134
- mode: 'boot',
135
- badge: 'BOOT',
136
- title: BOOT_TITLE,
137
- phase: 'Applying the app stylesheet',
138
- progress: 70,
139
- busy: true,
140
- blocking: true,
141
- tone: 'info',
142
- },
143
- 'importing-main': {
144
- visible: true,
145
- mode: 'boot',
146
- badge: 'BOOT',
147
- title: BOOT_TITLE,
148
- phase: 'Importing the app entry',
149
- progress: 82,
150
- busy: true,
151
- blocking: true,
152
- tone: 'info',
153
- },
154
- 'waiting-for-app': {
155
- visible: true,
156
- mode: 'boot',
157
- badge: 'BOOT',
158
- title: BOOT_TITLE,
159
- phase: 'Waiting for the app root view',
160
- progress: 94,
161
- busy: true,
162
- blocking: true,
163
- tone: 'info',
164
- },
165
- 'app-root-committed': {
166
- visible: true,
167
- mode: 'boot',
168
- badge: 'READY',
169
- title: BOOT_TITLE,
170
- phase: 'Real app root committed',
171
- progress: 100,
172
- busy: false,
173
- blocking: true,
174
- tone: 'info',
175
- },
176
- ready: {
177
- visible: true,
178
- mode: 'boot',
179
- badge: 'READY',
180
- title: BOOT_TITLE,
181
- phase: 'Boot complete',
182
- progress: 100,
183
- busy: false,
184
- blocking: true,
185
- tone: 'info',
186
- },
187
- error: {
188
- visible: true,
189
- mode: 'boot',
190
- badge: 'RETRY',
191
- title: BOOT_TITLE,
192
- phase: 'Retrying after a boot failure',
193
- progress: null,
194
- busy: true,
195
- blocking: true,
196
- tone: 'error',
197
- },
198
- };
199
- const base = phaseInfo[stage];
200
- let detail = info?.detail || '';
201
- if (!detail && stage === 'probing-origin' && info?.origin) {
202
- detail = `Trying ${info.origin}`;
203
- }
204
- if (attemptText) {
205
- detail = detail ? `${detail} ${attemptText}` : attemptText;
206
- }
207
- return {
208
- ...base,
209
- detail,
210
- progress: typeof info?.progress === 'number' || info?.progress === null ? info.progress : base.progress,
211
- };
212
- }
213
- export function createConnectionOverlaySnapshot(stage, info) {
214
- if (stage === 'healthy') {
215
- return { ...DEFAULT_SNAPSHOT };
216
- }
217
- const phaseInfo = {
218
- connecting: {
219
- visible: true,
220
- mode: 'connection',
221
- badge: 'SOCKET',
222
- title: 'Waiting for Vite dev server',
223
- phase: 'Opening websocket connection',
224
- detail: 'Live updates are paused until the connection is healthy.',
225
- progress: null,
226
- busy: true,
227
- blocking: false,
228
- tone: 'warn',
229
- },
230
- reconnecting: {
231
- visible: true,
232
- mode: 'connection',
233
- badge: 'SOCKET',
234
- title: 'HMR connection lost',
235
- phase: 'Reconnecting Vite websocket',
236
- detail: 'The app may be stale until the dev server reconnects.',
237
- progress: null,
238
- busy: true,
239
- blocking: false,
240
- tone: 'warn',
241
- },
242
- synchronizing: {
243
- visible: true,
244
- mode: 'connection',
245
- badge: 'SYNC',
246
- title: 'HMR connection restored',
247
- phase: 'Synchronizing live-update state',
248
- detail: 'Finalizing the module graph before dismissing the overlay.',
249
- progress: 95,
250
- busy: true,
251
- blocking: false,
252
- tone: 'info',
253
- },
254
- offline: {
255
- visible: true,
256
- mode: 'connection',
257
- badge: 'OFFLINE',
258
- title: 'Vite dev server offline',
259
- phase: 'Please check your terminal.',
260
- detail: 'The websocket and HTTP HMR path are both unavailable right now.',
261
- progress: null,
262
- busy: true,
263
- blocking: false,
264
- tone: 'error',
265
- },
266
- };
267
- const base = phaseInfo[stage];
268
- return {
269
- ...base,
270
- detail: info?.detail || base.detail,
271
- progress: typeof info?.progress === 'number' || info?.progress === null ? info.progress : base.progress,
272
- };
273
- }
274
- // Round-eleven.3 (alpha.62) — Snapshot factory for the HMR-applying
275
- // overlay. Each stage owns a fixed phase string, badge, and progress
276
- // %. We pick the percentages so users see continuous forward motion:
277
- // the cheap stages (mutex acquire, eviction call) advance fast; the
278
- // long tail (entry re-import + Angular reboot) sits at 60→90 so the
279
- // bar keeps moving even when the V8 ESM walk dominates wall time.
280
- //
281
- // The 'complete' stage holds for a brief moment (the API auto-hides
282
- // it via setUpdateStage) so the user gets visual closure ("the update
283
- // landed") without staring at a frozen overlay; tone stays 'success'
284
- // throughout so the colour scheme never flickers between phases.
285
- const HMR_UPDATE_TITLE = 'HMR update applying...';
286
- const HMR_UPDATE_DONE_TITLE = 'HMR update applied';
287
- export function createUpdateOverlaySnapshot(stage, info) {
288
- const phaseInfo = {
289
- received: {
290
- visible: true,
291
- mode: 'update',
292
- badge: 'HMR',
293
- title: HMR_UPDATE_TITLE,
294
- phase: 'Preparing update',
295
- detail: '',
296
- progress: 5,
297
- busy: true,
298
- blocking: false,
299
- tone: 'success',
300
- },
301
- evicting: {
302
- visible: true,
303
- mode: 'update',
304
- badge: 'HMR',
305
- title: HMR_UPDATE_TITLE,
306
- phase: 'Invalidating module cache',
307
- detail: '',
308
- progress: 30,
309
- busy: true,
310
- blocking: false,
311
- tone: 'success',
312
- },
313
- reimporting: {
314
- visible: true,
315
- mode: 'update',
316
- badge: 'HMR',
317
- title: HMR_UPDATE_TITLE,
318
- phase: 'Re-importing entry',
319
- detail: '',
320
- progress: 60,
321
- busy: true,
322
- blocking: false,
323
- tone: 'success',
324
- },
325
- rebooting: {
326
- visible: true,
327
- mode: 'update',
328
- badge: 'HMR',
329
- title: HMR_UPDATE_TITLE,
330
- phase: 'Rebooting Angular',
331
- detail: '',
332
- progress: 90,
333
- busy: true,
334
- blocking: false,
335
- tone: 'success',
336
- },
337
- complete: {
338
- visible: true,
339
- mode: 'update',
340
- badge: 'HMR',
341
- title: HMR_UPDATE_DONE_TITLE,
342
- phase: 'Update applied',
343
- detail: '',
344
- progress: 100,
345
- busy: false,
346
- blocking: false,
347
- tone: 'success',
348
- },
349
- };
350
- const base = phaseInfo[stage];
351
- return {
352
- ...base,
353
- detail: info?.detail || base.detail,
354
- progress: typeof info?.progress === 'number' || info?.progress === null ? info.progress : base.progress,
355
- };
356
- }
357
68
  function resolveCoreExport(name) {
358
69
  const g = getOverlayGlobal();
359
70
  try {
@@ -533,10 +244,28 @@ function findBootStatusLabel() {
533
244
  catch { }
534
245
  return null;
535
246
  }
247
+ function findBootDetailLabel() {
248
+ const g = getOverlayGlobal();
249
+ return g.__NS_DEV_BOOT_DETAIL_LABEL__ || null;
250
+ }
251
+ function findBootProgressFill() {
252
+ const g = getOverlayGlobal();
253
+ return g.__NS_DEV_BOOT_PROGRESS_FILL__ || null;
254
+ }
536
255
  function updateBootStatusLabel(snapshot) {
537
- const newText = formatStatusText(snapshot) || 'Preparing the HTTP HMR bootstrap (4%)';
538
256
  const statusLabel = findBootStatusLabel();
257
+ const detailLabel = findBootDetailLabel();
258
+ const progressFill = findBootProgressFill();
539
259
  const activityIndicator = findBootActivityIndicator();
260
+ // New (card) layout: phase line + detail line live in separate
261
+ // labels so the typography can differ. Legacy (single-label)
262
+ // layout: keep the original combined "phase (X%)\ndetail" text so
263
+ // nothing visually regresses for runtimes still attached to the
264
+ // older placeholder shape.
265
+ const hasSplitLabels = !!detailLabel;
266
+ const phaseLine = formatBootPrimaryLine(snapshot);
267
+ const detailLine = formatBootDetailLine(snapshot);
268
+ const combinedText = formatStatusText(snapshot) || 'Preparing the HTTP HMR bootstrap (4%)';
540
269
  if (!statusLabel) {
541
270
  if (activityIndicator) {
542
271
  try {
@@ -545,11 +274,16 @@ function updateBootStatusLabel(snapshot) {
545
274
  }
546
275
  catch { }
547
276
  }
277
+ applyBootProgressFill(progressFill, snapshot);
548
278
  return;
549
279
  }
550
280
  try {
551
- statusLabel.text = newText;
552
- statusLabel.color = asColor(snapshot.tone === 'error' ? '#b41810e6' : '#563e3fb1');
281
+ statusLabel.text = hasSplitLabels ? phaseLine || 'Preparing the HTTP HMR bootstrap' : combinedText;
282
+ // Card layout uses the calibrated phase-text colour from the
283
+ // palette; legacy single-label layout keeps the original muted
284
+ // brown so we don't visually regress mid-session.
285
+ const phaseColorHex = snapshot.tone === 'error' ? '#B91C1C' : hasSplitLabels ? '#475569' : '#563e3fb1';
286
+ statusLabel.color = asColor(phaseColorHex);
553
287
  if (typeof statusLabel.requestLayout === 'function') {
554
288
  statusLabel.requestLayout();
555
289
  }
@@ -559,6 +293,15 @@ function updateBootStatusLabel(snapshot) {
559
293
  }
560
294
  }
561
295
  catch { }
296
+ if (detailLabel) {
297
+ try {
298
+ detailLabel.text = detailLine;
299
+ detailLabel.color = asColor(snapshot.tone === 'error' ? '#DC2626' : '#94A3B8');
300
+ detailLabel.visibility = detailLine ? 'visible' : 'collapse';
301
+ }
302
+ catch { }
303
+ }
304
+ applyBootProgressFill(progressFill, snapshot);
562
305
  if (activityIndicator) {
563
306
  try {
564
307
  activityIndicator.busy = !!snapshot.busy;
@@ -567,6 +310,50 @@ function updateBootStatusLabel(snapshot) {
567
310
  catch { }
568
311
  }
569
312
  }
313
+ // Drive the progress fill scaleX from the snapshot. Uses NS's view
314
+ // animate API for a smooth 220 ms easeOut between heartbeat ticks; a
315
+ // monotonic ratchet on `globalThis.__NS_DEV_BOOT_PROGRESS_LAST_SCALE__`
316
+ // guards against the fill snapping backwards if a less-progressed
317
+ // snapshot ever lands between ticks (mirrors the JS-side
318
+ // `applyMonotonicBootProgress` contract).
319
+ function applyBootProgressFill(progressFill, snapshot) {
320
+ if (!progressFill)
321
+ return;
322
+ const g = getOverlayGlobal();
323
+ const isError = snapshot.tone === 'error';
324
+ progressFill.backgroundColor = asColor(isError ? '#B41810' : '#3B6FE5');
325
+ const targetScale = computeBootProgressFillScale(snapshot.progress ?? null);
326
+ const previousRaw = Number(g.__NS_DEV_BOOT_PROGRESS_LAST_SCALE__);
327
+ const previous = Number.isFinite(previousRaw) ? previousRaw : 0;
328
+ const next = Math.max(previous, targetScale);
329
+ g.__NS_DEV_BOOT_PROGRESS_LAST_SCALE__ = next;
330
+ try {
331
+ // NS view.animate scales around `originX`/`originY`; the
332
+ // placeholder builder pins `originX = 0` so the fill grows
333
+ // rightward. animate() may be unavailable in some headless
334
+ // test environments — fall through to a direct property set.
335
+ if (typeof progressFill.animate === 'function') {
336
+ progressFill
337
+ .animate({
338
+ scale: { x: next, y: 1 },
339
+ duration: BOOT_PLACEHOLDER_MOTION.progressDurationMs,
340
+ curve: 'easeOut',
341
+ })
342
+ .catch(() => {
343
+ try {
344
+ progressFill.scaleX = next;
345
+ }
346
+ catch { }
347
+ });
348
+ }
349
+ else {
350
+ progressFill.scaleX = next;
351
+ }
352
+ }
353
+ catch {
354
+ progressFill.scaleX = next;
355
+ }
356
+ }
570
357
  function resolveActivePage() {
571
358
  try {
572
359
  const Frame = resolveCoreExport('Frame');
@@ -590,6 +377,87 @@ function resolveActivePage() {
590
377
  catch { }
591
378
  return null;
592
379
  }
380
+ function readCachedAndroidSafeAreaInsets() {
381
+ const g = getOverlayGlobal();
382
+ const cached = g.__NS_HMR_ANDROID_SAFE_INSETS__;
383
+ if (cached && typeof cached.top === 'number') {
384
+ return cached;
385
+ }
386
+ return null;
387
+ }
388
+ /**
389
+ * Read the Android system-bar safe-area insets (status bar / navigation
390
+ * bar / display cutout) in device-independent pixels.
391
+ *
392
+ * NativeScript runs every Android activity edge-to-edge, so the overlay
393
+ * wrapper fills the whole window — we need these insets to keep the toast
394
+ * chip out from under the system bars (see `computeAndroidToastMargin`).
395
+ *
396
+ * Returns null on non-Android runtimes (iOS / web / vitest) so callers
397
+ * fall back to base margins. The last good reading is cached on the
398
+ * global so a transient null (e.g. insets queried before the decor view
399
+ * is attached) reuses the previous value instead of snapping the chip
400
+ * back under the status bar.
401
+ */
402
+ function readAndroidSafeAreaInsets() {
403
+ const g = getOverlayGlobal();
404
+ // `android.*` is exposed as a global only on the NativeScript Android
405
+ // runtime; its absence means iOS, web, or a test environment.
406
+ const androidNs = g.android || (typeof globalThis.android !== 'undefined' ? globalThis.android : undefined);
407
+ if (!androidNs) {
408
+ return null;
409
+ }
410
+ try {
411
+ const Application = resolveCoreExport('Application');
412
+ const activity = Application?.android?.foregroundActivity || Application?.android?.startActivity;
413
+ const decorView = activity?.getWindow?.()?.getDecorView?.();
414
+ const rootInsets = decorView?.getRootWindowInsets?.();
415
+ if (!rootInsets) {
416
+ return readCachedAndroidSafeAreaInsets();
417
+ }
418
+ let density = 1;
419
+ try {
420
+ const metricsDensity = Number(activity?.getResources?.()?.getDisplayMetrics?.()?.density);
421
+ if (Number.isFinite(metricsDensity) && metricsDensity > 0) {
422
+ density = metricsDensity;
423
+ }
424
+ }
425
+ catch { }
426
+ let px = { top: 0, bottom: 0, left: 0, right: 0 };
427
+ const WindowInsets = androidNs.view?.WindowInsets;
428
+ const Type = WindowInsets?.Type;
429
+ if (typeof rootInsets.getInsets === 'function' && Type && typeof Type.systemBars === 'function') {
430
+ // API 30+: query the system bars + display cutout so notches /
431
+ // camera holes are respected in landscape.
432
+ let mask = Type.systemBars();
433
+ if (typeof Type.displayCutout === 'function') {
434
+ mask = mask | Type.displayCutout();
435
+ }
436
+ const i = rootInsets.getInsets(mask);
437
+ px = { top: Number(i?.top) || 0, bottom: Number(i?.bottom) || 0, left: Number(i?.left) || 0, right: Number(i?.right) || 0 };
438
+ }
439
+ else {
440
+ // API < 30 fallback.
441
+ px = {
442
+ top: Number(rootInsets.getSystemWindowInsetTop?.()) || 0,
443
+ bottom: Number(rootInsets.getSystemWindowInsetBottom?.()) || 0,
444
+ left: Number(rootInsets.getSystemWindowInsetLeft?.()) || 0,
445
+ right: Number(rootInsets.getSystemWindowInsetRight?.()) || 0,
446
+ };
447
+ }
448
+ const insets = {
449
+ top: px.top / density,
450
+ bottom: px.bottom / density,
451
+ left: px.left / density,
452
+ right: px.right / density,
453
+ };
454
+ g.__NS_HMR_ANDROID_SAFE_INSETS__ = insets;
455
+ return insets;
456
+ }
457
+ catch {
458
+ return readCachedAndroidSafeAreaInsets();
459
+ }
460
+ }
593
461
  function buildLiveOverlayView(snapshot) {
594
462
  const GridLayout = resolveCoreExport('GridLayout');
595
463
  const StackLayout = resolveCoreExport('StackLayout');
@@ -603,8 +471,18 @@ function buildLiveOverlayView(snapshot) {
603
471
  overlay.height = '100%';
604
472
  overlay.horizontalAlignment = 'stretch';
605
473
  overlay.verticalAlignment = 'stretch';
474
+ // Toast mode lets touches reach the underlying app. We flip
475
+ // isUserInteractionEnabled in applySnapshotToLiveRefs based on
476
+ // the resolved position, but keep it false here as a safe default
477
+ // (the panel itself is purely informational).
478
+ try {
479
+ overlay.isUserInteractionEnabled = false;
480
+ }
481
+ catch { }
606
482
  const panel = new StackLayout();
607
483
  panel.horizontalAlignment = 'center';
484
+ // Vertical alignment is overridden in applySnapshotToLiveRefs
485
+ // based on getHmrDevOverlayPosition(); 'middle' is the default
608
486
  panel.verticalAlignment = 'middle';
609
487
  panel.width = 320;
610
488
  panel.margin = 24;
@@ -626,6 +504,8 @@ function buildLiveOverlayView(snapshot) {
626
504
  overlay,
627
505
  titleLabel,
628
506
  statusLabel,
507
+ wasVisible: false,
508
+ currentPosition: getHmrDevOverlayPosition(),
629
509
  };
630
510
  applySnapshotToLiveRefs(refs, snapshot);
631
511
  return refs;
@@ -682,33 +562,43 @@ function applySnapshotToLiveRefs(refs, snapshot) {
682
562
  if (!refs) {
683
563
  return;
684
564
  }
685
- // Round-eleven.3 — 'update' mode shares the live (in-tree) overlay
686
- // chrome with 'connection'. Both render a centered panel inside the
687
- // page; only the colours and text change with the snapshot's tone.
565
+ // 'update' mode shares the live (in-tree) overlay chrome with
566
+ // 'connection'. Both render a small panel inside the page; only
567
+ // the colours, text, and (now) panel position change with the
568
+ // snapshot's tone and the configured overlay position.
688
569
  const visible = snapshot.visible && (snapshot.mode === 'connection' || snapshot.mode === 'update');
689
- refs.overlay.visibility = visible ? 'visible' : 'collapse';
690
- // Backdrop tints by tone:
691
- // error → red wash (matches existing UX)
692
- // success → richer green wash; the previous 18% alpha was so
693
- // subtle on light app backgrounds that users couldn't
694
- // tell the overlay had even fired. 50% alpha keeps the
695
- // underlying app legible while making the apply event
696
- // unmistakable during the (often <300ms) cycle.
697
- // default → warm orange (existing connection-overlay look)
698
- const overlayBg = snapshot.tone === 'error' ? '#b4181068' : snapshot.tone === 'success' ? '#1f883d80' : '#a1771683';
699
- refs.overlay.backgroundColor = asColor(overlayBg);
570
+ const wasVisible = !!refs.wasVisible;
571
+ const position = getHmrDevOverlayPosition();
572
+ const previousPosition = refs.currentPosition || position;
573
+ const isToast = position !== 'center';
700
574
  refs.titleLabel.text = snapshot.title;
575
+ refs.statusLabel.text = formatStatusText(snapshot);
701
576
  const textColor = snapshot.tone === 'error' ? '#b41810e6' : snapshot.tone === 'success' ? '#0e6e2fff' : '#563e3fb1';
702
577
  refs.titleLabel.color = asColor(textColor);
703
- refs.statusLabel.text = formatStatusText(snapshot);
704
578
  refs.statusLabel.color = asColor(textColor);
579
+ // Backdrop tints (centered modal only). Toast modes use a fully
580
+ // transparent backdrop so the rest of the app stays visible AND
581
+ // reachable; the panel itself carries enough colour to stand out.
582
+ if (isToast) {
583
+ refs.overlay.backgroundColor = asColor('transparent');
584
+ }
585
+ else {
586
+ // Original wash-by-tone for centered:
587
+ // error → red wash (matches existing UX)
588
+ // success → richer green wash so the apply event is visible
589
+ // on bright app backgrounds
590
+ // default → warm orange (existing connection-overlay look)
591
+ const overlayBg = snapshot.tone === 'error' ? '#b4181068' : snapshot.tone === 'success' ? '#1f883d80' : '#a1771683';
592
+ refs.overlay.backgroundColor = asColor(overlayBg);
593
+ }
594
+ // Panel chrome — toast and centered share the same chip look,
595
+ // just position differs. We keep the slightly richer green tint
596
+ // for the HMR success state so it pops without needing the
597
+ // backdrop wash.
598
+ let panel = null;
705
599
  try {
706
- const panel = refs.titleLabel.parent;
600
+ panel = refs.titleLabel.parent;
707
601
  if (panel) {
708
- // Slightly richer green-tinted panel for HMR-apply so the
709
- // title/status text reads at a glance against the brighter
710
- // backdrop wash. White panel for connection/error keeps
711
- // existing UX intact.
712
602
  const panelBg = snapshot.tone === 'success' ? '#E6F8E9FF' : '#FFFFFFFF';
713
603
  panel.backgroundColor = asColor(panelBg);
714
604
  panel.opacity = 1;
@@ -717,9 +607,169 @@ function applySnapshotToLiveRefs(refs, snapshot) {
717
607
  panel.borderRadius = 12;
718
608
  }
719
609
  catch { }
610
+ // Position-aware alignment. The wrapper GridLayout fills the
611
+ // page content area. NativeScript runs every Android activity
612
+ // edge-to-edge, so that area extends under the status bar and
613
+ // navigation bar — we fold the system-bar safe-area insets into
614
+ // the chip's margin (via computeAndroidToastMargin) so a top
615
+ // chip clears the status bar and a bottom chip clears the nav
616
+ // bar instead of being clipped behind them. readAndroidSafeAreaInsets
617
+ // returns null off-Android, so the margins collapse to their base
618
+ // values (no behavioural change on iOS's in-tree fallback / tests).
619
+ try {
620
+ if (position === 'top' || position === 'bottom') {
621
+ const m = computeAndroidToastMargin({ position, safeInsets: readAndroidSafeAreaInsets() });
622
+ panel.verticalAlignment = position;
623
+ panel.margin = `${m.top} ${m.right} ${m.bottom} ${m.left}`;
624
+ }
625
+ else {
626
+ panel.verticalAlignment = 'middle';
627
+ panel.margin = 24;
628
+ }
629
+ }
630
+ catch { }
631
+ // Force a tight re-measure so the StackLayout panel hugs the
632
+ // CURRENT title+status text. Connection stages can swap between
633
+ // frames whose text wraps to a different number of lines (e.g. a
634
+ // long 'reconnecting' "Retrying ws://…" detail vs. the short
635
+ // 'offline' message). Without an explicit relayout the panel can
636
+ // retain the tallest height it ever measured, leaving an oversized
637
+ // gap between title and message. Mirrors updateBootStatusLabel.
638
+ try {
639
+ refs.titleLabel.requestLayout?.();
640
+ refs.statusLabel.requestLayout?.();
641
+ panel.requestLayout?.();
642
+ }
643
+ catch { }
720
644
  }
721
645
  }
722
646
  catch { }
647
+ // Touch passthrough for toast; centered mode keeps the
648
+ // blocking modal so the dim backdrop is meaningful.
649
+ try {
650
+ refs.overlay.isUserInteractionEnabled = !isToast;
651
+ }
652
+ catch { }
653
+ const positionChanged = previousPosition !== position;
654
+ const justAppeared = visible && (!wasVisible || positionChanged);
655
+ const justDismissed = !visible && wasVisible;
656
+ if (justAppeared) {
657
+ refs.overlay.visibility = 'visible';
658
+ if (isToast && panel && typeof panel.animate === 'function') {
659
+ animateLivePanelIn(panel, position);
660
+ }
661
+ else if (panel) {
662
+ try {
663
+ panel.translateY = 0;
664
+ panel.opacity = 1;
665
+ }
666
+ catch { }
667
+ }
668
+ }
669
+ else if (justDismissed) {
670
+ if (isToast && panel && typeof panel.animate === 'function') {
671
+ animateLivePanelOut(panel, previousPosition, () => {
672
+ try {
673
+ refs.overlay.visibility = 'collapse';
674
+ }
675
+ catch { }
676
+ });
677
+ }
678
+ else {
679
+ refs.overlay.visibility = 'collapse';
680
+ }
681
+ }
682
+ else {
683
+ // Steady-state refresh (e.g. offline → reconnecting → offline while
684
+ // already visible): no slide animation fires here, so clear any
685
+ // transform residue a previously-interrupted slide-in/out may have
686
+ // left on the panel. Otherwise the chip can appear shifted or
687
+ // faded across rapid connection-stage swaps.
688
+ if (visible && panel) {
689
+ try {
690
+ panel.translateY = 0;
691
+ panel.opacity = 1;
692
+ }
693
+ catch { }
694
+ }
695
+ refs.overlay.visibility = visible ? 'visible' : 'collapse';
696
+ }
697
+ if (typeof refs.wasVisible !== 'undefined')
698
+ refs.wasVisible = visible;
699
+ if (typeof refs.currentPosition !== 'undefined')
700
+ refs.currentPosition = position;
701
+ }
702
+ /**
703
+ * Slide-in animation for the in-tree toast panel.
704
+ *
705
+ * NativeScript's `View.animate({ translate, opacity, duration, curve })`
706
+ * is widely available across Core versions, so we don't depend on any
707
+ * specific curve enum being importable here. We use a moderate-to-snappy
708
+ * 320ms ease-out which feels close to a UIView spring without needing
709
+ * platform-specific APIs.
710
+ */
711
+ function animateLivePanelIn(panel, position) {
712
+ if (!panel || typeof panel.animate !== 'function')
713
+ return;
714
+ try {
715
+ const startY = position === 'bottom' ? 80 : -80;
716
+ panel.translateY = startY;
717
+ panel.opacity = 0;
718
+ const result = panel.animate({
719
+ translate: { x: 0, y: 0 },
720
+ opacity: 1,
721
+ duration: 320,
722
+ curve: 'easeOut',
723
+ });
724
+ if (result && typeof result.catch === 'function') {
725
+ result.catch(() => {
726
+ try {
727
+ panel.translateY = 0;
728
+ panel.opacity = 1;
729
+ }
730
+ catch { }
731
+ });
732
+ }
733
+ }
734
+ catch {
735
+ try {
736
+ panel.translateY = 0;
737
+ panel.opacity = 1;
738
+ }
739
+ catch { }
740
+ }
741
+ }
742
+ function animateLivePanelOut(panel, position, onComplete) {
743
+ if (!panel || typeof panel.animate !== 'function') {
744
+ onComplete();
745
+ return;
746
+ }
747
+ try {
748
+ const targetY = position === 'bottom' ? 80 : -80;
749
+ const result = panel.animate({
750
+ translate: { x: 0, y: targetY },
751
+ opacity: 0,
752
+ duration: 220,
753
+ curve: 'easeIn',
754
+ });
755
+ const finish = () => {
756
+ try {
757
+ panel.translateY = 0;
758
+ panel.opacity = 1;
759
+ }
760
+ catch { }
761
+ onComplete();
762
+ };
763
+ if (result && typeof result.then === 'function') {
764
+ result.then(finish, finish);
765
+ }
766
+ else {
767
+ finish();
768
+ }
769
+ }
770
+ catch {
771
+ onComplete();
772
+ }
723
773
  }
724
774
  // pure helpers for iOS window promotion. Factored out so the layout
725
775
  // math and window-level selection stay unit-testable without booting a
@@ -739,8 +789,17 @@ export function computeIosOverlayWindowLevel(baseAlert) {
739
789
  /**
740
790
  * Layout math for the live overlay when it runs inside its own UIWindow.
741
791
  * Pure, deterministic and independent of UIKit so we can verify the rules
742
- * (max panel width, centered placement, safe-area clamping, sane defaults)
743
- * from tests.
792
+ * (max panel width, position-aware placement, safe-area clamping, sane
793
+ * defaults) from tests.
794
+ *
795
+ * `position` controls where the panel sits vertically:
796
+ * - 'top': hugs `safeInsets.top + toastVerticalInset` so the chip
797
+ * sits just below the notch / Dynamic Island.
798
+ * - 'bottom': hugs `viewHeight - safeInsets.bottom - panelHeight -
799
+ * toastVerticalInset` so the chip sits just above the
800
+ * home indicator / nav bar.
801
+ * - 'center': original modal placement (vertically centered, clamped
802
+ * so it never crosses the top safe-area inset).
744
803
  */
745
804
  export function computeIosOverlayLayout(input) {
746
805
  const viewWidth = Math.max(0, Number(input.viewWidth) || 0);
@@ -758,15 +817,41 @@ export function computeIosOverlayLayout(input) {
758
817
  const panelPadding = Math.max(0, Number(input.panelPadding ?? 16));
759
818
  const interLabelSpacing = Math.max(0, Number(input.interLabelSpacing ?? 10));
760
819
  const minTopInset = Math.max(0, Number(input.minTopInset ?? 20));
820
+ // Default to 'center' on the pure function so the existing
821
+ // snapshot/layout tests remain stable; the runtime call site
822
+ // (layoutIosOverlayRefs) reads the configured position from
823
+ // `getHmrDevOverlayPosition()` and forwards it explicitly.
824
+ const position = input.position ?? 'center';
825
+ // Distance between the panel and the safe-area edge in toast
826
+ // modes. 8pt mirrors the typical iOS notification chip inset and
827
+ // keeps the chip from hugging the notch / home indicator.
828
+ const toastVerticalInset = Math.max(0, Number(input.toastVerticalInset ?? 8));
761
829
  const available = Math.max(0, viewWidth - 2 * horizontalMargin - safeInsets.left - safeInsets.right);
762
830
  const panelWidth = Math.min(maxPanelWidth, available);
763
831
  const innerWidth = Math.max(0, panelWidth - 2 * panelPadding);
764
832
  const spacing = titleHeight > 0 && statusHeight > 0 ? interLabelSpacing : 0;
765
833
  const panelHeight = panelPadding * 2 + titleHeight + spacing + statusHeight;
766
834
  const panelX = Math.max(0, (viewWidth - panelWidth) / 2);
767
- // Center vertically, but never cross the top safe-area inset (notch/Dynamic Island).
768
- const centered = (viewHeight - panelHeight) / 2;
769
- const panelY = Math.max(safeInsets.top + minTopInset, centered);
835
+ let panelY;
836
+ if (position === 'top') {
837
+ // Pin to the top safe-area inset (just below notch / Dynamic
838
+ // Island). Clamp non-negative for fully-NaN input.
839
+ panelY = Math.max(0, safeInsets.top + toastVerticalInset);
840
+ }
841
+ else if (position === 'bottom') {
842
+ // Pin to the bottom safe-area inset (just above home indicator
843
+ // / nav bar). If the panel can't fit between the safe-area
844
+ // insets we fall back to the top safe-area edge so the chip is
845
+ // always visible (rather than getting clipped off-screen).
846
+ const desired = viewHeight - safeInsets.bottom - panelHeight - toastVerticalInset;
847
+ panelY = Math.max(safeInsets.top + minTopInset, desired);
848
+ }
849
+ else {
850
+ // Center vertically, but never cross the top safe-area inset
851
+ // (notch/Dynamic Island). Original modal placement.
852
+ const centered = (viewHeight - panelHeight) / 2;
853
+ panelY = Math.max(safeInsets.top + minTopInset, centered);
854
+ }
770
855
  return {
771
856
  backdrop: { x: 0, y: 0, width: viewWidth, height: viewHeight },
772
857
  panel: { x: panelX, y: panelY, width: panelWidth, height: panelHeight },
@@ -779,6 +864,59 @@ export function computeIosOverlayLayout(input) {
779
864
  },
780
865
  };
781
866
  }
867
+ /**
868
+ * Margin math for the in-tree (Android) live/update toast chip.
869
+ *
870
+ * NativeScript enables edge-to-edge on every Android activity
871
+ * (`@nativescript/core` → `application.android.ts` → `enableEdgeToEdge`),
872
+ * so the page content — and therefore the overlay wrapper we inject into
873
+ * it — extends underneath the status bar and navigation bar. A fixed
874
+ * top/bottom margin leaves the chip tucked behind the system bars, where
875
+ * it gets clipped (Android 15 / API 35 enforces edge-to-edge, so this is
876
+ * now the norm rather than the exception).
877
+ *
878
+ * This pure helper folds the system-bar safe-area insets into the chip's
879
+ * margin so the toast always clears the status bar (top position) /
880
+ * navigation bar (bottom position). It is deterministic and free of
881
+ * native deps so the rules stay unit-testable — the runtime reads the
882
+ * live insets via `readAndroidSafeAreaInsets()` and forwards them here.
883
+ *
884
+ * - 'top': margin.top = baseVerticalInset + safeInsets.top
885
+ * - 'bottom': margin.bottom = baseVerticalInset + safeInsets.bottom
886
+ * - 'center': fixed `centerMargin` all around (vertically centered, so
887
+ * it never approaches the system bars on normal viewports).
888
+ *
889
+ * Horizontal margins always include the relevant safe-area inset so a
890
+ * landscape display cutout / gesture pill doesn't clip the chip edge.
891
+ */
892
+ export function computeAndroidToastMargin(input) {
893
+ // Clamp to a finite, non-negative number; fall back to `fallback`
894
+ // for missing/NaN input so a glitched measurement can't produce a
895
+ // negative or NaN margin (which NativeScript would silently drop).
896
+ const clamp = (value, fallback) => {
897
+ const n = Number(value);
898
+ return Number.isFinite(n) && n >= 0 ? n : fallback;
899
+ };
900
+ const safe = {
901
+ top: clamp(input.safeInsets?.top, 0),
902
+ bottom: clamp(input.safeInsets?.bottom, 0),
903
+ left: clamp(input.safeInsets?.left, 0),
904
+ right: clamp(input.safeInsets?.right, 0),
905
+ };
906
+ const baseVerticalInset = clamp(input.baseVerticalInset, 8);
907
+ const baseHorizontalInset = clamp(input.baseHorizontalInset, 16);
908
+ const centerMargin = clamp(input.centerMargin, 24);
909
+ if (input.position === 'center') {
910
+ return { top: centerMargin, right: centerMargin, bottom: centerMargin, left: centerMargin };
911
+ }
912
+ const left = Math.round(baseHorizontalInset + safe.left);
913
+ const right = Math.round(baseHorizontalInset + safe.right);
914
+ if (input.position === 'bottom') {
915
+ return { top: 0, right, bottom: Math.round(baseVerticalInset + safe.bottom), left };
916
+ }
917
+ // 'top' (and any unexpected value) hugs the status-bar safe area.
918
+ return { top: Math.round(baseVerticalInset + safe.top), right, bottom: 0, left };
919
+ }
782
920
  /**
783
921
  * Returns the iOS UIKit symbols we rely on if we're running on an iOS runtime
784
922
  * with the metadata bridge available. Returns null on Android, web, or in
@@ -833,10 +971,7 @@ function buildIosOverlayRefs(state) {
833
971
  const scene = findActiveWindowScene(host);
834
972
  if (!scene) {
835
973
  if (state.verbose) {
836
- try {
837
- console.info('[ns-hmr-overlay] no active UIWindowScene; skipping iOS overlay promotion');
838
- }
839
- catch { }
974
+ console.info('[ns-hmr-overlay] no active UIWindowScene; skipping iOS overlay promotion');
840
975
  }
841
976
  return null;
842
977
  }
@@ -883,13 +1018,35 @@ function buildIosOverlayRefs(state) {
883
1018
  statusLabel.font = UIFont.systemFontOfSize(13);
884
1019
  statusLabel.textColor = UIColor.darkGrayColor;
885
1020
  panel.addSubview(statusLabel);
886
- return { window, controller, backdrop, panel, titleLabel, statusLabel };
887
- }
888
- catch (err) {
1021
+ // Subtle drop-shadow so the toast chip reads against light app
1022
+ // content (white-on-white is invisible). The error / centered
1023
+ // branches still get the dim backdrop, so the shadow is mostly
1024
+ // a no-op for them — but it's a one-time setup.
889
1025
  try {
890
- console.warn('[ns-hmr-overlay] iOS overlay construction failed:', err?.message || err);
1026
+ panel.layer.shadowColor = UIColor.blackColor.CGColor;
1027
+ panel.layer.shadowOpacity = 0.18;
1028
+ panel.layer.shadowRadius = 8;
1029
+ panel.layer.shadowOffset = { width: 0, height: 2 };
1030
+ panel.layer.masksToBounds = false;
891
1031
  }
892
1032
  catch { }
1033
+ // `wasVisible` / `currentPosition` are mutated by
1034
+ // applySnapshotToIosRefs when the snapshot triggers a slide-in
1035
+ // or slide-out. They start in the "hidden" state so the very
1036
+ // first visible snapshot animates in cleanly.
1037
+ return {
1038
+ window,
1039
+ controller,
1040
+ backdrop,
1041
+ panel,
1042
+ titleLabel,
1043
+ statusLabel,
1044
+ wasVisible: false,
1045
+ currentPosition: getHmrDevOverlayPosition(),
1046
+ };
1047
+ }
1048
+ catch (err) {
1049
+ console.warn('[ns-hmr-overlay] iOS overlay construction failed:', err?.message || err);
893
1050
  return null;
894
1051
  }
895
1052
  }
@@ -909,7 +1066,7 @@ function ensureIosOverlayRefs(state) {
909
1066
  }
910
1067
  return state.iosRefs;
911
1068
  }
912
- function layoutIosOverlayRefs(refs) {
1069
+ function layoutIosOverlayRefs(refs, position) {
913
1070
  try {
914
1071
  const bounds = refs.controller.view.bounds;
915
1072
  const viewWidth = Number(bounds?.size?.width) || 0;
@@ -940,6 +1097,7 @@ function layoutIosOverlayRefs(refs) {
940
1097
  maxPanelWidth,
941
1098
  horizontalMargin,
942
1099
  panelPadding,
1100
+ position,
943
1101
  });
944
1102
  const toCgRect = (rect) => ({
945
1103
  origin: { x: rect.x, y: rect.y },
@@ -949,27 +1107,156 @@ function layoutIosOverlayRefs(refs) {
949
1107
  refs.panel.frame = toCgRect(layout.panel);
950
1108
  refs.titleLabel.frame = toCgRect(layout.title);
951
1109
  refs.statusLabel.frame = toCgRect(layout.status);
1110
+ return layout;
952
1111
  }
953
1112
  catch (err) {
1113
+ console.warn('[ns-hmr-overlay] iOS overlay layout failed:', err?.message || err);
1114
+ return null;
1115
+ }
1116
+ }
1117
+ /**
1118
+ * Slide-in animation for the iOS toast panel. Off-screen start frame
1119
+ * lives just above (top) or below (bottom) the visible area; the panel
1120
+ * snaps to its target frame with a spring so the motion feels physical
1121
+ * without the heavy "settle" overshoot of a hard spring (damping 0.85
1122
+ * lands quickly with a small overshoot).
1123
+ */
1124
+ function animateIosPanelIn(refs, position, layout) {
1125
+ const g = getOverlayGlobal();
1126
+ const UIView = g?.UIView;
1127
+ if (!UIView)
1128
+ return;
1129
+ try {
1130
+ const targetFrame = {
1131
+ origin: { x: layout.panel.x, y: layout.panel.y },
1132
+ size: { width: layout.panel.width, height: layout.panel.height },
1133
+ };
1134
+ // Off-screen start: distance includes a small fudge so the
1135
+ // shadow blur tail isn't visible at t=0.
1136
+ const startY = position === 'bottom' ? layout.backdrop.height + 24 : -(layout.panel.height + 24);
1137
+ refs.panel.frame = {
1138
+ origin: { x: layout.panel.x, y: startY },
1139
+ size: { width: layout.panel.width, height: layout.panel.height },
1140
+ };
1141
+ refs.panel.alpha = 0;
1142
+ try {
1143
+ if (typeof UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion === 'function') {
1144
+ UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(0.42, 0, 0.85, 0.7, 0, () => {
1145
+ refs.panel.frame = targetFrame;
1146
+ refs.panel.alpha = 1;
1147
+ }, null);
1148
+ }
1149
+ else if (typeof UIView.animateWithDurationAnimations === 'function') {
1150
+ UIView.animateWithDurationAnimations(0.32, () => {
1151
+ refs.panel.frame = targetFrame;
1152
+ refs.panel.alpha = 1;
1153
+ });
1154
+ }
1155
+ else {
1156
+ refs.panel.frame = targetFrame;
1157
+ refs.panel.alpha = 1;
1158
+ }
1159
+ }
1160
+ catch {
1161
+ refs.panel.frame = targetFrame;
1162
+ refs.panel.alpha = 1;
1163
+ }
1164
+ }
1165
+ catch { }
1166
+ }
1167
+ /**
1168
+ * Slide-out animation for the iOS toast panel. Mirrors animateIosPanelIn:
1169
+ * the panel travels to the nearest off-screen edge while fading out so
1170
+ * the dismissal still feels intentional even on fast HMR cycles.
1171
+ */
1172
+ function animateIosPanelOut(refs, position, onComplete) {
1173
+ const g = getOverlayGlobal();
1174
+ const UIView = g?.UIView;
1175
+ const currentFrame = refs.panel?.frame;
1176
+ if (!UIView || !currentFrame) {
1177
+ onComplete();
1178
+ return;
1179
+ }
1180
+ try {
1181
+ const bounds = refs.controller?.view?.bounds;
1182
+ const viewHeight = Number(bounds?.size?.height) || 0;
1183
+ const targetY = position === 'bottom' ? viewHeight + 24 : -(Number(currentFrame.size?.height) + 24);
1184
+ const startFrame = currentFrame;
1185
+ const targetFrame = {
1186
+ origin: { x: Number(startFrame.origin?.x) || 0, y: targetY },
1187
+ size: startFrame.size,
1188
+ };
954
1189
  try {
955
- console.warn('[ns-hmr-overlay] iOS overlay layout failed:', err?.message || err);
1190
+ if (typeof UIView.animateWithDurationDelayOptionsAnimationsCompletion === 'function') {
1191
+ // UIViewAnimationOptionCurveEaseIn = 1 << 16 — accelerate
1192
+ // out so the dismissal doesn't drag on screen.
1193
+ UIView.animateWithDurationDelayOptionsAnimationsCompletion(0.22, 0, 1 << 16, () => {
1194
+ refs.panel.frame = targetFrame;
1195
+ refs.panel.alpha = 0;
1196
+ }, () => onComplete());
1197
+ }
1198
+ else if (typeof UIView.animateWithDurationAnimationsCompletion === 'function') {
1199
+ UIView.animateWithDurationAnimationsCompletion(0.22, () => {
1200
+ refs.panel.frame = targetFrame;
1201
+ refs.panel.alpha = 0;
1202
+ }, () => onComplete());
1203
+ }
1204
+ else {
1205
+ refs.panel.alpha = 0;
1206
+ onComplete();
1207
+ }
1208
+ }
1209
+ catch {
1210
+ refs.panel.alpha = 0;
1211
+ onComplete();
956
1212
  }
957
- catch { }
1213
+ }
1214
+ catch {
1215
+ onComplete();
958
1216
  }
959
1217
  }
960
1218
  function applySnapshotToIosRefs(refs, snapshot) {
961
1219
  if (!refs)
962
1220
  return false;
963
1221
  try {
964
- // Round-eleven.3 — 'update' mode rides the same dedicated
965
- // UIWindow as 'connection' so the HMR apply overlay always
966
- // stacks above modals/sheets/system alerts. The window is
967
- // constructed lazily (ensureIosOverlayRefs) and reused for the
968
- // lifetime of the dev session.
1222
+ // 'update' mode rides the same dedicated UIWindow as
1223
+ // 'connection' so the HMR apply overlay always stacks above
1224
+ // modals/sheets/system alerts. The window is constructed
1225
+ // lazily (ensureIosOverlayRefs) and reused for the lifetime of
1226
+ // the dev session.
969
1227
  const visible = snapshot.visible && (snapshot.mode === 'connection' || snapshot.mode === 'update');
970
- refs.window.hidden = !visible;
971
- if (!visible)
1228
+ const wasVisible = !!refs.wasVisible;
1229
+ const position = getHmrDevOverlayPosition();
1230
+ const previousPosition = refs.currentPosition;
1231
+ const isToast = position !== 'center';
1232
+ // Touches pass through the overlay window in toast mode so
1233
+ // the user can keep tapping the app while the HMR chip is
1234
+ // shown. In centered mode we keep the blocking
1235
+ // behaviour (the dim backdrop is itself a hint to wait).
1236
+ try {
1237
+ refs.window.userInteractionEnabled = !isToast;
1238
+ }
1239
+ catch { }
1240
+ if (!visible) {
1241
+ // Animate out before hiding the window so the dismissal
1242
+ // has a discoverable motion. Only animate when previously
1243
+ // visible and in toast mode — centered modal hides instantly.
1244
+ if (wasVisible && isToast) {
1245
+ animateIosPanelOut(refs, previousPosition, () => {
1246
+ try {
1247
+ refs.window.hidden = true;
1248
+ }
1249
+ catch { }
1250
+ });
1251
+ }
1252
+ else {
1253
+ refs.window.hidden = true;
1254
+ }
1255
+ refs.wasVisible = false;
1256
+ refs.currentPosition = position;
972
1257
  return true;
1258
+ }
1259
+ refs.window.hidden = false;
973
1260
  refs.titleLabel.text = snapshot.title || '';
974
1261
  refs.statusLabel.text = formatStatusText(snapshot);
975
1262
  const host = getIosOverlayHost();
@@ -983,9 +1270,6 @@ function applySnapshotToIosRefs(refs, snapshot) {
983
1270
  refs.panel.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(1, 0.96, 0.96, 1);
984
1271
  refs.titleLabel.textColor = UIColor.colorWithRedGreenBlueAlpha(0.7, 0.1, 0.06, 1);
985
1272
  refs.statusLabel.textColor = UIColor.colorWithRedGreenBlueAlpha(0.7, 0.1, 0.06, 0.9);
986
- // Slightly stronger dimming on errors; users need to
987
- // notice these.
988
- refs.backdrop.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0, 0, 0, 0.35);
989
1273
  }
990
1274
  else if (isSuccess) {
991
1275
  // Slightly more saturated green panel + dark-green
@@ -997,31 +1281,56 @@ function applySnapshotToIosRefs(refs, snapshot) {
997
1281
  refs.panel.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0.9, 0.97, 0.91, 1);
998
1282
  refs.titleLabel.textColor = UIColor.colorWithRedGreenBlueAlpha(0.05, 0.43, 0.18, 1);
999
1283
  refs.statusLabel.textColor = UIColor.colorWithRedGreenBlueAlpha(0.05, 0.43, 0.18, 1);
1000
- // Bumped from 0.12 to 0.28. The 0.12 wash was so
1001
- // faint on bright app backgrounds that the overlay
1002
- // was effectively invisible during a fast cycle.
1003
- // 0.28 still keeps the app readable underneath but
1004
- // makes the HMR event visually unmistakable.
1005
- refs.backdrop.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0, 0.15, 0.05, 0.28);
1006
1284
  }
1007
1285
  else {
1008
1286
  // Default (info / warn) — existing connection look.
1009
1287
  refs.panel.backgroundColor = UIColor.whiteColor;
1010
1288
  refs.titleLabel.textColor = UIColor.blackColor;
1011
1289
  refs.statusLabel.textColor = UIColor.darkGrayColor;
1290
+ }
1291
+ // Backdrop dims only in centered mode; toast mode keeps
1292
+ // the rest of the app fully visible/usable. Errors get
1293
+ // a slightly stronger dim in centered mode because the
1294
+ // user MUST notice them.
1295
+ if (isToast) {
1296
+ refs.backdrop.backgroundColor = UIColor.clearColor;
1297
+ }
1298
+ else if (isError) {
1012
1299
  refs.backdrop.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0, 0, 0, 0.35);
1013
1300
  }
1301
+ else if (isSuccess) {
1302
+ refs.backdrop.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0, 0.15, 0.05, 0.28);
1303
+ }
1304
+ else {
1305
+ refs.backdrop.backgroundColor = UIColor.colorWithRedGreenBlueAlpha(0, 0, 0, 0.35);
1306
+ }
1307
+ }
1308
+ catch { }
1309
+ }
1310
+ const layout = layoutIosOverlayRefs(refs, position);
1311
+ // Slide-in animation only fires on the actual hidden→visible
1312
+ // transition (or on a position swap — e.g. dev toggling top
1313
+ // to bottom mid-cycle). Subsequent updates within the same
1314
+ // visible cycle just refresh text/colours without re-animating.
1315
+ const positionChanged = previousPosition !== position;
1316
+ const justAppeared = !wasVisible || positionChanged;
1317
+ if (justAppeared && isToast && layout) {
1318
+ animateIosPanelIn(refs, position, layout);
1319
+ }
1320
+ else if (justAppeared && !isToast) {
1321
+ // Centered modal: ensure alpha is reset to 1 in case a
1322
+ // previous toast-mode dismissal left it at 0.
1323
+ try {
1324
+ refs.panel.alpha = 1;
1014
1325
  }
1015
1326
  catch { }
1016
1327
  }
1017
- layoutIosOverlayRefs(refs);
1328
+ refs.wasVisible = true;
1329
+ refs.currentPosition = position;
1018
1330
  return true;
1019
1331
  }
1020
1332
  catch (err) {
1021
- try {
1022
- console.warn('[ns-hmr-overlay] iOS overlay apply failed:', err?.message || err);
1023
- }
1024
- catch { }
1333
+ console.warn('[ns-hmr-overlay] iOS overlay apply failed:', err?.message || err);
1025
1334
  return false;
1026
1335
  }
1027
1336
  }
@@ -1064,21 +1373,19 @@ function applyRuntimeSnapshot(snapshot) {
1064
1373
  }
1065
1374
  return state.snapshot;
1066
1375
  }
1067
- // Round-eleven.3 — How long the 'complete' frame stays on screen
1068
- // before we auto-hide. The original 350ms was too tight: many HMR
1069
- // cycles complete in 50–250ms, so the *total* overlay lifetime
1070
- // (received → complete + 350ms) was often under 500ms, which is
1071
- // faster than the human eye can comfortably register. 600ms gives
1072
- // the user time to read the "Total Xms" line and confirm visually
1073
- // that something happened.
1376
+ // How long the 'complete' frame stays on screen before we auto-hide.
1377
+ // The original 350ms was too tight: many HMR cycles complete in
1378
+ // 50–250ms, so the *total* overlay lifetime (received → complete +
1379
+ // 350ms) was often under 500ms, which is faster than the human eye
1380
+ // can comfortably register. 600ms gives the user time to read the
1381
+ // "Total Xms" line and confirm visually that something happened.
1074
1382
  const UPDATE_AUTO_HIDE_MS = 600;
1075
- // Round-eleven.3 (alpha.62 follow-up) — Minimum perceptible duration
1076
- // for an entire update overlay cycle (from 'received' to hide). If
1077
- // the cycle finished in 50ms (e.g., a tiny HTML edit on a warm
1078
- // cache), we still hold for ~MIN_VISIBLE_MS total before hiding so
1079
- // the overlay is actually seen. Combined with UPDATE_AUTO_HIDE_MS,
1080
- // the *effective* hold-after-complete = max(UPDATE_AUTO_HIDE_MS,
1081
- // MIN_VISIBLE_MS - elapsed-since-received).
1383
+ // Minimum perceptible duration for an entire update overlay cycle
1384
+ // (from 'received' to hide). If the cycle finished in 50ms (e.g., a
1385
+ // tiny HTML edit on a warm cache), we still hold for ~MIN_VISIBLE_MS
1386
+ // total before hiding so the overlay is actually seen. Combined with
1387
+ // UPDATE_AUTO_HIDE_MS, the *effective* hold-after-complete =
1388
+ // max(UPDATE_AUTO_HIDE_MS, MIN_VISIBLE_MS - elapsed-since-received).
1082
1389
  const UPDATE_MIN_VISIBLE_MS = 800;
1083
1390
  function clearUpdateAutoHideTimer(state) {
1084
1391
  if (state.updateAutoHideTimer) {
@@ -1157,7 +1464,17 @@ function createOverlayApi() {
1157
1464
  const state = getRuntimeState();
1158
1465
  clearUpdateAutoHideTimer(state);
1159
1466
  state.updateCycleStartedAt = 0;
1160
- return applyRuntimeSnapshot(createBootOverlaySnapshot(stage, info));
1467
+ const next = createBootOverlaySnapshot(stage, info);
1468
+ // Monotonic boot-progress ratchet: boot stages can fire out of
1469
+ // order across boot paths (JS session bootstrap vs the
1470
+ // http-bootloader fallback) and individual bases were tuned
1471
+ // independently, so clamp boot→boot transitions to never go
1472
+ // backwards. Non-boot snapshots (error/ready) bypass — they
1473
+ // genuinely want to reset the visual.
1474
+ if (next.mode === 'boot' && state.snapshot.mode === 'boot' && typeof next.progress === 'number' && typeof state.snapshot.progress === 'number' && next.progress < state.snapshot.progress) {
1475
+ next.progress = state.snapshot.progress;
1476
+ }
1477
+ return applyRuntimeSnapshot(next);
1161
1478
  },
1162
1479
  setConnectionStage(stage, info) {
1163
1480
  const state = getRuntimeState();
@@ -1217,12 +1534,54 @@ function createOverlayApi() {
1217
1534
  },
1218
1535
  };
1219
1536
  }
1537
+ // The NS_VITE_PROGRESS_OVERLAY opt-out. Read the build-time define (const-substituted
1538
+ // into served modules) first, then fall back to the globalThis seed, defaulting to
1539
+ // enabled — mirrors the gate used by the per-framework update overlays.
1540
+ function isHmrProgressOverlayEnabled() {
1541
+ try {
1542
+ if (typeof __NS_HMR_PROGRESS_OVERLAY_ENABLED__ === 'boolean')
1543
+ return __NS_HMR_PROGRESS_OVERLAY_ENABLED__;
1544
+ }
1545
+ catch { }
1546
+ try {
1547
+ const seeded = getGlobalScope().__NS_HMR_PROGRESS_OVERLAY_ENABLED__;
1548
+ if (typeof seeded === 'boolean')
1549
+ return seeded;
1550
+ }
1551
+ catch { }
1552
+ return true;
1553
+ }
1554
+ // When the overlay is opted out, every surface (boot / connection / update / pending)
1555
+ // becomes a no-op so nothing is ever drawn. The boot placeholder root and the
1556
+ // `__NS_HMR_BOOT_COMPLETE__` signal are owned by `root-placeholder.ts` and are
1557
+ // unaffected, so boot + HMR keep working — the user just sees no progress UI.
1558
+ function createNoopOverlayApi() {
1559
+ const snapshot = () => getRuntimeState().snapshot;
1560
+ return {
1561
+ ensureBootPage() {
1562
+ return null;
1563
+ },
1564
+ setBootStage() {
1565
+ return snapshot();
1566
+ },
1567
+ setConnectionStage() {
1568
+ return snapshot();
1569
+ },
1570
+ setUpdateStage() {
1571
+ return snapshot();
1572
+ },
1573
+ hide() { },
1574
+ getSnapshot() {
1575
+ return snapshot();
1576
+ },
1577
+ };
1578
+ }
1220
1579
  export function ensureHmrDevOverlayRuntimeInstalled(verbose) {
1221
1580
  const g = getOverlayGlobal();
1222
1581
  const state = getRuntimeState();
1223
1582
  state.verbose = state.verbose || !!verbose;
1224
1583
  if (!g.__NS_HMR_DEV_OVERLAY__) {
1225
- g.__NS_HMR_DEV_OVERLAY__ = createOverlayApi();
1584
+ g.__NS_HMR_DEV_OVERLAY__ = isHmrProgressOverlayEnabled() ? createOverlayApi() : createNoopOverlayApi();
1226
1585
  }
1227
1586
  return g.__NS_HMR_DEV_OVERLAY__;
1228
1587
  }
@@ -1235,11 +1594,11 @@ export function setHmrBootStage(stage, info) {
1235
1594
  export function setHmrConnectionStage(stage, info) {
1236
1595
  return ensureHmrDevOverlayRuntimeInstalled().setConnectionStage(stage, info);
1237
1596
  }
1238
- // Round-eleven.3 — Public entry point for driving the HMR-applying
1239
- // overlay. Callers walk through stages (received → evicting →
1240
- // reimporting → rebooting → complete); 'complete' auto-hides after a
1241
- // short interval. Soft-fails (no-op) if the runtime overlay was never
1242
- // installed (e.g., production builds, test environments).
1597
+ // Public entry point for driving the HMR-applying overlay. Callers
1598
+ // walk through stages (received → evicting → reimporting → rebooting
1599
+ // → complete); 'complete' auto-hides after a short interval.
1600
+ // Soft-fails (no-op) if the runtime overlay was never installed
1601
+ // (e.g., production builds, test environments).
1243
1602
  export function setHmrUpdateStage(stage, info) {
1244
1603
  return ensureHmrDevOverlayRuntimeInstalled().setUpdateStage(stage, info);
1245
1604
  }