@noego/wood 0.4.10 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +118 -42
  2. package/dist/bridge/backend_bridge.cjs.map +1 -1
  3. package/dist/bridge/backend_bridge.js.map +1 -1
  4. package/dist/client/index.cjs +78 -21
  5. package/dist/client/index.cjs.map +1 -1
  6. package/dist/client/index.d.cts +18 -3
  7. package/dist/client/index.d.ts +18 -3
  8. package/dist/client/index.js +80 -22
  9. package/dist/client/index.js.map +1 -1
  10. package/dist/client/renderer_log_transport.cjs +151 -0
  11. package/dist/client/renderer_log_transport.cjs.map +1 -0
  12. package/dist/client/renderer_log_transport.d.cts +54 -0
  13. package/dist/client/renderer_log_transport.d.ts +54 -0
  14. package/dist/client/renderer_log_transport.js +123 -0
  15. package/dist/client/renderer_log_transport.js.map +1 -0
  16. package/dist/codegen/controller_registration_generator.cjs +13 -2
  17. package/dist/codegen/controller_registration_generator.cjs.map +1 -1
  18. package/dist/codegen/controller_registration_generator.d.cts +12 -1
  19. package/dist/codegen/controller_registration_generator.d.ts +12 -1
  20. package/dist/codegen/controller_registration_generator.js +10 -1
  21. package/dist/codegen/controller_registration_generator.js.map +1 -1
  22. package/dist/codegen/index.d.cts +1 -0
  23. package/dist/codegen/index.d.ts +1 -0
  24. package/dist/codegen/preload_generator.cjs +13 -6
  25. package/dist/codegen/preload_generator.cjs.map +1 -1
  26. package/dist/codegen/preload_generator.d.cts +11 -2
  27. package/dist/codegen/preload_generator.d.ts +11 -2
  28. package/dist/codegen/preload_generator.js +13 -6
  29. package/dist/codegen/preload_generator.js.map +1 -1
  30. package/dist/codegen/renderer_app_generator.cjs +78 -42
  31. package/dist/codegen/renderer_app_generator.cjs.map +1 -1
  32. package/dist/codegen/renderer_app_generator.js +78 -42
  33. package/dist/codegen/renderer_app_generator.js.map +1 -1
  34. package/dist/codegen/type_generator.cjs +1 -0
  35. package/dist/codegen/type_generator.cjs.map +1 -1
  36. package/dist/codegen/type_generator.js +1 -0
  37. package/dist/codegen/type_generator.js.map +1 -1
  38. package/dist/config/config_parser.cjs +95 -4
  39. package/dist/config/config_parser.cjs.map +1 -1
  40. package/dist/config/config_parser.d.cts +10 -2
  41. package/dist/config/config_parser.d.ts +10 -2
  42. package/dist/config/config_parser.js +92 -3
  43. package/dist/config/config_parser.js.map +1 -1
  44. package/dist/config/index.cjs +6 -2
  45. package/dist/config/index.cjs.map +1 -1
  46. package/dist/config/index.d.cts +2 -2
  47. package/dist/config/index.d.ts +2 -2
  48. package/dist/config/index.js +8 -2
  49. package/dist/config/index.js.map +1 -1
  50. package/dist/controller/controller_resolver.cjs +51 -3
  51. package/dist/controller/controller_resolver.cjs.map +1 -1
  52. package/dist/controller/controller_resolver.d.cts +27 -4
  53. package/dist/controller/controller_resolver.d.ts +27 -4
  54. package/dist/controller/controller_resolver.js +48 -2
  55. package/dist/controller/controller_resolver.js.map +1 -1
  56. package/dist/controller/index.cjs +6 -2
  57. package/dist/controller/index.cjs.map +1 -1
  58. package/dist/controller/index.d.cts +1 -1
  59. package/dist/controller/index.d.ts +1 -1
  60. package/dist/controller/index.js +4 -2
  61. package/dist/controller/index.js.map +1 -1
  62. package/dist/dev/wood_dev_server.cjs +4 -1
  63. package/dist/dev/wood_dev_server.cjs.map +1 -1
  64. package/dist/dev/wood_dev_server.js +5 -2
  65. package/dist/dev/wood_dev_server.js.map +1 -1
  66. package/dist/dev/yaml_watcher.cjs +1 -1
  67. package/dist/dev/yaml_watcher.cjs.map +1 -1
  68. package/dist/dev/yaml_watcher.d.cts +4 -0
  69. package/dist/dev/yaml_watcher.d.ts +4 -0
  70. package/dist/dev/yaml_watcher.js +1 -1
  71. package/dist/dev/yaml_watcher.js.map +1 -1
  72. package/dist/frontend/frontend_lifecycle.cjs +74 -0
  73. package/dist/frontend/frontend_lifecycle.cjs.map +1 -0
  74. package/dist/frontend/frontend_lifecycle.d.cts +50 -0
  75. package/dist/frontend/frontend_lifecycle.d.ts +50 -0
  76. package/dist/frontend/frontend_lifecycle.js +50 -0
  77. package/dist/frontend/frontend_lifecycle.js.map +1 -0
  78. package/dist/frontend/frontend_page.cjs +122 -0
  79. package/dist/frontend/frontend_page.cjs.map +1 -0
  80. package/dist/frontend/frontend_page.d.cts +62 -0
  81. package/dist/frontend/frontend_page.d.ts +62 -0
  82. package/dist/frontend/frontend_page.js +98 -0
  83. package/dist/frontend/frontend_page.js.map +1 -0
  84. package/dist/frontend/frontend_surface.cjs +249 -0
  85. package/dist/frontend/frontend_surface.cjs.map +1 -0
  86. package/dist/frontend/frontend_surface.d.cts +64 -0
  87. package/dist/frontend/frontend_surface.d.ts +64 -0
  88. package/dist/frontend/frontend_surface.js +224 -0
  89. package/dist/frontend/frontend_surface.js.map +1 -0
  90. package/dist/frontend/index.cjs +52 -0
  91. package/dist/frontend/index.cjs.map +1 -0
  92. package/dist/frontend/index.d.cts +10 -0
  93. package/dist/frontend/index.d.ts +10 -0
  94. package/dist/frontend/index.js +19 -0
  95. package/dist/frontend/index.js.map +1 -0
  96. package/dist/frontend/page_catalog.cjs +135 -0
  97. package/dist/frontend/page_catalog.cjs.map +1 -0
  98. package/dist/frontend/page_catalog.d.cts +56 -0
  99. package/dist/frontend/page_catalog.d.ts +56 -0
  100. package/dist/frontend/page_catalog.js +108 -0
  101. package/dist/frontend/page_catalog.js.map +1 -0
  102. package/dist/frontend/tracked_transport.cjs +55 -0
  103. package/dist/frontend/tracked_transport.cjs.map +1 -0
  104. package/dist/frontend/tracked_transport.d.cts +36 -0
  105. package/dist/frontend/tracked_transport.d.ts +36 -0
  106. package/dist/frontend/tracked_transport.js +31 -0
  107. package/dist/frontend/tracked_transport.js.map +1 -0
  108. package/dist/frontend/work_registry.cjs +153 -0
  109. package/dist/frontend/work_registry.cjs.map +1 -0
  110. package/dist/frontend/work_registry.d.cts +70 -0
  111. package/dist/frontend/work_registry.d.ts +70 -0
  112. package/dist/frontend/work_registry.js +128 -0
  113. package/dist/frontend/work_registry.js.map +1 -0
  114. package/dist/index.cjs +24 -0
  115. package/dist/index.cjs.map +1 -1
  116. package/dist/index.d.cts +10 -7
  117. package/dist/index.d.ts +10 -7
  118. package/dist/index.js +27 -4
  119. package/dist/index.js.map +1 -1
  120. package/dist/main/index.cjs +10 -0
  121. package/dist/main/index.cjs.map +1 -1
  122. package/dist/main/index.d.cts +14 -2
  123. package/dist/main/index.d.ts +14 -2
  124. package/dist/main/index.js +16 -0
  125. package/dist/main/index.js.map +1 -1
  126. package/dist/middleware/middleware_resolver.cjs +22 -1
  127. package/dist/middleware/middleware_resolver.cjs.map +1 -1
  128. package/dist/middleware/middleware_resolver.d.cts +13 -1
  129. package/dist/middleware/middleware_resolver.d.ts +13 -1
  130. package/dist/middleware/middleware_resolver.js +22 -1
  131. package/dist/middleware/middleware_resolver.js.map +1 -1
  132. package/dist/navigation/index.cjs +3 -0
  133. package/dist/navigation/index.cjs.map +1 -1
  134. package/dist/navigation/index.d.cts +25 -1
  135. package/dist/navigation/index.d.ts +25 -1
  136. package/dist/navigation/index.js +2 -0
  137. package/dist/navigation/index.js.map +1 -1
  138. package/dist/{middleware/__fixtures__/middleware/auth.cjs → navigation/layout_preservation.cjs} +18 -20
  139. package/dist/navigation/layout_preservation.cjs.map +1 -0
  140. package/dist/navigation/layout_preservation.d.cts +2 -0
  141. package/dist/navigation/layout_preservation.d.ts +2 -0
  142. package/dist/navigation/layout_preservation.js +18 -0
  143. package/dist/navigation/layout_preservation.js.map +1 -0
  144. package/dist/parser/index.cjs +2 -0
  145. package/dist/parser/index.cjs.map +1 -1
  146. package/dist/parser/index.d.cts +1 -1
  147. package/dist/parser/index.d.ts +1 -1
  148. package/dist/parser/index.js +2 -1
  149. package/dist/parser/index.js.map +1 -1
  150. package/dist/parser/operations_parser.cjs +6 -0
  151. package/dist/parser/operations_parser.cjs.map +1 -1
  152. package/dist/parser/operations_parser.d.cts +9 -2
  153. package/dist/parser/operations_parser.d.ts +9 -2
  154. package/dist/parser/operations_parser.js +5 -0
  155. package/dist/parser/operations_parser.js.map +1 -1
  156. package/dist/parser/views_parser.cjs.map +1 -1
  157. package/dist/parser/views_parser.js.map +1 -1
  158. package/dist/router/index.d.cts +1 -0
  159. package/dist/router/index.d.ts +1 -0
  160. package/dist/router/wood_router.cjs +35 -3
  161. package/dist/router/wood_router.cjs.map +1 -1
  162. package/dist/router/wood_router.d.cts +15 -0
  163. package/dist/router/wood_router.d.ts +15 -0
  164. package/dist/router/wood_router.js +36 -4
  165. package/dist/router/wood_router.js.map +1 -1
  166. package/dist/runtime/get_container.cjs +9 -34
  167. package/dist/runtime/get_container.cjs.map +1 -1
  168. package/dist/runtime/get_container.d.cts +24 -4
  169. package/dist/runtime/get_container.d.ts +24 -4
  170. package/dist/runtime/get_container.js +8 -23
  171. package/dist/runtime/get_container.js.map +1 -1
  172. package/dist/runtime/index.cjs +9 -0
  173. package/dist/runtime/index.cjs.map +1 -1
  174. package/dist/runtime/index.d.cts +5 -2
  175. package/dist/runtime/index.d.ts +5 -2
  176. package/dist/runtime/index.js +10 -1
  177. package/dist/runtime/index.js.map +1 -1
  178. package/dist/runtime/renderer_config_extension.cjs +50 -0
  179. package/dist/runtime/renderer_config_extension.cjs.map +1 -0
  180. package/dist/runtime/renderer_config_extension.d.cts +19 -0
  181. package/dist/runtime/renderer_config_extension.d.ts +19 -0
  182. package/dist/runtime/renderer_config_extension.js +24 -0
  183. package/dist/runtime/renderer_config_extension.js.map +1 -0
  184. package/dist/runtime/renderer_log_batch_receiver.cjs +73 -0
  185. package/dist/runtime/renderer_log_batch_receiver.cjs.map +1 -0
  186. package/dist/runtime/renderer_log_batch_receiver.d.cts +29 -0
  187. package/dist/runtime/renderer_log_batch_receiver.d.ts +29 -0
  188. package/dist/runtime/renderer_log_batch_receiver.js +48 -0
  189. package/dist/runtime/renderer_log_batch_receiver.js.map +1 -0
  190. package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +1 -1
  191. package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +1 -1
  192. package/dist/runtime/runtime.cjs +14 -0
  193. package/dist/runtime/runtime.cjs.map +1 -1
  194. package/dist/runtime/runtime.d.cts +2 -1
  195. package/dist/runtime/runtime.d.ts +2 -1
  196. package/dist/runtime/runtime.js +14 -0
  197. package/dist/runtime/runtime.js.map +1 -1
  198. package/dist/stick/index.cjs.map +1 -1
  199. package/dist/stick/index.js.map +1 -1
  200. package/dist/testing/browser.cjs +104 -23
  201. package/dist/testing/browser.cjs.map +1 -1
  202. package/dist/testing/browser.d.cts +8 -3
  203. package/dist/testing/browser.d.ts +8 -3
  204. package/dist/testing/browser.js +102 -22
  205. package/dist/testing/browser.js.map +1 -1
  206. package/dist/testing/create_controller_harness.cjs +28 -8
  207. package/dist/testing/create_controller_harness.cjs.map +1 -1
  208. package/dist/testing/create_controller_harness.d.cts +17 -2
  209. package/dist/testing/create_controller_harness.d.ts +17 -2
  210. package/dist/testing/create_controller_harness.js +28 -8
  211. package/dist/testing/create_controller_harness.js.map +1 -1
  212. package/dist/testing/create_router_bridge.d.cts +1 -0
  213. package/dist/testing/create_router_bridge.d.ts +1 -0
  214. package/dist/testing/create_test_router.d.cts +1 -0
  215. package/dist/testing/create_test_router.d.ts +1 -0
  216. package/dist/testing/index.cjs +31 -0
  217. package/dist/testing/index.cjs.map +1 -1
  218. package/dist/testing/index.d.cts +20 -5
  219. package/dist/testing/index.d.ts +20 -5
  220. package/dist/testing/index.js +19 -1
  221. package/dist/testing/index.js.map +1 -1
  222. package/dist/{controller/__fixtures__/controllers/not_a_class.cjs → testing/test_wood.cjs} +15 -7
  223. package/dist/testing/test_wood.cjs.map +1 -0
  224. package/dist/testing/test_wood.d.cts +16 -0
  225. package/dist/testing/test_wood.d.ts +16 -0
  226. package/dist/testing/test_wood.js +12 -0
  227. package/dist/testing/test_wood.js.map +1 -0
  228. package/dist/testing/test_wood_config.cjs +272 -0
  229. package/dist/testing/test_wood_config.cjs.map +1 -0
  230. package/dist/testing/test_wood_config.d.cts +111 -0
  231. package/dist/testing/test_wood_config.d.ts +111 -0
  232. package/dist/testing/test_wood_config.js +247 -0
  233. package/dist/testing/test_wood_config.js.map +1 -0
  234. package/dist/testing/wood_config_source.cjs +146 -0
  235. package/dist/testing/wood_config_source.cjs.map +1 -0
  236. package/dist/testing/wood_config_source.d.cts +36 -0
  237. package/dist/testing/wood_config_source.d.ts +36 -0
  238. package/dist/testing/wood_config_source.js +112 -0
  239. package/dist/testing/wood_config_source.js.map +1 -0
  240. package/dist/testing/wood_env_renderer.cjs +210 -0
  241. package/dist/testing/wood_env_renderer.cjs.map +1 -0
  242. package/dist/testing/wood_env_renderer.d.cts +74 -0
  243. package/dist/testing/wood_env_renderer.d.ts +74 -0
  244. package/dist/testing/wood_env_renderer.js +188 -0
  245. package/dist/testing/wood_env_renderer.js.map +1 -0
  246. package/dist/testing/wood_test_selection.cjs +94 -0
  247. package/dist/testing/wood_test_selection.cjs.map +1 -0
  248. package/dist/testing/wood_test_selection.d.cts +39 -0
  249. package/dist/testing/wood_test_selection.d.ts +39 -0
  250. package/dist/testing/wood_test_selection.js +68 -0
  251. package/dist/testing/wood_test_selection.js.map +1 -0
  252. package/dist/trace-testing/index.d.cts +1 -2
  253. package/dist/trace-testing/index.d.ts +1 -2
  254. package/dist/trace-testing/trace_recorder.cjs +1 -1
  255. package/dist/trace-testing/trace_recorder.cjs.map +1 -1
  256. package/dist/trace-testing/trace_recorder.d.cts +1 -2
  257. package/dist/trace-testing/trace_recorder.d.ts +1 -2
  258. package/dist/trace-testing/trace_recorder.js +1 -1
  259. package/dist/trace-testing/trace_recorder.js.map +1 -1
  260. package/dist/trace-transport/index.d.cts +1 -1
  261. package/dist/trace-transport/index.d.ts +1 -1
  262. package/dist/{trace_hub-Cob54qRx.d.cts → trace_hub-Cpo_nVze.d.cts} +21 -1
  263. package/dist/{trace_hub-Cob54qRx.d.ts → trace_hub-Cpo_nVze.d.ts} +21 -1
  264. package/dist/tracing/index.cjs +9 -2
  265. package/dist/tracing/index.cjs.map +1 -1
  266. package/dist/tracing/index.d.cts +3 -2
  267. package/dist/tracing/index.d.ts +3 -2
  268. package/dist/tracing/index.js +7 -1
  269. package/dist/tracing/index.js.map +1 -1
  270. package/dist/tracing/renderer_trace_batch_host.d.cts +1 -1
  271. package/dist/tracing/renderer_trace_batch_host.d.ts +1 -1
  272. package/dist/tracing/renderer_trace_batch_transport.cjs +48 -6
  273. package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -1
  274. package/dist/tracing/renderer_trace_batch_transport.d.cts +17 -1
  275. package/dist/tracing/renderer_trace_batch_transport.d.ts +17 -1
  276. package/dist/tracing/renderer_trace_batch_transport.js +48 -6
  277. package/dist/tracing/renderer_trace_batch_transport.js.map +1 -1
  278. package/dist/tracing/trace_batch_adapter.cjs +110 -0
  279. package/dist/tracing/trace_batch_adapter.cjs.map +1 -0
  280. package/dist/tracing/trace_batch_adapter.d.cts +36 -0
  281. package/dist/tracing/trace_batch_adapter.d.ts +36 -0
  282. package/dist/tracing/trace_batch_adapter.js +86 -0
  283. package/dist/tracing/trace_batch_adapter.js.map +1 -0
  284. package/dist/tracing/trace_commit_writer.d.cts +1 -1
  285. package/dist/tracing/trace_commit_writer.d.ts +1 -1
  286. package/dist/tracing/trace_hub.cjs +87 -20
  287. package/dist/tracing/trace_hub.cjs.map +1 -1
  288. package/dist/tracing/trace_hub.d.cts +1 -1
  289. package/dist/tracing/trace_hub.d.ts +1 -1
  290. package/dist/tracing/trace_hub.js +85 -20
  291. package/dist/tracing/trace_hub.js.map +1 -1
  292. package/dist/tracing/trace_provider.cjs +21 -6
  293. package/dist/tracing/trace_provider.cjs.map +1 -1
  294. package/dist/tracing/trace_provider.d.cts +13 -4
  295. package/dist/tracing/trace_provider.d.ts +13 -4
  296. package/dist/tracing/trace_provider.js +22 -7
  297. package/dist/tracing/trace_provider.js.map +1 -1
  298. package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -1
  299. package/dist/tracing/types/wood_trace_batch.types.d.cts +15 -1
  300. package/dist/tracing/types/wood_trace_batch.types.d.ts +15 -1
  301. package/dist/tracing/types/wood_trace_sink.types.d.cts +1 -1
  302. package/dist/tracing/types/wood_trace_sink.types.d.ts +1 -1
  303. package/dist/tracing/wood_trace_batch_contract.cjs +2 -0
  304. package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -1
  305. package/dist/tracing/wood_trace_batch_contract.d.cts +1 -1
  306. package/dist/tracing/wood_trace_batch_contract.d.ts +1 -1
  307. package/dist/tracing/wood_trace_batch_contract.js +2 -0
  308. package/dist/tracing/wood_trace_batch_contract.js.map +1 -1
  309. package/dist/transport/build_transport_bridge.cjs +4 -2
  310. package/dist/transport/build_transport_bridge.cjs.map +1 -1
  311. package/dist/transport/build_transport_bridge.d.cts +7 -1
  312. package/dist/transport/build_transport_bridge.d.ts +7 -1
  313. package/dist/transport/build_transport_bridge.js +2 -1
  314. package/dist/transport/build_transport_bridge.js.map +1 -1
  315. package/dist/transport/in_process_router_transport.d.cts +1 -0
  316. package/dist/transport/in_process_router_transport.d.ts +1 -0
  317. package/dist/transport/index.d.cts +1 -0
  318. package/dist/transport/index.d.ts +1 -0
  319. package/dist/types/config.cjs.map +1 -1
  320. package/dist/types/config.d.cts +47 -1
  321. package/dist/types/config.d.ts +47 -1
  322. package/dist/types/context.cjs +12 -0
  323. package/dist/types/context.cjs.map +1 -1
  324. package/dist/types/context.d.cts +27 -1
  325. package/dist/types/context.d.ts +27 -1
  326. package/dist/types/context.js +4 -0
  327. package/dist/types/context.js.map +1 -1
  328. package/dist/types/index.d.cts +2 -2
  329. package/dist/types/index.d.ts +2 -2
  330. package/dist/types/operations.cjs.map +1 -1
  331. package/dist/types/operations.d.cts +2 -0
  332. package/dist/types/operations.d.ts +2 -0
  333. package/docs/axe.md +706 -0
  334. package/package.json +13 -5
  335. package/src/components/NavigationShell.scopes.browser.test.ts +363 -0
  336. package/src/components/NavigationShell.svelte +126 -49
  337. package/dist/controller/__fixtures__/controllers/chat.cjs +0 -32
  338. package/dist/controller/__fixtures__/controllers/chat.cjs.map +0 -1
  339. package/dist/controller/__fixtures__/controllers/chat.d.cts +0 -11
  340. package/dist/controller/__fixtures__/controllers/chat.d.ts +0 -11
  341. package/dist/controller/__fixtures__/controllers/chat.js +0 -12
  342. package/dist/controller/__fixtures__/controllers/chat.js.map +0 -1
  343. package/dist/controller/__fixtures__/controllers/not_a_class.cjs.map +0 -1
  344. package/dist/controller/__fixtures__/controllers/not_a_class.d.cts +0 -3
  345. package/dist/controller/__fixtures__/controllers/not_a_class.d.ts +0 -3
  346. package/dist/controller/__fixtures__/controllers/not_a_class.js +0 -5
  347. package/dist/controller/__fixtures__/controllers/not_a_class.js.map +0 -1
  348. package/dist/controller/__fixtures__/controllers/settings.controller.cjs +0 -32
  349. package/dist/controller/__fixtures__/controllers/settings.controller.cjs.map +0 -1
  350. package/dist/controller/__fixtures__/controllers/settings.controller.d.cts +0 -12
  351. package/dist/controller/__fixtures__/controllers/settings.controller.d.ts +0 -12
  352. package/dist/controller/__fixtures__/controllers/settings.controller.js +0 -12
  353. package/dist/controller/__fixtures__/controllers/settings.controller.js.map +0 -1
  354. package/dist/controller/__fixtures__/controllers/test.cjs +0 -29
  355. package/dist/controller/__fixtures__/controllers/test.cjs.map +0 -1
  356. package/dist/controller/__fixtures__/controllers/test.d.cts +0 -7
  357. package/dist/controller/__fixtures__/controllers/test.d.ts +0 -7
  358. package/dist/controller/__fixtures__/controllers/test.js +0 -9
  359. package/dist/controller/__fixtures__/controllers/test.js.map +0 -1
  360. package/dist/loader/__fixtures__/layouts/app.load.cjs +0 -27
  361. package/dist/loader/__fixtures__/layouts/app.load.cjs.map +0 -1
  362. package/dist/loader/__fixtures__/layouts/app.load.d.cts +0 -5
  363. package/dist/loader/__fixtures__/layouts/app.load.d.ts +0 -5
  364. package/dist/loader/__fixtures__/layouts/app.load.js +0 -7
  365. package/dist/loader/__fixtures__/layouts/app.load.js.map +0 -1
  366. package/dist/loader/__fixtures__/views/test/page.load.cjs +0 -27
  367. package/dist/loader/__fixtures__/views/test/page.load.cjs.map +0 -1
  368. package/dist/loader/__fixtures__/views/test/page.load.d.cts +0 -6
  369. package/dist/loader/__fixtures__/views/test/page.load.d.ts +0 -6
  370. package/dist/loader/__fixtures__/views/test/page.load.js +0 -7
  371. package/dist/loader/__fixtures__/views/test/page.load.js.map +0 -1
  372. package/dist/middleware/__fixtures__/middleware/auth.cjs.map +0 -1
  373. package/dist/middleware/__fixtures__/middleware/auth.d.cts +0 -6
  374. package/dist/middleware/__fixtures__/middleware/auth.d.ts +0 -6
  375. package/dist/middleware/__fixtures__/middleware/auth.js +0 -19
  376. package/dist/middleware/__fixtures__/middleware/auth.js.map +0 -1
  377. package/dist/middleware/__fixtures__/middleware/sequence.cjs +0 -47
  378. package/dist/middleware/__fixtures__/middleware/sequence.cjs.map +0 -1
  379. package/dist/middleware/__fixtures__/middleware/sequence.d.cts +0 -7
  380. package/dist/middleware/__fixtures__/middleware/sequence.d.ts +0 -7
  381. package/dist/middleware/__fixtures__/middleware/sequence.js +0 -21
  382. package/dist/middleware/__fixtures__/middleware/sequence.js.map +0 -1
