@needle-tools/engine 5.1.0-canary.30cc545 → 5.1.0-canary.40da791

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 (341) hide show
  1. package/.needle/generated/needle-bindings.gen.d.ts +5 -0
  2. package/CHANGELOG.md +91 -0
  3. package/SKILL.md +4 -1
  4. package/components.needle.json +1 -1
  5. package/dist/{needle-engine.bundle-d_9mSxN4.js → needle-engine.bundle-Cu2B9CsR.js} +16112 -15269
  6. package/dist/needle-engine.bundle-ZoVUaB89.umd.cjs +1733 -0
  7. package/dist/needle-engine.bundle-hBWUJPxm.min.js +1733 -0
  8. package/dist/needle-engine.d.ts +1527 -384
  9. package/dist/needle-engine.js +573 -569
  10. package/dist/needle-engine.min.js +1 -1
  11. package/dist/needle-engine.umd.cjs +1 -1
  12. package/dist/three.js +1 -0
  13. package/dist/three.min.js +21 -21
  14. package/dist/three.umd.cjs +16 -16
  15. package/lib/engine/api.d.ts +8 -1
  16. package/lib/engine/api.js +6 -0
  17. package/lib/engine/api.js.map +1 -1
  18. package/lib/engine/codegen/register_types.js +10 -18
  19. package/lib/engine/codegen/register_types.js.map +1 -1
  20. package/lib/engine/debug/debug_spatial_console.d.ts +2 -0
  21. package/lib/engine/debug/debug_spatial_console.js +10 -7
  22. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  23. package/lib/engine/engine_addressables.d.ts +2 -0
  24. package/lib/engine/engine_addressables.js +6 -3
  25. package/lib/engine/engine_addressables.js.map +1 -1
  26. package/lib/engine/engine_audio.d.ts +68 -0
  27. package/lib/engine/engine_audio.js +172 -0
  28. package/lib/engine/engine_audio.js.map +1 -1
  29. package/lib/engine/engine_camera.fit.js +16 -4
  30. package/lib/engine/engine_camera.fit.js.map +1 -1
  31. package/lib/engine/engine_components.js +1 -1
  32. package/lib/engine/engine_components.js.map +1 -1
  33. package/lib/engine/engine_context.d.ts +41 -27
  34. package/lib/engine/engine_context.js +57 -30
  35. package/lib/engine/engine_context.js.map +1 -1
  36. package/lib/engine/engine_context_eventbus.d.ts +47 -0
  37. package/lib/engine/engine_context_eventbus.js +47 -0
  38. package/lib/engine/engine_context_eventbus.js.map +1 -0
  39. package/lib/engine/engine_disposable.d.ts +172 -0
  40. package/lib/engine/engine_disposable.js +136 -0
  41. package/lib/engine/engine_disposable.js.map +1 -0
  42. package/lib/engine/engine_gameobject.d.ts +1 -10
  43. package/lib/engine/engine_gameobject.js +22 -120
  44. package/lib/engine/engine_gameobject.js.map +1 -1
  45. package/lib/engine/engine_gltf_builtin_components.js +7 -69
  46. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  47. package/lib/engine/engine_init.js +16 -1
  48. package/lib/engine/engine_init.js.map +1 -1
  49. package/lib/engine/engine_input.d.ts +24 -5
  50. package/lib/engine/engine_input.js +3 -2
  51. package/lib/engine/engine_input.js.map +1 -1
  52. package/lib/engine/engine_instantiate_resolve.d.ts +42 -0
  53. package/lib/engine/engine_instantiate_resolve.js +372 -0
  54. package/lib/engine/engine_instantiate_resolve.js.map +1 -0
  55. package/lib/engine/engine_license.d.ts +2 -0
  56. package/lib/engine/engine_license.js +14 -6
  57. package/lib/engine/engine_license.js.map +1 -1
  58. package/lib/engine/engine_lifecycle_functions_internal.js +5 -0
  59. package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
  60. package/lib/engine/engine_mainloop_utils.js +7 -4
  61. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  62. package/lib/engine/engine_networking.d.ts +51 -37
  63. package/lib/engine/engine_networking.js +132 -82
  64. package/lib/engine/engine_networking.js.map +1 -1
  65. package/lib/engine/engine_networking.transport.websocket.d.ts +15 -0
  66. package/lib/engine/engine_networking.transport.websocket.js +38 -0
  67. package/lib/engine/engine_networking.transport.websocket.js.map +1 -0
  68. package/lib/engine/engine_networking_blob.js +1 -1
  69. package/lib/engine/engine_networking_blob.js.map +1 -1
  70. package/lib/engine/engine_networking_instantiate.js +2 -2
  71. package/lib/engine/engine_networking_instantiate.js.map +1 -1
  72. package/lib/engine/engine_networking_types.d.ts +39 -1
  73. package/lib/engine/engine_networking_types.js +7 -0
  74. package/lib/engine/engine_networking_types.js.map +1 -1
  75. package/lib/engine/engine_physics_rapier.d.ts +21 -3
  76. package/lib/engine/engine_physics_rapier.js +94 -25
  77. package/lib/engine/engine_physics_rapier.js.map +1 -1
  78. package/lib/engine/engine_scenedata.d.ts +13 -17
  79. package/lib/engine/engine_scenedata.js +58 -31
  80. package/lib/engine/engine_scenedata.js.map +1 -1
  81. package/lib/engine/engine_serialization_builtin_serializer.d.ts +10 -16
  82. package/lib/engine/engine_serialization_builtin_serializer.js +56 -46
  83. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  84. package/lib/engine/engine_serialization_core.d.ts +1 -0
  85. package/lib/engine/engine_serialization_core.js +7 -0
  86. package/lib/engine/engine_serialization_core.js.map +1 -1
  87. package/lib/engine/engine_ssr.d.ts +2 -0
  88. package/lib/engine/engine_ssr.js +2 -0
  89. package/lib/engine/engine_ssr.js.map +1 -1
  90. package/lib/engine/engine_types.d.ts +31 -11
  91. package/lib/engine/engine_types.js +1 -1
  92. package/lib/engine/engine_types.js.map +1 -1
  93. package/lib/engine/engine_util_decorator.js +7 -2
  94. package/lib/engine/engine_util_decorator.js.map +1 -1
  95. package/lib/engine/engine_utils.d.ts +1 -1
  96. package/lib/engine/engine_utils.js +19 -5
  97. package/lib/engine/engine_utils.js.map +1 -1
  98. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  99. package/lib/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js.map +1 -1
  100. package/lib/engine/webcomponents/jsx.d.ts +51 -0
  101. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  102. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +3 -4
  103. package/lib/engine/webcomponents/needle menu/needle-menu.js +1 -1
  104. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  105. package/lib/engine/webcomponents/needle-button.js.map +1 -1
  106. package/lib/engine/webcomponents/needle-engine.d.ts +10 -4
  107. package/lib/engine/webcomponents/needle-engine.js +1 -1
  108. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  109. package/lib/engine/xr/NeedleXRSession.d.ts +3 -2
  110. package/lib/engine/xr/NeedleXRSession.js +50 -14
  111. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  112. package/lib/engine/xr/events.d.ts +1 -1
  113. package/lib/engine/xr/events.js.map +1 -1
  114. package/lib/engine-components/Animation.js +17 -16
  115. package/lib/engine-components/Animation.js.map +1 -1
  116. package/lib/engine-components/AnimationBuilder.d.ts +158 -0
  117. package/lib/engine-components/AnimationBuilder.js +305 -0
  118. package/lib/engine-components/AnimationBuilder.js.map +1 -0
  119. package/lib/engine-components/Animator.d.ts +6 -0
  120. package/lib/engine-components/Animator.js +23 -13
  121. package/lib/engine-components/Animator.js.map +1 -1
  122. package/lib/engine-components/AnimatorController.builder.d.ts +191 -0
  123. package/lib/engine-components/AnimatorController.builder.js +263 -0
  124. package/lib/engine-components/AnimatorController.builder.js.map +1 -0
  125. package/lib/engine-components/AnimatorController.d.ts +4 -119
  126. package/lib/engine-components/AnimatorController.js +37 -233
  127. package/lib/engine-components/AnimatorController.js.map +1 -1
  128. package/lib/engine-components/AudioSource.d.ts +19 -3
  129. package/lib/engine-components/AudioSource.js +121 -68
  130. package/lib/engine-components/AudioSource.js.map +1 -1
  131. package/lib/engine-components/Collider.d.ts +18 -9
  132. package/lib/engine-components/Collider.js +61 -14
  133. package/lib/engine-components/Collider.js.map +1 -1
  134. package/lib/engine-components/Component.d.ts +72 -9
  135. package/lib/engine-components/Component.js +114 -10
  136. package/lib/engine-components/Component.js.map +1 -1
  137. package/lib/engine-components/ContactShadows.d.ts +1 -0
  138. package/lib/engine-components/ContactShadows.js +14 -1
  139. package/lib/engine-components/ContactShadows.js.map +1 -1
  140. package/lib/engine-components/DragControls.d.ts +7 -0
  141. package/lib/engine-components/DragControls.js +19 -7
  142. package/lib/engine-components/DragControls.js.map +1 -1
  143. package/lib/engine-components/DropListener.js +3 -0
  144. package/lib/engine-components/DropListener.js.map +1 -1
  145. package/lib/engine-components/EventList.d.ts +31 -9
  146. package/lib/engine-components/EventList.js +37 -76
  147. package/lib/engine-components/EventList.js.map +1 -1
  148. package/lib/engine-components/Joints.d.ts +4 -2
  149. package/lib/engine-components/Joints.js +19 -3
  150. package/lib/engine-components/Joints.js.map +1 -1
  151. package/lib/engine-components/Light.d.ts +6 -8
  152. package/lib/engine-components/Light.js +48 -27
  153. package/lib/engine-components/Light.js.map +1 -1
  154. package/lib/engine-components/Networking.d.ts +1 -1
  155. package/lib/engine-components/Networking.js +1 -1
  156. package/lib/engine-components/OrbitControls.d.ts +0 -2
  157. package/lib/engine-components/OrbitControls.js +30 -12
  158. package/lib/engine-components/OrbitControls.js.map +1 -1
  159. package/lib/engine-components/ReflectionProbe.js +2 -0
  160. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  161. package/lib/engine-components/RigidBody.d.ts +12 -4
  162. package/lib/engine-components/RigidBody.js +18 -4
  163. package/lib/engine-components/RigidBody.js.map +1 -1
  164. package/lib/engine-components/SceneSwitcher.js +3 -0
  165. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  166. package/lib/engine-components/SeeThrough.js +2 -2
  167. package/lib/engine-components/SeeThrough.js.map +1 -1
  168. package/lib/engine-components/api.d.ts +2 -1
  169. package/lib/engine-components/api.js +2 -1
  170. package/lib/engine-components/api.js.map +1 -1
  171. package/lib/engine-components/codegen/components.d.ts +7 -13
  172. package/lib/engine-components/codegen/components.js +7 -13
  173. package/lib/engine-components/codegen/components.js.map +1 -1
  174. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  175. package/lib/engine-components/postprocessing/VolumeParameter.d.ts +2 -0
  176. package/lib/engine-components/postprocessing/VolumeParameter.js +4 -1
  177. package/lib/engine-components/postprocessing/VolumeParameter.js.map +1 -1
  178. package/lib/engine-components/timeline/PlayableDirector.d.ts +21 -11
  179. package/lib/engine-components/timeline/PlayableDirector.js +75 -67
  180. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  181. package/lib/engine-components/timeline/SignalAsset.d.ts +3 -1
  182. package/lib/engine-components/timeline/SignalAsset.js +1 -0
  183. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  184. package/lib/engine-components/timeline/TimelineBuilder.d.ts +413 -0
  185. package/lib/engine-components/timeline/TimelineBuilder.js +506 -0
  186. package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -0
  187. package/lib/engine-components/timeline/TimelineModels.d.ts +2 -1
  188. package/lib/engine-components/timeline/TimelineModels.js +3 -0
  189. package/lib/engine-components/timeline/TimelineModels.js.map +1 -1
  190. package/lib/engine-components/timeline/TimelineTracks.d.ts +37 -6
  191. package/lib/engine-components/timeline/TimelineTracks.js +92 -26
  192. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  193. package/lib/engine-components/timeline/index.d.ts +2 -1
  194. package/lib/engine-components/timeline/index.js +2 -0
  195. package/lib/engine-components/timeline/index.js.map +1 -1
  196. package/lib/engine-components/ui/Canvas.d.ts +1 -1
  197. package/lib/engine-components/ui/Canvas.js +2 -8
  198. package/lib/engine-components/ui/Canvas.js.map +1 -1
  199. package/lib/engine-components/ui/Text.d.ts +1 -0
  200. package/lib/engine-components/ui/Text.js +10 -7
  201. package/lib/engine-components/ui/Text.js.map +1 -1
  202. package/lib/engine-components/web/CursorFollow.d.ts +0 -1
  203. package/lib/engine-components/web/CursorFollow.js +21 -13
  204. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  205. package/lib/engine-components/webxr/WebXRImageTracking.js +4 -0
  206. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  207. package/lib/needle-engine.d.ts +2 -0
  208. package/lib/needle-engine.js +2 -0
  209. package/lib/needle-engine.js.map +1 -1
  210. package/package.json +3 -83
  211. package/plugins/common/license.js +5 -2
  212. package/plugins/common/worker.js +9 -4
  213. package/plugins/dts-generator/dts.codegen.js +255 -50
  214. package/plugins/dts-generator/dts.scan.js +37 -9
  215. package/plugins/dts-generator/dts.writer.js +1 -1
  216. package/plugins/dts-generator/glb.discovery.js +140 -23
  217. package/plugins/dts-generator/glb.extractor.js +48 -8
  218. package/plugins/dts-generator/glb.reader.js +80 -27
  219. package/plugins/dts-generator/index.js +1 -1
  220. package/plugins/types/needle-bindings.d.ts +25 -14
  221. package/plugins/types/userconfig.d.ts +12 -0
  222. package/plugins/vite/asap.js +18 -9
  223. package/plugins/vite/dependencies.js +29 -10
  224. package/plugins/vite/dependency-watcher.d.ts +2 -2
  225. package/plugins/vite/dependency-watcher.js +5 -6
  226. package/plugins/vite/drop.d.ts +2 -2
  227. package/plugins/vite/drop.js +3 -4
  228. package/plugins/vite/dts-generator.d.ts +2 -2
  229. package/plugins/vite/dts-generator.js +43 -9
  230. package/plugins/vite/editor-connection.js +3 -3
  231. package/plugins/vite/index.d.ts +9 -3
  232. package/plugins/vite/index.js +23 -10
  233. package/plugins/vite/license.js +19 -1
  234. package/plugins/vite/local-files-core.js +3 -3
  235. package/plugins/vite/local-files-utils.d.ts +3 -1
  236. package/plugins/vite/local-files-utils.js +29 -5
  237. package/plugins/vite/meta.js +4 -2
  238. package/plugins/vite/poster.d.ts +2 -2
  239. package/plugins/vite/poster.js +3 -5
  240. package/plugins/vite/reload.d.ts +2 -2
  241. package/plugins/vite/reload.js +23 -23
  242. package/plugins/vite/server.js +2 -1
  243. package/src/engine/api.ts +11 -1
  244. package/src/engine/codegen/register_types.ts +10 -18
  245. package/src/engine/debug/debug_spatial_console.ts +10 -7
  246. package/src/engine/engine_addressables.ts +6 -3
  247. package/src/engine/engine_audio.ts +184 -0
  248. package/src/engine/engine_camera.fit.ts +15 -4
  249. package/src/engine/engine_components.ts +1 -1
  250. package/src/engine/engine_context.ts +67 -37
  251. package/src/engine/engine_context_eventbus.ts +73 -0
  252. package/src/engine/engine_disposable.ts +214 -0
  253. package/src/engine/engine_gameobject.ts +54 -159
  254. package/src/engine/engine_gltf_builtin_components.ts +7 -76
  255. package/src/engine/engine_init.ts +15 -1
  256. package/src/engine/engine_input.ts +28 -7
  257. package/src/engine/engine_instantiate_resolve.ts +407 -0
  258. package/src/engine/engine_license.ts +12 -10
  259. package/src/engine/engine_lifecycle_functions_internal.ts +7 -0
  260. package/src/engine/engine_mainloop_utils.ts +7 -4
  261. package/src/engine/engine_networking.transport.websocket.ts +45 -0
  262. package/src/engine/engine_networking.ts +161 -137
  263. package/src/engine/engine_networking_blob.ts +1 -1
  264. package/src/engine/engine_networking_instantiate.ts +2 -2
  265. package/src/engine/engine_networking_types.ts +41 -1
  266. package/src/engine/engine_physics_rapier.ts +102 -33
  267. package/src/engine/engine_scenedata.ts +56 -30
  268. package/src/engine/engine_serialization_builtin_serializer.ts +64 -52
  269. package/src/engine/engine_serialization_core.ts +9 -0
  270. package/src/engine/engine_ssr.ts +3 -0
  271. package/src/engine/engine_types.ts +48 -27
  272. package/src/engine/engine_util_decorator.ts +7 -2
  273. package/src/engine/engine_utils.ts +16 -5
  274. package/src/engine/physics/workers/mesh-bvh/GenerateMeshBVHWorker.js +1 -1
  275. package/src/engine/webcomponents/jsx.d.ts +51 -0
  276. package/src/engine/webcomponents/logo-element.ts +1 -0
  277. package/src/engine/webcomponents/needle menu/needle-menu.ts +3 -2
  278. package/src/engine/webcomponents/needle-button.ts +1 -0
  279. package/src/engine/webcomponents/needle-engine.ts +11 -4
  280. package/src/engine/xr/NeedleXRSession.ts +48 -13
  281. package/src/engine/xr/events.ts +1 -1
  282. package/src/engine-components/Animation.ts +19 -16
  283. package/src/engine-components/AnimationBuilder.ts +472 -0
  284. package/src/engine-components/Animator.ts +24 -12
  285. package/src/engine-components/AnimatorController.builder.ts +387 -0
  286. package/src/engine-components/AnimatorController.ts +24 -292
  287. package/src/engine-components/AudioSource.ts +130 -79
  288. package/src/engine-components/Collider.ts +66 -18
  289. package/src/engine-components/Component.ts +118 -20
  290. package/src/engine-components/ContactShadows.ts +15 -1
  291. package/src/engine-components/DragControls.ts +18 -11
  292. package/src/engine-components/DropListener.ts +3 -0
  293. package/src/engine-components/EventList.ts +45 -83
  294. package/src/engine-components/Joints.ts +20 -4
  295. package/src/engine-components/Light.ts +49 -27
  296. package/src/engine-components/Networking.ts +1 -1
  297. package/src/engine-components/OrbitControls.ts +34 -14
  298. package/src/engine-components/ReflectionProbe.ts +2 -0
  299. package/src/engine-components/RigidBody.ts +18 -4
  300. package/src/engine-components/SceneSwitcher.ts +3 -0
  301. package/src/engine-components/SeeThrough.ts +2 -2
  302. package/src/engine-components/api.ts +2 -1
  303. package/src/engine-components/codegen/components.ts +7 -13
  304. package/src/engine-components/postprocessing/VolumeParameter.ts +4 -1
  305. package/src/engine-components/timeline/PlayableDirector.ts +83 -81
  306. package/src/engine-components/timeline/SignalAsset.ts +4 -1
  307. package/src/engine-components/timeline/TimelineBuilder.ts +824 -0
  308. package/src/engine-components/timeline/TimelineModels.ts +5 -1
  309. package/src/engine-components/timeline/TimelineTracks.ts +96 -27
  310. package/src/engine-components/timeline/index.ts +2 -1
  311. package/src/engine-components/ui/Canvas.ts +2 -8
  312. package/src/engine-components/ui/Text.ts +12 -8
  313. package/src/engine-components/web/CursorFollow.ts +21 -14
  314. package/src/engine-components/webxr/WebXRImageTracking.ts +2 -0
  315. package/src/needle-engine.ts +3 -0
  316. package/dist/needle-engine.bundle-BMlLSACE.umd.cjs +0 -1732
  317. package/dist/needle-engine.bundle-BXPPQRer.min.js +0 -1732
  318. package/lib/engine-components/AvatarLoader.d.ts +0 -80
  319. package/lib/engine-components/AvatarLoader.js +0 -232
  320. package/lib/engine-components/AvatarLoader.js.map +0 -1
  321. package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +0 -11
  322. package/lib/engine-components/avatar/AvatarBlink_Simple.js +0 -77
  323. package/lib/engine-components/avatar/AvatarBlink_Simple.js.map +0 -1
  324. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +0 -14
  325. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +0 -69
  326. package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js.map +0 -1
  327. package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +0 -29
  328. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +0 -122
  329. package/lib/engine-components/avatar/Avatar_Brain_LookAt.js.map +0 -1
  330. package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +0 -15
  331. package/lib/engine-components/avatar/Avatar_MouthShapes.js +0 -80
  332. package/lib/engine-components/avatar/Avatar_MouthShapes.js.map +0 -1
  333. package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +0 -9
  334. package/lib/engine-components/avatar/Avatar_MustacheShake.js +0 -30
  335. package/lib/engine-components/avatar/Avatar_MustacheShake.js.map +0 -1
  336. package/src/engine-components/AvatarLoader.ts +0 -264
  337. package/src/engine-components/avatar/AvatarBlink_Simple.ts +0 -70
  338. package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +0 -64
  339. package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +0 -140
  340. package/src/engine-components/avatar/Avatar_MouthShapes.ts +0 -84
  341. package/src/engine-components/avatar/Avatar_MustacheShake.ts +0 -32
