@noego/wood 0.0.1

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 (499) hide show
  1. package/README.md +107 -0
  2. package/bin/axe.js +202 -0
  3. package/bin/stick.js +96 -0
  4. package/bin/wood.js +572 -0
  5. package/dist/bridge/backend_bridge.cjs +186 -0
  6. package/dist/bridge/backend_bridge.cjs.map +1 -0
  7. package/dist/bridge/backend_bridge.d.cts +32 -0
  8. package/dist/bridge/backend_bridge.d.ts +32 -0
  9. package/dist/bridge/backend_bridge.js +152 -0
  10. package/dist/bridge/backend_bridge.js.map +1 -0
  11. package/dist/bridge/backend_entry.cjs +64 -0
  12. package/dist/bridge/backend_entry.cjs.map +1 -0
  13. package/dist/bridge/backend_entry.d.cts +14 -0
  14. package/dist/bridge/backend_entry.d.ts +14 -0
  15. package/dist/bridge/backend_entry.js +39 -0
  16. package/dist/bridge/backend_entry.js.map +1 -0
  17. package/dist/bridge/index.cjs +34 -0
  18. package/dist/bridge/index.cjs.map +1 -0
  19. package/dist/bridge/index.d.cts +2 -0
  20. package/dist/bridge/index.d.ts +2 -0
  21. package/dist/bridge/index.js +8 -0
  22. package/dist/bridge/index.js.map +1 -0
  23. package/dist/client/controller_contract.cjs +17 -0
  24. package/dist/client/controller_contract.cjs.map +1 -0
  25. package/dist/client/controller_contract.d.cts +15 -0
  26. package/dist/client/controller_contract.d.ts +15 -0
  27. package/dist/client/controller_contract.js +1 -0
  28. package/dist/client/controller_contract.js.map +1 -0
  29. package/dist/client/global_polyfill.cjs +6 -0
  30. package/dist/client/global_polyfill.cjs.map +1 -0
  31. package/dist/client/global_polyfill.d.cts +2 -0
  32. package/dist/client/global_polyfill.d.ts +2 -0
  33. package/dist/client/global_polyfill.js +5 -0
  34. package/dist/client/global_polyfill.js.map +1 -0
  35. package/dist/client/index.cjs +451 -0
  36. package/dist/client/index.cjs.map +1 -0
  37. package/dist/client/index.d.cts +75 -0
  38. package/dist/client/index.d.ts +75 -0
  39. package/dist/client/index.js +414 -0
  40. package/dist/client/index.js.map +1 -0
  41. package/dist/client/wood_controller.svelte.cjs +110 -0
  42. package/dist/client/wood_controller.svelte.cjs.map +1 -0
  43. package/dist/client/wood_controller.svelte.d.cts +30 -0
  44. package/dist/client/wood_controller.svelte.d.ts +30 -0
  45. package/dist/client/wood_controller.svelte.js +86 -0
  46. package/dist/client/wood_controller.svelte.js.map +1 -0
  47. package/dist/codegen/controller_registration_generator.cjs +138 -0
  48. package/dist/codegen/controller_registration_generator.cjs.map +1 -0
  49. package/dist/codegen/controller_registration_generator.d.cts +18 -0
  50. package/dist/codegen/controller_registration_generator.d.ts +18 -0
  51. package/dist/codegen/controller_registration_generator.js +104 -0
  52. package/dist/codegen/controller_registration_generator.js.map +1 -0
  53. package/dist/codegen/index.cjs +50 -0
  54. package/dist/codegen/index.cjs.map +1 -0
  55. package/dist/codegen/index.d.cts +10 -0
  56. package/dist/codegen/index.d.ts +10 -0
  57. package/dist/codegen/index.js +19 -0
  58. package/dist/codegen/index.js.map +1 -0
  59. package/dist/codegen/preload_generator.cjs +151 -0
  60. package/dist/codegen/preload_generator.cjs.map +1 -0
  61. package/dist/codegen/preload_generator.d.cts +8 -0
  62. package/dist/codegen/preload_generator.d.ts +8 -0
  63. package/dist/codegen/preload_generator.js +127 -0
  64. package/dist/codegen/preload_generator.js.map +1 -0
  65. package/dist/codegen/renderer_app_generator.cjs +397 -0
  66. package/dist/codegen/renderer_app_generator.cjs.map +1 -0
  67. package/dist/codegen/renderer_app_generator.d.cts +13 -0
  68. package/dist/codegen/renderer_app_generator.d.ts +13 -0
  69. package/dist/codegen/renderer_app_generator.js +363 -0
  70. package/dist/codegen/renderer_app_generator.js.map +1 -0
  71. package/dist/codegen/renderer_controller_registration_generator.cjs +122 -0
  72. package/dist/codegen/renderer_controller_registration_generator.cjs.map +1 -0
  73. package/dist/codegen/renderer_controller_registration_generator.d.cts +9 -0
  74. package/dist/codegen/renderer_controller_registration_generator.d.ts +9 -0
  75. package/dist/codegen/renderer_controller_registration_generator.js +88 -0
  76. package/dist/codegen/renderer_controller_registration_generator.js.map +1 -0
  77. package/dist/codegen/renderer_view_manifest_generator.cjs +126 -0
  78. package/dist/codegen/renderer_view_manifest_generator.cjs.map +1 -0
  79. package/dist/codegen/renderer_view_manifest_generator.d.cts +11 -0
  80. package/dist/codegen/renderer_view_manifest_generator.d.ts +11 -0
  81. package/dist/codegen/renderer_view_manifest_generator.js +92 -0
  82. package/dist/codegen/renderer_view_manifest_generator.js.map +1 -0
  83. package/dist/codegen/runtime_generator.cjs +156 -0
  84. package/dist/codegen/runtime_generator.cjs.map +1 -0
  85. package/dist/codegen/runtime_generator.d.cts +14 -0
  86. package/dist/codegen/runtime_generator.d.ts +14 -0
  87. package/dist/codegen/runtime_generator.js +122 -0
  88. package/dist/codegen/runtime_generator.js.map +1 -0
  89. package/dist/codegen/test_mock_generator.cjs +98 -0
  90. package/dist/codegen/test_mock_generator.cjs.map +1 -0
  91. package/dist/codegen/test_mock_generator.d.cts +5 -0
  92. package/dist/codegen/test_mock_generator.d.ts +5 -0
  93. package/dist/codegen/test_mock_generator.js +74 -0
  94. package/dist/codegen/test_mock_generator.js.map +1 -0
  95. package/dist/codegen/type_generator.cjs +203 -0
  96. package/dist/codegen/type_generator.cjs.map +1 -0
  97. package/dist/codegen/type_generator.d.cts +5 -0
  98. package/dist/codegen/type_generator.d.ts +5 -0
  99. package/dist/codegen/type_generator.js +179 -0
  100. package/dist/codegen/type_generator.js.map +1 -0
  101. package/dist/components/contextMenu.cjs +163 -0
  102. package/dist/components/contextMenu.cjs.map +1 -0
  103. package/dist/components/contextMenu.d.cts +43 -0
  104. package/dist/components/contextMenu.d.ts +43 -0
  105. package/dist/components/contextMenu.js +138 -0
  106. package/dist/components/contextMenu.js.map +1 -0
  107. package/dist/config/config_parser.cjs +176 -0
  108. package/dist/config/config_parser.cjs.map +1 -0
  109. package/dist/config/config_parser.d.cts +9 -0
  110. package/dist/config/config_parser.d.ts +9 -0
  111. package/dist/config/config_parser.js +142 -0
  112. package/dist/config/config_parser.js.map +1 -0
  113. package/dist/config/index.cjs +29 -0
  114. package/dist/config/index.cjs.map +1 -0
  115. package/dist/config/index.d.cts +2 -0
  116. package/dist/config/index.d.ts +2 -0
  117. package/dist/config/index.js +5 -0
  118. package/dist/config/index.js.map +1 -0
  119. package/dist/controller/__fixtures__/controllers/chat.cjs +32 -0
  120. package/dist/controller/__fixtures__/controllers/chat.cjs.map +1 -0
  121. package/dist/controller/__fixtures__/controllers/chat.d.cts +11 -0
  122. package/dist/controller/__fixtures__/controllers/chat.d.ts +11 -0
  123. package/dist/controller/__fixtures__/controllers/chat.js +12 -0
  124. package/dist/controller/__fixtures__/controllers/chat.js.map +1 -0
  125. package/dist/controller/__fixtures__/controllers/not_a_class.cjs +29 -0
  126. package/dist/controller/__fixtures__/controllers/not_a_class.cjs.map +1 -0
  127. package/dist/controller/__fixtures__/controllers/not_a_class.d.cts +3 -0
  128. package/dist/controller/__fixtures__/controllers/not_a_class.d.ts +3 -0
  129. package/dist/controller/__fixtures__/controllers/not_a_class.js +5 -0
  130. package/dist/controller/__fixtures__/controllers/not_a_class.js.map +1 -0
  131. package/dist/controller/__fixtures__/controllers/settings.controller.cjs +32 -0
  132. package/dist/controller/__fixtures__/controllers/settings.controller.cjs.map +1 -0
  133. package/dist/controller/__fixtures__/controllers/settings.controller.d.cts +12 -0
  134. package/dist/controller/__fixtures__/controllers/settings.controller.d.ts +12 -0
  135. package/dist/controller/__fixtures__/controllers/settings.controller.js +12 -0
  136. package/dist/controller/__fixtures__/controllers/settings.controller.js.map +1 -0
  137. package/dist/controller/__fixtures__/controllers/test.cjs +29 -0
  138. package/dist/controller/__fixtures__/controllers/test.cjs.map +1 -0
  139. package/dist/controller/__fixtures__/controllers/test.d.cts +7 -0
  140. package/dist/controller/__fixtures__/controllers/test.d.ts +7 -0
  141. package/dist/controller/__fixtures__/controllers/test.js +9 -0
  142. package/dist/controller/__fixtures__/controllers/test.js.map +1 -0
  143. package/dist/controller/controller_resolver.cjs +180 -0
  144. package/dist/controller/controller_resolver.cjs.map +1 -0
  145. package/dist/controller/controller_resolver.d.cts +51 -0
  146. package/dist/controller/controller_resolver.d.ts +51 -0
  147. package/dist/controller/controller_resolver.js +145 -0
  148. package/dist/controller/controller_resolver.js.map +1 -0
  149. package/dist/controller/index.cjs +31 -0
  150. package/dist/controller/index.cjs.map +1 -0
  151. package/dist/controller/index.d.cts +2 -0
  152. package/dist/controller/index.d.ts +2 -0
  153. package/dist/controller/index.js +6 -0
  154. package/dist/controller/index.js.map +1 -0
  155. package/dist/dev/backend_watcher.cjs +108 -0
  156. package/dist/dev/backend_watcher.cjs.map +1 -0
  157. package/dist/dev/backend_watcher.d.cts +22 -0
  158. package/dist/dev/backend_watcher.d.ts +22 -0
  159. package/dist/dev/backend_watcher.js +84 -0
  160. package/dist/dev/backend_watcher.js.map +1 -0
  161. package/dist/dev/dev_metadata.cjs +94 -0
  162. package/dist/dev/dev_metadata.cjs.map +1 -0
  163. package/dist/dev/dev_metadata.d.cts +20 -0
  164. package/dist/dev/dev_metadata.d.ts +20 -0
  165. package/dist/dev/dev_metadata.js +52 -0
  166. package/dist/dev/dev_metadata.js.map +1 -0
  167. package/dist/dev/esbuild_backend.cjs +124 -0
  168. package/dist/dev/esbuild_backend.cjs.map +1 -0
  169. package/dist/dev/esbuild_backend.d.cts +30 -0
  170. package/dist/dev/esbuild_backend.d.ts +30 -0
  171. package/dist/dev/esbuild_backend.js +90 -0
  172. package/dist/dev/esbuild_backend.js.map +1 -0
  173. package/dist/dev/index.cjs +57 -0
  174. package/dist/dev/index.cjs.map +1 -0
  175. package/dist/dev/index.d.cts +8 -0
  176. package/dist/dev/index.d.ts +8 -0
  177. package/dist/dev/index.js +31 -0
  178. package/dist/dev/index.js.map +1 -0
  179. package/dist/dev/wood_dev_server.cjs +220 -0
  180. package/dist/dev/wood_dev_server.cjs.map +1 -0
  181. package/dist/dev/wood_dev_server.d.cts +39 -0
  182. package/dist/dev/wood_dev_server.d.ts +39 -0
  183. package/dist/dev/wood_dev_server.js +186 -0
  184. package/dist/dev/wood_dev_server.js.map +1 -0
  185. package/dist/dev/yaml_watcher.cjs +142 -0
  186. package/dist/dev/yaml_watcher.cjs.map +1 -0
  187. package/dist/dev/yaml_watcher.d.cts +22 -0
  188. package/dist/dev/yaml_watcher.d.ts +22 -0
  189. package/dist/dev/yaml_watcher.js +108 -0
  190. package/dist/dev/yaml_watcher.js.map +1 -0
  191. package/dist/electron/index.cjs +176 -0
  192. package/dist/electron/index.cjs.map +1 -0
  193. package/dist/electron/index.d.cts +29 -0
  194. package/dist/electron/index.d.ts +29 -0
  195. package/dist/electron/index.js +140 -0
  196. package/dist/electron/index.js.map +1 -0
  197. package/dist/index.cjs +178 -0
  198. package/dist/index.cjs.map +1 -0
  199. package/dist/index.d.cts +41 -0
  200. package/dist/index.d.ts +41 -0
  201. package/dist/index.js +122 -0
  202. package/dist/index.js.map +1 -0
  203. package/dist/ipc/index.cjs +80 -0
  204. package/dist/ipc/index.cjs.map +1 -0
  205. package/dist/ipc/index.d.cts +12 -0
  206. package/dist/ipc/index.d.ts +12 -0
  207. package/dist/ipc/index.js +57 -0
  208. package/dist/ipc/index.js.map +1 -0
  209. package/dist/ipc/shared.cjs +50 -0
  210. package/dist/ipc/shared.cjs.map +1 -0
  211. package/dist/ipc/shared.d.cts +10 -0
  212. package/dist/ipc/shared.d.ts +10 -0
  213. package/dist/ipc/shared.js +23 -0
  214. package/dist/ipc/shared.js.map +1 -0
  215. package/dist/loader/__fixtures__/layouts/app.load.cjs +27 -0
  216. package/dist/loader/__fixtures__/layouts/app.load.cjs.map +1 -0
  217. package/dist/loader/__fixtures__/layouts/app.load.d.cts +5 -0
  218. package/dist/loader/__fixtures__/layouts/app.load.d.ts +5 -0
  219. package/dist/loader/__fixtures__/layouts/app.load.js +7 -0
  220. package/dist/loader/__fixtures__/layouts/app.load.js.map +1 -0
  221. package/dist/loader/__fixtures__/views/test/page.load.cjs +27 -0
  222. package/dist/loader/__fixtures__/views/test/page.load.cjs.map +1 -0
  223. package/dist/loader/__fixtures__/views/test/page.load.d.cts +6 -0
  224. package/dist/loader/__fixtures__/views/test/page.load.d.ts +6 -0
  225. package/dist/loader/__fixtures__/views/test/page.load.js +7 -0
  226. package/dist/loader/__fixtures__/views/test/page.load.js.map +1 -0
  227. package/dist/loader/index.cjs +29 -0
  228. package/dist/loader/index.cjs.map +1 -0
  229. package/dist/loader/index.d.cts +3 -0
  230. package/dist/loader/index.d.ts +3 -0
  231. package/dist/loader/index.js +5 -0
  232. package/dist/loader/index.js.map +1 -0
  233. package/dist/loader/loader_runner.cjs +109 -0
  234. package/dist/loader/loader_runner.cjs.map +1 -0
  235. package/dist/loader/loader_runner.d.cts +27 -0
  236. package/dist/loader/loader_runner.d.ts +27 -0
  237. package/dist/loader/loader_runner.js +75 -0
  238. package/dist/loader/loader_runner.js.map +1 -0
  239. package/dist/main/index.cjs +500 -0
  240. package/dist/main/index.cjs.map +1 -0
  241. package/dist/main/index.d.cts +98 -0
  242. package/dist/main/index.d.ts +98 -0
  243. package/dist/main/index.js +475 -0
  244. package/dist/main/index.js.map +1 -0
  245. package/dist/middleware/__fixtures__/middleware/auth.cjs +44 -0
  246. package/dist/middleware/__fixtures__/middleware/auth.cjs.map +1 -0
  247. package/dist/middleware/__fixtures__/middleware/auth.d.cts +6 -0
  248. package/dist/middleware/__fixtures__/middleware/auth.d.ts +6 -0
  249. package/dist/middleware/__fixtures__/middleware/auth.js +19 -0
  250. package/dist/middleware/__fixtures__/middleware/auth.js.map +1 -0
  251. package/dist/middleware/__fixtures__/middleware/sequence.cjs +47 -0
  252. package/dist/middleware/__fixtures__/middleware/sequence.cjs.map +1 -0
  253. package/dist/middleware/__fixtures__/middleware/sequence.d.cts +7 -0
  254. package/dist/middleware/__fixtures__/middleware/sequence.d.ts +7 -0
  255. package/dist/middleware/__fixtures__/middleware/sequence.js +21 -0
  256. package/dist/middleware/__fixtures__/middleware/sequence.js.map +1 -0
  257. package/dist/middleware/index.cjs +34 -0
  258. package/dist/middleware/index.cjs.map +1 -0
  259. package/dist/middleware/index.d.cts +3 -0
  260. package/dist/middleware/index.d.ts +3 -0
  261. package/dist/middleware/index.js +8 -0
  262. package/dist/middleware/index.js.map +1 -0
  263. package/dist/middleware/middleware_pipeline.cjs +55 -0
  264. package/dist/middleware/middleware_pipeline.cjs.map +1 -0
  265. package/dist/middleware/middleware_pipeline.d.cts +13 -0
  266. package/dist/middleware/middleware_pipeline.d.ts +13 -0
  267. package/dist/middleware/middleware_pipeline.js +30 -0
  268. package/dist/middleware/middleware_pipeline.js.map +1 -0
  269. package/dist/middleware/middleware_resolver.cjs +91 -0
  270. package/dist/middleware/middleware_resolver.cjs.map +1 -0
  271. package/dist/middleware/middleware_resolver.d.cts +19 -0
  272. package/dist/middleware/middleware_resolver.d.ts +19 -0
  273. package/dist/middleware/middleware_resolver.js +57 -0
  274. package/dist/middleware/middleware_resolver.js.map +1 -0
  275. package/dist/navigation/index.cjs +205 -0
  276. package/dist/navigation/index.cjs.map +1 -0
  277. package/dist/navigation/index.d.cts +34 -0
  278. package/dist/navigation/index.d.ts +34 -0
  279. package/dist/navigation/index.js +176 -0
  280. package/dist/navigation/index.js.map +1 -0
  281. package/dist/parser/index.cjs +36 -0
  282. package/dist/parser/index.cjs.map +1 -0
  283. package/dist/parser/index.d.cts +4 -0
  284. package/dist/parser/index.d.ts +4 -0
  285. package/dist/parser/index.js +9 -0
  286. package/dist/parser/index.js.map +1 -0
  287. package/dist/parser/operations_parser.cjs +94 -0
  288. package/dist/parser/operations_parser.cjs.map +1 -0
  289. package/dist/parser/operations_parser.d.cts +7 -0
  290. package/dist/parser/operations_parser.d.ts +7 -0
  291. package/dist/parser/operations_parser.js +59 -0
  292. package/dist/parser/operations_parser.js.map +1 -0
  293. package/dist/parser/views_parser.cjs +153 -0
  294. package/dist/parser/views_parser.cjs.map +1 -0
  295. package/dist/parser/views_parser.d.cts +11 -0
  296. package/dist/parser/views_parser.d.ts +11 -0
  297. package/dist/parser/views_parser.js +118 -0
  298. package/dist/parser/views_parser.js.map +1 -0
  299. package/dist/router/index.cjs +31 -0
  300. package/dist/router/index.cjs.map +1 -0
  301. package/dist/router/index.d.cts +2 -0
  302. package/dist/router/index.d.ts +2 -0
  303. package/dist/router/index.js +6 -0
  304. package/dist/router/index.js.map +1 -0
  305. package/dist/router/wood_router.cjs +246 -0
  306. package/dist/router/wood_router.cjs.map +1 -0
  307. package/dist/router/wood_router.d.cts +70 -0
  308. package/dist/router/wood_router.d.ts +70 -0
  309. package/dist/router/wood_router.js +221 -0
  310. package/dist/router/wood_router.js.map +1 -0
  311. package/dist/runtime/application_root.cjs +98 -0
  312. package/dist/runtime/application_root.cjs.map +1 -0
  313. package/dist/runtime/application_root.d.cts +5 -0
  314. package/dist/runtime/application_root.d.ts +5 -0
  315. package/dist/runtime/application_root.js +61 -0
  316. package/dist/runtime/application_root.js.map +1 -0
  317. package/dist/runtime/get_container.cjs +96 -0
  318. package/dist/runtime/get_container.cjs.map +1 -0
  319. package/dist/runtime/get_container.d.cts +16 -0
  320. package/dist/runtime/get_container.d.ts +16 -0
  321. package/dist/runtime/get_container.js +60 -0
  322. package/dist/runtime/get_container.js.map +1 -0
  323. package/dist/runtime/index.cjs +49 -0
  324. package/dist/runtime/index.cjs.map +1 -0
  325. package/dist/runtime/index.d.cts +8 -0
  326. package/dist/runtime/index.d.ts +8 -0
  327. package/dist/runtime/index.js +24 -0
  328. package/dist/runtime/index.js.map +1 -0
  329. package/dist/runtime/renderer_log_dispatcher.cjs +79 -0
  330. package/dist/runtime/renderer_log_dispatcher.cjs.map +1 -0
  331. package/dist/runtime/renderer_log_dispatcher.d.cts +27 -0
  332. package/dist/runtime/renderer_log_dispatcher.d.ts +27 -0
  333. package/dist/runtime/renderer_log_dispatcher.js +54 -0
  334. package/dist/runtime/renderer_log_dispatcher.js.map +1 -0
  335. package/dist/runtime/runtime.cjs +158 -0
  336. package/dist/runtime/runtime.cjs.map +1 -0
  337. package/dist/runtime/runtime.d.cts +35 -0
  338. package/dist/runtime/runtime.d.ts +35 -0
  339. package/dist/runtime/runtime.js +136 -0
  340. package/dist/runtime/runtime.js.map +1 -0
  341. package/dist/stick/allow_cli.cjs +39 -0
  342. package/dist/stick/allow_cli.cjs.map +1 -0
  343. package/dist/stick/allow_cli.d.cts +6 -0
  344. package/dist/stick/allow_cli.d.ts +6 -0
  345. package/dist/stick/allow_cli.js +15 -0
  346. package/dist/stick/allow_cli.js.map +1 -0
  347. package/dist/stick/index.cjs +276 -0
  348. package/dist/stick/index.cjs.map +1 -0
  349. package/dist/stick/index.d.cts +111 -0
  350. package/dist/stick/index.d.ts +111 -0
  351. package/dist/stick/index.js +237 -0
  352. package/dist/stick/index.js.map +1 -0
  353. package/dist/stick/static_renderer.cjs +144 -0
  354. package/dist/stick/static_renderer.cjs.map +1 -0
  355. package/dist/stick/static_renderer.d.cts +51 -0
  356. package/dist/stick/static_renderer.d.ts +51 -0
  357. package/dist/stick/static_renderer.js +119 -0
  358. package/dist/stick/static_renderer.js.map +1 -0
  359. package/dist/stick/template_resolver.cjs +156 -0
  360. package/dist/stick/template_resolver.cjs.map +1 -0
  361. package/dist/stick/template_resolver.d.cts +7 -0
  362. package/dist/stick/template_resolver.d.ts +7 -0
  363. package/dist/stick/template_resolver.js +122 -0
  364. package/dist/stick/template_resolver.js.map +1 -0
  365. package/dist/testing/create_controller_harness.cjs +175 -0
  366. package/dist/testing/create_controller_harness.cjs.map +1 -0
  367. package/dist/testing/create_controller_harness.d.cts +37 -0
  368. package/dist/testing/create_controller_harness.d.ts +37 -0
  369. package/dist/testing/create_controller_harness.js +162 -0
  370. package/dist/testing/create_controller_harness.js.map +1 -0
  371. package/dist/testing/create_router_bridge.cjs +103 -0
  372. package/dist/testing/create_router_bridge.cjs.map +1 -0
  373. package/dist/testing/create_router_bridge.d.cts +71 -0
  374. package/dist/testing/create_router_bridge.d.ts +71 -0
  375. package/dist/testing/create_router_bridge.js +78 -0
  376. package/dist/testing/create_router_bridge.js.map +1 -0
  377. package/dist/testing/create_test_container.cjs +72 -0
  378. package/dist/testing/create_test_container.cjs.map +1 -0
  379. package/dist/testing/create_test_container.d.cts +14 -0
  380. package/dist/testing/create_test_container.d.ts +14 -0
  381. package/dist/testing/create_test_container.js +48 -0
  382. package/dist/testing/create_test_container.js.map +1 -0
  383. package/dist/testing/create_test_router.cjs +57 -0
  384. package/dist/testing/create_test_router.cjs.map +1 -0
  385. package/dist/testing/create_test_router.d.cts +19 -0
  386. package/dist/testing/create_test_router.d.ts +19 -0
  387. package/dist/testing/create_test_router.js +33 -0
  388. package/dist/testing/create_test_router.js.map +1 -0
  389. package/dist/testing/index.cjs +48 -0
  390. package/dist/testing/index.cjs.map +1 -0
  391. package/dist/testing/index.d.cts +12 -0
  392. package/dist/testing/index.d.ts +12 -0
  393. package/dist/testing/index.js +22 -0
  394. package/dist/testing/index.js.map +1 -0
  395. package/dist/testing/mock_electron.cjs +100 -0
  396. package/dist/testing/mock_electron.cjs.map +1 -0
  397. package/dist/testing/mock_electron.d.cts +12 -0
  398. package/dist/testing/mock_electron.d.ts +12 -0
  399. package/dist/testing/mock_electron.js +75 -0
  400. package/dist/testing/mock_electron.js.map +1 -0
  401. package/dist/tracing/index.cjs +56 -0
  402. package/dist/tracing/index.cjs.map +1 -0
  403. package/dist/tracing/index.d.cts +4 -0
  404. package/dist/tracing/index.d.ts +4 -0
  405. package/dist/tracing/index.js +35 -0
  406. package/dist/tracing/index.js.map +1 -0
  407. package/dist/tracing/trace_hub.cjs +213 -0
  408. package/dist/tracing/trace_hub.cjs.map +1 -0
  409. package/dist/tracing/trace_hub.d.cts +47 -0
  410. package/dist/tracing/trace_hub.d.ts +47 -0
  411. package/dist/tracing/trace_hub.js +172 -0
  412. package/dist/tracing/trace_hub.js.map +1 -0
  413. package/dist/tracing/trace_provider.cjs +200 -0
  414. package/dist/tracing/trace_provider.cjs.map +1 -0
  415. package/dist/tracing/trace_provider.d.cts +69 -0
  416. package/dist/tracing/trace_provider.d.ts +69 -0
  417. package/dist/tracing/trace_provider.js +179 -0
  418. package/dist/tracing/trace_provider.js.map +1 -0
  419. package/dist/types/bridge.cjs +51 -0
  420. package/dist/types/bridge.cjs.map +1 -0
  421. package/dist/types/bridge.d.cts +56 -0
  422. package/dist/types/bridge.d.ts +56 -0
  423. package/dist/types/bridge.js +25 -0
  424. package/dist/types/bridge.js.map +1 -0
  425. package/dist/types/config.cjs +17 -0
  426. package/dist/types/config.cjs.map +1 -0
  427. package/dist/types/config.d.cts +74 -0
  428. package/dist/types/config.d.ts +74 -0
  429. package/dist/types/config.js +1 -0
  430. package/dist/types/config.js.map +1 -0
  431. package/dist/types/context.cjs +17 -0
  432. package/dist/types/context.cjs.map +1 -0
  433. package/dist/types/context.d.cts +61 -0
  434. package/dist/types/context.d.ts +61 -0
  435. package/dist/types/context.js +1 -0
  436. package/dist/types/context.js.map +1 -0
  437. package/dist/types/context_menu.cjs +17 -0
  438. package/dist/types/context_menu.cjs.map +1 -0
  439. package/dist/types/context_menu.d.cts +30 -0
  440. package/dist/types/context_menu.d.ts +30 -0
  441. package/dist/types/context_menu.js +1 -0
  442. package/dist/types/context_menu.js.map +1 -0
  443. package/dist/types/index.cjs +33 -0
  444. package/dist/types/index.cjs.map +1 -0
  445. package/dist/types/index.d.cts +6 -0
  446. package/dist/types/index.d.ts +6 -0
  447. package/dist/types/index.js +7 -0
  448. package/dist/types/index.js.map +1 -0
  449. package/dist/types/operations.cjs +17 -0
  450. package/dist/types/operations.cjs.map +1 -0
  451. package/dist/types/operations.d.cts +39 -0
  452. package/dist/types/operations.d.ts +39 -0
  453. package/dist/types/operations.js +1 -0
  454. package/dist/types/operations.js.map +1 -0
  455. package/dist/types/views.cjs +17 -0
  456. package/dist/types/views.cjs.map +1 -0
  457. package/dist/types/views.d.cts +44 -0
  458. package/dist/types/views.d.ts +44 -0
  459. package/dist/types/views.js +1 -0
  460. package/dist/types/views.js.map +1 -0
  461. package/dist/validation/index.cjs +29 -0
  462. package/dist/validation/index.cjs.map +1 -0
  463. package/dist/validation/index.d.cts +1 -0
  464. package/dist/validation/index.d.ts +1 -0
  465. package/dist/validation/index.js +5 -0
  466. package/dist/validation/index.js.map +1 -0
  467. package/dist/validation/schema_validator.cjs +86 -0
  468. package/dist/validation/schema_validator.cjs.map +1 -0
  469. package/dist/validation/schema_validator.d.cts +24 -0
  470. package/dist/validation/schema_validator.d.ts +24 -0
  471. package/dist/validation/schema_validator.js +52 -0
  472. package/dist/validation/schema_validator.js.map +1 -0
  473. package/dist/window/index.cjs +32 -0
  474. package/dist/window/index.cjs.map +1 -0
  475. package/dist/window/index.d.cts +4 -0
  476. package/dist/window/index.d.ts +4 -0
  477. package/dist/window/index.js +7 -0
  478. package/dist/window/index.js.map +1 -0
  479. package/dist/window/window_manager.cjs +354 -0
  480. package/dist/window/window_manager.cjs.map +1 -0
  481. package/dist/window/window_manager.d.cts +172 -0
  482. package/dist/window/window_manager.d.ts +172 -0
  483. package/dist/window/window_manager.js +330 -0
  484. package/dist/window/window_manager.js.map +1 -0
  485. package/dist/window/window_state_store.cjs +129 -0
  486. package/dist/window/window_state_store.cjs.map +1 -0
  487. package/dist/window/window_state_store.d.cts +39 -0
  488. package/dist/window/window_state_store.d.ts +39 -0
  489. package/dist/window/window_state_store.js +105 -0
  490. package/dist/window/window_state_store.js.map +1 -0
  491. package/loaders/loader.mjs +46 -0
  492. package/package.json +119 -0
  493. package/src/components/ContextMenuProvider.svelte +145 -0
  494. package/src/components/NavigationShell.svelte +204 -0
  495. package/src/components/WoodRecursiveRender.svelte +91 -0
  496. package/src/components/contextMenu.ts +228 -0
  497. package/src/components/index.d.ts +14 -0
  498. package/src/components/index.js +2 -0
  499. package/src/stick/WoodRecursiveRender.svelte +74 -0