@@ -237,69 +237,108 @@ function createScopedContainer(): WoodScopedContainer {
237
237
  }
238
238
 
239
239
  if (typeof scopedContainer.registerFunction === 'function') {
240
- scopedContainer.registerFunction(Navigation, () => getNavigation());
241
- scopedContainer.registerFunction(App, () => getApp());
242
- scopedContainer.registerFunction(Ipc, () => getIpc());
240
+ // Explicit Singleton lifetime: these return renderer-root globals, and
241
+ // registerFunction defaults to Transient \u2014 rejected by ioc >= 0.5's
242
+ // captive-lifetime validation under singleton dependents.
243
+ const singleton = { loadAs: 0 /* LoadAs.Singleton */ };
244
+ scopedContainer.registerFunction(Navigation, () => getNavigation(), singleton);
245
+ scopedContainer.registerFunction(App, () => getApp(), singleton);
246
+ scopedContainer.registerFunction(Ipc, () => getIpc(), singleton);
243
247
  }
244
248
 
245
249
  return scopedContainer as WoodScopedContainer;
246
250
  }
247
251
 
248
- async function resolveController(
252
+ async function resolveControllerInScope(
253
+ scope: WoodScopedContainer,
249
254
  entry: GeneratedAppViewEntry,
250
255
  ControllerClass: any,
251
256
  contextLabel: string,
252
257
  ): Promise<unknown> {
253
- const scopedContainer = createScopedContainer();
254
-
255
258
  if (typeof ControllerClass !== 'function') {
256
259
  throw new Error(
257
260
  \`Controller for \${contextLabel} in view "\${entry.key}" is invalid. Expected a default exported class.\`,
258
261
  );
259
262
  }
260
263
 
261
- if (typeof scopedContainer.registerClass === 'function') {
262
- scopedContainer.registerClass(ControllerClass);
264
+ if (typeof scope.registerClass === 'function') {
265
+ scope.registerClass(ControllerClass);
263
266
  }
264
267
 
265
- return await scopedContainer.get(ControllerClass);
268
+ return await scope.get(ControllerClass);
266
269
  }
267
270
 
268
- async function createViewController(
269
- entry: GeneratedAppViewEntry,
270
- ): Promise<unknown> {
271
- if (!entry.controllerClass) {
272
- return undefined;
271
+ async function disposeScopeQuietly(scope: { dispose?: () => Promise<void> } | null): Promise<void> {
272
+ if (!scope || typeof scope.dispose !== 'function') return;
273
+ try {
274
+ await scope.dispose();
275
+ } catch (error) {
276
+ console.error('[wood] renderer scope disposal failed:', error);
273
277
  }
274
-
275
- return await resolveController(entry, entry.controllerClass, 'page');
276
278
  }
277
279
 
278
- async function createLayoutControllers(
280
+ /**
281
+ * One page scope per view lifecycle: the view controller and every
282
+ * non-preservable layout controller resolve from the SAME scope, so Scoped
283
+ * services/state are shared within the page (the NoEgo renderer model).
284
+ * Layouts marked preservable in the manifest own dedicated scopes that
285
+ * survive page transitions and dispose when the layout finally leaves.
286
+ */
287
+ async function createControllerSet(
279
288
  entry: GeneratedAppViewEntry,
280
- startIndex = 0,
281
- ): Promise<Array<unknown>> {
282
- const controllers: unknown[] = [];
289
+ preservedDepth = 0,
290
+ ): Promise<{
291
+ controller: unknown;
292
+ layoutControllers: Array<unknown>;
293
+ pageScope: WoodScopedContainer;
294
+ layoutScopes: Array<WoodScopedContainer | null>;
295
+ }> {
296
+ const pageScope = createScopedContainer();
297
+ const layoutControllers: unknown[] = [];
298
+ const layoutScopes: Array<WoodScopedContainer | null> = [];
299
+ const createdLayoutScopes: WoodScopedContainer[] = [];
283
300
 
284
- for (let i = 0; i < startIndex; i += 1) {
285
- controllers.push(undefined);
286
- }
301
+ try {
302
+ for (let i = 0; i < preservedDepth; i += 1) {
303
+ layoutControllers.push(undefined);
304
+ layoutScopes.push(null);
305
+ }
287
306
 
288
- for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {
289
- const LayoutController = entry.layoutControllerClasses[i];
290
- if (!LayoutController) {
291
- controllers.push(undefined);
292
- continue;
307
+ for (let i = preservedDepth; i < entry.layoutControllerClasses.length; i += 1) {
308
+ const LayoutController = entry.layoutControllerClasses[i];
309
+ if (!LayoutController) {
310
+ layoutControllers.push(undefined);
311
+ layoutScopes.push(null);
312
+ continue;
313
+ }
314
+ const preservable = entry.layoutPreserve?.[i] === true;
315
+ let scope = pageScope;
316
+ if (preservable) {
317
+ scope = createScopedContainer();
318
+ createdLayoutScopes.push(scope);
319
+ }
320
+ const controller = await resolveControllerInScope(
321
+ scope,
322
+ entry,
323
+ LayoutController,
324
+ \`layout[\${i}]\`,
325
+ );
326
+ layoutControllers.push(controller);
327
+ layoutScopes.push(preservable ? scope : null);
293
328
  }
294
- const controller = await resolveController(
295
- entry,
296
- LayoutController,
297
- \`layout[\${i}]\`,
298
- );
299
- controllers.push(controller);
300
- }
301
329
 
302
- return controllers;
330
+ const controller = entry.controllerClass
331
+ ? await resolveControllerInScope(pageScope, entry, entry.controllerClass, 'page')
332
+ : undefined;
333
+
334
+ return { controller, layoutControllers, pageScope, layoutScopes };
335
+ } catch (error) {
336
+ // Failed transitions must not orphan scopes: dispose everything this
337
+ // set created before rethrowing.
338
+ for (const scope of createdLayoutScopes) await disposeScopeQuietly(scope as any);
339
+ await disposeScopeQuietly(pageScope as any);
340
+ throw error;
341
+ }
303
342
  }
304
343
 
305
344
  const DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';
@@ -375,18 +414,15 @@ export async function app(target: Element) {
375
414
  const bootstrapWindow = await getWoodBridge()?.__window?.current?.();
376
415
  installAutomationIntrospection({ windowId: bootstrapWindow?.windowId ?? null });
377
416
  }
378
- const controller = await createViewController(entry);
379
- const layoutControllers = await createLayoutControllers(entry);
417
+ const initialSet = await createControllerSet(entry);
380
418
 
381
419
  return mount(NavigationShell, {
382
420
  target,
383
421
  props: {
384
422
  manifest: VIEW_MANIFEST,
385
423
  initialEntry: entry,
386
- initialController: controller,
387
- initialLayoutControllers: layoutControllers,
388
- createViewControllerFn: createViewController,
389
- createLayoutControllersFn: createLayoutControllers,
424
+ initialControllerSet: initialSet,
425
+ createControllerSetFn: createControllerSet,
390
426
  getViewManifestEntryFn: getViewManifestEntry,
391
427
  },
392
428
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst RENDERER_APP_SOURCE_INSTRUCTIONS = [\n 'To change routes, page components, layouts, or renderer controllers, edit the views YAML',\n 'configured by wood.config.yml renderer.openapi and the matching UI source files.',\n] as const;\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n const layoutPreserve = view.layoutPreserve ?? Array.from(\n { length: view.layouts.length },\n () => false,\n );\n if (layoutPreserve.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout preserve count for view \"${key}\" does not match layout count.`,\n );\n }\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n layoutPreserve: ${JSON.stringify(layoutPreserve)},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `${generatedFileNotice(RENDERER_APP_SOURCE_INSTRUCTIONS)}\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation, installAutomationIntrospection } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n layoutPreserve: boolean[];\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n scopedContainer.registerFunction(Navigation, () => getNavigation());\n scopedContainer.registerFunction(App, () => getApp());\n scopedContainer.registerFunction(Ipc, () => getIpc());\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveController(\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n const scopedContainer = createScopedContainer();\n\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scopedContainer.registerClass === 'function') {\n scopedContainer.registerClass(ControllerClass);\n }\n\n return await scopedContainer.get(ControllerClass);\n}\n\nasync function createViewController(\n entry: GeneratedAppViewEntry,\n): Promise<unknown> {\n if (!entry.controllerClass) {\n return undefined;\n }\n\n return await resolveController(entry, entry.controllerClass, 'page');\n}\n\nasync function createLayoutControllers(\n entry: GeneratedAppViewEntry,\n startIndex = 0,\n): Promise<Array<unknown>> {\n const controllers: unknown[] = [];\n\n for (let i = 0; i < startIndex; i += 1) {\n controllers.push(undefined);\n }\n\n for (let i = startIndex; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n controllers.push(undefined);\n continue;\n }\n const controller = await resolveController(\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n controllers.push(controller);\n }\n\n return controllers;\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nfunction isAutomationBuild(): boolean {\n try {\n const env = (import.meta as { env?: { DEV?: boolean; MODE?: string } }).env;\n return Boolean(env?.DEV) || env?.MODE === 'test';\n } catch {\n return false;\n }\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n\n // Dev/test-only Axe introspection surface; never present in production builds.\n if (isAutomationBuild()) {\n const bootstrapWindow = await getWoodBridge()?.__window?.current?.();\n installAutomationIntrospection({ windowId: bootstrapWindow?.windowId ?? null });\n }\n const controller = await createViewController(entry);\n const layoutControllers = await createLayoutControllers(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialController: controller,\n initialLayoutControllers: layoutControllers,\n createViewControllerFn: createViewController,\n createLayoutControllersFn: createLayoutControllers,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/codegen/renderer_app_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { ViewDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst RENDERER_APP_SOURCE_INSTRUCTIONS = [\n 'To change routes, page components, layouts, or renderer controllers, edit the views YAML',\n 'configured by wood.config.yml renderer.openapi and the matching UI source files.',\n] as const;\n\nexport interface RendererAppGeneratorOptions {\n /** Absolute path to renderer component root (e.g. /app/ui) */\n componentDir: string;\n /** Absolute output directory where generated file will be written */\n outDir: string;\n /** Optional explicit default view key (e.g. \"main.chat\") */\n entryViewKey?: string;\n}\n\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n return rel.replace(/\\\\/g, '/');\n}\n\nfunction resolveFromComponentDir(componentDir: string, fileRef: string): string {\n if (path.isAbsolute(fileRef)) {\n return fileRef;\n }\n\n const normalizedRef = fileRef.replace(/\\\\/g, '/');\n const componentDirName = path.basename(componentDir).replace(/\\\\/g, '/');\n\n if (normalizedRef.startsWith(componentDirName + '/')) {\n const stripped = normalizedRef.slice(componentDirName.length + 1);\n return path.resolve(componentDir, stripped);\n }\n\n return path.resolve(componentDir, normalizedRef);\n}\n\nfunction viewKey(view: ViewDef): string {\n return `${view.windowName}.${view.pageName}`;\n}\n\nfunction toIdentifier(prefix: string, value: string): string {\n const core = value\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .trim()\n .split(/\\s+/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return `${prefix}${core || 'Component'}`;\n}\n\nfunction escapeSingleQuoted(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\nconst CONTROLLER_FILE_SUFFIXES = [\n '.ts',\n '.js',\n '.controller.ts',\n '.controller.js',\n] as const;\n\nconst CONTROLLER_INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\nfunction resolveControllerFile(controllerRef: string, componentDir: string): string | null {\n const normalized = controllerRef.trim();\n const basePath = resolveFromComponentDir(componentDir, normalized);\n\n if (existsSync(basePath)) {\n return basePath;\n }\n\n if (path.extname(basePath)) {\n return null;\n }\n\n for (const suffix of CONTROLLER_FILE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n for (const indexFile of CONTROLLER_INDEX_CANDIDATES) {\n const candidate = path.resolve(basePath, indexFile);\n if (existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction resolveDefaultViewKey(sortedViews: ViewDef[], entryViewKey?: string): string {\n if (sortedViews.length === 0) return '';\n\n const configuredEntry = entryViewKey?.trim();\n if (!configuredEntry) {\n return viewKey(sortedViews[0]);\n }\n\n const availableKeys = sortedViews.map((view) => viewKey(view));\n if (availableKeys.includes(configuredEntry)) {\n return configuredEntry;\n }\n\n throw new Error(\n `Renderer entry \"${configuredEntry}\" was not found in parsed views. Available view keys: ${availableKeys.join(', ')}`,\n );\n}\n\nexport function generateRendererApp(\n views: ViewDef[],\n options: RendererAppGeneratorOptions,\n): string {\n const sortedViews = [...views].sort((a, b) => viewKey(a).localeCompare(viewKey(b)));\n const defaultViewKey = resolveDefaultViewKey(sortedViews, options.entryViewKey);\n\n const importLines: string[] = [];\n const viewIdentifiers = new Map<string, string>();\n const layoutIdentifiers = new Map<string, string>();\n const controllerIdentifiers = new Map<string, { identifier: string; importPath: string }>();\n const usedNames = new Set<string>();\n\n const allocateName = (prefix: string, filePath: string): string => {\n const base = toIdentifier(prefix, filePath);\n let name = base;\n let suffix = 2;\n while (usedNames.has(name)) {\n name = `${base}${suffix}`;\n suffix += 1;\n }\n usedNames.add(name);\n return name;\n };\n\n const ensureControllerImported = (controllerRef: string, owningViewKey: string): void => {\n if (controllerIdentifiers.has(controllerRef)) return;\n\n const resolvedControllerFile = resolveControllerFile(controllerRef, options.componentDir);\n if (!resolvedControllerFile) {\n throw new Error(\n `Renderer app codegen failed: controller \"${controllerRef}\" for view \"${owningViewKey}\" was not found. ` +\n 'Controller must point to an existing file with a default exported class.',\n );\n }\n\n const identifier = allocateName('PageController', controllerRef);\n const importPath = computeImportPath(options.outDir, resolvedControllerFile);\n controllerIdentifiers.set(controllerRef, { identifier, importPath });\n importLines.push(`import ${identifier} from '${importPath}';`);\n };\n\n for (const view of sortedViews) {\n if (!viewIdentifiers.has(view.viewPath)) {\n const identifier = allocateName('View', view.viewPath);\n viewIdentifiers.set(view.viewPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, view.viewPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n for (const layoutPath of view.layouts) {\n if (layoutIdentifiers.has(layoutPath)) continue;\n const identifier = allocateName('Layout', layoutPath);\n layoutIdentifiers.set(layoutPath, identifier);\n const abs = resolveFromComponentDir(options.componentDir, layoutPath);\n const importPath = computeImportPath(options.outDir, abs);\n importLines.push(`import ${identifier} from '${importPath}';`);\n }\n\n if (view.controller) {\n ensureControllerImported(view.controller, viewKey(view));\n }\n\n for (const layoutController of view.layoutControllers ?? []) {\n if (!layoutController) continue;\n ensureControllerImported(layoutController, viewKey(view));\n }\n }\n\n const manifestEntries = sortedViews.map((view) => {\n const key = viewKey(view);\n const viewIdentifier = viewIdentifiers.get(view.viewPath)!;\n const layoutList = view.layouts.map((layoutPath) => layoutIdentifiers.get(layoutPath)!);\n const controllerPath = view.controller ? `'${escapeSingleQuoted(view.controller)}'` : 'undefined';\n const controllerClass = view.controller\n ? controllerIdentifiers.get(view.controller)!.identifier\n : 'undefined';\n const layoutControllerRefs = view.layoutControllers;\n if (layoutControllerRefs && layoutControllerRefs.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout controller count for view \"${key}\" does not match layout count.`,\n );\n }\n const normalizedLayoutControllerRefs = layoutControllerRefs ?? Array.from(\n { length: view.layouts.length },\n () => undefined,\n );\n const layoutControllerPaths = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? `'${escapeSingleQuoted(controllerRef)}'` : 'undefined'))\n .join(', ')}]`;\n const layoutControllerClasses = `[${normalizedLayoutControllerRefs\n .map((controllerRef) => (controllerRef ? controllerIdentifiers.get(controllerRef)!.identifier : 'undefined'))\n .join(', ')}]`;\n const layoutPreserve = view.layoutPreserve ?? Array.from(\n { length: view.layouts.length },\n () => false,\n );\n if (layoutPreserve.length !== view.layouts.length) {\n throw new Error(\n `Renderer app codegen failed: layout preserve count for view \"${key}\" does not match layout count.`,\n );\n }\n\n return ` '${escapeSingleQuoted(key)}': {\n key: '${escapeSingleQuoted(key)}',\n windowName: '${escapeSingleQuoted(view.windowName)}',\n pageName: '${escapeSingleQuoted(view.pageName)}',\n viewPath: '${escapeSingleQuoted(view.viewPath)}',\n layoutPaths: ${JSON.stringify(view.layouts)},\n layoutControllers: ${layoutControllerPaths},\n layoutPreserve: ${JSON.stringify(layoutPreserve)},\n controller: ${controllerPath},\n layoutControllerClasses: ${layoutControllerClasses},\n controllerClass: ${controllerClass},\n view: ${viewIdentifier},\n layouts: [${layoutList.join(', ')}],\n },`;\n });\n\n return `${generatedFileNotice(RENDERER_APP_SOURCE_INSTRUCTIONS)}\nimport { mount } from 'svelte';\nimport { App, getApp, getContainer } from '@noego/wood/client';\nimport { Navigation, getNavigation, installAutomationIntrospection } from '@noego/wood/navigation';\nimport { Ipc, getIpc } from '@noego/wood/ipc';\nimport NavigationShell from '@noego/wood/navigation-shell';\n${importLines.join('\\n')}\n\ninterface GeneratedAppViewEntry {\n key: string;\n windowName: string;\n pageName: string;\n viewPath: string;\n layoutPaths: string[];\n layoutControllers: Array<string | undefined>;\n layoutPreserve: boolean[];\n controller?: string;\n layoutControllerClasses: Array<any | undefined>;\n controllerClass?: any;\n view: any;\n layouts: any[];\n}\n\nconst VIEW_MANIFEST: Record<string, GeneratedAppViewEntry> = {\n${manifestEntries.join('\\n')}\n};\n\nfunction getViewManifestEntry(viewKey: string): GeneratedAppViewEntry | null {\n return VIEW_MANIFEST[viewKey] ?? null;\n}\n\ninterface WoodScopedContainer {\n get(token: any): unknown | Promise<unknown>;\n registerClass?(token: any): void;\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\ninterface WoodContainer extends WoodScopedContainer {\n extend?(): WoodScopedContainer;\n}\n\nfunction createScopedContainer(): WoodScopedContainer {\n const container = getContainer() as WoodContainer;\n if (typeof container.extend !== 'function') {\n throw new Error('Wood client container does not support extend().');\n }\n\n const scopedContainer = container.extend();\n\n if (!scopedContainer || typeof scopedContainer.get !== 'function') {\n throw new Error('Wood client container does not support get().');\n }\n\n if (typeof scopedContainer.registerFunction === 'function') {\n // Explicit Singleton lifetime: these return renderer-root globals, and\n // registerFunction defaults to Transient — rejected by ioc >= 0.5's\n // captive-lifetime validation under singleton dependents.\n const singleton = { loadAs: 0 /* LoadAs.Singleton */ };\n scopedContainer.registerFunction(Navigation, () => getNavigation(), singleton);\n scopedContainer.registerFunction(App, () => getApp(), singleton);\n scopedContainer.registerFunction(Ipc, () => getIpc(), singleton);\n }\n\n return scopedContainer as WoodScopedContainer;\n}\n\nasync function resolveControllerInScope(\n scope: WoodScopedContainer,\n entry: GeneratedAppViewEntry,\n ControllerClass: any,\n contextLabel: string,\n): Promise<unknown> {\n if (typeof ControllerClass !== 'function') {\n throw new Error(\n \\`Controller for \\${contextLabel} in view \"\\${entry.key}\" is invalid. Expected a default exported class.\\`,\n );\n }\n\n if (typeof scope.registerClass === 'function') {\n scope.registerClass(ControllerClass);\n }\n\n return await scope.get(ControllerClass);\n}\n\nasync function disposeScopeQuietly(scope: { dispose?: () => Promise<void> } | null): Promise<void> {\n if (!scope || typeof scope.dispose !== 'function') return;\n try {\n await scope.dispose();\n } catch (error) {\n console.error('[wood] renderer scope disposal failed:', error);\n }\n}\n\n/**\n * One page scope per view lifecycle: the view controller and every\n * non-preservable layout controller resolve from the SAME scope, so Scoped\n * services/state are shared within the page (the NoEgo renderer model).\n * Layouts marked preservable in the manifest own dedicated scopes that\n * survive page transitions and dispose when the layout finally leaves.\n */\nasync function createControllerSet(\n entry: GeneratedAppViewEntry,\n preservedDepth = 0,\n): Promise<{\n controller: unknown;\n layoutControllers: Array<unknown>;\n pageScope: WoodScopedContainer;\n layoutScopes: Array<WoodScopedContainer | null>;\n}> {\n const pageScope = createScopedContainer();\n const layoutControllers: unknown[] = [];\n const layoutScopes: Array<WoodScopedContainer | null> = [];\n const createdLayoutScopes: WoodScopedContainer[] = [];\n\n try {\n for (let i = 0; i < preservedDepth; i += 1) {\n layoutControllers.push(undefined);\n layoutScopes.push(null);\n }\n\n for (let i = preservedDepth; i < entry.layoutControllerClasses.length; i += 1) {\n const LayoutController = entry.layoutControllerClasses[i];\n if (!LayoutController) {\n layoutControllers.push(undefined);\n layoutScopes.push(null);\n continue;\n }\n const preservable = entry.layoutPreserve?.[i] === true;\n let scope = pageScope;\n if (preservable) {\n scope = createScopedContainer();\n createdLayoutScopes.push(scope);\n }\n const controller = await resolveControllerInScope(\n scope,\n entry,\n LayoutController,\n \\`layout[\\${i}]\\`,\n );\n layoutControllers.push(controller);\n layoutScopes.push(preservable ? scope : null);\n }\n\n const controller = entry.controllerClass\n ? await resolveControllerInScope(pageScope, entry, entry.controllerClass, 'page')\n : undefined;\n\n return { controller, layoutControllers, pageScope, layoutScopes };\n } catch (error) {\n // Failed transitions must not orphan scopes: dispose everything this\n // set created before rethrowing.\n for (const scope of createdLayoutScopes) await disposeScopeQuietly(scope as any);\n await disposeScopeQuietly(pageScope as any);\n throw error;\n }\n}\n\nconst DEFAULT_VIEW_KEY = '${escapeSingleQuoted(defaultViewKey)}';\n\ntype WoodWindowBootstrapInfo = {\n ok?: boolean;\n windowId?: string;\n defaultRoute?: string;\n};\n\ntype WoodBootstrapBridgeLike = {\n __window?: {\n current?: () => Promise<WoodWindowBootstrapInfo>;\n };\n};\n\nfunction getWoodBridge(): WoodBootstrapBridgeLike | null {\n const globalObj = globalThis as typeof globalThis & {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n window?: {\n __NOEGO_WOOD_BRIDGE__?: unknown;\n };\n };\n\n const bridge = globalObj.__NOEGO_WOOD_BRIDGE__ ?? globalObj.window?.__NOEGO_WOOD_BRIDGE__;\n if (!bridge || typeof bridge !== 'object') {\n return null;\n }\n\n return bridge as WoodBootstrapBridgeLike;\n}\n\nasync function resolveInitialEntry(): Promise<GeneratedAppViewEntry> {\n if (!DEFAULT_VIEW_KEY) {\n throw new Error('No views available in renderer manifest. Define at least one view in renderer OpenAPI YAML.');\n }\n\n const bridge = getWoodBridge();\n const bootstrapWindow = await bridge?.__window?.current?.();\n const requestedRoute = bootstrapWindow?.defaultRoute;\n\n if (requestedRoute) {\n const routeEntry = getViewManifestEntry(requestedRoute);\n if (routeEntry) {\n return routeEntry;\n }\n }\n\n const entry = getViewManifestEntry(DEFAULT_VIEW_KEY);\n if (!entry) {\n throw new Error(\\`Default view \"\\${DEFAULT_VIEW_KEY}\" is missing from generated view manifest.\\`);\n }\n\n return entry;\n}\n\nfunction isAutomationBuild(): boolean {\n try {\n const env = (import.meta as { env?: { DEV?: boolean; MODE?: string } }).env;\n return Boolean(env?.DEV) || env?.MODE === 'test';\n } catch {\n return false;\n }\n}\n\nexport async function app(target: Element) {\n const entry = await resolveInitialEntry();\n\n getNavigation().replace(entry.key, {}, {});\n\n // Dev/test-only Axe introspection surface; never present in production builds.\n if (isAutomationBuild()) {\n const bootstrapWindow = await getWoodBridge()?.__window?.current?.();\n installAutomationIntrospection({ windowId: bootstrapWindow?.windowId ?? null });\n }\n const initialSet = await createControllerSet(entry);\n\n return mount(NavigationShell, {\n target,\n props: {\n manifest: VIEW_MANIFEST,\n initialEntry: entry,\n initialControllerSet: initialSet,\n createControllerSetFn: createControllerSet,\n getViewManifestEntryFn: getViewManifestEntry,\n },\n });\n}\n`;\n}\n"],"mappings":"AAAA,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AAEjB,SAAS,2BAA2B;AAEpC,MAAM,mCAAmC;AAAA,EACvC;AAAA,EACA;AACF;AAWA,SAAS,kBAAkB,SAAiB,QAAwB;AAClE,MAAI,MAAM,KAAK,SAAS,SAAS,MAAM;AAEvC,MAAI,CAAC,IAAI,WAAW,GAAG,GAAG;AACxB,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,IAAI,QAAQ,OAAO,GAAG;AAC/B;AAEA,SAAS,wBAAwB,cAAsB,SAAyB;AAC9E,MAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,QAAQ,QAAQ,OAAO,GAAG;AAChD,QAAM,mBAAmB,KAAK,SAAS,YAAY,EAAE,QAAQ,OAAO,GAAG;AAEvE,MAAI,cAAc,WAAW,mBAAmB,GAAG,GAAG;AACpD,UAAM,WAAW,cAAc,MAAM,iBAAiB,SAAS,CAAC;AAChE,WAAO,KAAK,QAAQ,cAAc,QAAQ;AAAA,EAC5C;AAEA,SAAO,KAAK,QAAQ,cAAc,aAAa;AACjD;AAEA,SAAS,QAAQ,MAAuB;AACtC,SAAO,GAAG,KAAK,UAAU,IAAI,KAAK,QAAQ;AAC5C;AAEA,SAAS,aAAa,QAAgB,OAAuB;AAC3D,QAAM,OAAO,MACV,QAAQ,kBAAkB,GAAG,EAC7B,KAAK,EACL,MAAM,KAAK,EACX,IAAI,CAAC,YAAY,QAAQ,OAAO,CAAC,EAAE,YAAY,IAAI,QAAQ,MAAM,CAAC,CAAC,EACnE,KAAK,EAAE;AAEV,SAAO,GAAG,MAAM,GAAG,QAAQ,WAAW;AACxC;AAEA,SAAS,mBAAmB,OAAuB;AACjD,SAAO,MAAM,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AACzD;AAEA,MAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AACF;AAEA,SAAS,sBAAsB,eAAuB,cAAqC;AACzF,QAAM,aAAa,cAAc,KAAK;AACtC,QAAM,WAAW,wBAAwB,cAAc,UAAU;AAEjE,MAAI,WAAW,QAAQ,GAAG;AACxB,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,QAAQ,QAAQ,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,aAAW,UAAU,0BAA0B;AAC7C,UAAM,YAAY,WAAW;AAC7B,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,aAAW,aAAa,6BAA6B;AACnD,UAAM,YAAY,KAAK,QAAQ,UAAU,SAAS;AAClD,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,sBAAsB,aAAwB,cAA+B;AACpF,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,QAAM,kBAAkB,cAAc,KAAK;AAC3C,MAAI,CAAC,iBAAiB;AACpB,WAAO,QAAQ,YAAY,CAAC,CAAC;AAAA,EAC/B;AAEA,QAAM,gBAAgB,YAAY,IAAI,CAAC,SAAS,QAAQ,IAAI,CAAC;AAC7D,MAAI,cAAc,SAAS,eAAe,GAAG;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,IAAI;AAAA,IACR,mBAAmB,eAAe,yDAAyD,cAAc,KAAK,IAAI,CAAC;AAAA,EACrH;AACF;AAEO,SAAS,oBACd,OACA,SACQ;AACR,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM,QAAQ,CAAC,EAAE,cAAc,QAAQ,CAAC,CAAC,CAAC;AAClF,QAAM,iBAAiB,sBAAsB,aAAa,QAAQ,YAAY;AAE9E,QAAM,cAAwB,CAAC;AAC/B,QAAM,kBAAkB,oBAAI,IAAoB;AAChD,QAAM,oBAAoB,oBAAI,IAAoB;AAClD,QAAM,wBAAwB,oBAAI,IAAwD;AAC1F,QAAM,YAAY,oBAAI,IAAY;AAElC,QAAM,eAAe,CAAC,QAAgB,aAA6B;AACjE,UAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,QAAI,OAAO;AACX,QAAI,SAAS;AACb,WAAO,UAAU,IAAI,IAAI,GAAG;AAC1B,aAAO,GAAG,IAAI,GAAG,MAAM;AACvB,gBAAU;AAAA,IACZ;AACA,cAAU,IAAI,IAAI;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,2BAA2B,CAAC,eAAuB,kBAAgC;AACvF,QAAI,sBAAsB,IAAI,aAAa,EAAG;AAE9C,UAAM,yBAAyB,sBAAsB,eAAe,QAAQ,YAAY;AACxF,QAAI,CAAC,wBAAwB;AAC3B,YAAM,IAAI;AAAA,QACR,4CAA4C,aAAa,eAAe,aAAa;AAAA,MAEvF;AAAA,IACF;AAEA,UAAM,aAAa,aAAa,kBAAkB,aAAa;AAC/D,UAAM,aAAa,kBAAkB,QAAQ,QAAQ,sBAAsB;AAC3E,0BAAsB,IAAI,eAAe,EAAE,YAAY,WAAW,CAAC;AACnE,gBAAY,KAAK,UAAU,UAAU,UAAU,UAAU,IAAI;AAAA,EAC/D;AAEA,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,gBAAgB,IAAI,KAAK,QAAQ,GAAG;AACvC,YAAM,aAAa,aAAa,QAAQ,KAAK,QAAQ;AACrD,sBAAgB,IAAI,KAAK,UAAU,UAAU;AAC7C,YAAM,MAAM,wBAAwB,QAAQ,cAAc,KAAK,QAAQ;AACvE,YAAM,aAAa,kBAAkB,QAAQ,QAAQ,GAAG;AACxD,kBAAY,KAAK,UAAU,UAAU,UAAU,UAAU,IAAI;AAAA,IAC/D;AAEA,eAAW,cAAc,KAAK,SAAS;AACrC,UAAI,kBAAkB,IAAI,UAAU,EAAG;AACvC,YAAM,aAAa,aAAa,UAAU,UAAU;AACpD,wBAAkB,IAAI,YAAY,UAAU;AAC5C,YAAM,MAAM,wBAAwB,QAAQ,cAAc,UAAU;AACpE,YAAM,aAAa,kBAAkB,QAAQ,QAAQ,GAAG;AACxD,kBAAY,KAAK,UAAU,UAAU,UAAU,UAAU,IAAI;AAAA,IAC/D;AAEA,QAAI,KAAK,YAAY;AACnB,+BAAyB,KAAK,YAAY,QAAQ,IAAI,CAAC;AAAA,IACzD;AAEA,eAAW,oBAAoB,KAAK,qBAAqB,CAAC,GAAG;AAC3D,UAAI,CAAC,iBAAkB;AACvB,+BAAyB,kBAAkB,QAAQ,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,kBAAkB,YAAY,IAAI,CAAC,SAAS;AAChD,UAAM,MAAM,QAAQ,IAAI;AACxB,UAAM,iBAAiB,gBAAgB,IAAI,KAAK,QAAQ;AACxD,UAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,eAAe,kBAAkB,IAAI,UAAU,CAAE;AACtF,UAAM,iBAAiB,KAAK,aAAa,IAAI,mBAAmB,KAAK,UAAU,CAAC,MAAM;AACtF,UAAM,kBAAkB,KAAK,aACzB,sBAAsB,IAAI,KAAK,UAAU,EAAG,aAC5C;AACJ,UAAM,uBAAuB,KAAK;AAClC,QAAI,wBAAwB,qBAAqB,WAAW,KAAK,QAAQ,QAAQ;AAC/E,YAAM,IAAI;AAAA,QACR,kEAAkE,GAAG;AAAA,MACvE;AAAA,IACF;AACA,UAAM,iCAAiC,wBAAwB,MAAM;AAAA,MACnE,EAAE,QAAQ,KAAK,QAAQ,OAAO;AAAA,MAC9B,MAAM;AAAA,IACR;AACA,UAAM,wBAAwB,IAAI,+BAC/B,IAAI,CAAC,kBAAmB,gBAAgB,IAAI,mBAAmB,aAAa,CAAC,MAAM,WAAY,EAC/F,KAAK,IAAI,CAAC;AACb,UAAM,0BAA0B,IAAI,+BACjC,IAAI,CAAC,kBAAmB,gBAAgB,sBAAsB,IAAI,aAAa,EAAG,aAAa,WAAY,EAC3G,KAAK,IAAI,CAAC;AACb,UAAM,iBAAiB,KAAK,kBAAkB,MAAM;AAAA,MAClD,EAAE,QAAQ,KAAK,QAAQ,OAAO;AAAA,MAC9B,MAAM;AAAA,IACR;AACA,QAAI,eAAe,WAAW,KAAK,QAAQ,QAAQ;AACjD,YAAM,IAAI;AAAA,QACR,gEAAgE,GAAG;AAAA,MACrE;AAAA,IACF;AAEA,WAAO,MAAM,mBAAmB,GAAG,CAAC;AAAA,YAC5B,mBAAmB,GAAG,CAAC;AAAA,mBAChB,mBAAmB,KAAK,UAAU,CAAC;AAAA,iBACrC,mBAAmB,KAAK,QAAQ,CAAC;AAAA,iBACjC,mBAAmB,KAAK,QAAQ,CAAC;AAAA,mBAC/B,KAAK,UAAU,KAAK,OAAO,CAAC;AAAA,yBACtB,qBAAqB;AAAA,sBACxB,KAAK,UAAU,cAAc,CAAC;AAAA,kBAClC,cAAc;AAAA,+BACD,uBAAuB;AAAA,uBAC/B,eAAe;AAAA,YAC1B,cAAc;AAAA,gBACV,WAAW,KAAK,IAAI,CAAC;AAAA;AAAA,EAEnC,CAAC;AAED,SAAO,GAAG,oBAAoB,gCAAgC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/D,YAAY,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBtB,gBAAgB,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BA0IA,mBAAmB,cAAc,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuF9D;","names":[]}
@@ -223,6 +223,7 @@ export interface WoodApi extends GeneratedWoodBridge {
223
223
  reason?: 'unconfigured' | 'callback-error';
224
224
  errorMessage?: string;
225
225
  }>;