@@ -61,6 +61,35 @@ export function needleDependencies(command, config, userSettings) {
61
61
  }
62
62
  },
63
63
  },
64
+ // Vite 8's optimizer rebases `new URL(specifier, import.meta.url)` paths
65
+ // inside pre-bundled dependencies (PR #21434), but only handles truly relative
66
+ // paths (./ ../). Bare-specifier paths like `three-mesh-bvh/src/workers/...`
67
+ // are treated as relative to the *source file* that contained the `new URL()`
68
+ // call, producing a wrong URL such as:
69
+ // /node_modules/@needle-tools/engine/.../three-mesh-bvh/src/workers/generateMeshBVH.worker.js
70
+ // This middleware rewrites those broken URLs so the dev server finds the file at
71
+ // its real location in node_modules.
72
+ {
73
+ name: 'needle:worker-url-rewrite',
74
+ configureServer(server) {
75
+ const rewritePackages = ['three-mesh-bvh'];
76
+ server.middlewares.use((req, _res, next) => {
77
+ if (req.url) {
78
+ for (const pkg of rewritePackages) {
79
+ const marker = `/${pkg}/`;
80
+ if (req.url.includes(marker) && !req.url.startsWith(`/node_modules/${pkg}/`) && !req.url.startsWith('/@fs/')) {
81
+ const idx = req.url.indexOf(marker);
82
+ const rewritten = '/node_modules' + req.url.slice(idx);
83
+ needleLog('needle-dependencies', `Rewriting worker URL → ${rewritten}`);
84
+ req.url = rewritten;
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ next();
90
+ });
91
+ },
92
+ },
64
93
  ]
65
94
  }
66
95
 
@@ -158,16 +187,6 @@ function handleOptimizeDeps(config) {
158
187
  config.optimizeDeps.exclude.push('@needle-tools/engine');
159
188
  needleLog("needle-dependencies", 'Detected local @needle-tools/engine package → will exclude it from optimization');
160
189
  }
161
- // When engine is excluded from optimizeDeps, three-mesh-bvh must also be excluded.
162
- // The BVH worker (generateMeshBVH.worker.js) uses bare imports like `import 'three'`
163
- // which only resolve correctly when served through Vite's dev server module system.
164
- // If three-mesh-bvh is pre-bundled, the worker URL points into the cache and bare
165
- // imports fail at runtime → "Unknown error. Please check the server console."
166
- if (!config.optimizeDeps.include?.includes('three-mesh-bvh') &&
167
- !config.optimizeDeps.exclude.includes('three-mesh-bvh')) {
168
- config.optimizeDeps.exclude.push('three-mesh-bvh');
169
- needleLog("needle-dependencies", 'Detected local @needle-tools/engine package → will also exclude three-mesh-bvh from optimization');
170
- }
171
190
  }
