@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/runtime/runtime.ts"],"sourcesContent":["import { getLogger } from '@noego/logger';\nimport { WoodRouter } from '../router/wood_router.cjs';\nimport { getContainer } from './get_container.cjs';\nimport {\n RendererTraceBatchHost,\n TraceProviderConfiguration,\n dispatchRendererTracePayload,\n} from '../tracing/index.js';\nimport {\n setMainTraceMinLevel,\n setRendererTraceMinLevel,\n type TraceLevel,\n type TraceRuntimeContext,\n type WoodTraceBatchReceiver,\n} from '../tracing/index.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogDispatchResult,\n type RendererLogEntry,\n type RendererLogLevel,\n} from './renderer_log_dispatcher.js';\nimport { getRendererTraceBatchReceiver } from './renderer_trace_batch_receiver_registry.js';\nimport { resolveWoodAppEnv, type WoodAppEnv } from './app_env.js';\n\nconst logger = getLogger('wood:runtime');\n\ntype IpcMainLike = {\n handle: (channel: string, handler: (_event: unknown, data: unknown) => Promise<unknown> | unknown) => void;\n on: (channel: string, handler: (_event: unknown, ...args: unknown[]) => void) => void;\n removeHandler?: (channel: string) => void;\n removeAllListeners?: (channel: string) => void;\n};\n\nexport interface RegisterRuntimeRouter {\n registerController(name: string, cls: any): void;\n loadOperations(operations: Map<string, any>): void;\n}\n\nexport interface RuntimeOptions {\n ipcMain: IpcMainLike;\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n container?: any;\n controllersDir: string;\n middlewareDir: string;\n mode?: 'bundled' | 'dev';\n /** Override the resolved app environment tier reported to renderers via __woodConfig. */\n appEnv?: WoodAppEnv;\n enableRendererLogBridge?: boolean;\n enableRendererTraceBridge?: boolean;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n /** Resolves only with the acknowledgement produced by the downstream durable receiver. */\n rendererTraceBatchReceiver?: WoodTraceBatchReceiver;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onNavigate?: (data: unknown, event?: unknown) => Promise<unknown>;\n onWindow?: (data: unknown, event?: unknown) => Promise<unknown>;\n onDebug?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n resolveRendererTraceContext?: (event: unknown) => TraceRuntimeContext | undefined;\n}\n\nexport interface RuntimeResult {\n router: WoodRouter;\n}\n\ntype RendererLogPayload = {\n level: string;\n logger: string;\n message: string;\n context?: unknown;\n};\n\ntype IpcInvokeEventLike = {\n sender?: {\n id?: number;\n };\n};\n\ntype RuntimeReservedHandler = (\n data: unknown,\n event?: unknown,\n) => Promise<unknown>;\n\ntype RuntimeTraceSettings = Readonly<{\n enableRendererLogBridge: boolean;\n enableRendererTraceBridge: boolean;\n traceMinLevel: TraceLevel | undefined;\n rendererTraceEnabled: boolean;\n rendererTraceMinLevel: TraceLevel;\n rendererTraceBatchEnabled: boolean;\n}>;\n\nfunction normalizeRendererLogLevel(level: unknown): RendererLogLevel {\n if (typeof level === 'string') {\n const normalized = level.trim().toLowerCase();\n if (normalized.length > 0) {\n return normalized;\n }\n }\n return 'info';\n}\n\nfunction coerceRendererLogPayload(\n rawPayload: unknown,\n event: unknown,\n): RendererLogEntry {\n const payload = (rawPayload ?? {}) as Partial<RendererLogPayload>;\n const ipcEvent = event as IpcInvokeEventLike;\n\n return {\n level: normalizeRendererLogLevel(payload.level),\n logger: typeof payload.logger === 'string' && payload.logger.trim().length > 0\n ? payload.logger\n : 'renderer',\n message: typeof payload.message === 'string' ? payload.message : '',\n context: payload.context,\n timestamp: new Date().toISOString(),\n senderId: typeof ipcEvent?.sender?.id === 'number' ? ipcEvent.sender.id : null,\n };\n}\n\n/**\n * Boot a bundled-safe Wood runtime using pre-generated static runtime artifacts.\n */\nexport async function runtime(options: RuntimeOptions): Promise<RuntimeResult> {\n const {\n ipcMain,\n registerRuntime,\n controllersDir,\n middlewareDir,\n mode = 'bundled',\n enableRendererLogBridge = true,\n enableRendererTraceBridge = true,\n traceMinLevel,\n rendererTraceEnabled = false,\n rendererTraceMinLevel = 'debug',\n } = options;\n\n const container = options.container ?? getContainer();\n const rendererTraceBatchReceiver = options.rendererTraceBatchReceiver\n ?? getRendererTraceBatchReceiver();\n const rendererTraceBatchEnabled = rendererTraceBatchReceiver !== null;\n const rendererTraceBatchHost = new RendererTraceBatchHost(\n rendererTraceBatchReceiver,\n );\n\n logger.info('runtime start', {\n mode,\n hasProvidedContainer: !!options.container,\n controllersDir,\n middlewareDir,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel: traceMinLevel ?? 'debug',\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n });\n\n const traceSettings: RuntimeTraceSettings = {\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel,\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n };\n await configureRuntimeTracing(container, traceSettings);\n\n const router = new WoodRouter({\n container,\n controllersDir,\n middlewareDir,\n mode,\n });\n\n registerRuntime(router);\n logger.info('runtime registration complete');\n\n router.validateControllers();\n logger.info('runtime controller validation complete');\n\n router.precompileSchemas();\n logger.info('runtime schema pre-compilation complete');\n\n registerReservedRuntimeHandlers(router, options, traceSettings, rendererTraceBatchHost);\n registerRuntimeObservationBridges(ipcMain, traceSettings, options.resolveRendererTraceContext);\n\n router.registerIpcHandlers(ipcMain);\n logger.info('runtime ipc handlers registered', {\n channelCount: router.getChannels().length,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n });\n\n return { router };\n}\n\nasync function configureRuntimeTracing(\n container: any,\n settings: RuntimeTraceSettings,\n): Promise<void> {\n if (settings.traceMinLevel) {\n setMainTraceMinLevel(settings.traceMinLevel);\n }\n setRendererTraceMinLevel(settings.rendererTraceMinLevel);\n if (typeof container.instance !== 'function') {\n return;\n }\n\n const traceConfiguration = await container.instance(TraceProviderConfiguration);\n traceConfiguration.configureRuntime('main');\n if (settings.traceMinLevel) {\n traceConfiguration.configureMinLevel(settings.traceMinLevel);\n }\n}\n\nfunction registerReservedRuntimeHandlers(\n router: WoodRouter,\n options: RuntimeOptions,\n settings: RuntimeTraceSettings,\n rendererTraceBatchHost: RendererTraceBatchHost,\n): void {\n router.registerReservedHandler('__load', requireRuntimeHandler('__load', 'onLoad', options.onLoad));\n router.registerReservedHandler('__navigate', requireRuntimeHandler('__navigate', 'onNavigate', options.onNavigate));\n router.registerReservedHandler('__window', requireRuntimeHandler('__window', 'onWindow', options.onWindow));\n router.registerReservedHandler('__debug', requireRuntimeHandler('__debug', 'onDebug', options.onDebug));\n router.registerReservedHandler(\n '__contextMenu',\n requireRuntimeHandler('__contextMenu', 'onContextMenu', options.onContextMenu),\n );\n router.registerReservedHandler('__woodConfig', async () => ({\n rendererTraceEnabled: settings.rendererTraceEnabled,\n rendererTraceMinLevel: settings.rendererTraceMinLevel,\n rendererTraceBatchEnabled: settings.rendererTraceBatchEnabled,\n appEnv: options.appEnv ?? await resolveWoodAppEnv(),\n }));\n router.registerReservedHandler('__traceBatch', async (data, event) => {\n return rendererTraceBatchHost.receive(data, options.resolveRendererTraceContext?.(event) ?? {});\n });\n}\n\nfunction registerRuntimeObservationBridges(\n ipcMain: IpcMainLike,\n settings: RuntimeTraceSettings,\n resolveContext: RuntimeOptions['resolveRendererTraceContext'],\n): void {\n if (settings.enableRendererLogBridge) {\n registerRendererLogBridge(ipcMain);\n }\n ipcMain.removeAllListeners?.('__trace');\n if (settings.enableRendererTraceBridge && settings.rendererTraceEnabled) {\n registerRendererTraceBridge(ipcMain, resolveContext);\n }\n}\n\nfunction requireRuntimeHandler(\n channel: string,\n optionName: string,\n handler: RuntimeReservedHandler | undefined,\n): RuntimeReservedHandler {\n return async (data, event) => {\n if (!handler) {\n throw new Error(`Reserved channel \"${channel}\" not configured. Provide runtime({ ${optionName} }).`);\n }\n return handler(data, event);\n };\n}\n\nfunction registerRendererTraceBridge(\n ipcMain: IpcMainLike,\n resolveContext?: (event: unknown) => TraceRuntimeContext | undefined,\n): void {\n ipcMain.removeAllListeners?.('__trace');\n\n ipcMain.on('__trace', (event, rawPayload) => {\n dispatchRendererTracePayload(rawPayload, resolveContext?.(event));\n });\n\n logger.info('renderer trace bridge registered (fire-and-forget)');\n}\n\nfunction registerRendererLogBridge(ipcMain: IpcMainLike): void {\n const dispatcher = getRendererLogDispatcher();\n\n ipcMain.removeAllListeners?.('__log');\n\n ipcMain.on('__log', (_event, rawPayload) => {\n const entry = coerceRendererLogPayload(rawPayload, null);\n void dispatcher.dispatch(entry).then((result) => {\n const typedResult = result as RendererLogDispatchResult;\n if (!typedResult.ok) {\n logger.warn('renderer log dispatch failed', {\n logger: entry.logger,\n messageLength: entry.message.length,\n reason: typedResult.reason ?? null,\n errorMessage: typedResult.errorMessage ?? null,\n });\n }\n });\n });\n\n logger.info('renderer log bridge registered (fire-and-forget)');\n}\n"],"mappings":"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","names":["import_tracing"]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/runtime.ts"],"sourcesContent":["import { getLogger } from '@noego/logger';\nimport { WoodRouter } from '../router/wood_router.cjs';\nimport { getContainer } from './get_container.cjs';\nimport {\n RendererTraceBatchHost,\n TraceProviderConfiguration,\n dispatchRendererTracePayload,\n} from '../tracing/index.js';\nimport {\n setMainTraceMinLevel,\n setRendererTraceMinLevel,\n type TraceLevel,\n type TraceRuntimeContext,\n type WoodTraceBatchReceiver,\n} from '../tracing/index.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogDispatchResult,\n type RendererLogEntry,\n type RendererLogLevel,\n} from './renderer_log_dispatcher.js';\nimport { dispatchRendererLogBatch } from './renderer_log_batch_receiver.js';\nimport { resolveRendererConfigExtension } from './renderer_config_extension.js';\nimport { getRendererTraceBatchReceiver } from './renderer_trace_batch_receiver_registry.js';\nimport { resolveWoodAppEnv, type WoodAppEnv } from './app_env.js';\n\nconst logger = getLogger('wood:runtime');\n\ntype IpcMainLike = {\n handle: (channel: string, handler: (_event: unknown, data: unknown) => Promise<unknown> | unknown) => void;\n on: (channel: string, handler: (_event: unknown, ...args: unknown[]) => void) => void;\n removeHandler?: (channel: string) => void;\n removeAllListeners?: (channel: string) => void;\n};\n\nexport interface RegisterRuntimeRouter {\n registerController(name: string, cls: any): void;\n loadOperations(operations: Map<string, any>): void;\n}\n\nexport interface RuntimeOptions {\n ipcMain: IpcMainLike;\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n container?: any;\n controllersDir: string;\n middlewareDir: string;\n mode?: 'bundled' | 'dev';\n /** Override the resolved app environment tier reported to renderers via __woodConfig. */\n appEnv?: WoodAppEnv;\n enableRendererLogBridge?: boolean;\n enableRendererTraceBridge?: boolean;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n /** Resolves only with the acknowledgement produced by the downstream durable receiver. */\n rendererTraceBatchReceiver?: WoodTraceBatchReceiver;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onNavigate?: (data: unknown, event?: unknown) => Promise<unknown>;\n onWindow?: (data: unknown, event?: unknown) => Promise<unknown>;\n onDebug?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n resolveRendererTraceContext?: (event: unknown) => TraceRuntimeContext | undefined;\n}\n\nexport interface RuntimeResult {\n router: WoodRouter;\n}\n\ntype RendererLogPayload = {\n level: string;\n logger: string;\n message: string;\n context?: unknown;\n};\n\ntype IpcInvokeEventLike = {\n sender?: {\n id?: number;\n };\n};\n\ntype RuntimeReservedHandler = (\n data: unknown,\n event?: unknown,\n) => Promise<unknown>;\n\ntype RuntimeTraceSettings = Readonly<{\n enableRendererLogBridge: boolean;\n enableRendererTraceBridge: boolean;\n traceMinLevel: TraceLevel | undefined;\n rendererTraceEnabled: boolean;\n rendererTraceMinLevel: TraceLevel;\n rendererTraceBatchEnabled: boolean;\n}>;\n\nfunction normalizeRendererLogLevel(level: unknown): RendererLogLevel {\n if (typeof level === 'string') {\n const normalized = level.trim().toLowerCase();\n if (normalized.length > 0) {\n return normalized;\n }\n }\n return 'info';\n}\n\nfunction coerceRendererLogPayload(\n rawPayload: unknown,\n event: unknown,\n): RendererLogEntry {\n const payload = (rawPayload ?? {}) as Partial<RendererLogPayload>;\n const ipcEvent = event as IpcInvokeEventLike;\n\n return {\n level: normalizeRendererLogLevel(payload.level),\n logger: typeof payload.logger === 'string' && payload.logger.trim().length > 0\n ? payload.logger\n : 'renderer',\n message: typeof payload.message === 'string' ? payload.message : '',\n context: payload.context,\n timestamp: new Date().toISOString(),\n senderId: typeof ipcEvent?.sender?.id === 'number' ? ipcEvent.sender.id : null,\n };\n}\n\n/**\n * Boot a bundled-safe Wood runtime using pre-generated static runtime artifacts.\n */\nexport async function runtime(options: RuntimeOptions): Promise<RuntimeResult> {\n const {\n ipcMain,\n registerRuntime,\n controllersDir,\n middlewareDir,\n mode = 'bundled',\n enableRendererLogBridge = true,\n enableRendererTraceBridge = true,\n traceMinLevel,\n rendererTraceEnabled = false,\n rendererTraceMinLevel = 'debug',\n } = options;\n\n const container = options.container ?? getContainer();\n const rendererTraceBatchReceiver = options.rendererTraceBatchReceiver\n ?? getRendererTraceBatchReceiver();\n const rendererTraceBatchEnabled = rendererTraceBatchReceiver !== null;\n const rendererTraceBatchHost = new RendererTraceBatchHost(\n rendererTraceBatchReceiver,\n );\n\n logger.info('runtime start', {\n mode,\n hasProvidedContainer: !!options.container,\n controllersDir,\n middlewareDir,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel: traceMinLevel ?? 'debug',\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n });\n\n const traceSettings: RuntimeTraceSettings = {\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel,\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n };\n await configureRuntimeTracing(container, traceSettings);\n\n const router = new WoodRouter({\n container,\n controllersDir,\n middlewareDir,\n mode,\n });\n\n registerRuntime(router);\n logger.info('runtime registration complete');\n\n router.validateControllers();\n logger.info('runtime controller validation complete');\n\n router.precompileSchemas();\n logger.info('runtime schema pre-compilation complete');\n\n registerReservedRuntimeHandlers(router, options, traceSettings, rendererTraceBatchHost);\n registerRuntimeObservationBridges(ipcMain, traceSettings, options.resolveRendererTraceContext);\n\n router.registerIpcHandlers(ipcMain);\n logger.info('runtime ipc handlers registered', {\n channelCount: router.getChannels().length,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n });\n\n return { router };\n}\n\nasync function configureRuntimeTracing(\n container: any,\n settings: RuntimeTraceSettings,\n): Promise<void> {\n if (settings.traceMinLevel) {\n setMainTraceMinLevel(settings.traceMinLevel);\n }\n setRendererTraceMinLevel(settings.rendererTraceMinLevel);\n if (typeof container.instance !== 'function') {\n return;\n }\n\n const traceConfiguration = await container.instance(TraceProviderConfiguration);\n traceConfiguration.configureRuntime('main');\n if (settings.traceMinLevel) {\n traceConfiguration.configureMinLevel(settings.traceMinLevel);\n }\n}\n\nfunction registerReservedRuntimeHandlers(\n router: WoodRouter,\n options: RuntimeOptions,\n settings: RuntimeTraceSettings,\n rendererTraceBatchHost: RendererTraceBatchHost,\n): void {\n router.registerReservedHandler('__load', requireRuntimeHandler('__load', 'onLoad', options.onLoad));\n router.registerReservedHandler('__navigate', requireRuntimeHandler('__navigate', 'onNavigate', options.onNavigate));\n router.registerReservedHandler('__window', requireRuntimeHandler('__window', 'onWindow', options.onWindow));\n router.registerReservedHandler('__debug', requireRuntimeHandler('__debug', 'onDebug', options.onDebug));\n router.registerReservedHandler(\n '__contextMenu',\n requireRuntimeHandler('__contextMenu', 'onContextMenu', options.onContextMenu),\n );\n router.registerReservedHandler('__woodConfig', async () => ({\n // App extension fields first so Wood's reserved keys always win.\n ...(await resolveRendererConfigExtension()),\n rendererTraceEnabled: settings.rendererTraceEnabled,\n rendererTraceMinLevel: settings.rendererTraceMinLevel,\n rendererTraceBatchEnabled: settings.rendererTraceBatchEnabled,\n appEnv: options.appEnv ?? await resolveWoodAppEnv(),\n }));\n router.registerReservedHandler('__traceBatch', async (data, event) => {\n return rendererTraceBatchHost.receive(data, options.resolveRendererTraceContext?.(event) ?? {});\n });\n}\n\nfunction registerRuntimeObservationBridges(\n ipcMain: IpcMainLike,\n settings: RuntimeTraceSettings,\n resolveContext: RuntimeOptions['resolveRendererTraceContext'],\n): void {\n if (settings.enableRendererLogBridge) {\n registerRendererLogBridge(ipcMain);\n }\n ipcMain.removeAllListeners?.('__trace');\n if (settings.enableRendererTraceBridge && settings.rendererTraceEnabled) {\n registerRendererTraceBridge(ipcMain, resolveContext);\n }\n}\n\nfunction requireRuntimeHandler(\n channel: string,\n optionName: string,\n handler: RuntimeReservedHandler | undefined,\n): RuntimeReservedHandler {\n return async (data, event) => {\n if (!handler) {\n throw new Error(`Reserved channel \"${channel}\" not configured. Provide runtime({ ${optionName} }).`);\n }\n return handler(data, event);\n };\n}\n\nfunction registerRendererTraceBridge(\n ipcMain: IpcMainLike,\n resolveContext?: (event: unknown) => TraceRuntimeContext | undefined,\n): void {\n ipcMain.removeAllListeners?.('__trace');\n\n ipcMain.on('__trace', (event, rawPayload) => {\n dispatchRendererTracePayload(rawPayload, resolveContext?.(event));\n });\n\n logger.info('renderer trace bridge registered (fire-and-forget)');\n}\n\nfunction registerRendererLogBridge(ipcMain: IpcMainLike): void {\n const dispatcher = getRendererLogDispatcher();\n\n ipcMain.removeAllListeners?.('__log');\n\n ipcMain.on('__log', (_event, rawPayload) => {\n const entry = coerceRendererLogPayload(rawPayload, null);\n void dispatcher.dispatch(entry).then((result) => {\n const typedResult = result as RendererLogDispatchResult;\n if (!typedResult.ok) {\n logger.warn('renderer log dispatch failed', {\n logger: entry.logger,\n messageLength: entry.message.length,\n reason: typedResult.reason ?? null,\n errorMessage: typedResult.errorMessage ?? null,\n });\n }\n });\n });\n\n ipcMain.removeAllListeners?.('__log_batch');\n\n ipcMain.on('__log_batch', (_event, rawPayload) => {\n const result = dispatchRendererLogBatch(rawPayload);\n if (!result.ok) {\n logger.warn('renderer log batch rejected', {\n reason: result.reason ?? null,\n errorMessage: result.errorMessage ?? null,\n });\n }\n });\n\n logger.info('renderer log bridge registered (fire-and-forget)');\n}\n"],"mappings":"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","names":["import_tracing"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { WoodRouter } from '../router/wood_router.cjs';
|
|
2
|
-
import { c as TraceLevel, e as TraceRuntimeContext } from '../trace_hub-
|
|
2
|
+
import { c as TraceLevel, e as TraceRuntimeContext } from '../trace_hub-Cpo_nVze.cjs';
|
|
3
3
|
import { WoodTraceBatchReceiver } from '../tracing/types/wood_trace_batch.types.cjs';
|
|
4
4
|
import { WoodAppEnv } from './app_env.cjs';
|
|
5
5
|
import '../types/operations.cjs';
|
|
6
|
+
import '../types/context.cjs';
|
|
6
7
|
import 'rxjs';
|
|
7
8
|
import '@noego/telemetry/core';
|
|
8
9
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { WoodRouter } from '../router/wood_router.js';
|
|
2
|
-
import { c as TraceLevel, e as TraceRuntimeContext } from '../trace_hub-
|
|
2
|
+
import { c as TraceLevel, e as TraceRuntimeContext } from '../trace_hub-Cpo_nVze.js';
|
|
3
3
|
import { WoodTraceBatchReceiver } from '../tracing/types/wood_trace_batch.types.js';
|
|
4
4
|
import { WoodAppEnv } from './app_env.js';
|
|
5
5
|
import '../types/operations.js';
|
|
6
|
+
import '../types/context.js';
|
|
6
7
|
import 'rxjs';
|
|
7
8
|
import '@noego/telemetry/core';
|
|
8
9
|
|
package/dist/runtime/runtime.js
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
getRendererLogDispatcher
|
|
15
15
|
} from "./renderer_log_dispatcher.js";
|
|
16
|
+
import { dispatchRendererLogBatch } from "./renderer_log_batch_receiver.js";
|
|
17
|
+
import { resolveRendererConfigExtension } from "./renderer_config_extension.js";
|
|
16
18
|
import { getRendererTraceBatchReceiver } from "./renderer_trace_batch_receiver_registry.js";
|
|
17
19
|
import { resolveWoodAppEnv } from "./app_env.js";
|
|
18
20
|
const logger = getLogger("wood:runtime");
|
|
@@ -123,6 +125,8 @@ function registerReservedRuntimeHandlers(router, options, settings, rendererTrac
|
|
|
123
125
|
requireRuntimeHandler("__contextMenu", "onContextMenu", options.onContextMenu)
|
|
124
126
|
);
|
|
125
127
|
router.registerReservedHandler("__woodConfig", async () => ({
|
|
128
|
+
// App extension fields first so Wood's reserved keys always win.
|
|
129
|
+
...await resolveRendererConfigExtension(),
|
|
126
130
|
rendererTraceEnabled: settings.rendererTraceEnabled,
|
|
127
131
|
rendererTraceMinLevel: settings.rendererTraceMinLevel,
|
|
128
132
|
rendererTraceBatchEnabled: settings.rendererTraceBatchEnabled,
|
|
@@ -173,6 +177,16 @@ function registerRendererLogBridge(ipcMain) {
|
|
|
173
177
|
}
|
|
174
178
|
});
|
|
175
179
|
});
|
|
180
|
+
ipcMain.removeAllListeners?.("__log_batch");
|
|
181
|
+
ipcMain.on("__log_batch", (_event, rawPayload) => {
|
|
182
|
+
const result = dispatchRendererLogBatch(rawPayload);
|
|
183
|
+
if (!result.ok) {
|
|
184
|
+
logger.warn("renderer log batch rejected", {
|
|
185
|
+
reason: result.reason ?? null,
|
|
186
|
+
errorMessage: result.errorMessage ?? null
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
176
190
|
logger.info("renderer log bridge registered (fire-and-forget)");
|
|
177
191
|
}
|
|
178
192
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/runtime.ts"],"sourcesContent":["import { getLogger } from '@noego/logger';\nimport { WoodRouter } from '../router/wood_router.js';\nimport { getContainer } from './get_container.js';\nimport {\n RendererTraceBatchHost,\n TraceProviderConfiguration,\n dispatchRendererTracePayload,\n} from '../tracing/index.js';\nimport {\n setMainTraceMinLevel,\n setRendererTraceMinLevel,\n type TraceLevel,\n type TraceRuntimeContext,\n type WoodTraceBatchReceiver,\n} from '../tracing/index.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogDispatchResult,\n type RendererLogEntry,\n type RendererLogLevel,\n} from './renderer_log_dispatcher.js';\nimport { getRendererTraceBatchReceiver } from './renderer_trace_batch_receiver_registry.js';\nimport { resolveWoodAppEnv, type WoodAppEnv } from './app_env.js';\n\nconst logger = getLogger('wood:runtime');\n\ntype IpcMainLike = {\n handle: (channel: string, handler: (_event: unknown, data: unknown) => Promise<unknown> | unknown) => void;\n on: (channel: string, handler: (_event: unknown, ...args: unknown[]) => void) => void;\n removeHandler?: (channel: string) => void;\n removeAllListeners?: (channel: string) => void;\n};\n\nexport interface RegisterRuntimeRouter {\n registerController(name: string, cls: any): void;\n loadOperations(operations: Map<string, any>): void;\n}\n\nexport interface RuntimeOptions {\n ipcMain: IpcMainLike;\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n container?: any;\n controllersDir: string;\n middlewareDir: string;\n mode?: 'bundled' | 'dev';\n /** Override the resolved app environment tier reported to renderers via __woodConfig. */\n appEnv?: WoodAppEnv;\n enableRendererLogBridge?: boolean;\n enableRendererTraceBridge?: boolean;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n /** Resolves only with the acknowledgement produced by the downstream durable receiver. */\n rendererTraceBatchReceiver?: WoodTraceBatchReceiver;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onNavigate?: (data: unknown, event?: unknown) => Promise<unknown>;\n onWindow?: (data: unknown, event?: unknown) => Promise<unknown>;\n onDebug?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n resolveRendererTraceContext?: (event: unknown) => TraceRuntimeContext | undefined;\n}\n\nexport interface RuntimeResult {\n router: WoodRouter;\n}\n\ntype RendererLogPayload = {\n level: string;\n logger: string;\n message: string;\n context?: unknown;\n};\n\ntype IpcInvokeEventLike = {\n sender?: {\n id?: number;\n };\n};\n\ntype RuntimeReservedHandler = (\n data: unknown,\n event?: unknown,\n) => Promise<unknown>;\n\ntype RuntimeTraceSettings = Readonly<{\n enableRendererLogBridge: boolean;\n enableRendererTraceBridge: boolean;\n traceMinLevel: TraceLevel | undefined;\n rendererTraceEnabled: boolean;\n rendererTraceMinLevel: TraceLevel;\n rendererTraceBatchEnabled: boolean;\n}>;\n\nfunction normalizeRendererLogLevel(level: unknown): RendererLogLevel {\n if (typeof level === 'string') {\n const normalized = level.trim().toLowerCase();\n if (normalized.length > 0) {\n return normalized;\n }\n }\n return 'info';\n}\n\nfunction coerceRendererLogPayload(\n rawPayload: unknown,\n event: unknown,\n): RendererLogEntry {\n const payload = (rawPayload ?? {}) as Partial<RendererLogPayload>;\n const ipcEvent = event as IpcInvokeEventLike;\n\n return {\n level: normalizeRendererLogLevel(payload.level),\n logger: typeof payload.logger === 'string' && payload.logger.trim().length > 0\n ? payload.logger\n : 'renderer',\n message: typeof payload.message === 'string' ? payload.message : '',\n context: payload.context,\n timestamp: new Date().toISOString(),\n senderId: typeof ipcEvent?.sender?.id === 'number' ? ipcEvent.sender.id : null,\n };\n}\n\n/**\n * Boot a bundled-safe Wood runtime using pre-generated static runtime artifacts.\n */\nexport async function runtime(options: RuntimeOptions): Promise<RuntimeResult> {\n const {\n ipcMain,\n registerRuntime,\n controllersDir,\n middlewareDir,\n mode = 'bundled',\n enableRendererLogBridge = true,\n enableRendererTraceBridge = true,\n traceMinLevel,\n rendererTraceEnabled = false,\n rendererTraceMinLevel = 'debug',\n } = options;\n\n const container = options.container ?? getContainer();\n const rendererTraceBatchReceiver = options.rendererTraceBatchReceiver\n ?? getRendererTraceBatchReceiver();\n const rendererTraceBatchEnabled = rendererTraceBatchReceiver !== null;\n const rendererTraceBatchHost = new RendererTraceBatchHost(\n rendererTraceBatchReceiver,\n );\n\n logger.info('runtime start', {\n mode,\n hasProvidedContainer: !!options.container,\n controllersDir,\n middlewareDir,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel: traceMinLevel ?? 'debug',\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n });\n\n const traceSettings: RuntimeTraceSettings = {\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel,\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n };\n await configureRuntimeTracing(container, traceSettings);\n\n const router = new WoodRouter({\n container,\n controllersDir,\n middlewareDir,\n mode,\n });\n\n registerRuntime(router);\n logger.info('runtime registration complete');\n\n router.validateControllers();\n logger.info('runtime controller validation complete');\n\n router.precompileSchemas();\n logger.info('runtime schema pre-compilation complete');\n\n registerReservedRuntimeHandlers(router, options, traceSettings, rendererTraceBatchHost);\n registerRuntimeObservationBridges(ipcMain, traceSettings, options.resolveRendererTraceContext);\n\n router.registerIpcHandlers(ipcMain);\n logger.info('runtime ipc handlers registered', {\n channelCount: router.getChannels().length,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n });\n\n return { router };\n}\n\nasync function configureRuntimeTracing(\n container: any,\n settings: RuntimeTraceSettings,\n): Promise<void> {\n if (settings.traceMinLevel) {\n setMainTraceMinLevel(settings.traceMinLevel);\n }\n setRendererTraceMinLevel(settings.rendererTraceMinLevel);\n if (typeof container.instance !== 'function') {\n return;\n }\n\n const traceConfiguration = await container.instance(TraceProviderConfiguration);\n traceConfiguration.configureRuntime('main');\n if (settings.traceMinLevel) {\n traceConfiguration.configureMinLevel(settings.traceMinLevel);\n }\n}\n\nfunction registerReservedRuntimeHandlers(\n router: WoodRouter,\n options: RuntimeOptions,\n settings: RuntimeTraceSettings,\n rendererTraceBatchHost: RendererTraceBatchHost,\n): void {\n router.registerReservedHandler('__load', requireRuntimeHandler('__load', 'onLoad', options.onLoad));\n router.registerReservedHandler('__navigate', requireRuntimeHandler('__navigate', 'onNavigate', options.onNavigate));\n router.registerReservedHandler('__window', requireRuntimeHandler('__window', 'onWindow', options.onWindow));\n router.registerReservedHandler('__debug', requireRuntimeHandler('__debug', 'onDebug', options.onDebug));\n router.registerReservedHandler(\n '__contextMenu',\n requireRuntimeHandler('__contextMenu', 'onContextMenu', options.onContextMenu),\n );\n router.registerReservedHandler('__woodConfig', async () => ({\n rendererTraceEnabled: settings.rendererTraceEnabled,\n rendererTraceMinLevel: settings.rendererTraceMinLevel,\n rendererTraceBatchEnabled: settings.rendererTraceBatchEnabled,\n appEnv: options.appEnv ?? await resolveWoodAppEnv(),\n }));\n router.registerReservedHandler('__traceBatch', async (data, event) => {\n return rendererTraceBatchHost.receive(data, options.resolveRendererTraceContext?.(event) ?? {});\n });\n}\n\nfunction registerRuntimeObservationBridges(\n ipcMain: IpcMainLike,\n settings: RuntimeTraceSettings,\n resolveContext: RuntimeOptions['resolveRendererTraceContext'],\n): void {\n if (settings.enableRendererLogBridge) {\n registerRendererLogBridge(ipcMain);\n }\n ipcMain.removeAllListeners?.('__trace');\n if (settings.enableRendererTraceBridge && settings.rendererTraceEnabled) {\n registerRendererTraceBridge(ipcMain, resolveContext);\n }\n}\n\nfunction requireRuntimeHandler(\n channel: string,\n optionName: string,\n handler: RuntimeReservedHandler | undefined,\n): RuntimeReservedHandler {\n return async (data, event) => {\n if (!handler) {\n throw new Error(`Reserved channel \"${channel}\" not configured. Provide runtime({ ${optionName} }).`);\n }\n return handler(data, event);\n };\n}\n\nfunction registerRendererTraceBridge(\n ipcMain: IpcMainLike,\n resolveContext?: (event: unknown) => TraceRuntimeContext | undefined,\n): void {\n ipcMain.removeAllListeners?.('__trace');\n\n ipcMain.on('__trace', (event, rawPayload) => {\n dispatchRendererTracePayload(rawPayload, resolveContext?.(event));\n });\n\n logger.info('renderer trace bridge registered (fire-and-forget)');\n}\n\nfunction registerRendererLogBridge(ipcMain: IpcMainLike): void {\n const dispatcher = getRendererLogDispatcher();\n\n ipcMain.removeAllListeners?.('__log');\n\n ipcMain.on('__log', (_event, rawPayload) => {\n const entry = coerceRendererLogPayload(rawPayload, null);\n void dispatcher.dispatch(entry).then((result) => {\n const typedResult = result as RendererLogDispatchResult;\n if (!typedResult.ok) {\n logger.warn('renderer log dispatch failed', {\n logger: entry.logger,\n messageLength: entry.message.length,\n reason: typedResult.reason ?? null,\n errorMessage: typedResult.errorMessage ?? null,\n });\n }\n });\n });\n\n logger.info('renderer log bridge registered (fire-and-forget)');\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/runtime.ts"],"sourcesContent":["import { getLogger } from '@noego/logger';\nimport { WoodRouter } from '../router/wood_router.js';\nimport { getContainer } from './get_container.js';\nimport {\n RendererTraceBatchHost,\n TraceProviderConfiguration,\n dispatchRendererTracePayload,\n} from '../tracing/index.js';\nimport {\n setMainTraceMinLevel,\n setRendererTraceMinLevel,\n type TraceLevel,\n type TraceRuntimeContext,\n type WoodTraceBatchReceiver,\n} from '../tracing/index.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogDispatchResult,\n type RendererLogEntry,\n type RendererLogLevel,\n} from './renderer_log_dispatcher.js';\nimport { dispatchRendererLogBatch } from './renderer_log_batch_receiver.js';\nimport { resolveRendererConfigExtension } from './renderer_config_extension.js';\nimport { getRendererTraceBatchReceiver } from './renderer_trace_batch_receiver_registry.js';\nimport { resolveWoodAppEnv, type WoodAppEnv } from './app_env.js';\n\nconst logger = getLogger('wood:runtime');\n\ntype IpcMainLike = {\n handle: (channel: string, handler: (_event: unknown, data: unknown) => Promise<unknown> | unknown) => void;\n on: (channel: string, handler: (_event: unknown, ...args: unknown[]) => void) => void;\n removeHandler?: (channel: string) => void;\n removeAllListeners?: (channel: string) => void;\n};\n\nexport interface RegisterRuntimeRouter {\n registerController(name: string, cls: any): void;\n loadOperations(operations: Map<string, any>): void;\n}\n\nexport interface RuntimeOptions {\n ipcMain: IpcMainLike;\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n container?: any;\n controllersDir: string;\n middlewareDir: string;\n mode?: 'bundled' | 'dev';\n /** Override the resolved app environment tier reported to renderers via __woodConfig. */\n appEnv?: WoodAppEnv;\n enableRendererLogBridge?: boolean;\n enableRendererTraceBridge?: boolean;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n /** Resolves only with the acknowledgement produced by the downstream durable receiver. */\n rendererTraceBatchReceiver?: WoodTraceBatchReceiver;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onNavigate?: (data: unknown, event?: unknown) => Promise<unknown>;\n onWindow?: (data: unknown, event?: unknown) => Promise<unknown>;\n onDebug?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n resolveRendererTraceContext?: (event: unknown) => TraceRuntimeContext | undefined;\n}\n\nexport interface RuntimeResult {\n router: WoodRouter;\n}\n\ntype RendererLogPayload = {\n level: string;\n logger: string;\n message: string;\n context?: unknown;\n};\n\ntype IpcInvokeEventLike = {\n sender?: {\n id?: number;\n };\n};\n\ntype RuntimeReservedHandler = (\n data: unknown,\n event?: unknown,\n) => Promise<unknown>;\n\ntype RuntimeTraceSettings = Readonly<{\n enableRendererLogBridge: boolean;\n enableRendererTraceBridge: boolean;\n traceMinLevel: TraceLevel | undefined;\n rendererTraceEnabled: boolean;\n rendererTraceMinLevel: TraceLevel;\n rendererTraceBatchEnabled: boolean;\n}>;\n\nfunction normalizeRendererLogLevel(level: unknown): RendererLogLevel {\n if (typeof level === 'string') {\n const normalized = level.trim().toLowerCase();\n if (normalized.length > 0) {\n return normalized;\n }\n }\n return 'info';\n}\n\nfunction coerceRendererLogPayload(\n rawPayload: unknown,\n event: unknown,\n): RendererLogEntry {\n const payload = (rawPayload ?? {}) as Partial<RendererLogPayload>;\n const ipcEvent = event as IpcInvokeEventLike;\n\n return {\n level: normalizeRendererLogLevel(payload.level),\n logger: typeof payload.logger === 'string' && payload.logger.trim().length > 0\n ? payload.logger\n : 'renderer',\n message: typeof payload.message === 'string' ? payload.message : '',\n context: payload.context,\n timestamp: new Date().toISOString(),\n senderId: typeof ipcEvent?.sender?.id === 'number' ? ipcEvent.sender.id : null,\n };\n}\n\n/**\n * Boot a bundled-safe Wood runtime using pre-generated static runtime artifacts.\n */\nexport async function runtime(options: RuntimeOptions): Promise<RuntimeResult> {\n const {\n ipcMain,\n registerRuntime,\n controllersDir,\n middlewareDir,\n mode = 'bundled',\n enableRendererLogBridge = true,\n enableRendererTraceBridge = true,\n traceMinLevel,\n rendererTraceEnabled = false,\n rendererTraceMinLevel = 'debug',\n } = options;\n\n const container = options.container ?? getContainer();\n const rendererTraceBatchReceiver = options.rendererTraceBatchReceiver\n ?? getRendererTraceBatchReceiver();\n const rendererTraceBatchEnabled = rendererTraceBatchReceiver !== null;\n const rendererTraceBatchHost = new RendererTraceBatchHost(\n rendererTraceBatchReceiver,\n );\n\n logger.info('runtime start', {\n mode,\n hasProvidedContainer: !!options.container,\n controllersDir,\n middlewareDir,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel: traceMinLevel ?? 'debug',\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n });\n\n const traceSettings: RuntimeTraceSettings = {\n enableRendererLogBridge,\n enableRendererTraceBridge,\n traceMinLevel,\n rendererTraceEnabled,\n rendererTraceMinLevel,\n rendererTraceBatchEnabled,\n };\n await configureRuntimeTracing(container, traceSettings);\n\n const router = new WoodRouter({\n container,\n controllersDir,\n middlewareDir,\n mode,\n });\n\n registerRuntime(router);\n logger.info('runtime registration complete');\n\n router.validateControllers();\n logger.info('runtime controller validation complete');\n\n router.precompileSchemas();\n logger.info('runtime schema pre-compilation complete');\n\n registerReservedRuntimeHandlers(router, options, traceSettings, rendererTraceBatchHost);\n registerRuntimeObservationBridges(ipcMain, traceSettings, options.resolveRendererTraceContext);\n\n router.registerIpcHandlers(ipcMain);\n logger.info('runtime ipc handlers registered', {\n channelCount: router.getChannels().length,\n enableRendererLogBridge,\n enableRendererTraceBridge,\n });\n\n return { router };\n}\n\nasync function configureRuntimeTracing(\n container: any,\n settings: RuntimeTraceSettings,\n): Promise<void> {\n if (settings.traceMinLevel) {\n setMainTraceMinLevel(settings.traceMinLevel);\n }\n setRendererTraceMinLevel(settings.rendererTraceMinLevel);\n if (typeof container.instance !== 'function') {\n return;\n }\n\n const traceConfiguration = await container.instance(TraceProviderConfiguration);\n traceConfiguration.configureRuntime('main');\n if (settings.traceMinLevel) {\n traceConfiguration.configureMinLevel(settings.traceMinLevel);\n }\n}\n\nfunction registerReservedRuntimeHandlers(\n router: WoodRouter,\n options: RuntimeOptions,\n settings: RuntimeTraceSettings,\n rendererTraceBatchHost: RendererTraceBatchHost,\n): void {\n router.registerReservedHandler('__load', requireRuntimeHandler('__load', 'onLoad', options.onLoad));\n router.registerReservedHandler('__navigate', requireRuntimeHandler('__navigate', 'onNavigate', options.onNavigate));\n router.registerReservedHandler('__window', requireRuntimeHandler('__window', 'onWindow', options.onWindow));\n router.registerReservedHandler('__debug', requireRuntimeHandler('__debug', 'onDebug', options.onDebug));\n router.registerReservedHandler(\n '__contextMenu',\n requireRuntimeHandler('__contextMenu', 'onContextMenu', options.onContextMenu),\n );\n router.registerReservedHandler('__woodConfig', async () => ({\n // App extension fields first so Wood's reserved keys always win.\n ...(await resolveRendererConfigExtension()),\n rendererTraceEnabled: settings.rendererTraceEnabled,\n rendererTraceMinLevel: settings.rendererTraceMinLevel,\n rendererTraceBatchEnabled: settings.rendererTraceBatchEnabled,\n appEnv: options.appEnv ?? await resolveWoodAppEnv(),\n }));\n router.registerReservedHandler('__traceBatch', async (data, event) => {\n return rendererTraceBatchHost.receive(data, options.resolveRendererTraceContext?.(event) ?? {});\n });\n}\n\nfunction registerRuntimeObservationBridges(\n ipcMain: IpcMainLike,\n settings: RuntimeTraceSettings,\n resolveContext: RuntimeOptions['resolveRendererTraceContext'],\n): void {\n if (settings.enableRendererLogBridge) {\n registerRendererLogBridge(ipcMain);\n }\n ipcMain.removeAllListeners?.('__trace');\n if (settings.enableRendererTraceBridge && settings.rendererTraceEnabled) {\n registerRendererTraceBridge(ipcMain, resolveContext);\n }\n}\n\nfunction requireRuntimeHandler(\n channel: string,\n optionName: string,\n handler: RuntimeReservedHandler | undefined,\n): RuntimeReservedHandler {\n return async (data, event) => {\n if (!handler) {\n throw new Error(`Reserved channel \"${channel}\" not configured. Provide runtime({ ${optionName} }).`);\n }\n return handler(data, event);\n };\n}\n\nfunction registerRendererTraceBridge(\n ipcMain: IpcMainLike,\n resolveContext?: (event: unknown) => TraceRuntimeContext | undefined,\n): void {\n ipcMain.removeAllListeners?.('__trace');\n\n ipcMain.on('__trace', (event, rawPayload) => {\n dispatchRendererTracePayload(rawPayload, resolveContext?.(event));\n });\n\n logger.info('renderer trace bridge registered (fire-and-forget)');\n}\n\nfunction registerRendererLogBridge(ipcMain: IpcMainLike): void {\n const dispatcher = getRendererLogDispatcher();\n\n ipcMain.removeAllListeners?.('__log');\n\n ipcMain.on('__log', (_event, rawPayload) => {\n const entry = coerceRendererLogPayload(rawPayload, null);\n void dispatcher.dispatch(entry).then((result) => {\n const typedResult = result as RendererLogDispatchResult;\n if (!typedResult.ok) {\n logger.warn('renderer log dispatch failed', {\n logger: entry.logger,\n messageLength: entry.message.length,\n reason: typedResult.reason ?? null,\n errorMessage: typedResult.errorMessage ?? null,\n });\n }\n });\n });\n\n ipcMain.removeAllListeners?.('__log_batch');\n\n ipcMain.on('__log_batch', (_event, rawPayload) => {\n const result = dispatchRendererLogBatch(rawPayload);\n if (!result.ok) {\n logger.warn('renderer log batch rejected', {\n reason: result.reason ?? null,\n errorMessage: result.errorMessage ?? null,\n });\n }\n });\n\n logger.info('renderer log bridge registered (fire-and-forget)');\n}\n"],"mappings":"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","names":[]}
|
package/dist/stick/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.cjs';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.cjs';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.cjs';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.cjs');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.cjs';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.cjs';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.cjs';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer.cjs';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.cjs');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
|
package/dist/stick/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.js';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.js';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.js');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/stick/index.ts"],"sourcesContent":["import './allow_cli.js';\n// Type-only import — erased at runtime, won't trigger module loading\nimport type { WoodStaticRenderer } from './static_renderer.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { resolveImageRendererTemplate } from './template_resolver.js';\n\nexport type { WoodStaticRenderer };\nexport type {\n WoodStaticRendererConfig,\n WoodRenderOptions,\n WoodRenderToPageOptions,\n WoodRenderResult,\n} from './static_renderer.js';\n\n// ─────────────────────────────────────────────────────────────\n// Error Classes\n// ─────────────────────────────────────────────────────────────\n\nexport class PlaywrightNotInstalledError extends Error {\n name = 'PlaywrightNotInstalledError' as const;\n constructor() {\n super(\n 'ImageRenderer requires Playwright. Install it with:\\n' +\n ' npm install playwright\\n' +\n ' npx playwright install chromium'\n );\n }\n}\n\nexport class BrowserLaunchError extends Error {\n name = 'BrowserLaunchError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\nexport class RenderTimeoutError extends Error {\n name = 'RenderTimeoutError' as const;\n constructor(timeoutMs: number) {\n super(`Render timed out after ${timeoutMs}ms`);\n }\n}\n\nexport class RenderError extends Error {\n name = 'RenderError' as const;\n constructor(message: string, public cause?: Error) {\n super(message);\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────\n\nexport interface ImageRendererConfig {\n /** Output directory for screenshots */\n outputDir: string;\n /** Default width (default: 1920) */\n width?: number;\n /** Default height (default: 1080) */\n height?: number;\n /** Device scale factor for retina (default: 1) */\n deviceScaleFactor?: number;\n /** Image format (default: 'png') */\n format?: 'png' | 'jpeg';\n /** JPEG quality 0-100 (default: 80) */\n quality?: number;\n /** Wait condition (default: 'networkidle') */\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n /** Timeout in ms (default: 10000) */\n timeoutMs?: number;\n /** Custom HTML template with {{{HEAD}}}, {{{CSS}}}, {{{APP}}} placeholders */\n template?: string;\n\n // Static renderer config (one of these)\n /** Pre-created WoodStaticRenderer instance */\n staticRenderer?: WoodStaticRenderer;\n /** OR: Path to views.yaml */\n viewsConfig?: string;\n /**\n * Component directory (required if viewsConfig provided).\n * When template is omitted, stick auto-loads <componentDir>/index.html and\n * inlines <componentDir>/styles.css when present.\n */\n componentDir?: string;\n /** Asset path mappings (e.g., { '/images': ['public/images'] }) */\n assets?: Record<string, string[]>;\n}\n\nexport interface CaptureOptions {\n /** View component data */\n view?: any;\n /** Layout data (one object per layout) */\n layout?: any[];\n /** Wood bridge object passed as a prop to layouts and views */\n wood?: any;\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\nexport interface CaptureHtmlOptions {\n /** Override width */\n width?: number;\n /** Override height */\n height?: number;\n /** Capture full page (default: true) */\n fullPage?: boolean;\n /** Callback executed after page load, before screenshot. Receives the Playwright page object. */\n beforeCapture?: (page: any) => Promise<void>;\n}\n\ninterface CaptureResult {\n /** Raw image buffer */\n buffer: Buffer;\n /** Path where image was saved */\n path: string;\n}\n\n// ─────────────────────────────────────────────────────────────\n// Playwright Loader\n// ─────────────────────────────────────────────────────────────\n\ntype PlaywrightModule = typeof import('playwright');\n\nasync function loadPlaywright(): Promise<PlaywrightModule> {\n try {\n const playwright = await import('playwright');\n return playwright;\n } catch {\n throw new PlaywrightNotInstalledError();\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Content Type Helper\n// ─────────────────────────────────────────────────────────────\n\nfunction getContentType(filePath: string): string {\n const ext = path.extname(filePath).toLowerCase();\n const types: Record<string, string> = {\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n };\n return types[ext] || 'application/octet-stream';\n}\n\n// ─────────────────────────────────────────────────────────────\n// ImageRenderer Class\n// ─────────────────────────────────────────────────────────────\n\nexport class ImageRenderer {\n private browser: any;\n private staticRenderer: WoodStaticRenderer;\n private config: Required<Omit<ImageRendererConfig, 'staticRenderer' | 'viewsConfig' | 'componentDir' | 'template' | 'assets'>> & {\n outputDir: string;\n template?: string;\n assets?: Record<string, string[]>;\n };\n\n constructor(\n browser: any,\n staticRenderer: WoodStaticRenderer,\n config: ImageRendererConfig\n ) {\n this.browser = browser;\n this.staticRenderer = staticRenderer;\n this.config = {\n outputDir: config.outputDir,\n width: config.width ?? 1920,\n height: config.height ?? 1080,\n deviceScaleFactor: config.deviceScaleFactor ?? 1,\n format: config.format ?? 'png',\n quality: config.quality ?? 80,\n waitUntil: config.waitUntil ?? 'networkidle',\n timeoutMs: config.timeoutMs ?? 10000,\n template: config.template,\n assets: config.assets,\n };\n }\n\n /**\n * Capture a view by dot-path key and save to outputDir\n */\n async capture(\n name: string,\n viewKey: string,\n options?: CaptureOptions\n ): Promise<CaptureResult> {\n const { view, layout, wood } = options ?? {};\n const html = await this.staticRenderer.renderToPage({\n viewKey,\n data: { view, layout },\n wood,\n template: this.config.template,\n });\n\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Capture raw HTML and save to outputDir\n */\n async captureHtml(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n return this.captureHtmlInternal(name, html, options);\n }\n\n /**\n * Internal method to capture HTML to image\n */\n private async captureHtmlInternal(\n name: string,\n html: string,\n options?: CaptureHtmlOptions\n ): Promise<CaptureResult> {\n const width = options?.width ?? this.config.width;\n const height = options?.height ?? this.config.height;\n\n let context: any;\n let page: any;\n\n try {\n context = await this.browser.newContext({\n viewport: { width, height },\n deviceScaleFactor: this.config.deviceScaleFactor,\n });\n\n page = await context.newPage();\n\n // Route Interception Strategy:\n // We use page.goto() with a fake URL instead of page.setContent() because\n // setContent() has no base URL, so relative paths can't resolve.\n const FAKE_BASE_URL = 'http://stick-renderer/';\n\n await page.route(FAKE_BASE_URL, async (route: any) => {\n await route.fulfill({\n body: html,\n contentType: 'text/html',\n });\n });\n\n // Asset route interception\n if (this.config.assets) {\n for (const [urlPath, fsPaths] of Object.entries(this.config.assets)) {\n await page.route(`**${urlPath}/**`, async (route: any) => {\n const url = new URL(route.request().url());\n const relativePath = url.pathname.replace(urlPath, '');\n\n for (const fsPath of fsPaths) {\n const filePath = path.join(fsPath, relativePath);\n try {\n const body = await fs.promises.readFile(filePath);\n const contentType = getContentType(filePath);\n await route.fulfill({ body, contentType });\n return;\n } catch {\n // File not found in this path, try the next one\n }\n }\n\n await route.abort('filenotfound');\n });\n }\n }\n\n const waitUntilMapping = {\n 'load': 'load',\n 'domcontentloaded': 'domcontentloaded',\n 'networkidle': 'networkidle',\n } as const;\n\n try {\n await page.goto(FAKE_BASE_URL, {\n waitUntil: waitUntilMapping[this.config.waitUntil],\n timeout: this.config.timeoutMs,\n });\n } catch (error) {\n if (error instanceof Error && error.message.includes('timeout')) {\n throw new RenderTimeoutError(this.config.timeoutMs);\n }\n throw new RenderError(\n 'Failed to render HTML content',\n error instanceof Error ? error : undefined\n );\n }\n\n if (options?.beforeCapture) {\n await options.beforeCapture(page);\n }\n\n const screenshotOptions: {\n type: 'png' | 'jpeg';\n quality?: number;\n fullPage: boolean;\n } = {\n type: this.config.format,\n fullPage: options?.fullPage ?? true,\n };\n\n if (this.config.format === 'jpeg') {\n screenshotOptions.quality = this.config.quality;\n }\n\n const screenshot = await page.screenshot(screenshotOptions);\n const buffer = Buffer.from(screenshot);\n\n const filename = `${name}@${width}x${height}.${this.config.format}`;\n const outputPath = path.join(this.config.outputDir, filename);\n\n await fs.promises.mkdir(this.config.outputDir, { recursive: true });\n await fs.promises.writeFile(outputPath, buffer);\n\n return { buffer, path: outputPath };\n\n } finally {\n if (page) {\n await page.close().catch(() => {});\n }\n if (context) {\n await context.close().catch(() => {});\n }\n }\n }\n\n /**\n * Close browser and clean up resources\n */\n async close(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────\n// Factory Function\n// ─────────────────────────────────────────────────────────────\n\nexport async function createImageRenderer(\n config: ImageRendererConfig\n): Promise<ImageRenderer> {\n const resolvedTemplate = resolveImageRendererTemplate({\n template: config.template,\n componentDir: config.componentDir,\n });\n const resolvedConfig: ImageRendererConfig = {\n ...config,\n template: resolvedTemplate,\n };\n\n const playwright = await loadPlaywright();\n\n let browser: any;\n try {\n browser = await playwright.chromium.launch({\n headless: true,\n });\n } catch (error) {\n throw new BrowserLaunchError(\n 'Failed to launch Chromium. Ensure it is installed with: npx playwright install chromium',\n error instanceof Error ? error : undefined\n );\n }\n\n let staticRenderer: WoodStaticRenderer;\n if (resolvedConfig.staticRenderer) {\n staticRenderer = resolvedConfig.staticRenderer;\n } else if (resolvedConfig.viewsConfig && resolvedConfig.componentDir) {\n const { createWoodStaticRenderer } = await import('./static_renderer.js');\n staticRenderer = createWoodStaticRenderer({\n viewsConfig: resolvedConfig.viewsConfig,\n componentDir: resolvedConfig.componentDir,\n });\n } else {\n throw new Error(\n 'ImageRendererConfig requires either staticRenderer or both viewsConfig and componentDir'\n );\n }\n\n return new ImageRenderer(browser, staticRenderer, resolvedConfig);\n}\n"],"mappings":"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","names":[]}
|
package/dist/testing/browser.cjs
CHANGED
|
@@ -29,7 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
var browser_exports = {};
|
|
30
30
|
__export(browser_exports, {
|
|
31
31
|
browser: () => browser,
|
|
32
|
-
createBrowserBridgeFixture: () => createBrowserBridgeFixture
|
|
32
|
+
createBrowserBridgeFixture: () => createBrowserBridgeFixture,
|
|
33
|
+
startSharedBrowserViteServer: () => startSharedBrowserViteServer
|
|
33
34
|
});
|
|
34
35
|
module.exports = __toCommonJS(browser_exports);
|
|
35
36
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
@@ -49,6 +50,7 @@ const DEFAULT_RESOURCE_CLOSE_TIMEOUT_MS = 5e3;
|
|
|
49
50
|
const WORKER_RUNTIME_IDLE_CLOSE_MS = 5e3;
|
|
50
51
|
const browserWorkerRuntimes = /* @__PURE__ */ new Map();
|
|
51
52
|
const browserWorkerCacheDirs = /* @__PURE__ */ new Set();
|
|
53
|
+
const browserConnectWarnings = /* @__PURE__ */ new Set();
|
|
52
54
|
process.on("exit", () => {
|
|
53
55
|
for (const cacheDir of browserWorkerCacheDirs) {
|
|
54
56
|
try {
|
|
@@ -212,8 +214,9 @@ function buildBridgeInitScript(manifest, traceConfig, transportMode) {
|
|
|
212
214
|
})();
|
|
213
215
|
`;
|
|
214
216
|
}
|
|
215
|
-
async function loadPlaywright(browserName) {
|
|
216
|
-
const
|
|
217
|
+
async function loadPlaywright(browserName, rootDir) {
|
|
218
|
+
const playwrightPath = resolvePackageModule(rootDir, "playwright");
|
|
219
|
+
const playwright = playwrightPath ? await import((0, import_node_url.pathToFileURL)(playwrightPath).href) : await import("playwright");
|
|
217
220
|
return playwright[browserName];
|
|
218
221
|
}
|
|
219
222
|
async function loadVite() {
|
|
@@ -314,7 +317,14 @@ async function createViteServer(rootDir, cacheDir) {
|
|
|
314
317
|
resolve: {
|
|
315
318
|
dedupe: ["svelte"]
|
|
316
319
|
},
|
|
317
|
-
server: {
|
|
320
|
+
server: {
|
|
321
|
+
port: 0,
|
|
322
|
+
// Browser harnesses write independent HTML/entry files concurrently.
|
|
323
|
+
// HMR would broadcast another harness's temp-file changes to every page,
|
|
324
|
+
// causing unrelated mounts to reload; tests only need request-time transforms.
|
|
325
|
+
hmr: false,
|
|
326
|
+
fs: { allow: [rootDir, import_node_os.default.tmpdir()] }
|
|
327
|
+
}
|
|
318
328
|
});
|
|
319
329
|
await server.listen();
|
|
320
330
|
return server;
|
|
@@ -323,21 +333,53 @@ function workerRuntimeKey(input) {
|
|
|
323
333
|
return [
|
|
324
334
|
input.rootDir,
|
|
325
335
|
input.browserName,
|
|
326
|
-
input.headless ? "headless" : "headed"
|
|
336
|
+
input.headless ? "headless" : "headed",
|
|
337
|
+
input.wsEndpoint ?? "local-browser",
|
|
338
|
+
input.viteUrl ?? "local-vite"
|
|
327
339
|
].join("::");
|
|
328
340
|
}
|
|
329
341
|
async function createBrowserWorkerRuntime(input) {
|
|
330
|
-
const cacheRoot = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-browser-vite-"));
|
|
331
|
-
browserWorkerCacheDirs.add(cacheRoot);
|
|
332
342
|
let browser2 = null;
|
|
343
|
+
let cacheRoot = null;
|
|
344
|
+
let ownedServer = null;
|
|
333
345
|
try {
|
|
334
|
-
const playwrightBrowser = await loadPlaywright(input.browserName);
|
|
335
|
-
|
|
336
|
-
|
|
346
|
+
const playwrightBrowser = await loadPlaywright(input.browserName, input.rootDir);
|
|
347
|
+
if (input.wsEndpoint) {
|
|
348
|
+
try {
|
|
349
|
+
browser2 = await playwrightBrowser.connect(input.wsEndpoint);
|
|
350
|
+
} catch (error) {
|
|
351
|
+
if (!browserConnectWarnings.has(input.wsEndpoint)) {
|
|
352
|
+
browserConnectWarnings.add(input.wsEndpoint);
|
|
353
|
+
console.warn(
|
|
354
|
+
`[wood browser] Could not connect to shared Chromium at "${input.wsEndpoint}"; falling back to a per-worker launch.`,
|
|
355
|
+
error
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!browser2) {
|
|
361
|
+
browser2 = await playwrightBrowser.launch({ headless: input.headless });
|
|
362
|
+
}
|
|
363
|
+
let vite;
|
|
364
|
+
if (input.viteUrl) {
|
|
365
|
+
vite = {
|
|
366
|
+
baseUrl: input.viteUrl,
|
|
367
|
+
ownership: "external"
|
|
368
|
+
};
|
|
369
|
+
} else {
|
|
370
|
+
cacheRoot = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-browser-vite-"));
|
|
371
|
+
browserWorkerCacheDirs.add(cacheRoot);
|
|
372
|
+
ownedServer = await createViteServer(input.rootDir, import_node_path.default.join(cacheRoot, ".vite"));
|
|
373
|
+
vite = {
|
|
374
|
+
baseUrl: serverBaseUrl(ownedServer),
|
|
375
|
+
ownership: "worker",
|
|
376
|
+
server: ownedServer,
|
|
377
|
+
cacheDir: cacheRoot
|
|
378
|
+
};
|
|
379
|
+
}
|
|
337
380
|
return {
|
|
338
381
|
browser: browser2,
|
|
339
|
-
|
|
340
|
-
cacheDir: cacheRoot,
|
|
382
|
+
vite,
|
|
341
383
|
rootDir: input.rootDir,
|
|
342
384
|
key: input.key,
|
|
343
385
|
activeHarnesses: 0,
|
|
@@ -345,18 +387,25 @@ async function createBrowserWorkerRuntime(input) {
|
|
|
345
387
|
idleCloseTimer: null
|
|
346
388
|
};
|
|
347
389
|
} catch (error) {
|
|
348
|
-
await
|
|
349
|
-
|
|
350
|
-
|
|
390
|
+
await Promise.all([
|
|
391
|
+
browser2?.close().catch(() => void 0),
|
|
392
|
+
ownedServer?.close().catch(() => void 0)
|
|
393
|
+
]);
|
|
394
|
+
if (cacheRoot) {
|
|
395
|
+
import_node_fs.default.rmSync(cacheRoot, { recursive: true, force: true });
|
|
396
|
+
browserWorkerCacheDirs.delete(cacheRoot);
|
|
397
|
+
}
|
|
351
398
|
throw error;
|
|
352
399
|
}
|
|
353
400
|
}
|
|
354
401
|
async function acquireBrowserWorkerRuntime(input) {
|
|
355
|
-
const
|
|
402
|
+
const wsEndpoint = input.browserName === "chromium" ? process.env.WOOD_BROWSER_WS_ENDPOINT : void 0;
|
|
403
|
+
const viteUrl = process.env.WOOD_BROWSER_VITE_URL;
|
|
404
|
+
const key = workerRuntimeKey({ ...input, wsEndpoint, viteUrl });
|
|
356
405
|
let entry = browserWorkerRuntimes.get(key);
|
|
357
406
|
if (!entry) {
|
|
358
407
|
entry = {
|
|
359
|
-
promise: createBrowserWorkerRuntime({ ...input, key })
|
|
408
|
+
promise: createBrowserWorkerRuntime({ ...input, wsEndpoint, viteUrl, key })
|
|
360
409
|
};
|
|
361
410
|
browserWorkerRuntimes.set(key, entry);
|
|
362
411
|
}
|
|
@@ -379,12 +428,14 @@ async function closeBrowserWorkerRuntime(runtime) {
|
|
|
379
428
|
runtime.closing = true;
|
|
380
429
|
try {
|
|
381
430
|
await Promise.all([
|
|
382
|
-
waitForBoundedClose(runtime.server.close()),
|
|
431
|
+
...runtime.vite.ownership === "worker" ? [waitForBoundedClose(runtime.vite.server.close())] : [],
|
|
383
432
|
waitForBoundedClose(runtime.browser.close())
|
|
384
433
|
]);
|
|
385
434
|
} finally {
|
|
386
|
-
|
|
387
|
-
|
|
435
|
+
if (runtime.vite.ownership === "worker") {
|
|
436
|
+
import_node_fs.default.rmSync(runtime.vite.cacheDir, { recursive: true, force: true });
|
|
437
|
+
browserWorkerCacheDirs.delete(runtime.vite.cacheDir);
|
|
438
|
+
}
|
|
388
439
|
const entry = browserWorkerRuntimes.get(runtime.key);
|
|
389
440
|
const current = entry ? await entry.promise.catch(() => null) : null;
|
|
390
441
|
if (current === runtime) {
|
|
@@ -411,6 +462,35 @@ function releaseBrowserWorkerRuntime(runtime) {
|
|
|
411
462
|
function serverBaseUrl(server) {
|
|
412
463
|
return server.resolvedUrls?.local?.[0] ?? "http://127.0.0.1:5173";
|
|
413
464
|
}
|
|
465
|
+
async function startSharedBrowserViteServer(input) {
|
|
466
|
+
const rootDir = normalizeRoot(input.rootDir);
|
|
467
|
+
const cacheRoot = import_node_fs.default.mkdtempSync(import_node_path.default.join(import_node_os.default.tmpdir(), "wood-browser-vite-"));
|
|
468
|
+
browserWorkerCacheDirs.add(cacheRoot);
|
|
469
|
+
let server = null;
|
|
470
|
+
try {
|
|
471
|
+
server = await createViteServer(rootDir, import_node_path.default.join(cacheRoot, ".vite"));
|
|
472
|
+
} catch (error) {
|
|
473
|
+
import_node_fs.default.rmSync(cacheRoot, { recursive: true, force: true });
|
|
474
|
+
browserWorkerCacheDirs.delete(cacheRoot);
|
|
475
|
+
throw error;
|
|
476
|
+
}
|
|
477
|
+
let closed = false;
|
|
478
|
+
return {
|
|
479
|
+
url: serverBaseUrl(server),
|
|
480
|
+
async close() {
|
|
481
|
+
if (closed) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
closed = true;
|
|
485
|
+
try {
|
|
486
|
+
await waitForBoundedClose(server.close());
|
|
487
|
+
} finally {
|
|
488
|
+
import_node_fs.default.rmSync(cacheRoot, { recursive: true, force: true });
|
|
489
|
+
browserWorkerCacheDirs.delete(cacheRoot);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
}
|
|
414
494
|
function assertFileExists(filePath, label) {
|
|
415
495
|
if (!import_node_fs.default.existsSync(filePath)) {
|
|
416
496
|
throw new Error(`${label} does not exist: ${filePath}`);
|
|
@@ -1326,7 +1406,7 @@ async function openMountPage(input) {
|
|
|
1326
1406
|
...input.context
|
|
1327
1407
|
};
|
|
1328
1408
|
await input.hooks?.beforeMount?.(context);
|
|
1329
|
-
await page.goto(`${
|
|
1409
|
+
await page.goto(`${input.runtime.baseUrl}${viteImport(htmlPath)}`, {
|
|
1330
1410
|
waitUntil: "domcontentloaded"
|
|
1331
1411
|
});
|
|
1332
1412
|
for (const event of input.bridge.state.initialEvents) {
|
|
@@ -1390,7 +1470,7 @@ async function createHarness(config = {}) {
|
|
|
1390
1470
|
}
|
|
1391
1471
|
const runtime = {
|
|
1392
1472
|
context,
|
|
1393
|
-
|
|
1473
|
+
baseUrl: workerRuntime.vite.baseUrl,
|
|
1394
1474
|
page,
|
|
1395
1475
|
tempDir,
|
|
1396
1476
|
rootDir,
|
|
@@ -1560,6 +1640,7 @@ const browser = {
|
|
|
1560
1640
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1561
1641
|
0 && (module.exports = {
|
|
1562
1642
|
browser,
|
|
1563
|
-
createBrowserBridgeFixture
|
|
1643
|
+
createBrowserBridgeFixture,
|
|
1644
|
+
startSharedBrowserViteServer
|
|
1564
1645
|
});
|
|
1565
1646
|
//# sourceMappingURL=browser.cjs.map
|