226
+ __logBatch(batch: unknown): void;
226
227
  }
227
228
  `;
228
229
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codegen/type_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nconst TYPE_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels, input schemas, controller/action names, or renderer bridge types,',\n 'edit the operations YAML configured by wood.config.yml main.openapi and the matching controller methods.',\n] as const;\n\nfunction formatPropertyKey(key: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {\n return key;\n }\n\n return JSON.stringify(key);\n}\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\nfunction jsonSchemaToTS(schema: Record<string, unknown> | undefined, indent: string = ''): string {\n if (!schema) return 'unknown';\n\n const type = schema.type as string | undefined;\n\n if (type === 'string') {\n if (schema.enum) {\n return (schema.enum as string[]).map((v) => `'${v}'`).join(' | ');\n }\n return 'string';\n }\n if (type === 'number' || type === 'integer') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'array') {\n const itemType = jsonSchemaToTS(schema.items as Record<string, unknown>, indent);\n return `Array<${itemType}>`;\n }\n if (type === 'object') {\n const props = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required as string[]) ?? []);\n const entries = Object.entries(props);\n if (entries.length === 0) return 'Record<string, unknown>';\n\n const lines = entries.map(([key, val]) => {\n const optional = required.has(key) ? '' : '?';\n const valType = jsonSchemaToTS(val, indent + ' ');\n return `${indent} ${formatPropertyKey(key)}${optional}: ${valType};`;\n });\n return `{\\n${lines.join('\\n')}\\n${indent}}`;\n }\n\n return 'unknown';\n}\n\nfunction buildNestedTypeTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]] = { __operation: op };\n }\n return tree;\n}\n\nfunction generateTypeTree(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const inputType = jsonSchemaToTS(op.inputSchema as Record<string, unknown>, indent + ' ');\n const outputType = jsonSchemaToTS(op.outputSchema as Record<string, unknown>, indent + ' ');\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${formatPropertyKey(key)}(data: ${inputType}): Promise<${outputType}>;`);\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}(): Promise<${outputType}>;`);\n }\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}: {`);\n lines.push(generateTypeTree(entry, indent + ' '));\n lines.push(`${indent}};`);\n }\n }\n return lines.join('\\n');\n}\n\ntype RpcActionTypeEntry = {\n channel: string;\n inputType: string;\n outputType: string;\n hasInput: boolean;\n};\n\nfunction buildRpcControllerTree(\n operations: Map<string, OperationDef>,\n): Record<string, Record<string, RpcActionTypeEntry>> {\n const tree: Record<string, Record<string, RpcActionTypeEntry>> = {};\n\n for (const operation of operations.values()) {\n const controller = operation.controller;\n const action = operation.action;\n\n if (!tree[controller]) {\n tree[controller] = {};\n }\n\n if (tree[controller][action]) {\n throw new Error(\n `Type codegen failed: duplicate RPC action \"${controller}.${action}\" found in channel \"${operation.channel}\".`,\n );\n }\n\n tree[controller][action] = {\n channel: operation.channel,\n inputType: jsonSchemaToTS(operation.inputSchema as Record<string, unknown>, ' '),\n outputType: jsonSchemaToTS(operation.outputSchema as Record<string, unknown>, ' '),\n hasInput: operationHasInput(operation),\n };\n }\n\n return tree;\n}\n\nfunction generateRpcTypeTree(operations: Map<string, OperationDef>): string {\n const controllerTree = buildRpcControllerTree(operations);\n const controllerNames = Object.keys(controllerTree).sort((a, b) => a.localeCompare(b));\n const lines: string[] = [];\n\n for (const controllerName of controllerNames) {\n lines.push(` ${formatPropertyKey(controllerName)}: {`);\n const actions = controllerTree[controllerName];\n const actionNames = Object.keys(actions).sort((a, b) => a.localeCompare(b));\n for (const actionName of actionNames) {\n const action = actions[actionName];\n if (action.hasInput) {\n lines.push(` ${formatPropertyKey(actionName)}(data: ${action.inputType}): Promise<${action.outputType}>;`);\n } else {\n lines.push(` ${formatPropertyKey(actionName)}(): Promise<${action.outputType}>;`);\n }\n }\n lines.push(' };');\n }\n\n return lines.join('\\n');\n}\n\nexport function generateTypes(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTypeTree(operations);\n const typesCode = generateTypeTree(tree);\n const rpcTypeCode = generateRpcTypeTree(operations);\n\n return `${generatedFileNotice(TYPE_SOURCE_INSTRUCTIONS)}\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\n/**\n * Project-specific renderer App facade contract.\n *\n * This matches @noego/wood/client getApp() and injected App instances:\n * controller name -> controller action.\n */\nexport interface GeneratedApp {\n${rpcTypeCode}\n}\n\n/** Backward-compatible name for the generated client App facade contract. */\nexport interface WoodRpcApi extends GeneratedApp {}\n\n/**\n * Project-specific raw preload bridge contract.\n *\n * This matches the channel path exposed by preload.generated.ts:\n * operation channel segments -> invoke function.\n */\nexport interface GeneratedWoodBridge {\n${typesCode}\n}\n\nexport interface WoodApi extends GeneratedWoodBridge {\n __rpcManifest: WoodRpcManifestEntry[];\n __load(route: string, params: Record<string, string>): Promise<unknown>;\n __navigate(windowId: string, route: string): Promise<void>;\n __window: {\n current(): Promise<{ ok: boolean; windowId?: string; defaultRoute?: string }>;\n open(windowId: string, options?: Record<string, unknown>): Promise<void>;\n close(windowId?: string): Promise<void>;\n focus(windowId: string): Promise<void>;\n minimize(windowId?: string): Promise<void>;\n maximize(windowId?: string): Promise<void>;\n };\n __debug: {\n current(): Promise<{\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: Array<{\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n rendererHealth?: 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';\n }>;\n }>;\n };\n __contextMenu: {\n show(data: {\n items: Array<{ label?: string; action?: string; data?: string; _callbackId?: string; disabled?: boolean; type?: 'separator' }>;\n position: { x: number; y: number };\n }): Promise<void>;\n };\n on(channel: string, callback: (...args: unknown[]) => void): () => void;\n __log(level: string, logger: string, message: string, context?: unknown): Promise<{\n ok: boolean;\n forwarded: boolean;\n configured: boolean;\n reason?: 'unconfigured' | 'callback-error';\n errorMessage?: string;\n }>;\n}\n`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/codegen/type_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nconst TYPE_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels, input schemas, controller/action names, or renderer bridge types,',\n 'edit the operations YAML configured by wood.config.yml main.openapi and the matching controller methods.',\n] as const;\n\nfunction formatPropertyKey(key: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {\n return key;\n }\n\n return JSON.stringify(key);\n}\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\nfunction jsonSchemaToTS(schema: Record<string, unknown> | undefined, indent: string = ''): string {\n if (!schema) return 'unknown';\n\n const type = schema.type as string | undefined;\n\n if (type === 'string') {\n if (schema.enum) {\n return (schema.enum as string[]).map((v) => `'${v}'`).join(' | ');\n }\n return 'string';\n }\n if (type === 'number' || type === 'integer') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'array') {\n const itemType = jsonSchemaToTS(schema.items as Record<string, unknown>, indent);\n return `Array<${itemType}>`;\n }\n if (type === 'object') {\n const props = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required as string[]) ?? []);\n const entries = Object.entries(props);\n if (entries.length === 0) return 'Record<string, unknown>';\n\n const lines = entries.map(([key, val]) => {\n const optional = required.has(key) ? '' : '?';\n const valType = jsonSchemaToTS(val, indent + ' ');\n return `${indent} ${formatPropertyKey(key)}${optional}: ${valType};`;\n });\n return `{\\n${lines.join('\\n')}\\n${indent}}`;\n }\n\n return 'unknown';\n}\n\nfunction buildNestedTypeTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]] = { __operation: op };\n }\n return tree;\n}\n\nfunction generateTypeTree(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const inputType = jsonSchemaToTS(op.inputSchema as Record<string, unknown>, indent + ' ');\n const outputType = jsonSchemaToTS(op.outputSchema as Record<string, unknown>, indent + ' ');\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${formatPropertyKey(key)}(data: ${inputType}): Promise<${outputType}>;`);\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}(): Promise<${outputType}>;`);\n }\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}: {`);\n lines.push(generateTypeTree(entry, indent + ' '));\n lines.push(`${indent}};`);\n }\n }\n return lines.join('\\n');\n}\n\ntype RpcActionTypeEntry = {\n channel: string;\n inputType: string;\n outputType: string;\n hasInput: boolean;\n};\n\nfunction buildRpcControllerTree(\n operations: Map<string, OperationDef>,\n): Record<string, Record<string, RpcActionTypeEntry>> {\n const tree: Record<string, Record<string, RpcActionTypeEntry>> = {};\n\n for (const operation of operations.values()) {\n const controller = operation.controller;\n const action = operation.action;\n\n if (!tree[controller]) {\n tree[controller] = {};\n }\n\n if (tree[controller][action]) {\n throw new Error(\n `Type codegen failed: duplicate RPC action \"${controller}.${action}\" found in channel \"${operation.channel}\".`,\n );\n }\n\n tree[controller][action] = {\n channel: operation.channel,\n inputType: jsonSchemaToTS(operation.inputSchema as Record<string, unknown>, ' '),\n outputType: jsonSchemaToTS(operation.outputSchema as Record<string, unknown>, ' '),\n hasInput: operationHasInput(operation),\n };\n }\n\n return tree;\n}\n\nfunction generateRpcTypeTree(operations: Map<string, OperationDef>): string {\n const controllerTree = buildRpcControllerTree(operations);\n const controllerNames = Object.keys(controllerTree).sort((a, b) => a.localeCompare(b));\n const lines: string[] = [];\n\n for (const controllerName of controllerNames) {\n lines.push(` ${formatPropertyKey(controllerName)}: {`);\n const actions = controllerTree[controllerName];\n const actionNames = Object.keys(actions).sort((a, b) => a.localeCompare(b));\n for (const actionName of actionNames) {\n const action = actions[actionName];\n if (action.hasInput) {\n lines.push(` ${formatPropertyKey(actionName)}(data: ${action.inputType}): Promise<${action.outputType}>;`);\n } else {\n lines.push(` ${formatPropertyKey(actionName)}(): Promise<${action.outputType}>;`);\n }\n }\n lines.push(' };');\n }\n\n return lines.join('\\n');\n}\n\nexport function generateTypes(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTypeTree(operations);\n const typesCode = generateTypeTree(tree);\n const rpcTypeCode = generateRpcTypeTree(operations);\n\n return `${generatedFileNotice(TYPE_SOURCE_INSTRUCTIONS)}\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\n/**\n * Project-specific renderer App facade contract.\n *\n * This matches @noego/wood/client getApp() and injected App instances:\n * controller name -> controller action.\n */\nexport interface GeneratedApp {\n${rpcTypeCode}\n}\n\n/** Backward-compatible name for the generated client App facade contract. */\nexport interface WoodRpcApi extends GeneratedApp {}\n\n/**\n * Project-specific raw preload bridge contract.\n *\n * This matches the channel path exposed by preload.generated.ts:\n * operation channel segments -> invoke function.\n */\nexport interface GeneratedWoodBridge {\n${typesCode}\n}\n\nexport interface WoodApi extends GeneratedWoodBridge {\n __rpcManifest: WoodRpcManifestEntry[];\n __load(route: string, params: Record<string, string>): Promise<unknown>;\n __navigate(windowId: string, route: string): Promise<void>;\n __window: {\n current(): Promise<{ ok: boolean; windowId?: string; defaultRoute?: string }>;\n open(windowId: string, options?: Record<string, unknown>): Promise<void>;\n close(windowId?: string): Promise<void>;\n focus(windowId: string): Promise<void>;\n minimize(windowId?: string): Promise<void>;\n maximize(windowId?: string): Promise<void>;\n };\n __debug: {\n current(): Promise<{\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: Array<{\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n rendererHealth?: 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';\n }>;\n }>;\n };\n __contextMenu: {\n show(data: {\n items: Array<{ label?: string; action?: string; data?: string; _callbackId?: string; disabled?: boolean; type?: 'separator' }>;\n position: { x: number; y: number };\n }): Promise<void>;\n };\n on(channel: string, callback: (...args: unknown[]) => void): () => void;\n __log(level: string, logger: string, message: string, context?: unknown): Promise<{\n ok: boolean;\n forwarded: boolean;\n configured: boolean;\n reason?: 'unconfigured' | 'callback-error';\n errorMessage?: string;\n }>;\n __logBatch(batch: unknown): void;\n}\n`;\n}\n"],"mappings":"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","names":[]}
@@ -200,6 +200,7 @@ export interface WoodApi extends GeneratedWoodBridge {
200
200
  reason?: 'unconfigured' | 'callback-error';
201
201
  errorMessage?: string;
202
202
  }>;
203
+ __logBatch(batch: unknown): void;
203
204
  }
204
205
  `;