172
191
  }
173
192
 
@@ -1,10 +1,10 @@
1
1
  /**
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {unknown} _config
4
4
  * @param {import('../types').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | null}
6
6
  */
7
- export function needleDependencyWatcher(command: "build" | "serve", _config: unknown, userSettings: import("../types").userSettings): import("vite").Plugin | null;
7
+ export function needleDependencyWatcher(_command: "build" | "serve" | undefined, _config: unknown, userSettings: import("../types").userSettings): import("vite").Plugin | null;
8
8
  export type PackageJson = {
9
9
  dependencies?: Record<string, string>;
10
10
  devDependencies?: Record<string, string>;
@@ -12,14 +12,12 @@ function log(...msg) {
12
12
  }
13
13
 
14
14
  /**
15
- * @param {"build" | "serve"} command
15
+ * @param {"build" | "serve" | undefined} _command
16
16
  * @param {unknown} _config
17
17
  * @param {import('../types').userSettings} userSettings
18
18
  * @returns {import('vite').Plugin | null}
19
19
  */
20
- export function needleDependencyWatcher(command, _config, userSettings) {
21
- if (command === "build") return null;
22
-
20
+ export function needleDependencyWatcher(_command, _config, userSettings) {
23
21
  if (userSettings?.noDependencyWatcher === true) return null;
24
22
 
25
23
  const dir = process.cwd();
@@ -28,6 +26,7 @@ export function needleDependencyWatcher(command, _config, userSettings) {
28
26
 
29
27
  return /** @type {import('vite').Plugin} */ ({
30
28
  name: 'needle-dependency-watcher',
29
+ apply: 'serve',
31
30
  /** @param {import('vite').ViteDevServer} server */
32
31
  configureServer(server) {
33
32
  manageClients(server);
@@ -99,7 +98,7 @@ function watchPackageJson(server, projectDir, packageJsonPath, cachePath) {
99
98
 
100
99
  setTimeout(() => {
101
100
  requireInstall = testIfInstallIsRequired(projectDir, packageJson);
102
- }, 1000);
101
+ }, 1000).unref();
103
102
 
104
103
  setInterval(() => {
105
104
  if (!packageJson || lastEditTime === undefined) return;
@@ -150,7 +149,7 @@ function watchPackageJson(server, projectDir, packageJsonPath, cachePath) {
150
149
  restart(server, projectDir, cachePath);
151
150
  }
152
151
  }
153
- }, 2000);
152
+ }, 2000).unref();
154
153
  }
155
154
 
156
155
  /** @param {string} projectDir @param {PackageJson | undefined} packageJson @returns {boolean} */
@@ -1,7 +1,7 @@
1
1
  /** Experimental, allow dropping files from Unity into the running scene.
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
4
4
  * @param {import('../types/userconfig.js').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | null | undefined}
6
6
  */
7
- export function needleDrop(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types/userconfig.js").userSettings): import("vite").Plugin | null | undefined;
7
+ export function needleDrop(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types/userconfig.js").userSettings): import("vite").Plugin | null | undefined;
@@ -7,18 +7,17 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
9
  /** Experimental, allow dropping files from Unity into the running scene.
10
- * @param {"build" | "serve"} command
10
+ * @param {"build" | "serve" | undefined} _command
11
11
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
12
12
  * @param {import('../types/userconfig.js').userSettings} userSettings
13
13
  * @returns {import('vite').Plugin | null | undefined}
14
14
  */
15
- export function needleDrop(command, config, userSettings) {
16
- if (command === "build") return;
17
-
15
+ export function needleDrop(_command, config, userSettings) {
18
16
  if(userSettings.useDrop !== true) return null;
19
17
 
20
18
  return {
21
19
  name: "needle:drop",
20
+ apply: 'serve',
22
21
  config(/** @type {{ server?: { hmr?: { port?: number } } }} */ viteConfig) {
23
22
  if(userSettings)
24
23
  if (!viteConfig.server) viteConfig.server = {};
@@ -2,6 +2,6 @@
2
2
  * @param {"build" | "serve"} _command Vite command (unused — runs in both modes)
3
3
  * @param {import('../types/needleConfig').needleMeta | null | undefined} _config
4
4
  * @param {import('../types').userSettings} [_userSettings]
5
- * @returns {import('vite').Plugin}
5
+ * @returns {import('vite').Plugin | null}
6
6
  */
7
- export function needleDtsGenerator(_command: "build" | "serve", _config: import("../types/needleConfig").needleMeta | null | undefined, _userSettings?: import("../types").userSettings): import("vite").Plugin;
7
+ export function needleDtsGenerator(_command: "build" | "serve", _config: import("../types/needleConfig").needleMeta | null | undefined, _userSettings?: import("../types").userSettings): import("vite").Plugin | null;
@@ -16,12 +16,24 @@
16
16
  * needleDtsGenerator(command, needleConfig, userSettings)
17
17
  */
18
18
 
19
- import { join, resolve } from 'path';
20
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
19
+ import { join, resolve, dirname } from 'path';
20
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync } from 'fs';
21
21
  import { tryLoadProjectConfig } from './config.js';
22
22
  import { generateBindingsDts } from '../dts-generator/index.js';
23
23
  import { needleLog } from './logging.js';
24
24
 
25
+ // Two dirs up from plugins/vite/ → package root.
26
+ // Use fileURLToPath so %7E and other URL-encoded characters in the path are decoded correctly.
27
+ // realpathSync follows symlinks so the path is stable even in npm link / monorepo setups.
28
+ import { fileURLToPath } from 'url';
29
+ let _packageRoot = /** @type {string | null} */ (null);
30
+ try {
31
+ _packageRoot = realpathSync(join(dirname(fileURLToPath(import.meta.url)), '..', '..'));
32
+ } catch (_e) {
33
+ // If we can't resolve the package root (e.g. unusual install layout), the plugin
34
+ // will silently skip generation rather than crashing the dev server.
35
+ }
36
+
25
37
  /**
26
38
  * Ensure `.vscode/settings.json` references the generated `needle-html-data.json`
27
39
  * so VS Code provides `data-bind-needle` completions in HTML files automatically.
@@ -60,9 +72,14 @@ function ensureVscodeHtmlCustomData(projectRoot, htmlDataPath) {
60
72
  * @param {"build" | "serve"} _command Vite command (unused — runs in both modes)
61
73
  * @param {import('../types/needleConfig').needleMeta | null | undefined} _config
62
74
  * @param {import('../types').userSettings} [_userSettings]
63
- * @returns {import('vite').Plugin}
75
+ * @returns {import('vite').Plugin | null}
64
76
  */
65
77
  export function needleDtsGenerator(_command, _config, _userSettings) {
78
+
79
+ if(_userSettings?.dts?.enabled === false) {
80
+ return null;
81
+ }
82
+
66
83
  let projectRoot = process.cwd();
67
84
 
68
85
  function resolveCodegenDir() {
@@ -73,7 +90,11 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
73
90
  }
74
91
 
75
92
  function resolveOutputPath() {
76
- return join(resolveCodegenDir(), "needle-bindings.d.ts");
93
+ // Write to a .needle dotfolder at the package root.
94
+ // Not in the `files` allowlist → never npm-published.
95
+ // ../../.needle/ from plugins/types/ resolves correctly for both
96
+ // symlinked (js/package~/) and published (node_modules/@needle-tools/engine/) layouts.
97
+ return join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-bindings.gen.d.ts");
77
98
  }
78
99
 
79
100
  function resolveAssetsDir() {
@@ -86,14 +107,24 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
86
107
  /** @type {import('vite').ViteDevServer | undefined} */
87
108
  let devServer;
88
109
 
89
- async function run() {
110
+ /** @type {Promise<void> | null} */
111
+ let _runInFlight = null;
112
+
113
+ function run() {
114
+ if (_runInFlight) return _runInFlight;
115
+ _runInFlight = _doRun().finally(() => { _runInFlight = null; });
116
+ return _runInFlight;
117
+ }
118
+
119
+ async function _doRun() {
90
120
  try {
121
+ if (!_packageRoot) return;
91
122
  const assetsDir = resolveAssetsDir();
92
123
  const outputPath = resolveOutputPath();
93
124
  const codegenDir = resolveCodegenDir();
94
125
  const count = await generateBindingsDts({ assetsDir, outputPath, projectRoot, codegenDir });
95
- // Always register HTML custom data the file is written on every run
96
- const htmlDataPath = join(codegenDir, "needle-html-data.json");
126
+ // HTML custom data sits next to the generated dts in .needle/generated/
127
+ const htmlDataPath = join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-html-data.json");
97
128
  ensureVscodeHtmlCustomData(projectRoot, htmlDataPath);
98
129
  if (count !== false) {
99
130
  needleLog("needle:dts-generator", `${count} binding(s) → ${outputPath.replace(process.cwd(), ".")}`);
@@ -102,7 +133,7 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
102
133
  hot.send({ type: "full-reload", path: "*" });
103
134
  }
104
135
  } else {
105
- needleLog("needle:dts-generator", `up-to-date`);
136
+ needleLog("needle:dts-generator", `up-to-date → ${outputPath.replace(process.cwd(), ".")}`);
106
137
  }
107
138
  } catch (err) {
108
139
  needleLog("needle:dts-generator", "Failed: " + (/** @type {any} */ (err)?.message ?? err));
@@ -118,7 +149,10 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
118
149
  },
119
150
 
120
151
  buildStart() {
121
- return run();
152
+ // In serve mode, the configureServer post-hook runs instead.
153
+ // Only run here for actual builds (no devServer).
154
+ if (!devServer) return run();
155
+ return undefined;
122
156
  },
123
157
 
124
158
  /** @param {import('vite').ViteDevServer} server */
@@ -27,7 +27,7 @@ export async function editorConnection(command, config, userSettings, pluginsArr
27
27
  if (typeof config.generator === "string" && !config.generator.includes("Unity")) return;
28
28
 
29
29
  if (!config) {
30
- setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync can not be installed automatically to vite: missing config", "warn"), 1000);
30
+ setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync can not be installed automatically to vite: missing config", "warn"), 1000).unref();
31
31
  return createPlugin(false);
32
32
  }
33
33
 
@@ -42,14 +42,14 @@ export async function editorConnection(command, config, userSettings, pluginsArr
42
42
  // }
43
43
  // }
44
44
  if (needleEditorSettings && needleEditorSettings.enabled === false) {
45
- setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable", "warn"), 1000);
45
+ setTimeout(() => needleLog("needle-editor-sync", "Needle Editor Sync is not enabled. Add a 'Needle Editor Sync' component to your scene to enable", "warn"), 1000).unref();
46
46
  return createPlugin(false);
47
47
  }
48
48
 
49
49
  // Check if the editor package is installed
50
50
  let path = root + `/node_modules/${editorSyncPackageName}/plugins/index.js`;
51
51
  if (existsSync(path) === false) {
52
- setTimeout(() => needleLog("needle-editor-sync", `${editorSyncPackageName} is not installed: Add the "Needle Editor Sync" component to your scene if you want to send changes directly from the Unity Editor to web app`, "warn"), 1000);
52
+ setTimeout(() => needleLog("needle-editor-sync", `${editorSyncPackageName} is not installed: Add the "Needle Editor Sync" component to your scene if you want to send changes directly from the Unity Editor to web app`, "warn"), 1000).unref();
53
53
  return createPlugin(false);
54
54
  }
55
55
 
@@ -19,12 +19,18 @@
19
19
  * ],
20
20
  * }
21
21
  * ```
22
- * @param {"build" | "serve"} command
23
- * @param {import('../types/needleConfig').needleMeta | null | undefined} config
22
+ * When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
23
+ * the command is resolved automatically from Vite's `configResolved` hook.
24
+ * ```js
25
+ * // SvelteKit — no command needed:
26
+ * export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
27
+ * ```
28
+ * @param {"build" | "serve" | undefined} [command]
29
+ * @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
24
30
  * @param {import('../types/index.js').userSettings} [userSettings]
25
31
  * @returns {Promise<import('vite').Plugin[]>}
26
32
  */
27
- export function needlePlugins(command: "build" | "serve", config?: import("../types/needleConfig").needleMeta | null | undefined, userSettings?: import("../types/index.js").userSettings): Promise<import("vite").Plugin[]>;
33
+ export function needlePlugins(command?: "build" | "serve" | undefined, config?: import("../types/needleConfig").needleMeta | null | undefined, userSettings?: import("../types/index.js").userSettings): Promise<import("vite").Plugin[]>;
28
34
  export { needleAI } from "./ai.js";
29
35
  export { needleDtsGenerator } from "./dts-generator.js";
30
36
  export { needleAsap } from "./asap.js";
@@ -116,12 +116,18 @@ const defaultUserSettings = {
116
116
  * ],
117
117
  * }
118
118
  * ```
119
- * @param {"build" | "serve"} command
120
- * @param {import('../types/needleConfig').needleMeta | null | undefined} config
119
+ * When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
120
+ * the command is resolved automatically from Vite's `configResolved` hook.
121
+ * ```js
122
+ * // SvelteKit — no command needed:
123
+ * export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
124
+ * ```
125
+ * @param {"build" | "serve" | undefined} [command]
126
+ * @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
121
127
  * @param {import('../types/index.js').userSettings} [userSettings]
122
128
  * @returns {Promise<import('vite').Plugin[]>}
123
129
  */
124
- export async function needlePlugins(command, config = undefined, userSettings = {}) {
130
+ export async function needlePlugins(command = undefined, config = undefined, userSettings = {}) {
125
131
 
126
132
  if (!config) config = {}
127
133
 
@@ -168,14 +174,21 @@ export async function needlePlugins(command, config = undefined, userSettings =
168
174
  array.push(await editorConnection(command, config, userSettings, array));
169
175
  array.push(needleDependencyWatcher(command, config, userSettings));
170
176
 
171
- // Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive
172
- if (command === "serve") {
177
+ // Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive.
178
+ // If command is unknown at call time (e.g. SvelteKit plain defineConfig), defer to configResolved.
179
+ const registerSigint = () => {
173
180
  process.on('SIGINT', () => {
174
- // Wait a moment to allow plugins to clean up if needed, then exit
175
- setTimeout(() => {
176
- console.debug('\nGoodbye!');
177
- process.exit();
178
- }, 1000);
181
+ setTimeout(() => { console.debug('\nGoodbye!'); process.exit(); }, 1000);
182
+ });
183
+ };
184
+ if (command === "serve") {
185
+ registerSigint();
186
+ } else if (command === undefined) {
187
+ array.push({
188
+ name: "needle:sigint",
189
+ configResolved(config) {
190
+ if (config.command === "serve") registerSigint();
191
+ }
179
192
  });
180
193
  }
181
194
 
@@ -9,6 +9,7 @@ import { loadConfig } from './config.js';
9
9
  */
10
10
  export function needleLicense(command, config, userSettings) {
11
11
  let license = undefined;
12
+ let appliedLicense = false;
12
13
 
13
14
  return {
14
15
  name: "needle:license",
@@ -31,7 +32,15 @@ export function needleLicense(command, config, userSettings) {
31
32
 
32
33
  },
33
34
  async transform(src, id) {
34
- const isNeedleEngineFile = id.includes("engine/engine_license") || id.includes("needle-tools_engine");
35
+ if (appliedLicense === true) {
36
+ return;
37
+ }
38
+
39
+ // Vite 4 and 8 handling:
40
+ const isNeedleEngineFile = id.includes("engine/engine_license")
41
+ || id.includes("needle-tools_engine")
42
+ || id.includes("@needle-tools")
43
+ || id.includes("needle-engine");
35
44
  // sometimes the actual license parameter is in a unnamed chunk file
36
45
  const isViteChunkFile = id.includes("chunk") && id.includes(".vite");
37
46
  if (isNeedleEngineFile || isViteChunkFile) {
@@ -44,12 +53,21 @@ export function needleLicense(command, config, userSettings) {
44
53
  if (index >= 0) {
45
54
  const end = src.indexOf(";", index);
46
55
  if (end >= 0) {
56
+ appliedLicense = true;
47
57
  const line = src.substring(index, end);
48
58
  const replaced = "NEEDLE_ENGINE_LICENSE_TYPE = \"" + license + "\"";
49
59
  src = src.replace(line, replaced);
50
60
  return { code: src, map: null }
51
61
  }
52
62
  }
63
+ // @TODO: detect local needle engine dev setup and log error if not found
64
+ }
65
+ },
66
+ buildEnd() {
67
+ if (!appliedLicense) {
68
+ if (process.env.NEEDLE_TEST_ENV) {
69
+ console.error("ERR: License was not applied!");
70
+ }
53
71
  }
54
72
  }
55
73
  }
@@ -291,7 +291,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
291
291
  failedDownloads,
292
292
  localizationStats,
293
293
  }, activeHandlers);
294
- src = fixRelativeNewURL(src);
294
+ src = fixRelativeNewURL(src, viteConfig?.base);
295
295
  }
296
296
  catch (err) {
297
297
  needleLog("needle:local-files", "Error in transform: " + getErrMessage(err), "error");
@@ -303,7 +303,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
303
303
  },
304
304
  renderChunk(code, chunk) {
305
305
  if (!chunk.fileName?.endsWith(".js")) return null;
306
- const fixed = fixRelativeNewURL(code);
306
+ const fixed = fixRelativeNewURL(code, viteConfig?.base);
307
307
  if (fixed === code) return null;
308
308
  return {
309
309
  code: fixed,
@@ -314,7 +314,7 @@ export function needleMakeFilesLocal(command, _config, userSettings) {
314
314
  for (const output of Object.values(bundle)) {
315
315
  if (output.type !== "chunk") continue;
316
316
  if (!output.fileName?.endsWith(".js")) continue;
317
- const fixed = fixRelativeNewURL(output.code);
317
+ const fixed = fixRelativeNewURL(output.code, viteConfig?.base);
318
318
  if (fixed !== output.code) output.code = fixed;
319
319
  }
320
320
  },
@@ -24,9 +24,11 @@ export function normalizeWebPath(path: string): string;
24
24
  export function ensureTrailingSlash(path: string): string;
25
25
  /**
26
26
  * @param {string} src
27
+ * @param {string} [base] - Vite base path (e.g. "/" or "/app/"). When provided,
28
+ * ext/ paths are made absolute so they resolve correctly under SPA routing.
27
29
  * @returns {string}
28
30
  */
29
- export function fixRelativeNewURL(src: string): string;
31
+ export function fixRelativeNewURL(src: string, base?: string): string;
30
32
  /**
31
33
  * @param {string} src
32
34
  * @returns {string}
@@ -113,25 +113,49 @@ export function ensureTrailingSlash(path) {
113
113
 
114
114
  /**
115
115
  * @param {string} src
116
+ * @param {string} [base] - Vite base path (e.g. "/" or "/app/"). When provided,
117
+ * ext/ paths are made absolute so they resolve correctly under SPA routing.
116
118
  * @returns {string}
117
119
  */
118
- export function fixRelativeNewURL(src) {
120
+ export function fixRelativeNewURL(src, base) {
121
+ /** @param {string} path */
122
+ function makeAbsolute(path) {
123
+ // Strip any leading ./ ../ or / prefix to get the clean ext/... path
124
+ const clean = path.replace(/^(?:\.\.?\/)+/, '').replace(/^\//, '');
125
+ if (base) return base.replace(/\/+$/, '') + '/' + clean;
126
+ return clean;
127
+ }
128
+
119
129
  src = src.replace(
120
130
  /(?<==\s*)(["'])((?:(?:\.{1,2}\/)|\/)?ext\/[^"']*\/)\1/g,
121
131
  (/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
122
- const runtimePath = path.startsWith("/ext/") ? path.substring(1) : path;
123
- return `new URL(${quote}${runtimePath}${quote}, self.location?.href || ${quote}${quote}).href`;
132
+ const resolved = makeAbsolute(path);
133
+ return `new URL(${quote}${resolved}${quote}, self.location?.href || ${quote}${quote}).href`;
124
134
  }
125
135
  );
126
136
 
127
137
  src = src.replace(
128
138
  /new\s+URL\s*\(\s*(["'`])((?:(?:\.{1,2}\/)|\/)?ext\/[^"'`]+)\1\s*\)/g,
129
139
  (/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
130
- const runtimePath = path.startsWith("/ext/") ? path.substring(1) : path;
131
- return `new URL(${quote}${runtimePath}${quote}, self.location?.href)`;
140
+ const resolved = makeAbsolute(path);
141
+ return `new URL(${quote}${resolved}${quote}, self.location?.href)`;
132
142
  }
133
143
  );
134
144
 
145
+ // Make remaining ext/ string literals absolute (e.g. font paths passed as
146
+ // function arguments like addVariant("normal","normal","ext/fonts/...")).
147
+ // The regexes above already consumed paths inside new URL() calls and
148
+ // assignment-based patterns, so this only catches leftover bare strings.
149
+ if (base) {
150
+ src = src.replace(
151
+ /(["'`])((?:\.{1,2}\/)?ext\/[^"'`]+)\1/g,
152
+ (/** @type {string} */ _match, /** @type {string} */ quote, /** @type {string} */ path) => {
153
+ const resolved = makeAbsolute(path);
154
+ return `${quote}${resolved}${quote}`;
155
+ }
156
+ );
157
+ }
158
+
135
159
  return src;
136
160
  }
137
161
 
@@ -13,8 +13,7 @@ import { needleGreenBold, needleLog } from './logging.js';
13
13
  */
14
14
  export function needleMeta(command, config, userSettings) {
15
15
 
16
- // we can check if this is a build
17
- const isBuild = command === 'build';
16
+ let isBuild = command === 'build';
18
17
 
19
18
  async function updateConfig() {
20
19
  config = await loadConfig();
@@ -25,6 +24,9 @@ export function needleMeta(command, config, userSettings) {
25
24
  return {
26
25
  // replace meta tags
27
26
  name: 'needle:meta',
27
+ configResolved(resolvedConfig) {
28
+ isBuild = resolvedConfig.command === 'build';
29
+ },
28
30
  transformIndexHtml: {
29
31
  order: 'pre',
30
32
  handler(/** @type {string} */ html, /** @type {unknown} */ _ctx) {
@@ -1,8 +1,8 @@
1
1
  export function getPosterPath(): string;
2
2
  /**
3
- * @param {"build" | "serve"} command
3
+ * @param {"build" | "serve" | undefined} _command
4
4
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
5
5
  * @param {import('../types').userSettings} userSettings
6
6
  * @returns {import('vite').Plugin | undefined}
7
7
  */
8
- export function needlePoster(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
8
+ export function needlePoster(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
@@ -10,19 +10,17 @@ export function getPosterPath() {
10
10
  }
11
11
 
12
12
  /**
13
- * @param {"build" | "serve"} command
13
+ * @param {"build" | "serve" | undefined} _command
14
14
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
15
15
  * @param {import('../types').userSettings} userSettings
16
16
  * @returns {import('vite').Plugin | undefined}
17
17
  */
18
- export function needlePoster(command, config, userSettings) {
19
- // only relevant for local development
20
- if (command === 'build') return [];
21
-
18
+ export function needlePoster(_command, config, userSettings) {
22
19
  if (userSettings.noPoster) return;
23
20
 
24
21
  return {
25
22
  name: 'needle:poster',
23
+ apply: 'serve',
26
24
  configureServer(server) {
27
25
  const hot = server.hot ?? server.ws;
28
26
  hot.on('needle:screenshot', async (data, client) => {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {import('../types/needleConfig').needleMeta | null} config
4
4
  * @param {import('../types').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | undefined}
6
6
  */
7
- export function needleReload(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
7
+ export function needleReload(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;