@@ -0,0 +1,172 @@
1
+ import { WindowDef } from '../types/config.js';
2
+ import { ContextMenuItem } from '../types/context_menu.js';
3
+ import { ScreenLike } from './window_state_store.js';
4
+
5
+ /** Subset of Electron BrowserWindow used by WindowManager (avoids compile-time electron dep). */
6
+ interface BrowserWindowLike {
7
+ loadURL(url: string): Promise<void>;
8
+ loadFile(filePath: string): Promise<void>;
9
+ close(): void;
10
+ focus(): void;
11
+ show(): void;
12
+ destroy(): void;
13
+ isDestroyed(): boolean;
14
+ webContents: {
15
+ send(channel: string, ...args: unknown[]): void;
16
+ reload(): void;
17
+ setWindowOpenHandler(handler: (details: {
18
+ url: string;
19
+ }) => {
20
+ action: 'deny' | 'allow';
21
+ }): void;
22
+ on(event: string, handler: (...args: any[]) => void): void;
23
+ };
24
+ on(event: string, handler: (...args: unknown[]) => void): void;
25
+ getBounds(): {
26
+ x: number;
27
+ y: number;
28
+ width: number;
29
+ height: number;
30
+ };
31
+ isMaximized(): boolean;
32
+ isFullScreen(): boolean;
33
+ maximize(): void;
34
+ setFullScreen(flag: boolean): void;
35
+ }
36
+ interface BrowserWindowConstructor {
37
+ new (options: Record<string, unknown>): BrowserWindowLike;
38
+ getAllWindows(): BrowserWindowLike[];
39
+ }
40
+ /** Minimal shell interface for opening external URLs. */
41
+ interface ShellLike {
42
+ openExternal(url: string): Promise<unknown>;
43
+ }
44
+ /** Minimal clipboard interface for copying text. */
45
+ interface ClipboardLike {
46
+ writeText(text: string): void;
47
+ }
48
+ /** Minimal Menu interface for right-click context menus. */
49
+ interface MenuLike {
50
+ popup(options?: {
51
+ window?: BrowserWindowLike;
52
+ }): void;
53
+ }
54
+ interface MenuConstructorLike {
55
+ buildFromTemplate(template: Array<{
56
+ label: string;
57
+ click: () => void;
58
+ type?: 'separator';
59
+ enabled?: boolean;
60
+ }>): MenuLike;
61
+ }
62
+ declare class WindowManager {
63
+ private windows;
64
+ private windowDefs;
65
+ private BrowserWindowClass;
66
+ private preloadPath;
67
+ private rendererUrl?;
68
+ private rendererDir?;
69
+ private shell;
70
+ private clipboard;
71
+ private MenuClass;
72
+ private stateStore;
73
+ constructor(options: {
74
+ windowDefs: Record<string, WindowDef>;
75
+ preloadPath: string;
76
+ rendererUrl?: string;
77
+ rendererDir?: string;
78
+ applicationRoot?: string;
79
+ });
80
+ /**
81
+ * Set the BrowserWindow class (from electron).
82
+ * Called at runtime so we don't need electron at compile time.
83
+ */
84
+ setBrowserWindow(BW: BrowserWindowConstructor): void;
85
+ /**
86
+ * Set the shell module (from electron) for opening external URLs.
87
+ */
88
+ setShell(shell: ShellLike): void;
89
+ /**
90
+ * Set the clipboard module (from electron) for copying text.
91
+ */
92
+ setClipboard(clipboard: ClipboardLike): void;
93
+ /**
94
+ * Set the Menu class (from electron) for context menus.
95
+ */
96
+ setMenu(menu: MenuConstructorLike): void;
97
+ /**
98
+ * Set the user data path for persisting window state.
99
+ */
100
+ setUserDataPath(path: string): void;
101
+ /**
102
+ * Set the application root directory for Wood JSON state persistence.
103
+ */
104
+ setApplicationRoot(path: string): void;
105
+ /**
106
+ * Set the screen module (from electron) for display validation.
107
+ */
108
+ setScreen(screen: ScreenLike): void;
109
+ /**
110
+ * Create a window from its definition.
111
+ */
112
+ createWindow(windowId: string, extraOptions?: Record<string, unknown>): Promise<BrowserWindowLike>;
113
+ /**
114
+ * Get a window by ID.
115
+ */
116
+ getWindow(windowId: string): BrowserWindowLike | undefined;
117
+ /**
118
+ * Close a window by ID.
119
+ */
120
+ closeWindow(windowId: string): void;
121
+ /**
122
+ * Focus a window by ID.
123
+ */
124
+ focusWindow(windowId: string): void;
125
+ /**
126
+ * Send an event to all open windows.
127
+ */
128
+ broadcastToAll(channel: string, ...data: unknown[]): void;
129
+ /**
130
+ * Get all open window IDs.
131
+ */
132
+ getOpenWindowIds(): string[];
133
+ /**
134
+ * Close all windows.
135
+ */
136
+ closeAll(): void;
137
+ /**
138
+ * Handle the __window IPC channel.
139
+ */
140
+ handleWindowOperation(data: {
141
+ action: string;
142
+ windowId?: string;
143
+ options?: Record<string, unknown>;
144
+ }): Promise<void>;
145
+ /**
146
+ * Handle the __contextMenu IPC channel.
147
+ *
148
+ * Receives `{ action: 'show', items, position }` from the renderer's
149
+ * `use:contextMenu` action. Checks the window's contextMenu config:
150
+ * - **native**: builds Electron Menu from items, pops it. String actions
151
+ * are handled on main. Callback items send `__contextMenu:callback`.
152
+ * - **custom**: forwards items + position as `__contextMenu:show` push event.
153
+ */
154
+ handleContextMenu(windowId: string, data: {
155
+ action: string;
156
+ items: ContextMenuItem[];
157
+ position: {
158
+ x: number;
159
+ y: number;
160
+ };
161
+ }): void;
162
+ /**
163
+ * Build and show a native Electron context menu from serialized items.
164
+ */
165
+ private showNativeContextMenu;
166
+ /**
167
+ * Execute a built-in menu action on the main process.
168
+ */
169
+ private executeMenuAction;
170
+ }
171
+
172
+ export { type BrowserWindowConstructor, type BrowserWindowLike, type ClipboardLike, type MenuConstructorLike, type MenuLike, type ShellLike, WindowManager };
@@ -0,0 +1,330 @@
1
+ import { join } from "path";
2
+ import { getLogger } from "@noego/logger";
3
+ import { WindowStateStore } from "./window_state_store.js";
4
+ const logger = getLogger("wood:window");
5
+ class WindowManager {
6
+ constructor(options) {
7
+ this.windows = /* @__PURE__ */ new Map();
8
+ this.BrowserWindowClass = null;
9
+ this.shell = null;
10
+ this.clipboard = null;
11
+ this.MenuClass = null;
12
+ this.stateStore = new WindowStateStore();
13
+ this.windowDefs = options.windowDefs;
14
+ this.preloadPath = options.preloadPath;
15
+ this.rendererUrl = options.rendererUrl;
16
+ this.rendererDir = options.rendererDir;
17
+ if (options.applicationRoot) {
18
+ this.stateStore.setApplicationRoot(options.applicationRoot);
19
+ }
20
+ }
21
+ /**
22
+ * Set the BrowserWindow class (from electron).
23
+ * Called at runtime so we don't need electron at compile time.
24
+ */
25
+ setBrowserWindow(BW) {
26
+ this.BrowserWindowClass = BW;
27
+ }
28
+ /**
29
+ * Set the shell module (from electron) for opening external URLs.
30
+ */
31
+ setShell(shell) {
32
+ this.shell = shell;
33
+ }
34
+ /**
35
+ * Set the clipboard module (from electron) for copying text.
36
+ */
37
+ setClipboard(clipboard) {
38
+ this.clipboard = clipboard;
39
+ }
40
+ /**
41
+ * Set the Menu class (from electron) for context menus.
42
+ */
43
+ setMenu(menu) {
44
+ this.MenuClass = menu;
45
+ }
46
+ /**
47
+ * Set the user data path for persisting window state.
48
+ */
49
+ setUserDataPath(path) {
50
+ this.stateStore.setUserDataPath(path);
51
+ }
52
+ /**
53
+ * Set the application root directory for Wood JSON state persistence.
54
+ */
55
+ setApplicationRoot(path) {
56
+ this.stateStore.setApplicationRoot(path);
57
+ }
58
+ /**
59
+ * Set the screen module (from electron) for display validation.
60
+ */
61
+ setScreen(screen) {
62
+ this.stateStore.setScreen(screen);
63
+ }
64
+ /**
65
+ * Create a window from its definition.
66
+ */
67
+ async createWindow(windowId, extraOptions) {
68
+ if (!this.BrowserWindowClass) {
69
+ throw new Error("BrowserWindow class not set. Call setBrowserWindow() first.");
70
+ }
71
+ const def = this.windowDefs[windowId];
72
+ if (!def) {
73
+ throw new Error(`Window "${windowId}" not defined in config`);
74
+ }
75
+ const existing = this.windows.get(windowId);
76
+ if (existing && !existing.isDestroyed()) {
77
+ existing.focus();
78
+ return existing;
79
+ }
80
+ let parentWindow;
81
+ if (def.parent) {
82
+ parentWindow = this.windows.get(def.parent);
83
+ }
84
+ const useRememberBounds = def.rememberBounds === true;
85
+ const savedBounds = useRememberBounds ? this.stateStore.getBounds(windowId) : null;
86
+ const defShow = def.show ?? true;
87
+ const deferShow = useRememberBounds && savedBounds != null && defShow && extraOptions?.show !== false;
88
+ const options = {
89
+ title: def.title,
90
+ width: savedBounds?.width ?? def.width,
91
+ height: savedBounds?.height ?? def.height,
92
+ ...savedBounds && { x: savedBounds.x, y: savedBounds.y },
93
+ frame: def.frame ?? true,
94
+ transparent: def.transparent ?? false,
95
+ resizable: def.resizable ?? true,
96
+ alwaysOnTop: def.alwaysOnTop ?? false,
97
+ show: deferShow ? false : defShow,
98
+ modal: def.modal ?? false,
99
+ ...def.minWidth != null && { minWidth: def.minWidth },
100
+ ...def.minHeight != null && { minHeight: def.minHeight },
101
+ ...def.maxWidth != null && { maxWidth: def.maxWidth },
102
+ ...def.maxHeight != null && { maxHeight: def.maxHeight },
103
+ ...def.vibrancy && { vibrancy: def.vibrancy },
104
+ ...def.backgroundMaterial && { backgroundMaterial: def.backgroundMaterial },
105
+ ...parentWindow && { parent: parentWindow },
106
+ webPreferences: {
107
+ preload: this.preloadPath,
108
+ contextIsolation: true,
109
+ sandbox: true,
110
+ nodeIntegration: false
111
+ },
112
+ ...extraOptions
113
+ };
114
+ const win = new this.BrowserWindowClass(options);
115
+ if (savedBounds?.isMaximized) {
116
+ win.maximize();
117
+ } else if (savedBounds?.isFullScreen) {
118
+ win.setFullScreen(true);
119
+ }
120
+ if (deferShow) {
121
+ win.show();
122
+ }
123
+ if (this.rendererUrl) {
124
+ await win.loadURL(this.rendererUrl);
125
+ } else if (this.rendererDir) {
126
+ await win.loadFile(join(this.rendererDir, "index.html"));
127
+ }
128
+ if (this.shell) {
129
+ const shellRef = this.shell;
130
+ win.webContents.setWindowOpenHandler(({ url }) => {
131
+ if (url.startsWith("http://") || url.startsWith("https://")) {
132
+ shellRef.openExternal(url);
133
+ }
134
+ return { action: "deny" };
135
+ });
136
+ }
137
+ this.windows.set(windowId, win);
138
+ logger.debug(`Created window "${windowId}"`);
139
+ if (useRememberBounds) {
140
+ const captureNormalBounds = () => {
141
+ if (!win.isMaximized() && !win.isFullScreen()) {
142
+ const rect = win.getBounds();
143
+ this.stateStore.updateBoundsDebounced(windowId, {
144
+ ...rect,
145
+ isMaximized: false,
146
+ isFullScreen: false
147
+ });
148
+ }
149
+ };
150
+ win.on("move", captureNormalBounds);
151
+ win.on("resize", captureNormalBounds);
152
+ win.on("close", () => {
153
+ const rect = win.getBounds();
154
+ this.stateStore.saveBoundsSync(windowId, {
155
+ ...rect,
156
+ isMaximized: win.isMaximized(),
157
+ isFullScreen: win.isFullScreen()
158
+ });
159
+ });
160
+ }
161
+ win.on("closed", () => {
162
+ this.windows.delete(windowId);
163
+ logger.debug(`Window "${windowId}" closed`);
164
+ });
165
+ return win;
166
+ }
167
+ /**
168
+ * Get a window by ID.
169
+ */
170
+ getWindow(windowId) {
171
+ const win = this.windows.get(windowId);
172
+ if (win && !win.isDestroyed()) return win;
173
+ return void 0;
174
+ }
175
+ /**
176
+ * Close a window by ID.
177
+ */
178
+ closeWindow(windowId) {
179
+ const win = this.windows.get(windowId);
180
+ if (win && !win.isDestroyed()) {
181
+ win.close();
182
+ }
183
+ }
184
+ /**
185
+ * Focus a window by ID.
186
+ */
187
+ focusWindow(windowId) {
188
+ const win = this.windows.get(windowId);
189
+ if (win && !win.isDestroyed()) {
190
+ win.show();
191
+ win.focus();
192
+ }
193
+ }
194
+ /**
195
+ * Send an event to all open windows.
196
+ */
197
+ broadcastToAll(channel, ...data) {
198
+ for (const [, win] of this.windows) {
199
+ if (!win.isDestroyed()) {
200
+ win.webContents.send(channel, ...data);
201
+ }
202
+ }
203
+ }
204
+ /**
205
+ * Get all open window IDs.
206
+ */
207
+ getOpenWindowIds() {
208
+ return Array.from(this.windows.entries()).filter(([, win]) => !win.isDestroyed()).map(([id]) => id);
209
+ }
210
+ /**
211
+ * Close all windows.
212
+ */
213
+ closeAll() {
214
+ for (const [, win] of this.windows) {
215
+ if (!win.isDestroyed()) {
216
+ win.destroy();
217
+ }
218
+ }
219
+ this.windows.clear();
220
+ logger.debug("All windows closed");
221
+ }
222
+ /**
223
+ * Handle the __window IPC channel.
224
+ */
225
+ async handleWindowOperation(data) {
226
+ switch (data.action) {
227
+ case "open":
228
+ if (!data.windowId) throw new Error("windowId required for open");
229
+ await this.createWindow(data.windowId, data.options);
230
+ break;
231
+ case "close":
232
+ if (data.windowId) {
233
+ this.closeWindow(data.windowId);
234
+ }
235
+ break;
236
+ case "focus":
237
+ if (!data.windowId) throw new Error("windowId required for focus");
238
+ this.focusWindow(data.windowId);
239
+ break;
240
+ default:
241
+ throw new Error(`Unknown window action: ${data.action}`);
242
+ }
243
+ }
244
+ /**
245
+ * Handle the __contextMenu IPC channel.
246
+ *
247
+ * Receives `{ action: 'show', items, position }` from the renderer's
248
+ * `use:contextMenu` action. Checks the window's contextMenu config:
249
+ * - **native**: builds Electron Menu from items, pops it. String actions
250
+ * are handled on main. Callback items send `__contextMenu:callback`.
251
+ * - **custom**: forwards items + position as `__contextMenu:show` push event.
252
+ */
253
+ handleContextMenu(windowId, data) {
254
+ const win = this.windows.get(windowId);
255
+ if (!win || win.isDestroyed()) return;
256
+ const def = this.windowDefs[windowId];
257
+ if (!def) return;
258
+ if (data.action !== "show") return;
259
+ if (def.contextMenu === "native") {
260
+ this.showNativeContextMenu(win, data.items);
261
+ } else if (def.contextMenu === "custom") {
262
+ win.webContents.send("__event:__contextMenu:show", {
263
+ items: data.items,
264
+ position: data.position
265
+ });
266
+ }
267
+ }
268
+ /**
269
+ * Build and show a native Electron context menu from serialized items.
270
+ */
271
+ showNativeContextMenu(win, items) {
272
+ if (!this.MenuClass) return;
273
+ const template = items.map((item) => {
274
+ if (item.type === "separator") {
275
+ return { label: "", click: () => {
276
+ }, type: "separator", enabled: true };
277
+ }
278
+ return {
279
+ label: item.label ?? "",
280
+ enabled: item.disabled !== true,
281
+ click: () => {
282
+ if (item._callbackId) {
283
+ win.webContents.send("__event:__contextMenu:callback", item._callbackId);
284
+ } else if (item.action) {
285
+ this.executeMenuAction(item.action, item.data, win);
286
+ }
287
+ }
288
+ };
289
+ });
290
+ if (template.length === 0) return;
291
+ const menu = this.MenuClass.buildFromTemplate(template);
292
+ menu.popup({ window: win });
293
+ }
294
+ /**
295
+ * Execute a built-in menu action on the main process.
296
+ */
297
+ executeMenuAction(action, data, win) {
298
+ switch (action) {
299
+ case "openExternal":
300
+ if (data && this.shell) {
301
+ this.shell.openExternal(data);
302
+ }
303
+ break;
304
+ case "copyText":
305
+ if (data && this.clipboard) {
306
+ this.clipboard.writeText(data);
307
+ }
308
+ break;
309
+ case "copy":
310
+ win.webContents.send("__contextMenu:exec", "copy");
311
+ break;
312
+ case "cut":
313
+ win.webContents.send("__contextMenu:exec", "cut");
314
+ break;
315
+ case "paste":
316
+ win.webContents.send("__contextMenu:exec", "paste");
317
+ break;
318
+ case "selectAll":
319
+ win.webContents.send("__contextMenu:exec", "selectAll");
320
+ break;
321
+ default:
322
+ win.webContents.send("__contextMenu:action", action, data);
323
+ break;
324
+ }
325
+ }
326
+ }
327
+ export {
328
+ WindowManager
329
+ };
330
+ //# sourceMappingURL=window_manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/window/window_manager.ts"],"sourcesContent":["import { join } from 'path';\nimport type { WindowDef } from '../types/index.js';\nimport type { ContextMenuItem } from '../types/context_menu.js';\nimport { getLogger } from '@noego/logger';\nimport { WindowStateStore } from './window_state_store.js';\nimport type { ScreenLike } from './window_state_store.js';\n\nconst logger = getLogger('wood:window');\n\n/** Subset of Electron BrowserWindow used by WindowManager (avoids compile-time electron dep). */\nexport interface BrowserWindowLike {\n loadURL(url: string): Promise<void>;\n loadFile(filePath: string): Promise<void>;\n close(): void;\n focus(): void;\n show(): void;\n destroy(): void;\n isDestroyed(): boolean;\n webContents: {\n send(channel: string, ...args: unknown[]): void;\n reload(): void;\n setWindowOpenHandler(handler: (details: { url: string }) => { action: 'deny' | 'allow' }): void;\n on(event: string, handler: (...args: any[]) => void): void;\n };\n on(event: string, handler: (...args: unknown[]) => void): void;\n getBounds(): { x: number; y: number; width: number; height: number };\n isMaximized(): boolean;\n isFullScreen(): boolean;\n maximize(): void;\n setFullScreen(flag: boolean): void;\n}\n\nexport interface BrowserWindowConstructor {\n new (options: Record<string, unknown>): BrowserWindowLike;\n getAllWindows(): BrowserWindowLike[];\n}\n\n/** Minimal shell interface for opening external URLs. */\nexport interface ShellLike {\n openExternal(url: string): Promise<unknown>;\n}\n\n/** Minimal clipboard interface for copying text. */\nexport interface ClipboardLike {\n writeText(text: string): void;\n}\n\n/** Minimal Menu interface for right-click context menus. */\nexport interface MenuLike {\n popup(options?: { window?: BrowserWindowLike }): void;\n}\n\nexport interface MenuConstructorLike {\n buildFromTemplate(template: Array<{ label: string; click: () => void; type?: 'separator'; enabled?: boolean }>): MenuLike;\n}\n\nexport class WindowManager {\n private windows = new Map<string, BrowserWindowLike>();\n private windowDefs: Record<string, WindowDef>;\n private BrowserWindowClass: BrowserWindowConstructor | null = null;\n private preloadPath: string;\n private rendererUrl?: string;\n private rendererDir?: string;\n private shell: ShellLike | null = null;\n private clipboard: ClipboardLike | null = null;\n private MenuClass: MenuConstructorLike | null = null;\n private stateStore = new WindowStateStore();\n\n constructor(options: {\n windowDefs: Record<string, WindowDef>;\n preloadPath: string;\n rendererUrl?: string;\n rendererDir?: string;\n applicationRoot?: string;\n }) {\n this.windowDefs = options.windowDefs;\n this.preloadPath = options.preloadPath;\n this.rendererUrl = options.rendererUrl;\n this.rendererDir = options.rendererDir;\n if (options.applicationRoot) {\n this.stateStore.setApplicationRoot(options.applicationRoot);\n }\n }\n\n /**\n * Set the BrowserWindow class (from electron).\n * Called at runtime so we don't need electron at compile time.\n */\n setBrowserWindow(BW: BrowserWindowConstructor): void {\n this.BrowserWindowClass = BW;\n }\n\n /**\n * Set the shell module (from electron) for opening external URLs.\n */\n setShell(shell: ShellLike): void {\n this.shell = shell;\n }\n\n /**\n * Set the clipboard module (from electron) for copying text.\n */\n setClipboard(clipboard: ClipboardLike): void {\n this.clipboard = clipboard;\n }\n\n /**\n * Set the Menu class (from electron) for context menus.\n */\n setMenu(menu: MenuConstructorLike): void {\n this.MenuClass = menu;\n }\n\n /**\n * Set the user data path for persisting window state.\n */\n setUserDataPath(path: string): void {\n this.stateStore.setUserDataPath(path);\n }\n\n /**\n * Set the application root directory for Wood JSON state persistence.\n */\n setApplicationRoot(path: string): void {\n this.stateStore.setApplicationRoot(path);\n }\n\n /**\n * Set the screen module (from electron) for display validation.\n */\n setScreen(screen: ScreenLike): void {\n this.stateStore.setScreen(screen);\n }\n\n /**\n * Create a window from its definition.\n */\n async createWindow(windowId: string, extraOptions?: Record<string, unknown>): Promise<BrowserWindowLike> {\n if (!this.BrowserWindowClass) {\n throw new Error('BrowserWindow class not set. Call setBrowserWindow() first.');\n }\n\n const def = this.windowDefs[windowId];\n if (!def) {\n throw new Error(`Window \"${windowId}\" not defined in config`);\n }\n\n // If the window already exists and isn't destroyed, just focus it\n const existing = this.windows.get(windowId);\n if (existing && !existing.isDestroyed()) {\n existing.focus();\n return existing;\n }\n\n // Resolve parent window\n let parentWindow: BrowserWindowLike | undefined;\n if (def.parent) {\n parentWindow = this.windows.get(def.parent);\n }\n\n // Resolve saved bounds for rememberBounds\n const useRememberBounds = def.rememberBounds === true;\n const savedBounds = useRememberBounds ? this.stateStore.getBounds(windowId) : null;\n\n // Determine if we should defer showing (anti-flicker for restored windows)\n const defShow = def.show ?? true;\n const deferShow = useRememberBounds && savedBounds != null && defShow && extraOptions?.show !== false;\n\n // Build BrowserWindow options from WindowDef\n const options: Record<string, unknown> = {\n title: def.title,\n width: savedBounds?.width ?? def.width,\n height: savedBounds?.height ?? def.height,\n ...(savedBounds && { x: savedBounds.x, y: savedBounds.y }),\n frame: def.frame ?? true,\n transparent: def.transparent ?? false,\n resizable: def.resizable ?? true,\n alwaysOnTop: def.alwaysOnTop ?? false,\n show: deferShow ? false : defShow,\n modal: def.modal ?? false,\n ...(def.minWidth != null && { minWidth: def.minWidth }),\n ...(def.minHeight != null && { minHeight: def.minHeight }),\n ...(def.maxWidth != null && { maxWidth: def.maxWidth }),\n ...(def.maxHeight != null && { maxHeight: def.maxHeight }),\n ...(def.vibrancy && { vibrancy: def.vibrancy }),\n ...(def.backgroundMaterial && { backgroundMaterial: def.backgroundMaterial }),\n ...(parentWindow && { parent: parentWindow }),\n webPreferences: {\n preload: this.preloadPath,\n contextIsolation: true,\n sandbox: true,\n nodeIntegration: false,\n },\n ...extraOptions,\n };\n\n const win = new this.BrowserWindowClass(options);\n\n // Restore maximized/fullscreen state\n if (savedBounds?.isMaximized) {\n win.maximize();\n } else if (savedBounds?.isFullScreen) {\n win.setFullScreen(true);\n }\n\n // Show window after restoring state (anti-flicker)\n if (deferShow) {\n win.show();\n }\n\n // Load content\n if (this.rendererUrl) {\n await win.loadURL(this.rendererUrl);\n } else if (this.rendererDir) {\n await win.loadFile(join(this.rendererDir, 'index.html'));\n }\n\n // Open http/https links in system browser instead of inside Electron\n if (this.shell) {\n const shellRef = this.shell;\n win.webContents.setWindowOpenHandler(({ url }) => {\n if (url.startsWith('http://') || url.startsWith('https://')) {\n shellRef.openExternal(url);\n }\n return { action: 'deny' };\n });\n }\n\n // Track window\n this.windows.set(windowId, win);\n logger.debug(`Created window \"${windowId}\"`);\n\n // Persist bounds on move/resize/close\n if (useRememberBounds) {\n const captureNormalBounds = () => {\n if (!win.isMaximized() && !win.isFullScreen()) {\n const rect = win.getBounds();\n this.stateStore.updateBoundsDebounced(windowId, {\n ...rect,\n isMaximized: false,\n isFullScreen: false,\n });\n }\n };\n\n win.on('move', captureNormalBounds);\n win.on('resize', captureNormalBounds);\n\n win.on('close', () => {\n const rect = win.getBounds();\n this.stateStore.saveBoundsSync(windowId, {\n ...rect,\n isMaximized: win.isMaximized(),\n isFullScreen: win.isFullScreen(),\n });\n });\n }\n\n // Cleanup on close\n win.on('closed', () => {\n this.windows.delete(windowId);\n logger.debug(`Window \"${windowId}\" closed`);\n });\n\n return win;\n }\n\n /**\n * Get a window by ID.\n */\n getWindow(windowId: string): BrowserWindowLike | undefined {\n const win = this.windows.get(windowId);\n if (win && !win.isDestroyed()) return win;\n return undefined;\n }\n\n /**\n * Close a window by ID.\n */\n closeWindow(windowId: string): void {\n const win = this.windows.get(windowId);\n if (win && !win.isDestroyed()) {\n win.close();\n }\n }\n\n /**\n * Focus a window by ID.\n */\n focusWindow(windowId: string): void {\n const win = this.windows.get(windowId);\n if (win && !win.isDestroyed()) {\n win.show();\n win.focus();\n }\n }\n\n /**\n * Send an event to all open windows.\n */\n broadcastToAll(channel: string, ...data: unknown[]): void {\n for (const [, win] of this.windows) {\n if (!win.isDestroyed()) {\n win.webContents.send(channel, ...data);\n }\n }\n }\n\n /**\n * Get all open window IDs.\n */\n getOpenWindowIds(): string[] {\n return Array.from(this.windows.entries())\n .filter(([, win]) => !win.isDestroyed())\n .map(([id]) => id);\n }\n\n /**\n * Close all windows.\n */\n closeAll(): void {\n for (const [, win] of this.windows) {\n if (!win.isDestroyed()) {\n win.destroy();\n }\n }\n this.windows.clear();\n logger.debug('All windows closed');\n }\n\n /**\n * Handle the __window IPC channel.\n */\n async handleWindowOperation(data: {\n action: string;\n windowId?: string;\n options?: Record<string, unknown>;\n }): Promise<void> {\n switch (data.action) {\n case 'open':\n if (!data.windowId) throw new Error('windowId required for open');\n await this.createWindow(data.windowId, data.options);\n break;\n case 'close':\n if (data.windowId) {\n this.closeWindow(data.windowId);\n }\n break;\n case 'focus':\n if (!data.windowId) throw new Error('windowId required for focus');\n this.focusWindow(data.windowId);\n break;\n default:\n throw new Error(`Unknown window action: ${data.action}`);\n }\n }\n\n /**\n * Handle the __contextMenu IPC channel.\n *\n * Receives `{ action: 'show', items, position }` from the renderer's\n * `use:contextMenu` action. Checks the window's contextMenu config:\n * - **native**: builds Electron Menu from items, pops it. String actions\n * are handled on main. Callback items send `__contextMenu:callback`.\n * - **custom**: forwards items + position as `__contextMenu:show` push event.\n */\n handleContextMenu(\n windowId: string,\n data: { action: string; items: ContextMenuItem[]; position: { x: number; y: number } },\n ): void {\n const win = this.windows.get(windowId);\n if (!win || win.isDestroyed()) return;\n\n const def = this.windowDefs[windowId];\n if (!def) return;\n\n if (data.action !== 'show') return;\n\n if (def.contextMenu === 'native') {\n this.showNativeContextMenu(win, data.items);\n } else if (def.contextMenu === 'custom') {\n win.webContents.send('__event:__contextMenu:show', {\n items: data.items,\n position: data.position,\n });\n }\n }\n\n /**\n * Build and show a native Electron context menu from serialized items.\n */\n private showNativeContextMenu(win: BrowserWindowLike, items: ContextMenuItem[]): void {\n if (!this.MenuClass) return;\n\n const template = items.map(item => {\n if (item.type === 'separator') {\n return { label: '', click: () => {}, type: 'separator' as const, enabled: true };\n }\n return {\n label: item.label ?? '',\n enabled: item.disabled !== true,\n click: () => {\n if (item._callbackId) {\n win.webContents.send('__event:__contextMenu:callback', item._callbackId);\n } else if (item.action) {\n this.executeMenuAction(item.action, item.data, win);\n }\n },\n };\n });\n\n if (template.length === 0) return;\n\n const menu = this.MenuClass.buildFromTemplate(template);\n menu.popup({ window: win });\n }\n\n /**\n * Execute a built-in menu action on the main process.\n */\n private executeMenuAction(action: string, data: string | undefined, win: BrowserWindowLike): void {\n switch (action) {\n case 'openExternal':\n if (data && this.shell) {\n this.shell.openExternal(data);\n }\n break;\n case 'copyText':\n if (data && this.clipboard) {\n this.clipboard.writeText(data);\n }\n break;\n case 'copy':\n win.webContents.send('__contextMenu:exec', 'copy');\n break;\n case 'cut':\n win.webContents.send('__contextMenu:exec', 'cut');\n break;\n case 'paste':\n win.webContents.send('__contextMenu:exec', 'paste');\n break;\n case 'selectAll':\n win.webContents.send('__contextMenu:exec', 'selectAll');\n break;\n default:\n // Unknown action — dispatch to renderer\n win.webContents.send('__contextMenu:action', action, data);\n break;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var window_state_store_exports = {};
20
+ __export(window_state_store_exports, {
21
+ WindowStateStore: () => WindowStateStore
22
+ });
23
+ module.exports = __toCommonJS(window_state_store_exports);
24
+ var import_fs = require("fs");
25
+ var import_path = require("path");
26
+ var import_logger = require("@noego/logger");
27
+ var import_application_root = require("../runtime/application_root.cjs");
28
+ const logger = (0, import_logger.getLogger)("wood:window-state");
29
+ class WindowStateStore {
30
+ constructor() {
31
+ this.state = {};
32
+ this.filePath = null;
33
+ this.screen = null;
34
+ this.debounceTimers = /* @__PURE__ */ new Map();
35
+ this.ensureConfigured();
36
+ }
37
+ setApplicationRoot(path) {
38
+ this.filePath = (0, import_path.join)(path, "window-state.json");
39
+ this.load();
40
+ }
41
+ setUserDataPath(path) {
42
+ this.setApplicationRoot((0, import_path.join)(path, "wood-settings"));
43
+ }
44
+ setScreen(screen) {
45
+ this.screen = screen;
46
+ }
47
+ getBounds(windowId) {
48
+ this.ensureConfigured();
49
+ const bounds = this.state[windowId];
50
+ if (!bounds) return null;
51
+ if (!this.isVisibleOnAnyDisplay(bounds)) return null;
52
+ return bounds;
53
+ }
54
+ updateBoundsDebounced(windowId, bounds) {
55
+ this.ensureConfigured();
56
+ this.state[windowId] = bounds;
57
+ const existing = this.debounceTimers.get(windowId);
58
+ if (existing) clearTimeout(existing);
59
+ this.debounceTimers.set(
60
+ windowId,
61
+ setTimeout(() => {
62
+ this.debounceTimers.delete(windowId);
63
+ this.save();
64
+ }, 300)
65
+ );
66
+ }
67
+ saveBoundsSync(windowId, bounds) {
68
+ this.ensureConfigured();
69
+ const existing = this.debounceTimers.get(windowId);
70
+ if (existing) {
71
+ clearTimeout(existing);
72
+ this.debounceTimers.delete(windowId);
73
+ }
74
+ this.state[windowId] = bounds;
75
+ this.save();
76
+ }
77
+ ensureConfigured() {
78
+ if (this.filePath) {
79
+ return;
80
+ }
81
+ const root = (0, import_application_root.getApplicationRoot)();
82
+ if (root) {
83
+ this.setApplicationRoot(root);
84
+ }
85
+ }
86
+ load() {
87
+ if (!this.filePath) return;
88
+ try {
89
+ const raw = (0, import_fs.readFileSync)(this.filePath, "utf-8");
90
+ this.state = JSON.parse(raw);
91
+ logger.debug(`Loaded window state from ${this.filePath}`);
92
+ } catch {
93
+ this.state = {};
94
+ }
95
+ }
96
+ save() {
97
+ if (!this.filePath) return;
98
+ try {
99
+ (0, import_fs.mkdirSync)((0, import_path.dirname)(this.filePath), { recursive: true });
100
+ (0, import_fs.writeFileSync)(this.filePath, JSON.stringify(this.state, null, 2), "utf-8");
101
+ } catch (err) {
102
+ logger.warn(`Failed to save window state: ${err}`);
103
+ }
104
+ }
105
+ isVisibleOnAnyDisplay(bounds) {
106
+ if (!this.screen) return true;
107
+ const displays = this.screen.getAllDisplays();
108
+ if (displays.length === 0) return true;
109
+ const MIN_OVERLAP = 100;
110
+ for (const display of displays) {
111
+ const db = display.bounds;
112
+ const overlapX = Math.max(
113
+ 0,
114
+ Math.min(bounds.x + bounds.width, db.x + db.width) - Math.max(bounds.x, db.x)
115
+ );
116
+ const overlapY = Math.max(
117
+ 0,
118
+ Math.min(bounds.y + bounds.height, db.y + db.height) - Math.max(bounds.y, db.y)
119
+ );
120
+ if (overlapX >= MIN_OVERLAP && overlapY >= MIN_OVERLAP) return true;
121
+ }
122
+ return false;
123
+ }
124
+ }
125
+ // Annotate the CommonJS export names for ESM import in node:
126
+ 0 && (module.exports = {
127
+ WindowStateStore
128
+ });
129
+ //# sourceMappingURL=window_state_store.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/window/window_state_store.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { getLogger } from '@noego/logger';\nimport { getApplicationRoot } from '../runtime/application_root.cjs';\n\nconst logger = getLogger('wood:window-state');\n\nexport interface WindowBounds {\n x: number;\n y: number;\n width: number;\n height: number;\n isMaximized: boolean;\n isFullScreen: boolean;\n}\n\nexport type WindowStateFile = Record<string, WindowBounds>;\n\n/** DI interface for Electron's `screen` module. */\nexport interface ScreenLike {\n getAllDisplays(): Array<{ bounds: { x: number; y: number; width: number; height: number } }>;\n}\n\nexport class WindowStateStore {\n private state: WindowStateFile = {};\n private filePath: string | null = null;\n private screen: ScreenLike | null = null;\n private debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n constructor() {\n this.ensureConfigured();\n }\n\n setApplicationRoot(path: string): void {\n this.filePath = join(path, 'window-state.json');\n this.load();\n }\n\n setUserDataPath(path: string): void {\n this.setApplicationRoot(join(path, 'wood-settings'));\n }\n\n setScreen(screen: ScreenLike): void {\n this.screen = screen;\n }\n\n getBounds(windowId: string): WindowBounds | null {\n this.ensureConfigured();\n\n const bounds = this.state[windowId];\n if (!bounds) return null;\n if (!this.isVisibleOnAnyDisplay(bounds)) return null;\n return bounds;\n }\n\n updateBoundsDebounced(windowId: string, bounds: WindowBounds): void {\n this.ensureConfigured();\n\n this.state[windowId] = bounds;\n\n const existing = this.debounceTimers.get(windowId);\n if (existing) clearTimeout(existing);\n\n this.debounceTimers.set(\n windowId,\n setTimeout(() => {\n this.debounceTimers.delete(windowId);\n this.save();\n }, 300),\n );\n }\n\n saveBoundsSync(windowId: string, bounds: WindowBounds): void {\n this.ensureConfigured();\n\n // Flush any pending debounce for this window\n const existing = this.debounceTimers.get(windowId);\n if (existing) {\n clearTimeout(existing);\n this.debounceTimers.delete(windowId);\n }\n\n this.state[windowId] = bounds;\n this.save();\n }\n\n private ensureConfigured(): void {\n if (this.filePath) {\n return;\n }\n\n const root = getApplicationRoot();\n if (root) {\n this.setApplicationRoot(root);\n }\n }\n\n private load(): void {\n if (!this.filePath) return;\n try {\n const raw = readFileSync(this.filePath, 'utf-8');\n this.state = JSON.parse(raw) as WindowStateFile;\n logger.debug(`Loaded window state from ${this.filePath}`);\n } catch {\n this.state = {};\n }\n }\n\n private save(): void {\n if (!this.filePath) return;\n try {\n mkdirSync(dirname(this.filePath), { recursive: true });\n writeFileSync(this.filePath, JSON.stringify(this.state, null, 2), 'utf-8');\n } catch (err) {\n logger.warn(`Failed to save window state: ${err}`);\n }\n }\n\n private isVisibleOnAnyDisplay(bounds: WindowBounds): boolean {\n if (!this.screen) return true;\n\n const displays = this.screen.getAllDisplays();\n if (displays.length === 0) return true;\n\n const MIN_OVERLAP = 100;\n\n for (const display of displays) {\n const db = display.bounds;\n const overlapX = Math.max(\n 0,\n Math.min(bounds.x + bounds.width, db.x + db.width) - Math.max(bounds.x, db.x),\n );\n const overlapY = Math.max(\n 0,\n Math.min(bounds.y + bounds.height, db.y + db.height) - Math.max(bounds.y, db.y),\n );\n if (overlapX >= MIN_OVERLAP && overlapY >= MIN_OVERLAP) return true;\n }\n\n return false;\n }\n}\n"],"mappings":"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","names":[]}