205
206
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codegen/type_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst TYPE_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels, input schemas, controller/action names, or renderer bridge types,',\n 'edit the operations YAML configured by wood.config.yml main.openapi and the matching controller methods.',\n] as const;\n\nfunction formatPropertyKey(key: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {\n return key;\n }\n\n return JSON.stringify(key);\n}\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\nfunction jsonSchemaToTS(schema: Record<string, unknown> | undefined, indent: string = ''): string {\n if (!schema) return 'unknown';\n\n const type = schema.type as string | undefined;\n\n if (type === 'string') {\n if (schema.enum) {\n return (schema.enum as string[]).map((v) => `'${v}'`).join(' | ');\n }\n return 'string';\n }\n if (type === 'number' || type === 'integer') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'array') {\n const itemType = jsonSchemaToTS(schema.items as Record<string, unknown>, indent);\n return `Array<${itemType}>`;\n }\n if (type === 'object') {\n const props = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required as string[]) ?? []);\n const entries = Object.entries(props);\n if (entries.length === 0) return 'Record<string, unknown>';\n\n const lines = entries.map(([key, val]) => {\n const optional = required.has(key) ? '' : '?';\n const valType = jsonSchemaToTS(val, indent + ' ');\n return `${indent} ${formatPropertyKey(key)}${optional}: ${valType};`;\n });\n return `{\\n${lines.join('\\n')}\\n${indent}}`;\n }\n\n return 'unknown';\n}\n\nfunction buildNestedTypeTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]] = { __operation: op };\n }\n return tree;\n}\n\nfunction generateTypeTree(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const inputType = jsonSchemaToTS(op.inputSchema as Record<string, unknown>, indent + ' ');\n const outputType = jsonSchemaToTS(op.outputSchema as Record<string, unknown>, indent + ' ');\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${formatPropertyKey(key)}(data: ${inputType}): Promise<${outputType}>;`);\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}(): Promise<${outputType}>;`);\n }\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}: {`);\n lines.push(generateTypeTree(entry, indent + ' '));\n lines.push(`${indent}};`);\n }\n }\n return lines.join('\\n');\n}\n\ntype RpcActionTypeEntry = {\n channel: string;\n inputType: string;\n outputType: string;\n hasInput: boolean;\n};\n\nfunction buildRpcControllerTree(\n operations: Map<string, OperationDef>,\n): Record<string, Record<string, RpcActionTypeEntry>> {\n const tree: Record<string, Record<string, RpcActionTypeEntry>> = {};\n\n for (const operation of operations.values()) {\n const controller = operation.controller;\n const action = operation.action;\n\n if (!tree[controller]) {\n tree[controller] = {};\n }\n\n if (tree[controller][action]) {\n throw new Error(\n `Type codegen failed: duplicate RPC action \"${controller}.${action}\" found in channel \"${operation.channel}\".`,\n );\n }\n\n tree[controller][action] = {\n channel: operation.channel,\n inputType: jsonSchemaToTS(operation.inputSchema as Record<string, unknown>, ' '),\n outputType: jsonSchemaToTS(operation.outputSchema as Record<string, unknown>, ' '),\n hasInput: operationHasInput(operation),\n };\n }\n\n return tree;\n}\n\nfunction generateRpcTypeTree(operations: Map<string, OperationDef>): string {\n const controllerTree = buildRpcControllerTree(operations);\n const controllerNames = Object.keys(controllerTree).sort((a, b) => a.localeCompare(b));\n const lines: string[] = [];\n\n for (const controllerName of controllerNames) {\n lines.push(` ${formatPropertyKey(controllerName)}: {`);\n const actions = controllerTree[controllerName];\n const actionNames = Object.keys(actions).sort((a, b) => a.localeCompare(b));\n for (const actionName of actionNames) {\n const action = actions[actionName];\n if (action.hasInput) {\n lines.push(` ${formatPropertyKey(actionName)}(data: ${action.inputType}): Promise<${action.outputType}>;`);\n } else {\n lines.push(` ${formatPropertyKey(actionName)}(): Promise<${action.outputType}>;`);\n }\n }\n lines.push(' };');\n }\n\n return lines.join('\\n');\n}\n\nexport function generateTypes(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTypeTree(operations);\n const typesCode = generateTypeTree(tree);\n const rpcTypeCode = generateRpcTypeTree(operations);\n\n return `${generatedFileNotice(TYPE_SOURCE_INSTRUCTIONS)}\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\n/**\n * Project-specific renderer App facade contract.\n *\n * This matches @noego/wood/client getApp() and injected App instances:\n * controller name -> controller action.\n */\nexport interface GeneratedApp {\n${rpcTypeCode}\n}\n\n/** Backward-compatible name for the generated client App facade contract. */\nexport interface WoodRpcApi extends GeneratedApp {}\n\n/**\n * Project-specific raw preload bridge contract.\n *\n * This matches the channel path exposed by preload.generated.ts:\n * operation channel segments -> invoke function.\n */\nexport interface GeneratedWoodBridge {\n${typesCode}\n}\n\nexport interface WoodApi extends GeneratedWoodBridge {\n __rpcManifest: WoodRpcManifestEntry[];\n __load(route: string, params: Record<string, string>): Promise<unknown>;\n __navigate(windowId: string, route: string): Promise<void>;\n __window: {\n current(): Promise<{ ok: boolean; windowId?: string; defaultRoute?: string }>;\n open(windowId: string, options?: Record<string, unknown>): Promise<void>;\n close(windowId?: string): Promise<void>;\n focus(windowId: string): Promise<void>;\n minimize(windowId?: string): Promise<void>;\n maximize(windowId?: string): Promise<void>;\n };\n __debug: {\n current(): Promise<{\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: Array<{\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n rendererHealth?: 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';\n }>;\n }>;\n };\n __contextMenu: {\n show(data: {\n items: Array<{ label?: string; action?: string; data?: string; _callbackId?: string; disabled?: boolean; type?: 'separator' }>;\n position: { x: number; y: number };\n }): Promise<void>;\n };\n on(channel: string, callback: (...args: unknown[]) => void): () => void;\n __log(level: string, logger: string, message: string, context?: unknown): Promise<{\n ok: boolean;\n forwarded: boolean;\n configured: boolean;\n reason?: 'unconfigured' | 'callback-error';\n errorMessage?: string;\n }>;\n}\n`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/codegen/type_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst TYPE_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels, input schemas, controller/action names, or renderer bridge types,',\n 'edit the operations YAML configured by wood.config.yml main.openapi and the matching controller methods.',\n] as const;\n\nfunction formatPropertyKey(key: string): string {\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {\n return key;\n }\n\n return JSON.stringify(key);\n}\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\nfunction jsonSchemaToTS(schema: Record<string, unknown> | undefined, indent: string = ''): string {\n if (!schema) return 'unknown';\n\n const type = schema.type as string | undefined;\n\n if (type === 'string') {\n if (schema.enum) {\n return (schema.enum as string[]).map((v) => `'${v}'`).join(' | ');\n }\n return 'string';\n }\n if (type === 'number' || type === 'integer') return 'number';\n if (type === 'boolean') return 'boolean';\n if (type === 'array') {\n const itemType = jsonSchemaToTS(schema.items as Record<string, unknown>, indent);\n return `Array<${itemType}>`;\n }\n if (type === 'object') {\n const props = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const required = new Set((schema.required as string[]) ?? []);\n const entries = Object.entries(props);\n if (entries.length === 0) return 'Record<string, unknown>';\n\n const lines = entries.map(([key, val]) => {\n const optional = required.has(key) ? '' : '?';\n const valType = jsonSchemaToTS(val, indent + ' ');\n return `${indent} ${formatPropertyKey(key)}${optional}: ${valType};`;\n });\n return `{\\n${lines.join('\\n')}\\n${indent}}`;\n }\n\n return 'unknown';\n}\n\nfunction buildNestedTypeTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n current[parts[parts.length - 1]] = { __operation: op };\n }\n return tree;\n}\n\nfunction generateTypeTree(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const inputType = jsonSchemaToTS(op.inputSchema as Record<string, unknown>, indent + ' ');\n const outputType = jsonSchemaToTS(op.outputSchema as Record<string, unknown>, indent + ' ');\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${formatPropertyKey(key)}(data: ${inputType}): Promise<${outputType}>;`);\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}(): Promise<${outputType}>;`);\n }\n } else {\n lines.push(`${indent}${formatPropertyKey(key)}: {`);\n lines.push(generateTypeTree(entry, indent + ' '));\n lines.push(`${indent}};`);\n }\n }\n return lines.join('\\n');\n}\n\ntype RpcActionTypeEntry = {\n channel: string;\n inputType: string;\n outputType: string;\n hasInput: boolean;\n};\n\nfunction buildRpcControllerTree(\n operations: Map<string, OperationDef>,\n): Record<string, Record<string, RpcActionTypeEntry>> {\n const tree: Record<string, Record<string, RpcActionTypeEntry>> = {};\n\n for (const operation of operations.values()) {\n const controller = operation.controller;\n const action = operation.action;\n\n if (!tree[controller]) {\n tree[controller] = {};\n }\n\n if (tree[controller][action]) {\n throw new Error(\n `Type codegen failed: duplicate RPC action \"${controller}.${action}\" found in channel \"${operation.channel}\".`,\n );\n }\n\n tree[controller][action] = {\n channel: operation.channel,\n inputType: jsonSchemaToTS(operation.inputSchema as Record<string, unknown>, ' '),\n outputType: jsonSchemaToTS(operation.outputSchema as Record<string, unknown>, ' '),\n hasInput: operationHasInput(operation),\n };\n }\n\n return tree;\n}\n\nfunction generateRpcTypeTree(operations: Map<string, OperationDef>): string {\n const controllerTree = buildRpcControllerTree(operations);\n const controllerNames = Object.keys(controllerTree).sort((a, b) => a.localeCompare(b));\n const lines: string[] = [];\n\n for (const controllerName of controllerNames) {\n lines.push(` ${formatPropertyKey(controllerName)}: {`);\n const actions = controllerTree[controllerName];\n const actionNames = Object.keys(actions).sort((a, b) => a.localeCompare(b));\n for (const actionName of actionNames) {\n const action = actions[actionName];\n if (action.hasInput) {\n lines.push(` ${formatPropertyKey(actionName)}(data: ${action.inputType}): Promise<${action.outputType}>;`);\n } else {\n lines.push(` ${formatPropertyKey(actionName)}(): Promise<${action.outputType}>;`);\n }\n }\n lines.push(' };');\n }\n\n return lines.join('\\n');\n}\n\nexport function generateTypes(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTypeTree(operations);\n const typesCode = generateTypeTree(tree);\n const rpcTypeCode = generateRpcTypeTree(operations);\n\n return `${generatedFileNotice(TYPE_SOURCE_INSTRUCTIONS)}\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\n/**\n * Project-specific renderer App facade contract.\n *\n * This matches @noego/wood/client getApp() and injected App instances:\n * controller name -> controller action.\n */\nexport interface GeneratedApp {\n${rpcTypeCode}\n}\n\n/** Backward-compatible name for the generated client App facade contract. */\nexport interface WoodRpcApi extends GeneratedApp {}\n\n/**\n * Project-specific raw preload bridge contract.\n *\n * This matches the channel path exposed by preload.generated.ts:\n * operation channel segments -> invoke function.\n */\nexport interface GeneratedWoodBridge {\n${typesCode}\n}\n\nexport interface WoodApi extends GeneratedWoodBridge {\n __rpcManifest: WoodRpcManifestEntry[];\n __load(route: string, params: Record<string, string>): Promise<unknown>;\n __navigate(windowId: string, route: string): Promise<void>;\n __window: {\n current(): Promise<{ ok: boolean; windowId?: string; defaultRoute?: string }>;\n open(windowId: string, options?: Record<string, unknown>): Promise<void>;\n close(windowId?: string): Promise<void>;\n focus(windowId: string): Promise<void>;\n minimize(windowId?: string): Promise<void>;\n maximize(windowId?: string): Promise<void>;\n };\n __debug: {\n current(): Promise<{\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: Array<{\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n rendererHealth?: 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';\n }>;\n }>;\n };\n __contextMenu: {\n show(data: {\n items: Array<{ label?: string; action?: string; data?: string; _callbackId?: string; disabled?: boolean; type?: 'separator' }>;\n position: { x: number; y: number };\n }): Promise<void>;\n };\n on(channel: string, callback: (...args: unknown[]) => void): () => void;\n __log(level: string, logger: string, message: string, context?: unknown): Promise<{\n ok: boolean;\n forwarded: boolean;\n configured: boolean;\n reason?: 'unconfigured' | 'callback-error';\n errorMessage?: string;\n }>;\n __logBatch(batch: unknown): void;\n}\n`;\n}\n"],"mappings":"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","names":[]}
@@ -28,7 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var config_parser_exports = {};
30
30
  __export(config_parser_exports, {
31
- parseConfig: () => parseConfig
31
+ RENDERER_TRACE_BATCHING_DEFAULTS: () => RENDERER_TRACE_BATCHING_DEFAULTS,
32
+ parseConfig: () => parseConfig,
33
+ resolveRendererTraceBatching: () => resolveRendererTraceBatching
32
34
  });
