@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.
- package/README.md +118 -42
- package/dist/bridge/backend_bridge.cjs.map +1 -1
- package/dist/bridge/backend_bridge.js.map +1 -1
- package/dist/client/index.cjs +78 -21
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +18 -3
- package/dist/client/index.d.ts +18 -3
- package/dist/client/index.js +80 -22
- package/dist/client/index.js.map +1 -1
- package/dist/client/renderer_log_transport.cjs +151 -0
- package/dist/client/renderer_log_transport.cjs.map +1 -0
- package/dist/client/renderer_log_transport.d.cts +54 -0
- package/dist/client/renderer_log_transport.d.ts +54 -0
- package/dist/client/renderer_log_transport.js +123 -0
- package/dist/client/renderer_log_transport.js.map +1 -0
- package/dist/codegen/controller_registration_generator.cjs +13 -2
- package/dist/codegen/controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/controller_registration_generator.d.cts +12 -1
- package/dist/codegen/controller_registration_generator.d.ts +12 -1
- package/dist/codegen/controller_registration_generator.js +10 -1
- package/dist/codegen/controller_registration_generator.js.map +1 -1
- package/dist/codegen/index.d.cts +1 -0
- package/dist/codegen/index.d.ts +1 -0
- package/dist/codegen/preload_generator.cjs +13 -6
- package/dist/codegen/preload_generator.cjs.map +1 -1
- package/dist/codegen/preload_generator.d.cts +11 -2
- package/dist/codegen/preload_generator.d.ts +11 -2
- package/dist/codegen/preload_generator.js +13 -6
- package/dist/codegen/preload_generator.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +78 -42
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +78 -42
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +1 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +1 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/config/config_parser.cjs +95 -4
- package/dist/config/config_parser.cjs.map +1 -1
- package/dist/config/config_parser.d.cts +10 -2
- package/dist/config/config_parser.d.ts +10 -2
- package/dist/config/config_parser.js +92 -3
- package/dist/config/config_parser.js.map +1 -1
- package/dist/config/index.cjs +6 -2
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.d.cts +2 -2
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.js +8 -2
- package/dist/config/index.js.map +1 -1
- package/dist/controller/controller_resolver.cjs +51 -3
- package/dist/controller/controller_resolver.cjs.map +1 -1
- package/dist/controller/controller_resolver.d.cts +27 -4
- package/dist/controller/controller_resolver.d.ts +27 -4
- package/dist/controller/controller_resolver.js +48 -2
- package/dist/controller/controller_resolver.js.map +1 -1
- package/dist/controller/index.cjs +6 -2
- package/dist/controller/index.cjs.map +1 -1
- package/dist/controller/index.d.cts +1 -1
- package/dist/controller/index.d.ts +1 -1
- package/dist/controller/index.js +4 -2
- package/dist/controller/index.js.map +1 -1
- package/dist/dev/wood_dev_server.cjs +4 -1
- package/dist/dev/wood_dev_server.cjs.map +1 -1
- package/dist/dev/wood_dev_server.js +5 -2
- package/dist/dev/wood_dev_server.js.map +1 -1
- package/dist/dev/yaml_watcher.cjs +1 -1
- package/dist/dev/yaml_watcher.cjs.map +1 -1
- package/dist/dev/yaml_watcher.d.cts +4 -0
- package/dist/dev/yaml_watcher.d.ts +4 -0
- package/dist/dev/yaml_watcher.js +1 -1
- package/dist/dev/yaml_watcher.js.map +1 -1
- package/dist/frontend/frontend_lifecycle.cjs +74 -0
- package/dist/frontend/frontend_lifecycle.cjs.map +1 -0
- package/dist/frontend/frontend_lifecycle.d.cts +50 -0
- package/dist/frontend/frontend_lifecycle.d.ts +50 -0
- package/dist/frontend/frontend_lifecycle.js +50 -0
- package/dist/frontend/frontend_lifecycle.js.map +1 -0
- package/dist/frontend/frontend_page.cjs +122 -0
- package/dist/frontend/frontend_page.cjs.map +1 -0
- package/dist/frontend/frontend_page.d.cts +62 -0
- package/dist/frontend/frontend_page.d.ts +62 -0
- package/dist/frontend/frontend_page.js +98 -0
- package/dist/frontend/frontend_page.js.map +1 -0
- package/dist/frontend/frontend_surface.cjs +249 -0
- package/dist/frontend/frontend_surface.cjs.map +1 -0
- package/dist/frontend/frontend_surface.d.cts +64 -0
- package/dist/frontend/frontend_surface.d.ts +64 -0
- package/dist/frontend/frontend_surface.js +224 -0
- package/dist/frontend/frontend_surface.js.map +1 -0
- package/dist/frontend/index.cjs +52 -0
- package/dist/frontend/index.cjs.map +1 -0
- package/dist/frontend/index.d.cts +10 -0
- package/dist/frontend/index.d.ts +10 -0
- package/dist/frontend/index.js +19 -0
- package/dist/frontend/index.js.map +1 -0
- package/dist/frontend/page_catalog.cjs +135 -0
- package/dist/frontend/page_catalog.cjs.map +1 -0
- package/dist/frontend/page_catalog.d.cts +56 -0
- package/dist/frontend/page_catalog.d.ts +56 -0
- package/dist/frontend/page_catalog.js +108 -0
- package/dist/frontend/page_catalog.js.map +1 -0
- package/dist/frontend/tracked_transport.cjs +55 -0
- package/dist/frontend/tracked_transport.cjs.map +1 -0
- package/dist/frontend/tracked_transport.d.cts +36 -0
- package/dist/frontend/tracked_transport.d.ts +36 -0
- package/dist/frontend/tracked_transport.js +31 -0
- package/dist/frontend/tracked_transport.js.map +1 -0
- package/dist/frontend/work_registry.cjs +153 -0
- package/dist/frontend/work_registry.cjs.map +1 -0
- package/dist/frontend/work_registry.d.cts +70 -0
- package/dist/frontend/work_registry.d.ts +70 -0
- package/dist/frontend/work_registry.js +128 -0
- package/dist/frontend/work_registry.js.map +1 -0
- package/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -7
- package/dist/index.d.ts +10 -7
- package/dist/index.js +27 -4
- package/dist/index.js.map +1 -1
- package/dist/main/index.cjs +10 -0
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +14 -2
- package/dist/main/index.d.ts +14 -2
- package/dist/main/index.js +16 -0
- package/dist/main/index.js.map +1 -1
- package/dist/middleware/middleware_resolver.cjs +22 -1
- package/dist/middleware/middleware_resolver.cjs.map +1 -1
- package/dist/middleware/middleware_resolver.d.cts +13 -1
- package/dist/middleware/middleware_resolver.d.ts +13 -1
- package/dist/middleware/middleware_resolver.js +22 -1
- package/dist/middleware/middleware_resolver.js.map +1 -1
- package/dist/navigation/index.cjs +3 -0
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +25 -1
- package/dist/navigation/index.d.ts +25 -1
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/index.js.map +1 -1
- package/dist/{middleware/__fixtures__/middleware/auth.cjs → navigation/layout_preservation.cjs} +18 -20
- package/dist/navigation/layout_preservation.cjs.map +1 -0
- package/dist/navigation/layout_preservation.d.cts +2 -0
- package/dist/navigation/layout_preservation.d.ts +2 -0
- package/dist/navigation/layout_preservation.js +18 -0
- package/dist/navigation/layout_preservation.js.map +1 -0
- package/dist/parser/index.cjs +2 -0
- package/dist/parser/index.cjs.map +1 -1
- package/dist/parser/index.d.cts +1 -1
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/index.js +2 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/operations_parser.cjs +6 -0
- package/dist/parser/operations_parser.cjs.map +1 -1
- package/dist/parser/operations_parser.d.cts +9 -2
- package/dist/parser/operations_parser.d.ts +9 -2
- package/dist/parser/operations_parser.js +5 -0
- package/dist/parser/operations_parser.js.map +1 -1
- package/dist/parser/views_parser.cjs.map +1 -1
- package/dist/parser/views_parser.js.map +1 -1
- package/dist/router/index.d.cts +1 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/router/wood_router.cjs +35 -3
- package/dist/router/wood_router.cjs.map +1 -1
- package/dist/router/wood_router.d.cts +15 -0
- package/dist/router/wood_router.d.ts +15 -0
- package/dist/router/wood_router.js +36 -4
- package/dist/router/wood_router.js.map +1 -1
- package/dist/runtime/get_container.cjs +9 -34
- package/dist/runtime/get_container.cjs.map +1 -1
- package/dist/runtime/get_container.d.cts +24 -4
- package/dist/runtime/get_container.d.ts +24 -4
- package/dist/runtime/get_container.js +8 -23
- package/dist/runtime/get_container.js.map +1 -1
- package/dist/runtime/index.cjs +9 -0
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +5 -2
- package/dist/runtime/index.d.ts +5 -2
- package/dist/runtime/index.js +10 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/renderer_config_extension.cjs +50 -0
- package/dist/runtime/renderer_config_extension.cjs.map +1 -0
- package/dist/runtime/renderer_config_extension.d.cts +19 -0
- package/dist/runtime/renderer_config_extension.d.ts +19 -0
- package/dist/runtime/renderer_config_extension.js +24 -0
- package/dist/runtime/renderer_config_extension.js.map +1 -0
- package/dist/runtime/renderer_log_batch_receiver.cjs +73 -0
- package/dist/runtime/renderer_log_batch_receiver.cjs.map +1 -0
- package/dist/runtime/renderer_log_batch_receiver.d.cts +29 -0
- package/dist/runtime/renderer_log_batch_receiver.d.ts +29 -0
- package/dist/runtime/renderer_log_batch_receiver.js +48 -0
- package/dist/runtime/renderer_log_batch_receiver.js.map +1 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +1 -1
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +1 -1
- package/dist/runtime/runtime.cjs +14 -0
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +2 -1
- package/dist/runtime/runtime.d.ts +2 -1
- package/dist/runtime/runtime.js +14 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/stick/index.cjs.map +1 -1
- package/dist/stick/index.js.map +1 -1
- package/dist/testing/browser.cjs +104 -23
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +8 -3
- package/dist/testing/browser.d.ts +8 -3
- package/dist/testing/browser.js +102 -22
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.cjs +28 -8
- package/dist/testing/create_controller_harness.cjs.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +17 -2
- package/dist/testing/create_controller_harness.d.ts +17 -2
- package/dist/testing/create_controller_harness.js +28 -8
- package/dist/testing/create_controller_harness.js.map +1 -1
- package/dist/testing/create_router_bridge.d.cts +1 -0
- package/dist/testing/create_router_bridge.d.ts +1 -0
- package/dist/testing/create_test_router.d.cts +1 -0
- package/dist/testing/create_test_router.d.ts +1 -0
- package/dist/testing/index.cjs +31 -0
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +20 -5
- package/dist/testing/index.d.ts +20 -5
- package/dist/testing/index.js +19 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/{controller/__fixtures__/controllers/not_a_class.cjs → testing/test_wood.cjs} +15 -7
- package/dist/testing/test_wood.cjs.map +1 -0
- package/dist/testing/test_wood.d.cts +16 -0
- package/dist/testing/test_wood.d.ts +16 -0
- package/dist/testing/test_wood.js +12 -0
- package/dist/testing/test_wood.js.map +1 -0
- package/dist/testing/test_wood_config.cjs +272 -0
- package/dist/testing/test_wood_config.cjs.map +1 -0
- package/dist/testing/test_wood_config.d.cts +111 -0
- package/dist/testing/test_wood_config.d.ts +111 -0
- package/dist/testing/test_wood_config.js +247 -0
- package/dist/testing/test_wood_config.js.map +1 -0
- package/dist/testing/wood_config_source.cjs +146 -0
- package/dist/testing/wood_config_source.cjs.map +1 -0
- package/dist/testing/wood_config_source.d.cts +36 -0
- package/dist/testing/wood_config_source.d.ts +36 -0
- package/dist/testing/wood_config_source.js +112 -0
- package/dist/testing/wood_config_source.js.map +1 -0
- package/dist/testing/wood_env_renderer.cjs +210 -0
- package/dist/testing/wood_env_renderer.cjs.map +1 -0
- package/dist/testing/wood_env_renderer.d.cts +74 -0
- package/dist/testing/wood_env_renderer.d.ts +74 -0
- package/dist/testing/wood_env_renderer.js +188 -0
- package/dist/testing/wood_env_renderer.js.map +1 -0
- package/dist/testing/wood_test_selection.cjs +94 -0
- package/dist/testing/wood_test_selection.cjs.map +1 -0
- package/dist/testing/wood_test_selection.d.cts +39 -0
- package/dist/testing/wood_test_selection.d.ts +39 -0
- package/dist/testing/wood_test_selection.js +68 -0
- package/dist/testing/wood_test_selection.js.map +1 -0
- package/dist/trace-testing/index.d.cts +1 -2
- package/dist/trace-testing/index.d.ts +1 -2
- package/dist/trace-testing/trace_recorder.cjs +1 -1
- package/dist/trace-testing/trace_recorder.cjs.map +1 -1
- package/dist/trace-testing/trace_recorder.d.cts +1 -2
- package/dist/trace-testing/trace_recorder.d.ts +1 -2
- package/dist/trace-testing/trace_recorder.js +1 -1
- package/dist/trace-testing/trace_recorder.js.map +1 -1
- package/dist/trace-transport/index.d.cts +1 -1
- package/dist/trace-transport/index.d.ts +1 -1
- package/dist/{trace_hub-Cob54qRx.d.cts → trace_hub-Cpo_nVze.d.cts} +21 -1
- package/dist/{trace_hub-Cob54qRx.d.ts → trace_hub-Cpo_nVze.d.ts} +21 -1
- package/dist/tracing/index.cjs +9 -2
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +3 -2
- package/dist/tracing/index.d.ts +3 -2
- package/dist/tracing/index.js +7 -1
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/renderer_trace_batch_host.d.cts +1 -1
- package/dist/tracing/renderer_trace_batch_host.d.ts +1 -1
- package/dist/tracing/renderer_trace_batch_transport.cjs +48 -6
- package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -1
- package/dist/tracing/renderer_trace_batch_transport.d.cts +17 -1
- package/dist/tracing/renderer_trace_batch_transport.d.ts +17 -1
- package/dist/tracing/renderer_trace_batch_transport.js +48 -6
- package/dist/tracing/renderer_trace_batch_transport.js.map +1 -1
- package/dist/tracing/trace_batch_adapter.cjs +110 -0
- package/dist/tracing/trace_batch_adapter.cjs.map +1 -0
- package/dist/tracing/trace_batch_adapter.d.cts +36 -0
- package/dist/tracing/trace_batch_adapter.d.ts +36 -0
- package/dist/tracing/trace_batch_adapter.js +86 -0
- package/dist/tracing/trace_batch_adapter.js.map +1 -0
- package/dist/tracing/trace_commit_writer.d.cts +1 -1
- package/dist/tracing/trace_commit_writer.d.ts +1 -1
- package/dist/tracing/trace_hub.cjs +87 -20
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +1 -1
- package/dist/tracing/trace_hub.d.ts +1 -1
- package/dist/tracing/trace_hub.js +85 -20
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +21 -6
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +13 -4
- package/dist/tracing/trace_provider.d.ts +13 -4
- package/dist/tracing/trace_provider.js +22 -7
- package/dist/tracing/trace_provider.js.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.d.cts +15 -1
- package/dist/tracing/types/wood_trace_batch.types.d.ts +15 -1
- package/dist/tracing/types/wood_trace_sink.types.d.cts +1 -1
- package/dist/tracing/types/wood_trace_sink.types.d.ts +1 -1
- package/dist/tracing/wood_trace_batch_contract.cjs +2 -0
- package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -1
- package/dist/tracing/wood_trace_batch_contract.d.cts +1 -1
- package/dist/tracing/wood_trace_batch_contract.d.ts +1 -1
- package/dist/tracing/wood_trace_batch_contract.js +2 -0
- package/dist/tracing/wood_trace_batch_contract.js.map +1 -1
- package/dist/transport/build_transport_bridge.cjs +4 -2
- package/dist/transport/build_transport_bridge.cjs.map +1 -1
- package/dist/transport/build_transport_bridge.d.cts +7 -1
- package/dist/transport/build_transport_bridge.d.ts +7 -1
- package/dist/transport/build_transport_bridge.js +2 -1
- package/dist/transport/build_transport_bridge.js.map +1 -1
- package/dist/transport/in_process_router_transport.d.cts +1 -0
- package/dist/transport/in_process_router_transport.d.ts +1 -0
- package/dist/transport/index.d.cts +1 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +47 -1
- package/dist/types/config.d.ts +47 -1
- package/dist/types/context.cjs +12 -0
- package/dist/types/context.cjs.map +1 -1
- package/dist/types/context.d.cts +27 -1
- package/dist/types/context.d.ts +27 -1
- package/dist/types/context.js +4 -0
- package/dist/types/context.js.map +1 -1
- package/dist/types/index.d.cts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/operations.cjs.map +1 -1
- package/dist/types/operations.d.cts +2 -0
- package/dist/types/operations.d.ts +2 -0
- package/docs/axe.md +706 -0
- package/package.json +13 -5
- package/src/components/NavigationShell.scopes.browser.test.ts +363 -0
- package/src/components/NavigationShell.svelte +126 -49
- package/dist/controller/__fixtures__/controllers/chat.cjs +0 -32
- package/dist/controller/__fixtures__/controllers/chat.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/chat.d.cts +0 -11
- package/dist/controller/__fixtures__/controllers/chat.d.ts +0 -11
- package/dist/controller/__fixtures__/controllers/chat.js +0 -12
- package/dist/controller/__fixtures__/controllers/chat.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/not_a_class.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/not_a_class.d.cts +0 -3
- package/dist/controller/__fixtures__/controllers/not_a_class.d.ts +0 -3
- package/dist/controller/__fixtures__/controllers/not_a_class.js +0 -5
- package/dist/controller/__fixtures__/controllers/not_a_class.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/settings.controller.cjs +0 -32
- package/dist/controller/__fixtures__/controllers/settings.controller.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/settings.controller.d.cts +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.d.ts +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.js +0 -12
- package/dist/controller/__fixtures__/controllers/settings.controller.js.map +0 -1
- package/dist/controller/__fixtures__/controllers/test.cjs +0 -29
- package/dist/controller/__fixtures__/controllers/test.cjs.map +0 -1
- package/dist/controller/__fixtures__/controllers/test.d.cts +0 -7
- package/dist/controller/__fixtures__/controllers/test.d.ts +0 -7
- package/dist/controller/__fixtures__/controllers/test.js +0 -9
- package/dist/controller/__fixtures__/controllers/test.js.map +0 -1
- package/dist/loader/__fixtures__/layouts/app.load.cjs +0 -27
- package/dist/loader/__fixtures__/layouts/app.load.cjs.map +0 -1
- package/dist/loader/__fixtures__/layouts/app.load.d.cts +0 -5
- package/dist/loader/__fixtures__/layouts/app.load.d.ts +0 -5
- package/dist/loader/__fixtures__/layouts/app.load.js +0 -7
- package/dist/loader/__fixtures__/layouts/app.load.js.map +0 -1
- package/dist/loader/__fixtures__/views/test/page.load.cjs +0 -27
- package/dist/loader/__fixtures__/views/test/page.load.cjs.map +0 -1
- package/dist/loader/__fixtures__/views/test/page.load.d.cts +0 -6
- package/dist/loader/__fixtures__/views/test/page.load.d.ts +0 -6
- package/dist/loader/__fixtures__/views/test/page.load.js +0 -7
- package/dist/loader/__fixtures__/views/test/page.load.js.map +0 -1
- package/dist/middleware/__fixtures__/middleware/auth.cjs.map +0 -1
- package/dist/middleware/__fixtures__/middleware/auth.d.cts +0 -6
- package/dist/middleware/__fixtures__/middleware/auth.d.ts +0 -6
- package/dist/middleware/__fixtures__/middleware/auth.js +0 -19
- package/dist/middleware/__fixtures__/middleware/auth.js.map +0 -1
- package/dist/middleware/__fixtures__/middleware/sequence.cjs +0 -47
- package/dist/middleware/__fixtures__/middleware/sequence.cjs.map +0 -1
- package/dist/middleware/__fixtures__/middleware/sequence.d.cts +0 -7
- package/dist/middleware/__fixtures__/middleware/sequence.d.ts +0 -7
- package/dist/middleware/__fixtures__/middleware/sequence.js +0 -21
- package/dist/middleware/__fixtures__/middleware/sequence.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/controller/controller_resolver.ts"],"sourcesContent":["import path from 'path';\nimport { pathToFileURL } from 'node:url';\nimport { getLogger } from '@noego/logger';\nimport type { IpcContext, ControllerArgs } from '../types/context.js';\n\nconst logger = getLogger('wood:controller');\n\n// Node's ESM loader rejects raw absolute Windows paths (`C:\\...`) — they must\n// be file:// URLs. Bare specifiers and relative paths pass through unchanged.\nfunction toImportSpecifier(spec: string): string {\n return path.isAbsolute(spec) ? pathToFileURL(spec).href : spec;\n}\n\nexport class ControllerResolver {\n private baseDir: string;\n private classCache = new Map<string, any>();\n private pathCache = new Map<string, string>(); // name -> import path\n private mode: 'bundled' | 'dev';\n\n constructor(controllersDir: string, options?: { mode?: 'bundled' | 'dev' }) {\n this.baseDir = controllersDir;\n // Default to bundled mode for safety. Dev mode must be explicitly opted into.\n this.mode = options?.mode ?? (process.env.WOOD_MODE === 'development' ? 'dev' : 'bundled');\n }\n\n /**\n * Check whether a controller name has been pre-registered (class or path).\n */\n has(name: string): boolean {\n return this.classCache.has(name) || this.pathCache.has(name);\n }\n\n /**\n * Register an import path for a controller. The controller will be lazily\n * imported from this path when first needed. This avoids circular dependencies\n * at module load time.\n */\n registerPath(name: string, importPath: string): void {\n if (!importPath) {\n throw new Error(`registerPath(\"${name}\"): importPath cannot be empty`);\n }\n this.pathCache.set(name, importPath);\n }\n\n /**\n * Resolve a controller name to its class.\n *\n * 1. Check class cache (already imported)\n * 2. Check path cache (registered via registerPath) and lazily import\n * 3. In dev mode only: fall back to filesystem resolution\n *\n * Classes are cached -- same class reference returned for same name.\n */\n async resolveClass(controllerName: string): Promise<any> {\n const cached = this.classCache.get(controllerName);\n if (cached) return cached;\n\n // Check if import path is registered — lazily load it\n const importPath = this.pathCache.get(controllerName);\n if (importPath) {\n const mod = await import(toImportSpecifier(importPath));\n const ControllerClass = mod.default ?? mod[Object.keys(mod)[0]];\n if (!ControllerClass || typeof ControllerClass !== 'function') {\n throw new Error(\n `Controller \"${controllerName}\" at ${importPath}: module does not export a class`\n );\n }\n this.classCache.set(controllerName, ControllerClass);\n logger.debug(`Resolved controller \"${controllerName}\" from registered path`);\n return ControllerClass;\n }\n\n if (this.mode === 'bundled') {\n throw new Error(\n `Controller \"${controllerName}\" is not registered. ` +\n `In bundled mode, all controllers must be pre-registered via controllers.generated.ts. ` +\n `Run \"npx wood build\" to regenerate the registration file.\\n` +\n `Registered controllers: [${Array.from(this.pathCache.keys()).join(', ')}]`\n );\n }\n\n // Dev mode: attempt dynamic filesystem imports\n return this.resolveFromFilesystem(controllerName);\n }\n\n private async resolveFromFilesystem(controllerName: string): Promise<any> {\n const basePath = path.resolve(this.baseDir, controllerName);\n const candidates = [\n basePath + '.ts',\n basePath + '.controller.ts',\n basePath + '.js',\n basePath + '.controller.js',\n path.resolve(this.baseDir, controllerName, 'index.ts'),\n path.resolve(this.baseDir, controllerName, 'index.js'),\n ];\n\n let mod: any;\n let loaded = false;\n\n for (const candidate of candidates) {\n try {\n mod = await import(toImportSpecifier(candidate));\n loaded = true;\n break;\n } catch {\n // Try next candidate\n }\n }\n\n if (!loaded) {\n throw new Error(\n `Controller \"${controllerName}\" not found. Searched:\\n` +\n candidates.map(c => ` - ${c}`).join('\\n')\n );\n }\n\n const ControllerClass = mod.default ?? mod[Object.keys(mod)[0]];\n if (!ControllerClass || typeof ControllerClass !== 'function') {\n throw new Error(\n `Controller \"${controllerName}\": module does not export a class`\n );\n }\n\n logger.debug(`Resolved controller \"${controllerName}\" from ${this.baseDir}`);\n this.classCache.set(controllerName, ControllerClass);\n return ControllerClass;\n }\n\n /**\n * Create a controller instance using IoC container.\n * Per-request scoped: container.extend() creates an isolated scope.\n */\n async createInstance(ControllerClass: any, container: any): Promise<any> {\n const scopedContainer = container.extend();\n return scopedContainer.instance(ControllerClass);\n }\n\n /**\n * Pre-register a controller class by name so that resolveClass()\n * finds it in the cache without attempting a filesystem import.\n */\n register(name: string, ControllerClass: any): void {\n if (typeof ControllerClass !== 'function') {\n throw new Error(`register(\"${name}\"): expected a class/constructor, got ${typeof ControllerClass}`);\n }\n this.classCache.set(name, ControllerClass);\n }\n\n clearCache(): void {\n this.classCache.clear();\n }\n}\n\n/**\n * Build controller args from IPC context.\n * Creates a fake req/res that matches the Dinner web pattern so\n * existing controllers work without modification.\n */\nexport function buildControllerArgs(ipcContext: IpcContext, container: unknown): ControllerArgs {\n return {\n req: {\n body: ipcContext.body ?? {},\n params: ipcContext.params ?? {},\n query: ipcContext.query ?? {},\n context: ipcContext.context ?? {},\n headers: {},\n },\n res: {\n status: (_code: number) => {},\n cookie: (_name: string, _value: string, _opts?: unknown) => {},\n clearCookie: (_name: string, _opts?: unknown) => {},\n set: (_header: string, _value: string) => {},\n },\n container,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/controller/controller_resolver.ts"],"sourcesContent":["import path from 'path';\nimport { pathToFileURL } from 'node:url';\nimport { getLogger } from '@noego/logger';\nimport type { IpcContext, ControllerArgs } from '../types/context.js';\n\nconst logger = getLogger('wood:controller');\n\n// Node's ESM loader rejects raw absolute Windows paths (`C:\\...`) — they must\n// be file:// URLs. Bare specifiers and relative paths pass through unchanged.\nfunction toImportSpecifier(spec: string): string {\n return path.isAbsolute(spec) ? pathToFileURL(spec).href : spec;\n}\n\nexport class ControllerResolver {\n private baseDir: string;\n private classCache = new Map<string, any>();\n private pathCache = new Map<string, string>(); // name -> import path\n private loaderCache = new Map<string, () => Promise<unknown>>(); // name -> lazy module loader\n private mode: 'bundled' | 'dev';\n\n constructor(controllersDir: string, options?: { mode?: 'bundled' | 'dev' }) {\n this.baseDir = controllersDir;\n // Default to bundled mode for safety. Dev mode must be explicitly opted into.\n this.mode = options?.mode ?? (process.env.WOOD_MODE === 'development' ? 'dev' : 'bundled');\n }\n\n /**\n * Check whether a controller name has been pre-registered (class or path).\n */\n has(name: string): boolean {\n return this.classCache.has(name) || this.pathCache.has(name) || this.loaderCache.has(name);\n }\n\n /**\n * Register a lazy module loader for a controller. The loader is the\n * CALLER's `() => import('...literal specifier...')`, so the import runs in\n * the caller's module resolution (bundler/test-runner identity) instead of\n * a raw filesystem import — same class identity as every other import of\n * that module. Invoked only on first resolution.\n */\n registerLoader(name: string, loader: () => Promise<unknown>): void {\n if (typeof loader !== 'function') {\n throw new Error(`registerLoader(\"${name}\"): expected a () => Promise<module> function`);\n }\n this.loaderCache.set(name, loader);\n }\n\n /**\n * Register an import path for a controller. The controller will be lazily\n * imported from this path when first needed. This avoids circular dependencies\n * at module load time.\n */\n registerPath(name: string, importPath: string): void {\n if (!importPath) {\n throw new Error(`registerPath(\"${name}\"): importPath cannot be empty`);\n }\n this.pathCache.set(name, importPath);\n }\n\n /**\n * Resolve a controller name to its class.\n *\n * 1. Check class cache (already imported)\n * 2. Check path cache (registered via registerPath) and lazily import\n * 3. In dev mode only: fall back to filesystem resolution\n *\n * Classes are cached -- same class reference returned for same name.\n */\n async resolveClass(controllerName: string): Promise<any> {\n const cached = this.classCache.get(controllerName);\n if (cached) return cached;\n\n // Lazy loader (caller-owned import) takes precedence: it preserves the\n // caller's module identity for the controller and its dependency graph.\n const loader = this.loaderCache.get(controllerName);\n if (loader) {\n const mod = (await loader()) as Record<string, unknown>;\n const ControllerClass = (mod.default ?? mod[Object.keys(mod)[0]]) as unknown;\n if (!ControllerClass || typeof ControllerClass !== 'function') {\n throw new Error(\n `Controller \"${controllerName}\": registered loader's module does not export a class`\n );\n }\n this.classCache.set(controllerName, ControllerClass);\n logger.debug(`Resolved controller \"${controllerName}\" from registered loader`);\n return ControllerClass;\n }\n\n // Check if import path is registered — lazily load it\n const importPath = this.pathCache.get(controllerName);\n if (importPath) {\n const mod = await import(toImportSpecifier(importPath));\n const ControllerClass = mod.default ?? mod[Object.keys(mod)[0]];\n if (!ControllerClass || typeof ControllerClass !== 'function') {\n throw new Error(\n `Controller \"${controllerName}\" at ${importPath}: module does not export a class`\n );\n }\n this.classCache.set(controllerName, ControllerClass);\n logger.debug(`Resolved controller \"${controllerName}\" from registered path`);\n return ControllerClass;\n }\n\n if (this.mode === 'bundled') {\n throw new Error(\n `Controller \"${controllerName}\" is not registered. ` +\n `In bundled mode, all controllers must be pre-registered via controllers.generated.ts. ` +\n `Run \"npx wood build\" to regenerate the registration file.\\n` +\n `Registered controllers: [${Array.from(this.pathCache.keys()).join(', ')}]`\n );\n }\n\n // Dev mode: attempt dynamic filesystem imports\n return this.resolveFromFilesystem(controllerName);\n }\n\n private async resolveFromFilesystem(controllerName: string): Promise<any> {\n const basePath = path.resolve(this.baseDir, controllerName);\n const candidates = [\n basePath + '.ts',\n basePath + '.controller.ts',\n basePath + '.js',\n basePath + '.controller.js',\n path.resolve(this.baseDir, controllerName, 'index.ts'),\n path.resolve(this.baseDir, controllerName, 'index.js'),\n ];\n\n let mod: any;\n let loaded = false;\n\n for (const candidate of candidates) {\n try {\n mod = await import(toImportSpecifier(candidate));\n loaded = true;\n break;\n } catch {\n // Try next candidate\n }\n }\n\n if (!loaded) {\n throw new Error(\n `Controller \"${controllerName}\" not found. Searched:\\n` +\n candidates.map(c => ` - ${c}`).join('\\n')\n );\n }\n\n const ControllerClass = mod.default ?? mod[Object.keys(mod)[0]];\n if (!ControllerClass || typeof ControllerClass !== 'function') {\n throw new Error(\n `Controller \"${controllerName}\": module does not export a class`\n );\n }\n\n logger.debug(`Resolved controller \"${controllerName}\" from ${this.baseDir}`);\n this.classCache.set(controllerName, ControllerClass);\n return ControllerClass;\n }\n\n /**\n * Create a controller instance using IoC container.\n * Per-request scoped: container.extend() creates an isolated scope.\n */\n async createInstance(ControllerClass: any, container: any): Promise<any> {\n const scopedContainer = container.extend();\n return scopedContainer.instance(ControllerClass);\n }\n\n /**\n * Pre-register a controller class by name so that resolveClass()\n * finds it in the cache without attempting a filesystem import.\n */\n register(name: string, ControllerClass: any): void {\n if (typeof ControllerClass !== 'function') {\n throw new Error(`register(\"${name}\"): expected a class/constructor, got ${typeof ControllerClass}`);\n }\n this.classCache.set(name, ControllerClass);\n }\n\n clearCache(): void {\n this.classCache.clear();\n }\n}\n\n/**\n * Whether a controller class opted into the native Desktop boundary\n * (`static woodContext = 'operation'`). Native actions receive a\n * WoodOperationContext; everything else keeps the legacy args pair.\n */\nexport function usesOperationContext(ControllerClass: unknown): boolean {\n return (ControllerClass as { woodContext?: string })?.woodContext === 'operation';\n}\n\n/**\n * Build the native Wood operation context for a controller action.\n * Desktop-shaped: operation identity, validated input, middleware state,\n * sender/window — no fabricated HTTP surface, no container.\n */\nexport function buildOperationContext(\n operation: string,\n ipcContext: IpcContext\n): import('../types/context.js').WoodOperationContext {\n const state = ipcContext.context ?? {};\n return {\n operation,\n input: ipcContext.body,\n state,\n sender: ipcContext.sender,\n windowId: ipcContext.windowId,\n get<T>(key: string): T | undefined {\n return state[key] as T | undefined;\n },\n };\n}\n\n/**\n * Build controller args from IPC context.\n * LEGACY-COMPAT: creates a fake req/res matching the Dinner web pattern so\n * pre-native controllers work without modification. New controllers declare\n * `static woodContext = 'operation'` and receive a WoodOperationContext\n * (see buildOperationContext) instead.\n */\nexport function buildControllerArgs(ipcContext: IpcContext, container: unknown): ControllerArgs {\n return {\n req: {\n body: ipcContext.body ?? {},\n params: ipcContext.params ?? {},\n query: ipcContext.query ?? {},\n context: ipcContext.context ?? {},\n headers: {},\n },\n res: {\n status: (_code: number) => {},\n cookie: (_name: string, _value: string, _opts?: unknown) => {},\n clearCookie: (_name: string, _opts?: unknown) => {},\n set: (_header: string, _value: string) => {},\n },\n container,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -20,7 +20,9 @@ var controller_exports = {};
|
|
|
20
20
|
__export(controller_exports, {
|
|
21
21
|
ControllerResolver: () => import_controller_resolver.ControllerResolver,
|
|
22
22
|
buildControllerArgs: () => import_controller_resolver.buildControllerArgs,
|
|
23
|
-
|
|
23
|
+
buildOperationContext: () => import_controller_resolver.buildOperationContext,
|
|
24
|
+
disposeControllerLifecycle: () => import_controller_lifecycle.disposeControllerLifecycle,
|
|
25
|
+
usesOperationContext: () => import_controller_resolver.usesOperationContext
|
|
24
26
|
});
|
|
25
27
|
module.exports = __toCommonJS(controller_exports);
|
|
26
28
|
var import_controller_resolver = require("./controller_resolver.cjs");
|
|
@@ -29,6 +31,8 @@ var import_controller_lifecycle = require("./controller_lifecycle.cjs");
|
|
|
29
31
|
0 && (module.exports = {
|
|
30
32
|
ControllerResolver,
|
|
31
33
|
buildControllerArgs,
|
|
32
|
-
|
|
34
|
+
buildOperationContext,
|
|
35
|
+
disposeControllerLifecycle,
|
|
36
|
+
usesOperationContext
|
|
33
37
|
});
|
|
34
38
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/controller/index.ts"],"sourcesContent":["export { ControllerResolver, buildControllerArgs } from './controller_resolver.cjs';\nexport type { ControllerLifecycle } from './controller_lifecycle.cjs';\nexport { disposeControllerLifecycle } from './controller_lifecycle.cjs';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/controller/index.ts"],"sourcesContent":["export { ControllerResolver, buildControllerArgs, buildOperationContext, usesOperationContext } from './controller_resolver.cjs';\nexport type { ControllerLifecycle } from './controller_lifecycle.cjs';\nexport { disposeControllerLifecycle } from './controller_lifecycle.cjs';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAAqG;AAErG,kCAA2C;","names":[]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ControllerResolver, buildControllerArgs } from './controller_resolver.cjs';
|
|
1
|
+
export { ControllerResolver, buildControllerArgs, buildOperationContext, usesOperationContext } from './controller_resolver.cjs';
|
|
2
2
|
export { ControllerLifecycle, disposeControllerLifecycle } from './controller_lifecycle.cjs';
|
|
3
3
|
import '../types/context.cjs';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { ControllerResolver, buildControllerArgs } from './controller_resolver.js';
|
|
1
|
+
export { ControllerResolver, buildControllerArgs, buildOperationContext, usesOperationContext } from './controller_resolver.js';
|
|
2
2
|
export { ControllerLifecycle, disposeControllerLifecycle } from './controller_lifecycle.js';
|
|
3
3
|
import '../types/context.js';
|
package/dist/controller/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ControllerResolver, buildControllerArgs } from "./controller_resolver.js";
|
|
1
|
+
import { ControllerResolver, buildControllerArgs, buildOperationContext, usesOperationContext } from "./controller_resolver.js";
|
|
2
2
|
import { disposeControllerLifecycle } from "./controller_lifecycle.js";
|
|
3
3
|
export {
|
|
4
4
|
ControllerResolver,
|
|
5
5
|
buildControllerArgs,
|
|
6
|
-
|
|
6
|
+
buildOperationContext,
|
|
7
|
+
disposeControllerLifecycle,
|
|
8
|
+
usesOperationContext
|
|
7
9
|
};
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/controller/index.ts"],"sourcesContent":["export { ControllerResolver, buildControllerArgs } from './controller_resolver.js';\nexport type { ControllerLifecycle } from './controller_lifecycle.js';\nexport { disposeControllerLifecycle } from './controller_lifecycle.js';\n"],"mappings":"AAAA,SAAS,oBAAoB,
|
|
1
|
+
{"version":3,"sources":["../../src/controller/index.ts"],"sourcesContent":["export { ControllerResolver, buildControllerArgs, buildOperationContext, usesOperationContext } from './controller_resolver.js';\nexport type { ControllerLifecycle } from './controller_lifecycle.js';\nexport { disposeControllerLifecycle } from './controller_lifecycle.js';\n"],"mappings":"AAAA,SAAS,oBAAoB,qBAAqB,uBAAuB,4BAA4B;AAErG,SAAS,kCAAkC;","names":[]}
|
|
@@ -88,7 +88,9 @@ class WoodDevServer {
|
|
|
88
88
|
logger.info("views parsed", { count: views.length });
|
|
89
89
|
const outDir = import_path.default.resolve(this.cwd, this.config.outDir);
|
|
90
90
|
(0, import_fs.mkdirSync)(outDir, { recursive: true });
|
|
91
|
-
const preloadCode = (0, import_preload_generator.generatePreload)(operations
|
|
91
|
+
const preloadCode = (0, import_preload_generator.generatePreload)(operations, {
|
|
92
|
+
traceBatching: (0, import_config_parser.resolveRendererTraceBatching)(this.config)
|
|
93
|
+
});
|
|
92
94
|
(0, import_fs.writeFileSync)(import_path.default.join(outDir, "preload.generated.ts"), preloadCode);
|
|
93
95
|
const typesCode = (0, import_type_generator.generateTypes)(operations);
|
|
94
96
|
(0, import_fs.writeFileSync)(import_path.default.join(outDir, "wood.d.ts"), typesCode);
|
|
@@ -191,6 +193,7 @@ class WoodDevServer {
|
|
|
191
193
|
outDir,
|
|
192
194
|
rendererOutDir: import_path.default.resolve(this.cwd, this.config.renderer.componentDir, "generated"),
|
|
193
195
|
cwd: this.cwd,
|
|
196
|
+
traceBatching: (0, import_config_parser.resolveRendererTraceBatching)(this.config),
|
|
194
197
|
onViewsChange: async () => {
|
|
195
198
|
const viewsContent = (0, import_fs.readFileSync)(
|
|
196
199
|
import_path.default.resolve(this.cwd, this.config.renderer.openapi),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dev/wood_dev_server.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseConfig } from '../config/config_parser.cjs';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { parseViews } from '../parser/views_parser.cjs';\nimport { generatePreload } from '../codegen/preload_generator.cjs';\nimport { generateTypes } from '../codegen/type_generator.cjs';\nimport { generateTestMock } from '../codegen/test_mock_generator.cjs';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.cjs';\nimport { generateRuntime } from '../codegen/runtime_generator.cjs';\nimport { generateRendererApp } from '../codegen/renderer_app_generator.cjs';\nimport { BackendBridge } from '../bridge/backend_bridge.cjs';\nimport { BackendWatcher } from './backend_watcher.cjs';\nimport { YamlWatcher } from './yaml_watcher.cjs';\nimport { EsbuildBackend } from './esbuild_backend.cjs';\nimport type { WoodConfig } from '../types/index.cjs';\n\nconst logger = getLogger('wood:dev');\n\nexport interface DevServerOptions {\n configPath?: string;\n cwd?: string;\n}\n\nexport class WoodDevServer {\n private config: WoodConfig | null = null;\n private bridge: BackendBridge | null = null;\n private backendWatcher: BackendWatcher | null = null;\n private yamlWatcher: YamlWatcher | null = null;\n private esbuild: EsbuildBackend | null = null;\n private cwd: string;\n\n constructor(options: DevServerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n }\n\n /**\n * Start the Wood development server.\n *\n * Automatically sets process.env.WOOD_MODE = 'development' so the app\n * can conditionally use dynamic controller imports (dev) vs pre-registered\n * controllers from the generated file (production).\n *\n * Steps:\n * 1. Parse config\n * 2. Parse + stitch YAML\n * 3. Generate preload, types, mock\n * 4. Build backend with esbuild\n * 5. (electron-vite would be started here -- omitted for MVP)\n * 6. Spawn backend via bridge\n * 7. Start watchers\n */\n async start(): Promise<void> {\n process.env.WOOD_MODE = 'development';\n\n // 1. Parse config\n const configPath = path.resolve(this.cwd, 'wood.config.yml');\n this.config = parseConfig(configPath);\n logger.info('config loaded', { outDir: this.config.outDir });\n\n // 2. Parse operations YAML\n const opsYamlPath = path.resolve(this.cwd, this.config.main.openapi);\n const opsContent = readFileSync(opsYamlPath, 'utf-8');\n const operations = parseOperations(opsContent);\n logger.info('operations parsed', { count: operations.size });\n\n // 3. Parse views YAML\n const viewsYamlPath = path.resolve(this.cwd, this.config.renderer.openapi);\n const viewsContent = readFileSync(viewsYamlPath, 'utf-8');\n const views = parseViews(viewsContent);\n logger.info('views parsed', { count: views.length });\n\n // 4. Generate files\n const outDir = path.resolve(this.cwd, this.config.outDir);\n mkdirSync(outDir, { recursive: true });\n\n const preloadCode = generatePreload(operations);\n writeFileSync(path.join(outDir, 'preload.generated.ts'), preloadCode);\n\n const typesCode = generateTypes(operations);\n writeFileSync(path.join(outDir, 'wood.d.ts'), typesCode);\n\n const mockCode = generateTestMock(operations);\n writeFileSync(path.join(outDir, 'wood.mock.ts'), mockCode);\n\n const controllersDir = path.resolve(this.cwd, this.config.main.controllers);\n const controllerRegCode = generateControllerRegistration(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'controllers.generated.ts'), controllerRegCode);\n\n const runtimeCode = generateRuntime(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'runtime.generated.ts'), runtimeCode);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(path.join(rendererOutDir, 'wood.d.ts'), typesCode);\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config.renderer.entry,\n }),\n );\n\n logger.info('codegen complete', { outDir });\n\n // 5. Build backend with esbuild (initial build + create incremental context)\n const backendEntry = this.config.main.entry;\n const backendOutfile = path.join(this.config.outDir, 'backend', 'index.js');\n\n this.esbuild = new EsbuildBackend({\n entryPoint: backendEntry,\n outfile: backendOutfile,\n cwd: this.cwd,\n external: this.config.build ? [] : undefined,\n });\n\n await this.esbuild.build();\n await this.esbuild.createContext();\n\n // 6. Start backend bridge (split-serve)\n if (this.config.dev?.splitServe !== false) {\n const resolvedBackendEntry = path.resolve(this.cwd, backendOutfile);\n this.bridge = new BackendBridge({\n backendEntry: resolvedBackendEntry,\n onReady: () => {\n logger.info('backend ready (split-serve)');\n },\n onPush: (channel, data) => {\n logger.debug('backend push', { channel, data });\n },\n onExit: (code, signal) => {\n logger.debug('backend exited', { code, signal });\n },\n });\n await this.bridge.start();\n }\n\n // 7. Start watchers\n if (this.config.dev?.watch !== false) {\n this.startWatchers(outDir);\n }\n }\n\n /** Stop the dev server and clean up all resources. */\n async stop(): Promise<void> {\n this.backendWatcher?.stop();\n this.yamlWatcher?.stop();\n\n if (this.bridge) {\n await this.bridge.stop();\n logger.info('backend bridge stopped');\n }\n\n if (this.esbuild) {\n await this.esbuild.dispose();\n }\n }\n\n /** Get the parsed config. */\n getConfig(): WoodConfig | null {\n return this.config;\n }\n\n private startWatchers(outDir: string): void {\n if (!this.config) return;\n\n // Backend watcher: server + middleware files -> rebuild + restart\n if (this.bridge && this.esbuild) {\n const backendPatterns = [\n `${this.config.main.controllers}/**/*.ts`,\n `${this.config.main.middleware}/**/*.ts`,\n `${this.config.main.entry}`,\n ...(this.config.main.watch ?? []),\n ];\n\n const esbuild = this.esbuild;\n this.backendWatcher = new BackendWatcher({\n patterns: backendPatterns,\n bridge: this.bridge,\n buildFn: () => esbuild.rebuild().then(() => {}),\n cwd: this.cwd,\n });\n this.backendWatcher.start();\n logger.info('backend watcher started', { patterns: backendPatterns });\n }\n\n // YAML watcher: operations + views YAML -> regenerate codegen\n this.yamlWatcher = new YamlWatcher({\n operationsYamlPath: this.config.main.openapi,\n viewsYamlPath: this.config.renderer.openapi,\n controllersDir: this.config.main.controllers,\n outDir,\n rendererOutDir: path.resolve(this.cwd, this.config.renderer.componentDir, 'generated'),\n cwd: this.cwd,\n onViewsChange: async () => {\n // Re-parse views and regenerate client router manifest\n const viewsContent = readFileSync(\n path.resolve(this.cwd, this.config!.renderer.openapi),\n 'utf-8',\n );\n const views = parseViews(viewsContent);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config!.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config!.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config!.renderer.entry,\n }),\n );\n\n logger.info('views renderer codegen regenerated', { rendererOutDir });\n },\n });\n this.yamlWatcher.start();\n logger.info('yaml watcher started');\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
1
|
+
{"version":3,"sources":["../../src/dev/wood_dev_server.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseConfig, resolveRendererTraceBatching } from '../config/config_parser.cjs';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { parseViews } from '../parser/views_parser.cjs';\nimport { generatePreload } from '../codegen/preload_generator.cjs';\nimport { generateTypes } from '../codegen/type_generator.cjs';\nimport { generateTestMock } from '../codegen/test_mock_generator.cjs';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.cjs';\nimport { generateRuntime } from '../codegen/runtime_generator.cjs';\nimport { generateRendererApp } from '../codegen/renderer_app_generator.cjs';\nimport { BackendBridge } from '../bridge/backend_bridge.cjs';\nimport { BackendWatcher } from './backend_watcher.cjs';\nimport { YamlWatcher } from './yaml_watcher.cjs';\nimport { EsbuildBackend } from './esbuild_backend.cjs';\nimport type { WoodConfig } from '../types/index.cjs';\n\nconst logger = getLogger('wood:dev');\n\nexport interface DevServerOptions {\n configPath?: string;\n cwd?: string;\n}\n\nexport class WoodDevServer {\n private config: WoodConfig | null = null;\n private bridge: BackendBridge | null = null;\n private backendWatcher: BackendWatcher | null = null;\n private yamlWatcher: YamlWatcher | null = null;\n private esbuild: EsbuildBackend | null = null;\n private cwd: string;\n\n constructor(options: DevServerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n }\n\n /**\n * Start the Wood development server.\n *\n * Automatically sets process.env.WOOD_MODE = 'development' so the app\n * can conditionally use dynamic controller imports (dev) vs pre-registered\n * controllers from the generated file (production).\n *\n * Steps:\n * 1. Parse config\n * 2. Parse + stitch YAML\n * 3. Generate preload, types, mock\n * 4. Build backend with esbuild\n * 5. (electron-vite would be started here -- omitted for MVP)\n * 6. Spawn backend via bridge\n * 7. Start watchers\n */\n async start(): Promise<void> {\n process.env.WOOD_MODE = 'development';\n\n // 1. Parse config\n const configPath = path.resolve(this.cwd, 'wood.config.yml');\n this.config = parseConfig(configPath);\n logger.info('config loaded', { outDir: this.config.outDir });\n\n // 2. Parse operations YAML\n const opsYamlPath = path.resolve(this.cwd, this.config.main.openapi);\n const opsContent = readFileSync(opsYamlPath, 'utf-8');\n const operations = parseOperations(opsContent);\n logger.info('operations parsed', { count: operations.size });\n\n // 3. Parse views YAML\n const viewsYamlPath = path.resolve(this.cwd, this.config.renderer.openapi);\n const viewsContent = readFileSync(viewsYamlPath, 'utf-8');\n const views = parseViews(viewsContent);\n logger.info('views parsed', { count: views.length });\n\n // 4. Generate files\n const outDir = path.resolve(this.cwd, this.config.outDir);\n mkdirSync(outDir, { recursive: true });\n\n const preloadCode = generatePreload(operations, {\n traceBatching: resolveRendererTraceBatching(this.config),\n });\n writeFileSync(path.join(outDir, 'preload.generated.ts'), preloadCode);\n\n const typesCode = generateTypes(operations);\n writeFileSync(path.join(outDir, 'wood.d.ts'), typesCode);\n\n const mockCode = generateTestMock(operations);\n writeFileSync(path.join(outDir, 'wood.mock.ts'), mockCode);\n\n const controllersDir = path.resolve(this.cwd, this.config.main.controllers);\n const controllerRegCode = generateControllerRegistration(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'controllers.generated.ts'), controllerRegCode);\n\n const runtimeCode = generateRuntime(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'runtime.generated.ts'), runtimeCode);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(path.join(rendererOutDir, 'wood.d.ts'), typesCode);\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config.renderer.entry,\n }),\n );\n\n logger.info('codegen complete', { outDir });\n\n // 5. Build backend with esbuild (initial build + create incremental context)\n const backendEntry = this.config.main.entry;\n const backendOutfile = path.join(this.config.outDir, 'backend', 'index.js');\n\n this.esbuild = new EsbuildBackend({\n entryPoint: backendEntry,\n outfile: backendOutfile,\n cwd: this.cwd,\n external: this.config.build ? [] : undefined,\n });\n\n await this.esbuild.build();\n await this.esbuild.createContext();\n\n // 6. Start backend bridge (split-serve)\n if (this.config.dev?.splitServe !== false) {\n const resolvedBackendEntry = path.resolve(this.cwd, backendOutfile);\n this.bridge = new BackendBridge({\n backendEntry: resolvedBackendEntry,\n onReady: () => {\n logger.info('backend ready (split-serve)');\n },\n onPush: (channel, data) => {\n logger.debug('backend push', { channel, data });\n },\n onExit: (code, signal) => {\n logger.debug('backend exited', { code, signal });\n },\n });\n await this.bridge.start();\n }\n\n // 7. Start watchers\n if (this.config.dev?.watch !== false) {\n this.startWatchers(outDir);\n }\n }\n\n /** Stop the dev server and clean up all resources. */\n async stop(): Promise<void> {\n this.backendWatcher?.stop();\n this.yamlWatcher?.stop();\n\n if (this.bridge) {\n await this.bridge.stop();\n logger.info('backend bridge stopped');\n }\n\n if (this.esbuild) {\n await this.esbuild.dispose();\n }\n }\n\n /** Get the parsed config. */\n getConfig(): WoodConfig | null {\n return this.config;\n }\n\n private startWatchers(outDir: string): void {\n if (!this.config) return;\n\n // Backend watcher: server + middleware files -> rebuild + restart\n if (this.bridge && this.esbuild) {\n const backendPatterns = [\n `${this.config.main.controllers}/**/*.ts`,\n `${this.config.main.middleware}/**/*.ts`,\n `${this.config.main.entry}`,\n ...(this.config.main.watch ?? []),\n ];\n\n const esbuild = this.esbuild;\n this.backendWatcher = new BackendWatcher({\n patterns: backendPatterns,\n bridge: this.bridge,\n buildFn: () => esbuild.rebuild().then(() => {}),\n cwd: this.cwd,\n });\n this.backendWatcher.start();\n logger.info('backend watcher started', { patterns: backendPatterns });\n }\n\n // YAML watcher: operations + views YAML -> regenerate codegen\n this.yamlWatcher = new YamlWatcher({\n operationsYamlPath: this.config.main.openapi,\n viewsYamlPath: this.config.renderer.openapi,\n controllersDir: this.config.main.controllers,\n outDir,\n rendererOutDir: path.resolve(this.cwd, this.config.renderer.componentDir, 'generated'),\n cwd: this.cwd,\n traceBatching: resolveRendererTraceBatching(this.config),\n onViewsChange: async () => {\n // Re-parse views and regenerate client router manifest\n const viewsContent = readFileSync(\n path.resolve(this.cwd, this.config!.renderer.openapi),\n 'utf-8',\n );\n const views = parseViews(viewsContent);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config!.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config!.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config!.renderer.entry,\n }),\n );\n\n logger.info('views renderer codegen regenerated', { rendererOutDir });\n },\n });\n this.yamlWatcher.start();\n logger.info('yaml watcher started');\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { getLogger } from "@noego/logger";
|
|
4
|
-
import { parseConfig } from "../config/config_parser.js";
|
|
4
|
+
import { parseConfig, resolveRendererTraceBatching } from "../config/config_parser.js";
|
|
5
5
|
import { parseOperations } from "../parser/operations_parser.js";
|
|
6
6
|
import { parseViews } from "../parser/views_parser.js";
|
|
7
7
|
import { generatePreload } from "../codegen/preload_generator.js";
|
|
@@ -55,7 +55,9 @@ class WoodDevServer {
|
|
|
55
55
|
logger.info("views parsed", { count: views.length });
|
|
56
56
|
const outDir = path.resolve(this.cwd, this.config.outDir);
|
|
57
57
|
mkdirSync(outDir, { recursive: true });
|
|
58
|
-
const preloadCode = generatePreload(operations
|
|
58
|
+
const preloadCode = generatePreload(operations, {
|
|
59
|
+
traceBatching: resolveRendererTraceBatching(this.config)
|
|
60
|
+
});
|
|
59
61
|
writeFileSync(path.join(outDir, "preload.generated.ts"), preloadCode);
|
|
60
62
|
const typesCode = generateTypes(operations);
|
|
61
63
|
writeFileSync(path.join(outDir, "wood.d.ts"), typesCode);
|
|
@@ -158,6 +160,7 @@ class WoodDevServer {
|
|
|
158
160
|
outDir,
|
|
159
161
|
rendererOutDir: path.resolve(this.cwd, this.config.renderer.componentDir, "generated"),
|
|
160
162
|
cwd: this.cwd,
|
|
163
|
+
traceBatching: resolveRendererTraceBatching(this.config),
|
|
161
164
|
onViewsChange: async () => {
|
|
162
165
|
const viewsContent = readFileSync(
|
|
163
166
|
path.resolve(this.cwd, this.config.renderer.openapi),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dev/wood_dev_server.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseConfig } from '../config/config_parser.js';\nimport { parseOperations } from '../parser/operations_parser.js';\nimport { parseViews } from '../parser/views_parser.js';\nimport { generatePreload } from '../codegen/preload_generator.js';\nimport { generateTypes } from '../codegen/type_generator.js';\nimport { generateTestMock } from '../codegen/test_mock_generator.js';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.js';\nimport { generateRuntime } from '../codegen/runtime_generator.js';\nimport { generateRendererApp } from '../codegen/renderer_app_generator.js';\nimport { BackendBridge } from '../bridge/backend_bridge.js';\nimport { BackendWatcher } from './backend_watcher.js';\nimport { YamlWatcher } from './yaml_watcher.js';\nimport { EsbuildBackend } from './esbuild_backend.js';\nimport type { WoodConfig } from '../types/index.js';\n\nconst logger = getLogger('wood:dev');\n\nexport interface DevServerOptions {\n configPath?: string;\n cwd?: string;\n}\n\nexport class WoodDevServer {\n private config: WoodConfig | null = null;\n private bridge: BackendBridge | null = null;\n private backendWatcher: BackendWatcher | null = null;\n private yamlWatcher: YamlWatcher | null = null;\n private esbuild: EsbuildBackend | null = null;\n private cwd: string;\n\n constructor(options: DevServerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n }\n\n /**\n * Start the Wood development server.\n *\n * Automatically sets process.env.WOOD_MODE = 'development' so the app\n * can conditionally use dynamic controller imports (dev) vs pre-registered\n * controllers from the generated file (production).\n *\n * Steps:\n * 1. Parse config\n * 2. Parse + stitch YAML\n * 3. Generate preload, types, mock\n * 4. Build backend with esbuild\n * 5. (electron-vite would be started here -- omitted for MVP)\n * 6. Spawn backend via bridge\n * 7. Start watchers\n */\n async start(): Promise<void> {\n process.env.WOOD_MODE = 'development';\n\n // 1. Parse config\n const configPath = path.resolve(this.cwd, 'wood.config.yml');\n this.config = parseConfig(configPath);\n logger.info('config loaded', { outDir: this.config.outDir });\n\n // 2. Parse operations YAML\n const opsYamlPath = path.resolve(this.cwd, this.config.main.openapi);\n const opsContent = readFileSync(opsYamlPath, 'utf-8');\n const operations = parseOperations(opsContent);\n logger.info('operations parsed', { count: operations.size });\n\n // 3. Parse views YAML\n const viewsYamlPath = path.resolve(this.cwd, this.config.renderer.openapi);\n const viewsContent = readFileSync(viewsYamlPath, 'utf-8');\n const views = parseViews(viewsContent);\n logger.info('views parsed', { count: views.length });\n\n // 4. Generate files\n const outDir = path.resolve(this.cwd, this.config.outDir);\n mkdirSync(outDir, { recursive: true });\n\n const preloadCode = generatePreload(operations);\n writeFileSync(path.join(outDir, 'preload.generated.ts'), preloadCode);\n\n const typesCode = generateTypes(operations);\n writeFileSync(path.join(outDir, 'wood.d.ts'), typesCode);\n\n const mockCode = generateTestMock(operations);\n writeFileSync(path.join(outDir, 'wood.mock.ts'), mockCode);\n\n const controllersDir = path.resolve(this.cwd, this.config.main.controllers);\n const controllerRegCode = generateControllerRegistration(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'controllers.generated.ts'), controllerRegCode);\n\n const runtimeCode = generateRuntime(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'runtime.generated.ts'), runtimeCode);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(path.join(rendererOutDir, 'wood.d.ts'), typesCode);\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config.renderer.entry,\n }),\n );\n\n logger.info('codegen complete', { outDir });\n\n // 5. Build backend with esbuild (initial build + create incremental context)\n const backendEntry = this.config.main.entry;\n const backendOutfile = path.join(this.config.outDir, 'backend', 'index.js');\n\n this.esbuild = new EsbuildBackend({\n entryPoint: backendEntry,\n outfile: backendOutfile,\n cwd: this.cwd,\n external: this.config.build ? [] : undefined,\n });\n\n await this.esbuild.build();\n await this.esbuild.createContext();\n\n // 6. Start backend bridge (split-serve)\n if (this.config.dev?.splitServe !== false) {\n const resolvedBackendEntry = path.resolve(this.cwd, backendOutfile);\n this.bridge = new BackendBridge({\n backendEntry: resolvedBackendEntry,\n onReady: () => {\n logger.info('backend ready (split-serve)');\n },\n onPush: (channel, data) => {\n logger.debug('backend push', { channel, data });\n },\n onExit: (code, signal) => {\n logger.debug('backend exited', { code, signal });\n },\n });\n await this.bridge.start();\n }\n\n // 7. Start watchers\n if (this.config.dev?.watch !== false) {\n this.startWatchers(outDir);\n }\n }\n\n /** Stop the dev server and clean up all resources. */\n async stop(): Promise<void> {\n this.backendWatcher?.stop();\n this.yamlWatcher?.stop();\n\n if (this.bridge) {\n await this.bridge.stop();\n logger.info('backend bridge stopped');\n }\n\n if (this.esbuild) {\n await this.esbuild.dispose();\n }\n }\n\n /** Get the parsed config. */\n getConfig(): WoodConfig | null {\n return this.config;\n }\n\n private startWatchers(outDir: string): void {\n if (!this.config) return;\n\n // Backend watcher: server + middleware files -> rebuild + restart\n if (this.bridge && this.esbuild) {\n const backendPatterns = [\n `${this.config.main.controllers}/**/*.ts`,\n `${this.config.main.middleware}/**/*.ts`,\n `${this.config.main.entry}`,\n ...(this.config.main.watch ?? []),\n ];\n\n const esbuild = this.esbuild;\n this.backendWatcher = new BackendWatcher({\n patterns: backendPatterns,\n bridge: this.bridge,\n buildFn: () => esbuild.rebuild().then(() => {}),\n cwd: this.cwd,\n });\n this.backendWatcher.start();\n logger.info('backend watcher started', { patterns: backendPatterns });\n }\n\n // YAML watcher: operations + views YAML -> regenerate codegen\n this.yamlWatcher = new YamlWatcher({\n operationsYamlPath: this.config.main.openapi,\n viewsYamlPath: this.config.renderer.openapi,\n controllersDir: this.config.main.controllers,\n outDir,\n rendererOutDir: path.resolve(this.cwd, this.config.renderer.componentDir, 'generated'),\n cwd: this.cwd,\n onViewsChange: async () => {\n // Re-parse views and regenerate client router manifest\n const viewsContent = readFileSync(\n path.resolve(this.cwd, this.config!.renderer.openapi),\n 'utf-8',\n );\n const views = parseViews(viewsContent);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config!.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config!.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config!.renderer.entry,\n }),\n );\n\n logger.info('views renderer codegen regenerated', { rendererOutDir });\n },\n });\n this.yamlWatcher.start();\n logger.info('yaml watcher started');\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/dev/wood_dev_server.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseConfig, resolveRendererTraceBatching } from '../config/config_parser.js';\nimport { parseOperations } from '../parser/operations_parser.js';\nimport { parseViews } from '../parser/views_parser.js';\nimport { generatePreload } from '../codegen/preload_generator.js';\nimport { generateTypes } from '../codegen/type_generator.js';\nimport { generateTestMock } from '../codegen/test_mock_generator.js';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.js';\nimport { generateRuntime } from '../codegen/runtime_generator.js';\nimport { generateRendererApp } from '../codegen/renderer_app_generator.js';\nimport { BackendBridge } from '../bridge/backend_bridge.js';\nimport { BackendWatcher } from './backend_watcher.js';\nimport { YamlWatcher } from './yaml_watcher.js';\nimport { EsbuildBackend } from './esbuild_backend.js';\nimport type { WoodConfig } from '../types/index.js';\n\nconst logger = getLogger('wood:dev');\n\nexport interface DevServerOptions {\n configPath?: string;\n cwd?: string;\n}\n\nexport class WoodDevServer {\n private config: WoodConfig | null = null;\n private bridge: BackendBridge | null = null;\n private backendWatcher: BackendWatcher | null = null;\n private yamlWatcher: YamlWatcher | null = null;\n private esbuild: EsbuildBackend | null = null;\n private cwd: string;\n\n constructor(options: DevServerOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n }\n\n /**\n * Start the Wood development server.\n *\n * Automatically sets process.env.WOOD_MODE = 'development' so the app\n * can conditionally use dynamic controller imports (dev) vs pre-registered\n * controllers from the generated file (production).\n *\n * Steps:\n * 1. Parse config\n * 2. Parse + stitch YAML\n * 3. Generate preload, types, mock\n * 4. Build backend with esbuild\n * 5. (electron-vite would be started here -- omitted for MVP)\n * 6. Spawn backend via bridge\n * 7. Start watchers\n */\n async start(): Promise<void> {\n process.env.WOOD_MODE = 'development';\n\n // 1. Parse config\n const configPath = path.resolve(this.cwd, 'wood.config.yml');\n this.config = parseConfig(configPath);\n logger.info('config loaded', { outDir: this.config.outDir });\n\n // 2. Parse operations YAML\n const opsYamlPath = path.resolve(this.cwd, this.config.main.openapi);\n const opsContent = readFileSync(opsYamlPath, 'utf-8');\n const operations = parseOperations(opsContent);\n logger.info('operations parsed', { count: operations.size });\n\n // 3. Parse views YAML\n const viewsYamlPath = path.resolve(this.cwd, this.config.renderer.openapi);\n const viewsContent = readFileSync(viewsYamlPath, 'utf-8');\n const views = parseViews(viewsContent);\n logger.info('views parsed', { count: views.length });\n\n // 4. Generate files\n const outDir = path.resolve(this.cwd, this.config.outDir);\n mkdirSync(outDir, { recursive: true });\n\n const preloadCode = generatePreload(operations, {\n traceBatching: resolveRendererTraceBatching(this.config),\n });\n writeFileSync(path.join(outDir, 'preload.generated.ts'), preloadCode);\n\n const typesCode = generateTypes(operations);\n writeFileSync(path.join(outDir, 'wood.d.ts'), typesCode);\n\n const mockCode = generateTestMock(operations);\n writeFileSync(path.join(outDir, 'wood.mock.ts'), mockCode);\n\n const controllersDir = path.resolve(this.cwd, this.config.main.controllers);\n const controllerRegCode = generateControllerRegistration(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'controllers.generated.ts'), controllerRegCode);\n\n const runtimeCode = generateRuntime(operations, {\n controllersDir,\n outDir,\n });\n writeFileSync(path.join(outDir, 'runtime.generated.ts'), runtimeCode);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(path.join(rendererOutDir, 'wood.d.ts'), typesCode);\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config.renderer.entry,\n }),\n );\n\n logger.info('codegen complete', { outDir });\n\n // 5. Build backend with esbuild (initial build + create incremental context)\n const backendEntry = this.config.main.entry;\n const backendOutfile = path.join(this.config.outDir, 'backend', 'index.js');\n\n this.esbuild = new EsbuildBackend({\n entryPoint: backendEntry,\n outfile: backendOutfile,\n cwd: this.cwd,\n external: this.config.build ? [] : undefined,\n });\n\n await this.esbuild.build();\n await this.esbuild.createContext();\n\n // 6. Start backend bridge (split-serve)\n if (this.config.dev?.splitServe !== false) {\n const resolvedBackendEntry = path.resolve(this.cwd, backendOutfile);\n this.bridge = new BackendBridge({\n backendEntry: resolvedBackendEntry,\n onReady: () => {\n logger.info('backend ready (split-serve)');\n },\n onPush: (channel, data) => {\n logger.debug('backend push', { channel, data });\n },\n onExit: (code, signal) => {\n logger.debug('backend exited', { code, signal });\n },\n });\n await this.bridge.start();\n }\n\n // 7. Start watchers\n if (this.config.dev?.watch !== false) {\n this.startWatchers(outDir);\n }\n }\n\n /** Stop the dev server and clean up all resources. */\n async stop(): Promise<void> {\n this.backendWatcher?.stop();\n this.yamlWatcher?.stop();\n\n if (this.bridge) {\n await this.bridge.stop();\n logger.info('backend bridge stopped');\n }\n\n if (this.esbuild) {\n await this.esbuild.dispose();\n }\n }\n\n /** Get the parsed config. */\n getConfig(): WoodConfig | null {\n return this.config;\n }\n\n private startWatchers(outDir: string): void {\n if (!this.config) return;\n\n // Backend watcher: server + middleware files -> rebuild + restart\n if (this.bridge && this.esbuild) {\n const backendPatterns = [\n `${this.config.main.controllers}/**/*.ts`,\n `${this.config.main.middleware}/**/*.ts`,\n `${this.config.main.entry}`,\n ...(this.config.main.watch ?? []),\n ];\n\n const esbuild = this.esbuild;\n this.backendWatcher = new BackendWatcher({\n patterns: backendPatterns,\n bridge: this.bridge,\n buildFn: () => esbuild.rebuild().then(() => {}),\n cwd: this.cwd,\n });\n this.backendWatcher.start();\n logger.info('backend watcher started', { patterns: backendPatterns });\n }\n\n // YAML watcher: operations + views YAML -> regenerate codegen\n this.yamlWatcher = new YamlWatcher({\n operationsYamlPath: this.config.main.openapi,\n viewsYamlPath: this.config.renderer.openapi,\n controllersDir: this.config.main.controllers,\n outDir,\n rendererOutDir: path.resolve(this.cwd, this.config.renderer.componentDir, 'generated'),\n cwd: this.cwd,\n traceBatching: resolveRendererTraceBatching(this.config),\n onViewsChange: async () => {\n // Re-parse views and regenerate client router manifest\n const viewsContent = readFileSync(\n path.resolve(this.cwd, this.config!.renderer.openapi),\n 'utf-8',\n );\n const views = parseViews(viewsContent);\n\n const rendererComponentDir = path.resolve(this.cwd, this.config!.renderer.componentDir);\n const rendererOutDir = path.resolve(this.cwd, this.config!.renderer.componentDir, 'generated');\n mkdirSync(rendererOutDir, { recursive: true });\n\n writeFileSync(\n path.join(rendererOutDir, 'app.ts'),\n generateRendererApp(views, {\n componentDir: rendererComponentDir,\n outDir: rendererOutDir,\n entryViewKey: this.config!.renderer.entry,\n }),\n );\n\n logger.info('views renderer codegen regenerated', { rendererOutDir });\n },\n });\n this.yamlWatcher.start();\n logger.info('yaml watcher started');\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -98,7 +98,7 @@ class YamlWatcher {
|
|
|
98
98
|
const typesCode = (0, import_type_generator.generateTypes)(operations);
|
|
99
99
|
(0, import_fs.writeFileSync)(
|
|
100
100
|
import_path.default.join(this.options.outDir, "preload.generated.ts"),
|
|
101
|
-
(0, import_preload_generator.generatePreload)(operations)
|
|
101
|
+
(0, import_preload_generator.generatePreload)(operations, { traceBatching: this.options.traceBatching })
|
|
102
102
|
);
|
|
103
103
|
(0, import_fs.writeFileSync)(
|
|
104
104
|
import_path.default.join(this.options.outDir, "wood.d.ts"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dev/yaml_watcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { Subject, debounceTime, switchMap, from } from 'rxjs';\nimport { readFileSync, writeFileSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { generatePreload } from '../codegen/preload_generator.cjs';\nimport { generateTypes } from '../codegen/type_generator.cjs';\nimport { generateTestMock } from '../codegen/test_mock_generator.cjs';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.cjs';\nimport { generateRuntime } from '../codegen/runtime_generator.cjs';\n\nconst logger = getLogger('wood:dev:yaml-watcher');\n\nexport interface YamlWatcherOptions {\n operationsYamlPath: string;\n viewsYamlPath: string;\n controllersDir: string;\n outDir: string;\n rendererOutDir?: string;\n cwd: string;\n /** Called after views YAML changes to regenerate the client router manifest. */\n onViewsChange?: () => Promise<void>;\n}\n\nexport class YamlWatcher {\n private watcher: FSWatcher | null = null;\n private change$ = new Subject<string>();\n\n constructor(private options: YamlWatcherOptions) {}\n\n start(): void {\n const patterns = [\n this.options.operationsYamlPath,\n this.options.viewsYamlPath,\n path.dirname(this.options.operationsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.operationsYamlPath) + '/**/*.yml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yml',\n ];\n\n this.watcher = watch(patterns, {\n cwd: this.options.cwd,\n ignoreInitial: true,\n });\n\n this.watcher.on('change', (filePath: string) => {\n logger.debug('yaml file changed', { filePath });\n this.change$.next(filePath);\n });\n\n this.change$.pipe(\n debounceTime(100),\n switchMap((filePath) => from(this.regenerate(filePath))),\n ).subscribe({\n error: (err) => {\n logger.error('yaml watcher pipeline error', { error: String(err) });\n },\n });\n }\n\n stop(): void {\n this.watcher?.close();\n this.change$.complete();\n }\n\n private isOperationsYaml(filePath: string): boolean {\n const opsDir = path.dirname(this.options.operationsYamlPath);\n return filePath.startsWith(opsDir) || filePath === this.options.operationsYamlPath;\n }\n\n private isViewsYaml(filePath: string): boolean {\n const viewsDir = path.dirname(this.options.viewsYamlPath);\n return filePath.startsWith(viewsDir) || filePath === this.options.viewsYamlPath;\n }\n\n private async regenerate(filePath: string): Promise<void> {\n try {\n if (this.isOperationsYaml(filePath)) {\n // Operations change -> regenerate preload + types + mock\n const opsContent = readFileSync(\n path.resolve(this.options.cwd, this.options.operationsYamlPath),\n 'utf-8',\n );\n const operations = parseOperations(opsContent);\n const typesCode = generateTypes(operations);\n\n writeFileSync(\n path.join(this.options.outDir, 'preload.generated.ts'),\n generatePreload(operations),\n );\n writeFileSync(\n path.join(this.options.outDir, 'wood.d.ts'),\n typesCode,\n );\n if (this.options.rendererOutDir) {\n writeFileSync(\n path.join(this.options.rendererOutDir, 'wood.d.ts'),\n typesCode,\n );\n }\n writeFileSync(\n path.join(this.options.outDir, 'wood.mock.ts'),\n generateTestMock(operations),\n );\n\n const controllersDir = path.resolve(this.options.cwd, this.options.controllersDir);\n writeFileSync(\n path.join(this.options.outDir, 'controllers.generated.ts'),\n generateControllerRegistration(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n writeFileSync(\n path.join(this.options.outDir, 'runtime.generated.ts'),\n generateRuntime(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n logger.info('operations codegen regenerated');\n }\n\n if (this.isViewsYaml(filePath)) {\n // Views change -> regenerate client router manifest\n if (this.options.onViewsChange) {\n await this.options.onViewsChange();\n }\n\n logger.info('views manifest regenerated');\n }\n } catch (err) {\n logger.error('yaml regeneration failed', { error: String(err) });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAsC;AACtC,kBAAuD;AACvD,gBAA4C;AAC5C,kBAAiB;AACjB,oBAA0B;AAC1B,+BAAgC;AAChC,+BAAgC;AAChC,4BAA8B;AAC9B,iCAAiC;AACjC,+CAA+C;AAC/C,+BAAgC;AAEhC,MAAM,aAAS,yBAAU,uBAAuB;
|
|
1
|
+
{"version":3,"sources":["../../src/dev/yaml_watcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { Subject, debounceTime, switchMap, from } from 'rxjs';\nimport { readFileSync, writeFileSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseOperations } from '../parser/operations_parser.cjs';\nimport { generatePreload } from '../codegen/preload_generator.cjs';\nimport { generateTypes } from '../codegen/type_generator.cjs';\nimport { generateTestMock } from '../codegen/test_mock_generator.cjs';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.cjs';\nimport { generateRuntime } from '../codegen/runtime_generator.cjs';\n\nconst logger = getLogger('wood:dev:yaml-watcher');\n\nexport interface YamlWatcherOptions {\n operationsYamlPath: string;\n viewsYamlPath: string;\n controllersDir: string;\n outDir: string;\n rendererOutDir?: string;\n cwd: string;\n /** Resolved renderer→main trace batching policy for preload generation. */\n traceBatching?: import('../types/config.cjs').RendererTraceBatchingConfig;\n /** Called after views YAML changes to regenerate the client router manifest. */\n onViewsChange?: () => Promise<void>;\n}\n\nexport class YamlWatcher {\n private watcher: FSWatcher | null = null;\n private change$ = new Subject<string>();\n\n constructor(private options: YamlWatcherOptions) {}\n\n start(): void {\n const patterns = [\n this.options.operationsYamlPath,\n this.options.viewsYamlPath,\n path.dirname(this.options.operationsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.operationsYamlPath) + '/**/*.yml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yml',\n ];\n\n this.watcher = watch(patterns, {\n cwd: this.options.cwd,\n ignoreInitial: true,\n });\n\n this.watcher.on('change', (filePath: string) => {\n logger.debug('yaml file changed', { filePath });\n this.change$.next(filePath);\n });\n\n this.change$.pipe(\n debounceTime(100),\n switchMap((filePath) => from(this.regenerate(filePath))),\n ).subscribe({\n error: (err) => {\n logger.error('yaml watcher pipeline error', { error: String(err) });\n },\n });\n }\n\n stop(): void {\n this.watcher?.close();\n this.change$.complete();\n }\n\n private isOperationsYaml(filePath: string): boolean {\n const opsDir = path.dirname(this.options.operationsYamlPath);\n return filePath.startsWith(opsDir) || filePath === this.options.operationsYamlPath;\n }\n\n private isViewsYaml(filePath: string): boolean {\n const viewsDir = path.dirname(this.options.viewsYamlPath);\n return filePath.startsWith(viewsDir) || filePath === this.options.viewsYamlPath;\n }\n\n private async regenerate(filePath: string): Promise<void> {\n try {\n if (this.isOperationsYaml(filePath)) {\n // Operations change -> regenerate preload + types + mock\n const opsContent = readFileSync(\n path.resolve(this.options.cwd, this.options.operationsYamlPath),\n 'utf-8',\n );\n const operations = parseOperations(opsContent);\n const typesCode = generateTypes(operations);\n\n writeFileSync(\n path.join(this.options.outDir, 'preload.generated.ts'),\n generatePreload(operations, { traceBatching: this.options.traceBatching }),\n );\n writeFileSync(\n path.join(this.options.outDir, 'wood.d.ts'),\n typesCode,\n );\n if (this.options.rendererOutDir) {\n writeFileSync(\n path.join(this.options.rendererOutDir, 'wood.d.ts'),\n typesCode,\n );\n }\n writeFileSync(\n path.join(this.options.outDir, 'wood.mock.ts'),\n generateTestMock(operations),\n );\n\n const controllersDir = path.resolve(this.options.cwd, this.options.controllersDir);\n writeFileSync(\n path.join(this.options.outDir, 'controllers.generated.ts'),\n generateControllerRegistration(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n writeFileSync(\n path.join(this.options.outDir, 'runtime.generated.ts'),\n generateRuntime(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n logger.info('operations codegen regenerated');\n }\n\n if (this.isViewsYaml(filePath)) {\n // Views change -> regenerate client router manifest\n if (this.options.onViewsChange) {\n await this.options.onViewsChange();\n }\n\n logger.info('views manifest regenerated');\n }\n } catch (err) {\n logger.error('yaml regeneration failed', { error: String(err) });\n }\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RendererTraceBatchingConfig } from '../types/config.cjs';
|
|
2
|
+
|
|
1
3
|
interface YamlWatcherOptions {
|
|
2
4
|
operationsYamlPath: string;
|
|
3
5
|
viewsYamlPath: string;
|
|
@@ -5,6 +7,8 @@ interface YamlWatcherOptions {
|
|
|
5
7
|
outDir: string;
|
|
6
8
|
rendererOutDir?: string;
|
|
7
9
|
cwd: string;
|
|
10
|
+
/** Resolved renderer→main trace batching policy for preload generation. */
|
|
11
|
+
traceBatching?: RendererTraceBatchingConfig;
|
|
8
12
|
/** Called after views YAML changes to regenerate the client router manifest. */
|
|
9
13
|
onViewsChange?: () => Promise<void>;
|
|
10
14
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RendererTraceBatchingConfig } from '../types/config.js';
|
|
2
|
+
|
|
1
3
|
interface YamlWatcherOptions {
|
|
2
4
|
operationsYamlPath: string;
|
|
3
5
|
viewsYamlPath: string;
|
|
@@ -5,6 +7,8 @@ interface YamlWatcherOptions {
|
|
|
5
7
|
outDir: string;
|
|
6
8
|
rendererOutDir?: string;
|
|
7
9
|
cwd: string;
|
|
10
|
+
/** Resolved renderer→main trace batching policy for preload generation. */
|
|
11
|
+
traceBatching?: RendererTraceBatchingConfig;
|
|
8
12
|
/** Called after views YAML changes to regenerate the client router manifest. */
|
|
9
13
|
onViewsChange?: () => Promise<void>;
|
|
10
14
|
}
|
package/dist/dev/yaml_watcher.js
CHANGED
|
@@ -65,7 +65,7 @@ class YamlWatcher {
|
|
|
65
65
|
const typesCode = generateTypes(operations);
|
|
66
66
|
writeFileSync(
|
|
67
67
|
path.join(this.options.outDir, "preload.generated.ts"),
|
|
68
|
-
generatePreload(operations)
|
|
68
|
+
generatePreload(operations, { traceBatching: this.options.traceBatching })
|
|
69
69
|
);
|
|
70
70
|
writeFileSync(
|
|
71
71
|
path.join(this.options.outDir, "wood.d.ts"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/dev/yaml_watcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { Subject, debounceTime, switchMap, from } from 'rxjs';\nimport { readFileSync, writeFileSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseOperations } from '../parser/operations_parser.js';\nimport { generatePreload } from '../codegen/preload_generator.js';\nimport { generateTypes } from '../codegen/type_generator.js';\nimport { generateTestMock } from '../codegen/test_mock_generator.js';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.js';\nimport { generateRuntime } from '../codegen/runtime_generator.js';\n\nconst logger = getLogger('wood:dev:yaml-watcher');\n\nexport interface YamlWatcherOptions {\n operationsYamlPath: string;\n viewsYamlPath: string;\n controllersDir: string;\n outDir: string;\n rendererOutDir?: string;\n cwd: string;\n /** Called after views YAML changes to regenerate the client router manifest. */\n onViewsChange?: () => Promise<void>;\n}\n\nexport class YamlWatcher {\n private watcher: FSWatcher | null = null;\n private change$ = new Subject<string>();\n\n constructor(private options: YamlWatcherOptions) {}\n\n start(): void {\n const patterns = [\n this.options.operationsYamlPath,\n this.options.viewsYamlPath,\n path.dirname(this.options.operationsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.operationsYamlPath) + '/**/*.yml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yml',\n ];\n\n this.watcher = watch(patterns, {\n cwd: this.options.cwd,\n ignoreInitial: true,\n });\n\n this.watcher.on('change', (filePath: string) => {\n logger.debug('yaml file changed', { filePath });\n this.change$.next(filePath);\n });\n\n this.change$.pipe(\n debounceTime(100),\n switchMap((filePath) => from(this.regenerate(filePath))),\n ).subscribe({\n error: (err) => {\n logger.error('yaml watcher pipeline error', { error: String(err) });\n },\n });\n }\n\n stop(): void {\n this.watcher?.close();\n this.change$.complete();\n }\n\n private isOperationsYaml(filePath: string): boolean {\n const opsDir = path.dirname(this.options.operationsYamlPath);\n return filePath.startsWith(opsDir) || filePath === this.options.operationsYamlPath;\n }\n\n private isViewsYaml(filePath: string): boolean {\n const viewsDir = path.dirname(this.options.viewsYamlPath);\n return filePath.startsWith(viewsDir) || filePath === this.options.viewsYamlPath;\n }\n\n private async regenerate(filePath: string): Promise<void> {\n try {\n if (this.isOperationsYaml(filePath)) {\n // Operations change -> regenerate preload + types + mock\n const opsContent = readFileSync(\n path.resolve(this.options.cwd, this.options.operationsYamlPath),\n 'utf-8',\n );\n const operations = parseOperations(opsContent);\n const typesCode = generateTypes(operations);\n\n writeFileSync(\n path.join(this.options.outDir, 'preload.generated.ts'),\n generatePreload(operations),\n );\n writeFileSync(\n path.join(this.options.outDir, 'wood.d.ts'),\n typesCode,\n );\n if (this.options.rendererOutDir) {\n writeFileSync(\n path.join(this.options.rendererOutDir, 'wood.d.ts'),\n typesCode,\n );\n }\n writeFileSync(\n path.join(this.options.outDir, 'wood.mock.ts'),\n generateTestMock(operations),\n );\n\n const controllersDir = path.resolve(this.options.cwd, this.options.controllersDir);\n writeFileSync(\n path.join(this.options.outDir, 'controllers.generated.ts'),\n generateControllerRegistration(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n writeFileSync(\n path.join(this.options.outDir, 'runtime.generated.ts'),\n generateRuntime(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n logger.info('operations codegen regenerated');\n }\n\n if (this.isViewsYaml(filePath)) {\n // Views change -> regenerate client router manifest\n if (this.options.onViewsChange) {\n await this.options.onViewsChange();\n }\n\n logger.info('views manifest regenerated');\n }\n } catch (err) {\n logger.error('yaml regeneration failed', { error: String(err) });\n }\n }\n}\n"],"mappings":"AAAA,SAAS,aAA6B;AACtC,SAAS,SAAS,cAAc,WAAW,YAAY;AACvD,SAAS,cAAc,qBAAqB;AAC5C,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAC1B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,sCAAsC;AAC/C,SAAS,uBAAuB;AAEhC,MAAM,SAAS,UAAU,uBAAuB;
|
|
1
|
+
{"version":3,"sources":["../../src/dev/yaml_watcher.ts"],"sourcesContent":["import { watch, type FSWatcher } from 'chokidar';\nimport { Subject, debounceTime, switchMap, from } from 'rxjs';\nimport { readFileSync, writeFileSync } from 'fs';\nimport path from 'path';\nimport { getLogger } from '@noego/logger';\nimport { parseOperations } from '../parser/operations_parser.js';\nimport { generatePreload } from '../codegen/preload_generator.js';\nimport { generateTypes } from '../codegen/type_generator.js';\nimport { generateTestMock } from '../codegen/test_mock_generator.js';\nimport { generateControllerRegistration } from '../codegen/controller_registration_generator.js';\nimport { generateRuntime } from '../codegen/runtime_generator.js';\n\nconst logger = getLogger('wood:dev:yaml-watcher');\n\nexport interface YamlWatcherOptions {\n operationsYamlPath: string;\n viewsYamlPath: string;\n controllersDir: string;\n outDir: string;\n rendererOutDir?: string;\n cwd: string;\n /** Resolved renderer→main trace batching policy for preload generation. */\n traceBatching?: import('../types/config.js').RendererTraceBatchingConfig;\n /** Called after views YAML changes to regenerate the client router manifest. */\n onViewsChange?: () => Promise<void>;\n}\n\nexport class YamlWatcher {\n private watcher: FSWatcher | null = null;\n private change$ = new Subject<string>();\n\n constructor(private options: YamlWatcherOptions) {}\n\n start(): void {\n const patterns = [\n this.options.operationsYamlPath,\n this.options.viewsYamlPath,\n path.dirname(this.options.operationsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.operationsYamlPath) + '/**/*.yml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yaml',\n path.dirname(this.options.viewsYamlPath) + '/**/*.yml',\n ];\n\n this.watcher = watch(patterns, {\n cwd: this.options.cwd,\n ignoreInitial: true,\n });\n\n this.watcher.on('change', (filePath: string) => {\n logger.debug('yaml file changed', { filePath });\n this.change$.next(filePath);\n });\n\n this.change$.pipe(\n debounceTime(100),\n switchMap((filePath) => from(this.regenerate(filePath))),\n ).subscribe({\n error: (err) => {\n logger.error('yaml watcher pipeline error', { error: String(err) });\n },\n });\n }\n\n stop(): void {\n this.watcher?.close();\n this.change$.complete();\n }\n\n private isOperationsYaml(filePath: string): boolean {\n const opsDir = path.dirname(this.options.operationsYamlPath);\n return filePath.startsWith(opsDir) || filePath === this.options.operationsYamlPath;\n }\n\n private isViewsYaml(filePath: string): boolean {\n const viewsDir = path.dirname(this.options.viewsYamlPath);\n return filePath.startsWith(viewsDir) || filePath === this.options.viewsYamlPath;\n }\n\n private async regenerate(filePath: string): Promise<void> {\n try {\n if (this.isOperationsYaml(filePath)) {\n // Operations change -> regenerate preload + types + mock\n const opsContent = readFileSync(\n path.resolve(this.options.cwd, this.options.operationsYamlPath),\n 'utf-8',\n );\n const operations = parseOperations(opsContent);\n const typesCode = generateTypes(operations);\n\n writeFileSync(\n path.join(this.options.outDir, 'preload.generated.ts'),\n generatePreload(operations, { traceBatching: this.options.traceBatching }),\n );\n writeFileSync(\n path.join(this.options.outDir, 'wood.d.ts'),\n typesCode,\n );\n if (this.options.rendererOutDir) {\n writeFileSync(\n path.join(this.options.rendererOutDir, 'wood.d.ts'),\n typesCode,\n );\n }\n writeFileSync(\n path.join(this.options.outDir, 'wood.mock.ts'),\n generateTestMock(operations),\n );\n\n const controllersDir = path.resolve(this.options.cwd, this.options.controllersDir);\n writeFileSync(\n path.join(this.options.outDir, 'controllers.generated.ts'),\n generateControllerRegistration(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n writeFileSync(\n path.join(this.options.outDir, 'runtime.generated.ts'),\n generateRuntime(operations, {\n controllersDir,\n outDir: this.options.outDir,\n }),\n );\n\n logger.info('operations codegen regenerated');\n }\n\n if (this.isViewsYaml(filePath)) {\n // Views change -> regenerate client router manifest\n if (this.options.onViewsChange) {\n await this.options.onViewsChange();\n }\n\n logger.info('views manifest regenerated');\n }\n } catch (err) {\n logger.error('yaml regeneration failed', { error: String(err) });\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
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 frontend_lifecycle_exports = {};
|
|
20
|
+
__export(frontend_lifecycle_exports, {
|
|
21
|
+
FrontendLifecycleOwner: () => FrontendLifecycleOwner
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(frontend_lifecycle_exports);
|
|
24
|
+
var import_work_registry = require("./work_registry.js");
|
|
25
|
+
class FrontendLifecycleOwner {
|
|
26
|
+
constructor(registry, owner) {
|
|
27
|
+
this.registry = registry;
|
|
28
|
+
this.owner = owner;
|
|
29
|
+
this.abortController = new AbortController();
|
|
30
|
+
this.resources = [];
|
|
31
|
+
this.disposed = false;
|
|
32
|
+
}
|
|
33
|
+
get signal() {
|
|
34
|
+
return this.abortController.signal;
|
|
35
|
+
}
|
|
36
|
+
track(work, options) {
|
|
37
|
+
if (this.disposed) {
|
|
38
|
+
throw new import_work_registry.FrontendWorkError(
|
|
39
|
+
`cannot track "${options.label}": lifecycle "${this.owner}" is disposed. Work started after a page/environment ended is a product lifecycle bug.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return this.registry.track(work, {
|
|
43
|
+
label: options.label,
|
|
44
|
+
kind: options.kind ?? "tracked",
|
|
45
|
+
owner: this.owner
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
own(resource) {
|
|
49
|
+
if (this.disposed) {
|
|
50
|
+
throw new import_work_registry.FrontendWorkError(
|
|
51
|
+
`cannot own a resource: lifecycle "${this.owner}" is disposed.`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
this.resources.push(resource);
|
|
55
|
+
}
|
|
56
|
+
get isDisposed() {
|
|
57
|
+
return this.disposed;
|
|
58
|
+
}
|
|
59
|
+
/** Abort owned work and dispose owned resources in reverse order. */
|
|
60
|
+
async dispose() {
|
|
61
|
+
if (this.disposed) return;
|
|
62
|
+
this.disposed = true;
|
|
63
|
+
this.abortController.abort();
|
|
64
|
+
for (const resource of this.resources.reverse()) {
|
|
65
|
+
await resource.dispose();
|
|
66
|
+
}
|
|
67
|
+
this.resources.length = 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
71
|
+
0 && (module.exports = {
|
|
72
|
+
FrontendLifecycleOwner
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=frontend_lifecycle.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/frontend/frontend_lifecycle.ts"],"sourcesContent":["/**\n * Production lifecycle owners for deliberately detached frontend work\n * (18A D-FAS-01 §2.2). Two natural owners exist per environment:\n *\n * page lifecycle — default for PageController work; aborted and\n * disposed when that page ends\n * application lifecycle — explicit for work that intentionally survives\n * page navigation; disposed with the environment\n *\n * PageControllers/client services register their own deliberately detached\n * finite work through their injected lifecycle owner — tests do not repair\n * unowned product code by wrapping it in track() from the outside.\n */\nimport { WorkRegistry, FrontendWorkError } from './work_registry.js';\n\nexport interface FrontendLifecycle {\n readonly signal: AbortSignal;\n\n track<T>(\n work: Promise<T>,\n options: {\n label: string;\n kind?: string;\n },\n ): Promise<T>;\n\n own(resource: { dispose(): void | Promise<void> }): void;\n}\n\nexport class FrontendLifecycleOwner implements FrontendLifecycle {\n private readonly abortController = new AbortController();\n private readonly resources: Array<{ dispose(): void | Promise<void> }> = [];\n private disposed = false;\n\n constructor(\n private readonly registry: WorkRegistry,\n /** Diagnostic owner identity, e.g. `page main.chat_dom` or `application`. */\n readonly owner: string,\n ) {}\n\n get signal(): AbortSignal {\n return this.abortController.signal;\n }\n\n track<T>(work: Promise<T>, options: { label: string; kind?: string }): Promise<T> {\n if (this.disposed) {\n throw new FrontendWorkError(\n `cannot track \"${options.label}\": lifecycle \"${this.owner}\" is disposed. ` +\n 'Work started after a page/environment ended is a product lifecycle bug.',\n );\n }\n return this.registry.track(work, {\n label: options.label,\n kind: options.kind ?? 'tracked',\n owner: this.owner,\n });\n }\n\n own(resource: { dispose(): void | Promise<void> }): void {\n if (this.disposed) {\n throw new FrontendWorkError(\n `cannot own a resource: lifecycle \"${this.owner}\" is disposed.`,\n );\n }\n this.resources.push(resource);\n }\n\n get isDisposed(): boolean {\n return this.disposed;\n }\n\n /** Abort owned work and dispose owned resources in reverse order. */\n async dispose(): Promise<void> {\n if (this.disposed) return;\n this.disposed = true;\n this.abortController.abort();\n for (const resource of this.resources.reverse()) {\n await resource.dispose();\n }\n this.resources.length = 0;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,2BAAgD;AAgBzC,MAAM,uBAAoD;AAAA,EAK/D,YACmB,UAER,OACT;AAHiB;AAER;AAPX,SAAiB,kBAAkB,IAAI,gBAAgB;AACvD,SAAiB,YAAwD,CAAC;AAC1E,SAAQ,WAAW;AAAA,EAMhB;AAAA,EAEH,IAAI,SAAsB;AACxB,WAAO,KAAK,gBAAgB;AAAA,EAC9B;AAAA,EAEA,MAAS,MAAkB,SAAuD;AAChF,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI;AAAA,QACR,iBAAiB,QAAQ,KAAK,iBAAiB,KAAK,KAAK;AAAA,MAE3D;AAAA,IACF;AACA,WAAO,KAAK,SAAS,MAAM,MAAM;AAAA,MAC/B,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ,QAAQ;AAAA,MACtB,OAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,UAAqD;AACvD,QAAI,KAAK,UAAU;AACjB,YAAM,IAAI;AAAA,QACR,qCAAqC,KAAK,KAAK;AAAA,MACjD;AAAA,IACF;AACA,SAAK,UAAU,KAAK,QAAQ;AAAA,EAC9B;AAAA,EAEA,IAAI,aAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,QAAI,KAAK,SAAU;AACnB,SAAK,WAAW;AAChB,SAAK,gBAAgB,MAAM;AAC3B,eAAW,YAAY,KAAK,UAAU,QAAQ,GAAG;AAC/C,YAAM,SAAS,QAAQ;AAAA,IACzB;AACA,SAAK,UAAU,SAAS;AAAA,EAC1B;AACF;","names":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { WorkRegistry } from './work_registry.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Production lifecycle owners for deliberately detached frontend work
|
|
5
|
+
* (18A D-FAS-01 §2.2). Two natural owners exist per environment:
|
|
6
|
+
*
|
|
7
|
+
* page lifecycle — default for PageController work; aborted and
|
|
8
|
+
* disposed when that page ends
|
|
9
|
+
* application lifecycle — explicit for work that intentionally survives
|
|
10
|
+
* page navigation; disposed with the environment
|
|
11
|
+
*
|
|
12
|
+
* PageControllers/client services register their own deliberately detached
|
|
13
|
+
* finite work through their injected lifecycle owner — tests do not repair
|
|
14
|
+
* unowned product code by wrapping it in track() from the outside.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface FrontendLifecycle {
|
|
18
|
+
readonly signal: AbortSignal;
|
|
19
|
+
track<T>(work: Promise<T>, options: {
|
|
20
|
+
label: string;
|
|
21
|
+
kind?: string;
|
|
22
|
+
}): Promise<T>;
|
|
23
|
+
own(resource: {
|
|
24
|
+
dispose(): void | Promise<void>;
|
|
25
|
+
}): void;
|
|
26
|
+
}
|
|
27
|
+
declare class FrontendLifecycleOwner implements FrontendLifecycle {
|
|
28
|
+
private readonly registry;
|
|
29
|
+
/** Diagnostic owner identity, e.g. `page main.chat_dom` or `application`. */
|
|
30
|
+
readonly owner: string;
|
|
31
|
+
private readonly abortController;
|
|
32
|
+
private readonly resources;
|
|
33
|
+
private disposed;
|
|
34
|
+
constructor(registry: WorkRegistry,
|
|
35
|
+
/** Diagnostic owner identity, e.g. `page main.chat_dom` or `application`. */
|
|
36
|
+
owner: string);
|
|
37
|
+
get signal(): AbortSignal;
|
|
38
|
+
track<T>(work: Promise<T>, options: {
|
|
39
|
+
label: string;
|
|
40
|
+
kind?: string;
|
|
41
|
+
}): Promise<T>;
|
|
42
|
+
own(resource: {
|
|
43
|
+
dispose(): void | Promise<void>;
|
|
44
|
+
}): void;
|
|
45
|
+
get isDisposed(): boolean;
|
|
46
|
+
/** Abort owned work and dispose owned resources in reverse order. */
|
|
47
|
+
dispose(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { type FrontendLifecycle, FrontendLifecycleOwner };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { WorkRegistry } from './work_registry.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Production lifecycle owners for deliberately detached frontend work
|
|
5
|
+
* (18A D-FAS-01 §2.2). Two natural owners exist per environment:
|
|
6
|
+
*
|
|
7
|
+
* page lifecycle — default for PageController work; aborted and
|
|
8
|
+
* disposed when that page ends
|
|
9
|
+
* application lifecycle — explicit for work that intentionally survives
|
|
10
|
+
* page navigation; disposed with the environment
|
|
11
|
+
*
|
|
12
|
+
* PageControllers/client services register their own deliberately detached
|
|
13
|
+
* finite work through their injected lifecycle owner — tests do not repair
|
|
14
|
+
* unowned product code by wrapping it in track() from the outside.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
interface FrontendLifecycle {
|
|
18
|
+
readonly signal: AbortSignal;
|
|
19
|
+
track<T>(work: Promise<T>, options: {
|
|
20
|
+
label: string;
|
|
21
|
+
kind?: string;
|
|
22
|
+
}): Promise<T>;
|
|
23
|
+
own(resource: {
|
|
24
|
+
dispose(): void | Promise<void>;
|
|
25
|
+
}): void;
|
|
26
|
+
}
|
|
27
|
+
declare class FrontendLifecycleOwner implements FrontendLifecycle {
|
|
28
|
+
private readonly registry;
|
|
29
|
+
/** Diagnostic owner identity, e.g. `page main.chat_dom` or `application`. */
|
|
30
|
+
readonly owner: string;
|
|
31
|
+
private readonly abortController;
|
|
32
|
+
private readonly resources;
|
|
33
|
+
private disposed;
|
|
34
|
+
constructor(registry: WorkRegistry,
|
|
35
|
+
/** Diagnostic owner identity, e.g. `page main.chat_dom` or `application`. */
|
|
36
|
+
owner: string);
|
|
37
|
+
get signal(): AbortSignal;
|
|
38
|
+
track<T>(work: Promise<T>, options: {
|
|
39
|
+
label: string;
|
|
40
|
+
kind?: string;
|
|
41
|
+
}): Promise<T>;
|
|
42
|
+
own(resource: {
|
|
43
|
+
dispose(): void | Promise<void>;
|
|
44
|
+
}): void;
|
|
45
|
+
get isDisposed(): boolean;
|
|
46
|
+
/** Abort owned work and dispose owned resources in reverse order. */
|
|
47
|
+
dispose(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { type FrontendLifecycle, FrontendLifecycleOwner };
|