33
35
  module.exports = __toCommonJS(config_parser_exports);
34
36
  var import_js_yaml = __toESM(require("js-yaml"), 1);
@@ -112,6 +114,23 @@ function requireNumber(_doc, field, value) {
112
114
  throw new Error(`Config validation error: "${field}" is required and must be a number`);
113
115
  }
114
116
  }
117
+ function parseTestingSection(section, raw, allowedKeys) {
118
+ if (raw === void 0) return {};
119
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
120
+ throw new Error(`Config validation error: "${section}.testing" must be an object`);
121
+ }
122
+ const testing = {};
123
+ for (const [key, value] of Object.entries(raw)) {
124
+ if (!allowedKeys.includes(key)) {
125
+ throw new Error(
126
+ `Config validation error: "${section}.testing.${key}" is not a known hook (allowed: ${allowedKeys.join(", ")})`
127
+ );
128
+ }
129
+ requireString(raw, `${section}.testing.${key}`, value);
130
+ testing[key] = value;
131
+ }
132
+ return { testing };
133
+ }
115
134
  function applyDefaults(doc) {
116
135
  const app = doc.app;
117
136
  const main = doc.main;
@@ -140,14 +159,16 @@ function applyDefaults(doc) {
140
159
  controllers: main.controllers,
141
160
  middleware: main.middleware,
142
161
  openapi: main.openapi,
143
- watch: Array.isArray(main.watch) ? main.watch : []
162
+ watch: Array.isArray(main.watch) ? main.watch : [],
163
+ ...parseTestingSection("main", main.testing, ["compose"])
144
164
  },
145
165
  renderer: {
146
166
  openapi: renderer.openapi,
147
167
  componentDir: renderer.componentDir,
148
168
  controllers: renderer.controllers,
149
169
  ...typeof renderer.entry === "string" ? { entry: renderer.entry } : {},
150
- ...Array.isArray(renderer.watch) ? { watch: renderer.watch } : {}
170
+ ...Array.isArray(renderer.watch) ? { watch: renderer.watch } : {},
171
+ ...parseTestingSection("renderer", renderer.testing, ["host"])
151
172
  },
152
173
  windows,
153
174
  dev
@@ -167,10 +188,80 @@ function applyDefaults(doc) {
167
188
  if (doc.build && typeof doc.build === "object") {
168
189
  config.build = doc.build;
169
190
  }
191
+ if (doc.observability && typeof doc.observability === "object") {
192
+ config.observability = parseObservability(doc.observability);
193
+ }
170
194
  return config;
171
195
  }
196
+ const RENDERER_TRACE_BATCHING_DEFAULTS = Object.freeze({
197
+ maxQueuedEvents: 256,
198
+ maxBatchEvents: 32,
199
+ acknowledgementTimeoutMs: 1e3,
200
+ retryLimit: 3,
201
+ retryBaseDelayMs: 25
202
+ });
203
+ function resolveRendererTraceBatching(config) {
204
+ return {
205
+ ...RENDERER_TRACE_BATCHING_DEFAULTS,
206
+ ...config.observability?.trace?.rendererToMain?.batching
207
+ };
208
+ }
209
+ function parseObservability(raw) {
210
+ const trace = raw.trace;
211
+ if (trace === void 0) {
212
+ return {};
213
+ }
214
+ if (typeof trace !== "object" || trace === null) {
215
+ throw new Error('Config validation error: "observability.trace" must be an object');
216
+ }
217
+ const rendererToMain = trace.rendererToMain;
218
+ if (rendererToMain === void 0) {
219
+ return { trace: {} };
220
+ }
221
+ if (typeof rendererToMain !== "object" || rendererToMain === null) {
222
+ throw new Error('Config validation error: "observability.trace.rendererToMain" must be an object');
223
+ }
224
+ const batching = rendererToMain.batching;
225
+ if (batching === void 0) {
226
+ return { trace: { rendererToMain: {} } };
227
+ }
228
+ if (typeof batching !== "object" || batching === null) {
229
+ throw new Error('Config validation error: "observability.trace.rendererToMain.batching" must be an object');
230
+ }
231
+ const resolved = {
232
+ ...RENDERER_TRACE_BATCHING_DEFAULTS,
233
+ ...batching
234
+ };
235
+ const positiveIntFields = ["maxQueuedEvents", "maxBatchEvents", "acknowledgementTimeoutMs"];
236
+ for (const field of positiveIntFields) {
237
+ const value = resolved[field];
238
+ if (!Number.isSafeInteger(value) || value <= 0) {
239
+ throw new Error(
240
+ `Config validation error: "observability.trace.rendererToMain.batching.${field}" must be a positive integer`
241
+ );
242
+ }
243
+ }
244
+ if (!Number.isSafeInteger(resolved.retryLimit) || resolved.retryLimit < 0) {
245
+ throw new Error(
246
+ 'Config validation error: "observability.trace.rendererToMain.batching.retryLimit" must be a non-negative integer'
247
+ );
248
+ }
249
+ if (!Number.isFinite(resolved.retryBaseDelayMs) || resolved.retryBaseDelayMs < 0) {
250
+ throw new Error(
251
+ 'Config validation error: "observability.trace.rendererToMain.batching.retryBaseDelayMs" must be a non-negative number'
252
+ );
253
+ }
254
+ if (resolved.maxBatchEvents > resolved.maxQueuedEvents) {
255
+ throw new Error(
256
+ 'Config validation error: "observability.trace.rendererToMain.batching.maxBatchEvents" cannot exceed maxQueuedEvents'
257
+ );
258
+ }
259
+ return { trace: { rendererToMain: { batching: resolved } } };
260
+ }
172
261
  // Annotate the CommonJS export names for ESM import in node:
173
262
  0 && (module.exports = {
174
- parseConfig
263
+ RENDERER_TRACE_BATCHING_DEFAULTS,
264
+ parseConfig,
265
+ resolveRendererTraceBatching
175
266
  });
176
267
  //# sourceMappingURL=config_parser.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/config/config_parser.ts"],"sourcesContent":["import yaml from 'js-yaml';\nimport { readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport type { WoodConfig, WindowDef, DevConfig } from '../types/config.cjs';\n\nconst logger = getLogger('wood:config');\n\n/** Default values applied when optional fields are omitted. */\nconst WINDOW_DEFAULTS: Partial<WindowDef> = {\n frame: true,\n resizable: true,\n show: true,\n modal: false,\n};\n\nconst DEV_DEFAULTS: DevConfig = {\n watch: true,\n splitServe: true,\n port: 5173,\n};\n\n/**\n * Parse and validate a wood.config.yml file, returning a fully-typed WoodConfig\n * with defaults applied for optional fields.\n */\nexport function parseConfig(configPath: string): WoodConfig {\n const resolved = path.resolve(configPath);\n\n if (!existsSync(resolved)) {\n throw new Error(`Config file not found: ${resolved}`);\n }\n\n const raw = readFileSync(resolved, 'utf-8');\n const doc = yaml.load(raw) as Record<string, unknown> | null;\n\n if (!doc || typeof doc !== 'object') {\n throw new Error(`Invalid YAML in config file: ${resolved}`);\n }\n\n validateRequired(doc);\n\n const config = applyDefaults(doc as RawConfig);\n\n logger.info('Parsed config', { path: resolved, windows: Object.keys(config.windows) });\n\n return config;\n}\n\n/** Shape of the raw YAML before defaults are applied. */\ntype RawConfig = Record<string, unknown>;\n\nfunction validateRequired(doc: Record<string, unknown>): void {\n requireString(doc, 'app.boot', (doc as Record<string, Record<string, unknown>>).app?.boot);\n requireString(doc, 'main.entry', (doc as Record<string, Record<string, unknown>>).main?.entry);\n requireString(doc, 'main.controllers', (doc as Record<string, Record<string, unknown>>).main?.controllers);\n requireString(doc, 'main.middleware', (doc as Record<string, Record<string, unknown>>).main?.middleware);\n requireString(doc, 'main.openapi', (doc as Record<string, Record<string, unknown>>).main?.openapi);\n requireString(doc, 'renderer.openapi', (doc as Record<string, Record<string, unknown>>).renderer?.openapi);\n requireString(doc, 'renderer.componentDir', (doc as Record<string, Record<string, unknown>>).renderer?.componentDir);\n requireString(doc, 'renderer.controllers', (doc as Record<string, Record<string, unknown>>).renderer?.controllers);\n const rendererEntry = (doc as Record<string, Record<string, unknown>>).renderer?.entry;\n if (rendererEntry !== undefined) {\n requireString(doc, 'renderer.entry', rendererEntry);\n }\n\n // Windows validation\n const windows = doc.windows;\n if (!windows || typeof windows !== 'object') {\n throw new Error('Config validation error: \"windows\" is required and must be an object with at least one window');\n }\n\n const windowKeys = Object.keys(windows as Record<string, unknown>);\n if (windowKeys.length === 0) {\n throw new Error('Config validation error: \"windows\" must contain at least one window definition');\n }\n\n for (const key of windowKeys) {\n const win = (windows as Record<string, Record<string, unknown>>)[key];\n if (!win || typeof win !== 'object') {\n throw new Error(`Config validation error: window \"${key}\" must be an object`);\n }\n requireString(doc, `windows.${key}.title`, win.title);\n requireNumber(doc, `windows.${key}.width`, win.width);\n requireNumber(doc, `windows.${key}.height`, win.height);\n requireString(doc, `windows.${key}.defaultRoute`, win.defaultRoute);\n\n if (win.contextMenu !== undefined) {\n if (typeof win.contextMenu !== 'string') {\n throw new Error(`Config validation error: \"windows.${key}.contextMenu\" must be a string`);\n }\n if (win.contextMenu !== 'native' && win.contextMenu !== 'custom') {\n throw new Error(`Config validation error: \"windows.${key}.contextMenu\" must be \"native\" or \"custom\"`);\n }\n }\n }\n}\n\nfunction requireString(_doc: Record<string, unknown>, field: string, value: unknown): asserts value is string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Config validation error: \"${field}\" is required and must be a non-empty string`);\n }\n}\n\nfunction requireNumber(_doc: Record<string, unknown>, field: string, value: unknown): asserts value is number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new Error(`Config validation error: \"${field}\" is required and must be a number`);\n }\n}\n\nfunction applyDefaults(doc: RawConfig): WoodConfig {\n const app = doc.app as Record<string, unknown>;\n const main = doc.main as Record<string, unknown>;\n const renderer = doc.renderer as Record<string, unknown>;\n const rawWindows = doc.windows as Record<string, Record<string, unknown>>;\n\n const windows: Record<string, WindowDef> = {};\n for (const [key, rawWin] of Object.entries(rawWindows)) {\n windows[key] = {\n ...WINDOW_DEFAULTS,\n ...rawWin,\n } as WindowDef;\n }\n\n const dev: DevConfig = {\n ...DEV_DEFAULTS,\n ...(doc.dev as Record<string, unknown> | undefined),\n };\n\n const config: WoodConfig = {\n root: typeof doc.root === 'string' ? doc.root : '.',\n outDir: typeof doc.outDir === 'string' ? doc.outDir : 'dist',\n app: {\n boot: app.boot as string,\n watch: Array.isArray(app.watch) ? (app.watch as string[]) : [],\n },\n main: {\n entry: main.entry as string,\n controllers: main.controllers as string,\n middleware: main.middleware as string,\n openapi: main.openapi as string,\n watch: Array.isArray(main.watch) ? (main.watch as string[]) : [],\n },\n renderer: {\n openapi: renderer.openapi as string,\n componentDir: renderer.componentDir as string,\n controllers: renderer.controllers as string,\n ...(typeof renderer.entry === 'string' ? { entry: renderer.entry as string } : {}),\n ...(Array.isArray(renderer.watch) ? { watch: renderer.watch as string[] } : {}),\n },\n windows,\n dev,\n };\n\n // Optional database section (preserve :userData: token for runtime expansion)\n if (doc.database && typeof doc.database === 'object') {\n const db = doc.database as Record<string, unknown>;\n if (typeof db.path === 'string') {\n config.database = {\n path: db.path,\n ...(typeof db.migrations === 'string' ? { migrations: db.migrations } : {}),\n };\n }\n }\n\n // Optional assets\n if (Array.isArray(doc.assets)) {\n config.assets = doc.assets as string[];\n }\n\n // Optional build section\n if (doc.build && typeof doc.build === 'object') {\n config.build = doc.build as WoodConfig['build'];\n }\n\n return config;\n}\n"],"mappings":"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","names":["path","yaml"]}
1
+ {"version":3,"sources":["../../src/config/config_parser.ts"],"sourcesContent":["import yaml from 'js-yaml';\nimport { readFileSync, existsSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport type {\n WoodConfig,\n WindowDef,\n DevConfig,\n RendererTraceBatchingConfig,\n} from '../types/config.cjs';\n\nconst logger = getLogger('wood:config');\n\n/** Default values applied when optional fields are omitted. */\nconst WINDOW_DEFAULTS: Partial<WindowDef> = {\n frame: true,\n resizable: true,\n show: true,\n modal: false,\n};\n\nconst DEV_DEFAULTS: DevConfig = {\n watch: true,\n splitServe: true,\n port: 5173,\n};\n\n/**\n * Parse and validate a wood.config.yml file, returning a fully-typed WoodConfig\n * with defaults applied for optional fields.\n */\nexport function parseConfig(configPath: string): WoodConfig {\n const resolved = path.resolve(configPath);\n\n if (!existsSync(resolved)) {\n throw new Error(`Config file not found: ${resolved}`);\n }\n\n const raw = readFileSync(resolved, 'utf-8');\n const doc = yaml.load(raw) as Record<string, unknown> | null;\n\n if (!doc || typeof doc !== 'object') {\n throw new Error(`Invalid YAML in config file: ${resolved}`);\n }\n\n validateRequired(doc);\n\n const config = applyDefaults(doc as RawConfig);\n\n logger.info('Parsed config', { path: resolved, windows: Object.keys(config.windows) });\n\n return config;\n}\n\n/** Shape of the raw YAML before defaults are applied. */\ntype RawConfig = Record<string, unknown>;\n\nfunction validateRequired(doc: Record<string, unknown>): void {\n requireString(doc, 'app.boot', (doc as Record<string, Record<string, unknown>>).app?.boot);\n requireString(doc, 'main.entry', (doc as Record<string, Record<string, unknown>>).main?.entry);\n requireString(doc, 'main.controllers', (doc as Record<string, Record<string, unknown>>).main?.controllers);\n requireString(doc, 'main.middleware', (doc as Record<string, Record<string, unknown>>).main?.middleware);\n requireString(doc, 'main.openapi', (doc as Record<string, Record<string, unknown>>).main?.openapi);\n requireString(doc, 'renderer.openapi', (doc as Record<string, Record<string, unknown>>).renderer?.openapi);\n requireString(doc, 'renderer.componentDir', (doc as Record<string, Record<string, unknown>>).renderer?.componentDir);\n requireString(doc, 'renderer.controllers', (doc as Record<string, Record<string, unknown>>).renderer?.controllers);\n const rendererEntry = (doc as Record<string, Record<string, unknown>>).renderer?.entry;\n if (rendererEntry !== undefined) {\n requireString(doc, 'renderer.entry', rendererEntry);\n }\n\n // Windows validation\n const windows = doc.windows;\n if (!windows || typeof windows !== 'object') {\n throw new Error('Config validation error: \"windows\" is required and must be an object with at least one window');\n }\n\n const windowKeys = Object.keys(windows as Record<string, unknown>);\n if (windowKeys.length === 0) {\n throw new Error('Config validation error: \"windows\" must contain at least one window definition');\n }\n\n for (const key of windowKeys) {\n const win = (windows as Record<string, Record<string, unknown>>)[key];\n if (!win || typeof win !== 'object') {\n throw new Error(`Config validation error: window \"${key}\" must be an object`);\n }\n requireString(doc, `windows.${key}.title`, win.title);\n requireNumber(doc, `windows.${key}.width`, win.width);\n requireNumber(doc, `windows.${key}.height`, win.height);\n requireString(doc, `windows.${key}.defaultRoute`, win.defaultRoute);\n\n if (win.contextMenu !== undefined) {\n if (typeof win.contextMenu !== 'string') {\n throw new Error(`Config validation error: \"windows.${key}.contextMenu\" must be a string`);\n }\n if (win.contextMenu !== 'native' && win.contextMenu !== 'custom') {\n throw new Error(`Config validation error: \"windows.${key}.contextMenu\" must be \"native\" or \"custom\"`);\n }\n }\n }\n}\n\nfunction requireString(_doc: Record<string, unknown>, field: string, value: unknown): asserts value is string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new Error(`Config validation error: \"${field}\" is required and must be a non-empty string`);\n }\n}\n\nfunction requireNumber(_doc: Record<string, unknown>, field: string, value: unknown): asserts value is number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new Error(`Config validation error: \"${field}\" is required and must be a number`);\n }\n}\n\n/**\n * Parse an optional `<section>.testing` mapping: every allowed key is an\n * optional non-empty string (a config-relative module path); anything else\n * is a validation error so a typo cannot silently drop a hook.\n */\nfunction parseTestingSection(\n section: 'main' | 'renderer',\n raw: unknown,\n allowedKeys: readonly string[],\n): { testing?: Record<string, string> } {\n if (raw === undefined) return {};\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error(`Config validation error: \"${section}.testing\" must be an object`);\n }\n const testing: Record<string, string> = {};\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n if (!allowedKeys.includes(key)) {\n throw new Error(\n `Config validation error: \"${section}.testing.${key}\" is not a known hook (allowed: ${allowedKeys.join(', ')})`,\n );\n }\n requireString(raw as Record<string, unknown>, `${section}.testing.${key}`, value);\n testing[key] = value;\n }\n return { testing };\n}\n\nfunction applyDefaults(doc: RawConfig): WoodConfig {\n const app = doc.app as Record<string, unknown>;\n const main = doc.main as Record<string, unknown>;\n const renderer = doc.renderer as Record<string, unknown>;\n const rawWindows = doc.windows as Record<string, Record<string, unknown>>;\n\n const windows: Record<string, WindowDef> = {};\n for (const [key, rawWin] of Object.entries(rawWindows)) {\n windows[key] = {\n ...WINDOW_DEFAULTS,\n ...rawWin,\n } as WindowDef;\n }\n\n const dev: DevConfig = {\n ...DEV_DEFAULTS,\n ...(doc.dev as Record<string, unknown> | undefined),\n };\n\n const config: WoodConfig = {\n root: typeof doc.root === 'string' ? doc.root : '.',\n outDir: typeof doc.outDir === 'string' ? doc.outDir : 'dist',\n app: {\n boot: app.boot as string,\n watch: Array.isArray(app.watch) ? (app.watch as string[]) : [],\n },\n main: {\n entry: main.entry as string,\n controllers: main.controllers as string,\n middleware: main.middleware as string,\n openapi: main.openapi as string,\n watch: Array.isArray(main.watch) ? (main.watch as string[]) : [],\n ...parseTestingSection('main', main.testing, ['compose']),\n },\n renderer: {\n openapi: renderer.openapi as string,\n componentDir: renderer.componentDir as string,\n controllers: renderer.controllers as string,\n ...(typeof renderer.entry === 'string' ? { entry: renderer.entry as string } : {}),\n ...(Array.isArray(renderer.watch) ? { watch: renderer.watch as string[] } : {}),\n ...parseTestingSection('renderer', renderer.testing, ['host']),\n },\n windows,\n dev,\n };\n\n // Optional database section (preserve :userData: token for runtime expansion)\n if (doc.database && typeof doc.database === 'object') {\n const db = doc.database as Record<string, unknown>;\n if (typeof db.path === 'string') {\n config.database = {\n path: db.path,\n ...(typeof db.migrations === 'string' ? { migrations: db.migrations } : {}),\n };\n }\n }\n\n // Optional assets\n if (Array.isArray(doc.assets)) {\n config.assets = doc.assets as string[];\n }\n\n // Optional build section\n if (doc.build && typeof doc.build === 'object') {\n config.build = doc.build as WoodConfig['build'];\n }\n\n // Optional observability section (renderer→main trace batching policy)\n if (doc.observability && typeof doc.observability === 'object') {\n config.observability = parseObservability(doc.observability as Record<string, unknown>);\n }\n\n return config;\n}\n\n/**\n * Default renderer→main IPC trace batching policy. These values match the\n * policy previously hard-coded in the generated preload; wood.config.yml\n * `observability.trace.rendererToMain.batching` is now the owner.\n */\nexport const RENDERER_TRACE_BATCHING_DEFAULTS: RendererTraceBatchingConfig = Object.freeze({\n maxQueuedEvents: 256,\n maxBatchEvents: 32,\n acknowledgementTimeoutMs: 1_000,\n retryLimit: 3,\n retryBaseDelayMs: 25,\n});\n\n/** Resolves the renderer trace batching policy from a parsed config. */\nexport function resolveRendererTraceBatching(\n config: Pick<WoodConfig, 'observability'>,\n): RendererTraceBatchingConfig {\n return {\n ...RENDERER_TRACE_BATCHING_DEFAULTS,\n ...config.observability?.trace?.rendererToMain?.batching,\n };\n}\n\nfunction parseObservability(raw: Record<string, unknown>): WoodConfig['observability'] {\n const trace = raw.trace;\n if (trace === undefined) {\n return {};\n }\n if (typeof trace !== 'object' || trace === null) {\n throw new Error('Config validation error: \"observability.trace\" must be an object');\n }\n const rendererToMain = (trace as Record<string, unknown>).rendererToMain;\n if (rendererToMain === undefined) {\n return { trace: {} };\n }\n if (typeof rendererToMain !== 'object' || rendererToMain === null) {\n throw new Error('Config validation error: \"observability.trace.rendererToMain\" must be an object');\n }\n const batching = (rendererToMain as Record<string, unknown>).batching;\n if (batching === undefined) {\n return { trace: { rendererToMain: {} } };\n }\n if (typeof batching !== 'object' || batching === null) {\n throw new Error('Config validation error: \"observability.trace.rendererToMain.batching\" must be an object');\n }\n\n const resolved: RendererTraceBatchingConfig = {\n ...RENDERER_TRACE_BATCHING_DEFAULTS,\n ...(batching as Partial<RendererTraceBatchingConfig>),\n };\n\n const positiveIntFields = ['maxQueuedEvents', 'maxBatchEvents', 'acknowledgementTimeoutMs'] as const;\n for (const field of positiveIntFields) {\n const value = resolved[field];\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new Error(\n `Config validation error: \"observability.trace.rendererToMain.batching.${field}\" must be a positive integer`,\n );\n }\n }\n if (!Number.isSafeInteger(resolved.retryLimit) || resolved.retryLimit < 0) {\n throw new Error(\n 'Config validation error: \"observability.trace.rendererToMain.batching.retryLimit\" must be a non-negative integer',\n );\n }\n if (!Number.isFinite(resolved.retryBaseDelayMs) || resolved.retryBaseDelayMs < 0) {\n throw new Error(\n 'Config validation error: \"observability.trace.rendererToMain.batching.retryBaseDelayMs\" must be a non-negative number',\n );\n }\n if (resolved.maxBatchEvents > resolved.maxQueuedEvents) {\n throw new Error(\n 'Config validation error: \"observability.trace.rendererToMain.batching.maxBatchEvents\" cannot exceed maxQueuedEvents',\n );\n }\n\n return { trace: { rendererToMain: { batching: resolved } } };\n}\n"],"mappings":"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","names":["path","yaml"]}