@noego/wood 0.4.9 → 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/bin/axe.js +313 -98
- package/dist/{loader/__fixtures__/layouts/app.load.cjs → automation/actions.cjs} +3 -13
- package/dist/automation/actions.cjs.map +1 -0
- package/dist/automation/actions.d.cts +57 -0
- package/dist/automation/actions.d.ts +57 -0
- package/dist/automation/actions.js +1 -0
- package/dist/automation/actions.js.map +1 -0
- package/dist/automation/actions_executor.cjs +101 -0
- package/dist/automation/actions_executor.cjs.map +1 -0
- package/dist/automation/actions_executor.d.cts +16 -0
- package/dist/automation/actions_executor.d.ts +16 -0
- package/dist/automation/actions_executor.js +76 -0
- package/dist/automation/actions_executor.js.map +1 -0
- package/dist/automation/connection.cjs +86 -0
- package/dist/automation/connection.cjs.map +1 -0
- package/dist/automation/connection.d.cts +18 -0
- package/dist/automation/connection.d.ts +18 -0
- package/dist/automation/connection.js +51 -0
- package/dist/automation/connection.js.map +1 -0
- package/dist/{middleware/__fixtures__/middleware/sequence.cjs → automation/errors.cjs} +25 -22
- package/dist/automation/errors.cjs.map +1 -0
- package/dist/automation/errors.d.cts +31 -0
- package/dist/automation/errors.d.ts +31 -0
- package/dist/automation/errors.js +24 -0
- package/dist/automation/errors.js.map +1 -0
- package/dist/automation/index.cjs +49 -0
- package/dist/automation/index.cjs.map +1 -0
- package/dist/automation/index.d.cts +16 -0
- package/dist/automation/index.d.ts +16 -0
- package/dist/automation/index.js +15 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/introspection_reader.cjs +75 -0
- package/dist/automation/introspection_reader.cjs.map +1 -0
- package/dist/automation/introspection_reader.d.cts +20 -0
- package/dist/automation/introspection_reader.d.ts +20 -0
- package/dist/automation/introspection_reader.js +48 -0
- package/dist/automation/introspection_reader.js.map +1 -0
- package/dist/automation/locator.cjs +102 -0
- package/dist/automation/locator.cjs.map +1 -0
- package/dist/automation/locator.d.cts +51 -0
- package/dist/automation/locator.d.ts +51 -0
- package/dist/automation/locator.js +75 -0
- package/dist/automation/locator.js.map +1 -0
- package/dist/{loader/__fixtures__/views/test/page.load.cjs → automation/observation.cjs} +3 -13
- package/dist/automation/observation.cjs.map +1 -0
- package/dist/automation/observation.d.cts +44 -0
- package/dist/automation/observation.d.ts +44 -0
- package/dist/automation/observation.js +1 -0
- package/dist/automation/observation.js.map +1 -0
- package/dist/{controller/__fixtures__/controllers/test.cjs → automation/receipts.cjs} +3 -15
- package/dist/automation/receipts.cjs.map +1 -0
- package/dist/automation/receipts.d.cts +27 -0
- package/dist/automation/receipts.d.ts +27 -0
- package/dist/automation/receipts.js +1 -0
- package/dist/automation/receipts.js.map +1 -0
- package/dist/automation/scenario.cjs +696 -0
- package/dist/automation/scenario.cjs.map +1 -0
- package/dist/automation/scenario.d.cts +89 -0
- package/dist/automation/scenario.d.ts +89 -0
- package/dist/automation/scenario.js +660 -0
- package/dist/automation/scenario.js.map +1 -0
- package/dist/automation/scrolling.cjs +17 -0
- package/dist/automation/scrolling.cjs.map +1 -0
- package/dist/automation/scrolling.d.cts +51 -0
- package/dist/automation/scrolling.d.ts +51 -0
- package/dist/automation/scrolling.js +1 -0
- package/dist/automation/scrolling.js.map +1 -0
- package/dist/automation/scrolling_executor.cjs +109 -0
- package/dist/automation/scrolling_executor.cjs.map +1 -0
- package/dist/automation/scrolling_executor.d.cts +13 -0
- package/dist/automation/scrolling_executor.d.ts +13 -0
- package/dist/automation/scrolling_executor.js +84 -0
- package/dist/automation/scrolling_executor.js.map +1 -0
- package/dist/automation/target_identity.cjs +17 -0
- package/dist/automation/target_identity.cjs.map +1 -0
- package/dist/automation/target_identity.d.cts +28 -0
- package/dist/automation/target_identity.d.ts +28 -0
- package/dist/automation/target_identity.js +1 -0
- package/dist/automation/target_identity.js.map +1 -0
- package/dist/automation/target_registry.cjs +148 -0
- package/dist/automation/target_registry.cjs.map +1 -0
- package/dist/automation/target_registry.d.cts +32 -0
- package/dist/automation/target_registry.d.ts +32 -0
- package/dist/automation/target_registry.js +122 -0
- package/dist/automation/target_registry.js.map +1 -0
- package/dist/automation/waits.cjs +17 -0
- package/dist/automation/waits.cjs.map +1 -0
- package/dist/automation/waits.d.cts +44 -0
- package/dist/automation/waits.d.ts +44 -0
- package/dist/automation/waits.js +1 -0
- package/dist/automation/waits.js.map +1 -0
- package/dist/automation/waits_executor.cjs +104 -0
- package/dist/automation/waits_executor.cjs.map +1 -0
- package/dist/automation/waits_executor.d.cts +14 -0
- package/dist/automation/waits_executor.d.ts +14 -0
- package/dist/automation/waits_executor.js +79 -0
- package/dist/automation/waits_executor.js.map +1 -0
- 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 +19 -3
- package/dist/client/index.d.ts +19 -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 +95 -44
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +95 -44
- 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 +11 -7
- package/dist/index.d.ts +11 -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/automation_introspection.cjs +110 -0
- package/dist/navigation/automation_introspection.cjs.map +1 -0
- package/dist/navigation/automation_introspection.d.cts +60 -0
- package/dist/navigation/automation_introspection.d.ts +60 -0
- package/dist/navigation/automation_introspection.js +85 -0
- package/dist/navigation/automation_introspection.js.map +1 -0
- package/dist/navigation/index.cjs +10 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +27 -1
- package/dist/navigation/index.d.ts +27 -1
- package/dist/navigation/index.js +6 -1
- 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/automation_assertions.cjs +417 -0
- package/dist/testing/automation_assertions.cjs.map +1 -0
- package/dist/testing/automation_assertions.d.cts +44 -0
- package/dist/testing/automation_assertions.d.ts +44 -0
- package/dist/testing/automation_assertions.js +385 -0
- package/dist/testing/automation_assertions.js.map +1 -0
- package/dist/testing/browser.cjs +130 -57
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +10 -4
- package/dist/testing/browser.d.ts +10 -4
- package/dist/testing/browser.js +132 -53
- 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 +18 -2
- package/dist/testing/create_controller_harness.d.ts +18 -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/geometry.cjs +109 -0
- package/dist/testing/geometry.cjs.map +1 -0
- package/dist/testing/geometry.d.cts +45 -0
- package/dist/testing/geometry.d.ts +45 -0
- package/dist/testing/geometry.js +79 -0
- package/dist/testing/geometry.js.map +1 -0
- package/dist/testing/index.cjs +62 -2
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +23 -4
- package/dist/testing/index.d.ts +23 -4
- package/dist/testing/index.js +50 -2
- 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 +19 -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.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.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.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.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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { automationError, automationOk } from "./errors.js";
|
|
2
|
+
import { readAutomationSnapshot, waitForRendererIdle } from "./introspection_reader.js";
|
|
3
|
+
import { toPlaywrightLocator } from "./locator.js";
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 5e3;
|
|
5
|
+
function matchesUrl(actual, expected, match = "exact") {
|
|
6
|
+
if (match === "exact") return actual === expected;
|
|
7
|
+
if (match === "regex") {
|
|
8
|
+
try {
|
|
9
|
+
return new RegExp(expected).test(actual);
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const escaped = expected.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
15
|
+
return new RegExp(`^${escaped}$`).test(actual);
|
|
16
|
+
}
|
|
17
|
+
async function awaitCondition(page, condition, options) {
|
|
18
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
19
|
+
const started = Date.now();
|
|
20
|
+
let lastObserved = null;
|
|
21
|
+
if (condition.kind === "trace" || condition.kind === "target") {
|
|
22
|
+
return automationError("UNSUPPORTED", `${condition.kind} waits require an unavailable ${condition.kind} observation capability.`, { details: { capability: condition.kind, lastObserved } });
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
if (condition.kind === "visible" || condition.kind === "hidden" || condition.kind === "attached" || condition.kind === "detached") {
|
|
26
|
+
await toPlaywrightLocator(page, condition.target).waitFor({ state: condition.kind, timeout: timeoutMs });
|
|
27
|
+
} else if (condition.kind === "enabled") {
|
|
28
|
+
const locator = toPlaywrightLocator(page, condition.target);
|
|
29
|
+
await locator.waitFor({ state: "visible", timeout: timeoutMs });
|
|
30
|
+
await page.waitForFunction((element) => !element.disabled && element.getAttribute("aria-disabled") !== "true", await locator.elementHandle(), { timeout: timeoutMs });
|
|
31
|
+
} else if (condition.kind === "app_idle") {
|
|
32
|
+
lastObserved = await readAutomationSnapshot(page);
|
|
33
|
+
if (!await waitForRendererIdle(page, { timeoutMs })) throw new Error("Renderer did not become idle.");
|
|
34
|
+
} else if (condition.kind === "url") {
|
|
35
|
+
while (!matchesUrl(lastObserved = page.url(), condition.value, condition.match)) {
|
|
36
|
+
if (Date.now() - started >= timeoutMs) throw new Error("URL did not match.");
|
|
37
|
+
await page.waitForTimeout(25);
|
|
38
|
+
}
|
|
39
|
+
} else if (condition.kind === "route") {
|
|
40
|
+
while (true) {
|
|
41
|
+
const snapshot = await readAutomationSnapshot(page);
|
|
42
|
+
lastObserved = snapshot?.currentRoute ?? null;
|
|
43
|
+
const route = snapshot?.currentRoute;
|
|
44
|
+
const includes = (wanted, actual) => !wanted || Object.entries(wanted).every(([key, value]) => actual[key] === value);
|
|
45
|
+
if (route?.page === condition.page && includes(condition.params, route.params) && includes(condition.query, route.query)) break;
|
|
46
|
+
if (Date.now() - started >= timeoutMs) throw new Error("Route did not match.");
|
|
47
|
+
await page.waitForTimeout(25);
|
|
48
|
+
}
|
|
49
|
+
} else if (condition.kind === "scroll_edge") {
|
|
50
|
+
const locator = condition.container.kind === "locator" ? toPlaywrightLocator(page, condition.container.target) : null;
|
|
51
|
+
await page.waitForFunction(({ element, edge }) => {
|
|
52
|
+
const node = element ?? document.scrollingElement ?? document.documentElement;
|
|
53
|
+
return edge === "top" ? node.scrollTop <= 0 : edge === "bottom" ? node.scrollTop + node.clientHeight >= node.scrollHeight - 1 : edge === "left" ? node.scrollLeft <= 0 : node.scrollLeft + node.clientWidth >= node.scrollWidth - 1;
|
|
54
|
+
}, { element: locator ? await locator.elementHandle() : null, edge: condition.edge }, { timeout: timeoutMs });
|
|
55
|
+
} else {
|
|
56
|
+
const locator = condition.target ? toPlaywrightLocator(page, condition.target) : null;
|
|
57
|
+
lastObserved = await page.evaluate(async ({ element, frames }) => {
|
|
58
|
+
const target = element;
|
|
59
|
+
let previous = target?.getBoundingClientRect() ?? { x: 0, y: 0, width: innerWidth, height: innerHeight };
|
|
60
|
+
let stable = 0;
|
|
61
|
+
while (stable < frames) {
|
|
62
|
+
await new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
63
|
+
const next = target?.getBoundingClientRect() ?? { x: 0, y: 0, width: innerWidth, height: innerHeight };
|
|
64
|
+
stable = next.x === previous.x && next.y === previous.y && next.width === previous.width && next.height === previous.height ? stable + 1 : 0;
|
|
65
|
+
previous = next;
|
|
66
|
+
}
|
|
67
|
+
return { x: previous.x, y: previous.y, width: previous.width, height: previous.height, stableFrames: stable };
|
|
68
|
+
}, { element: locator ? await locator.elementHandle() : null, frames: condition.kind === "visual_stable" ? condition.frames ?? 3 : 3 });
|
|
69
|
+
}
|
|
70
|
+
return automationOk({ waitedMs: Date.now() - started });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return automationError("ACTION_FAILED", `Timed out waiting for ${condition.kind} after ${timeoutMs}ms.`, { details: { timeoutMs, lastObserved, cause: error instanceof Error ? error.message : String(error) } });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
awaitCondition,
|
|
77
|
+
matchesUrl
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=waits_executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/automation/waits_executor.ts"],"sourcesContent":["import type { Page } from 'playwright';\nimport { automationError, automationOk, type WoodAutomationResult } from './errors.js';\nimport { readAutomationSnapshot, waitForRendererIdle } from './introspection_reader.js';\nimport { toPlaywrightLocator } from './locator.js';\nimport type { WoodWaitCondition } from './waits.js';\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport function matchesUrl(actual: string, expected: string, match: 'exact' | 'glob' | 'regex' = 'exact'): boolean {\n if (match === 'exact') return actual === expected;\n if (match === 'regex') {\n try { return new RegExp(expected).test(actual); } catch { return false; }\n }\n const escaped = expected.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*').replace(/\\?/g, '.');\n return new RegExp(`^${escaped}$`).test(actual);\n}\n\nexport async function awaitCondition(page: Page, condition: WoodWaitCondition, options?: { timeoutMs?: number }): Promise<WoodAutomationResult<{ waitedMs: number }>> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const started = Date.now();\n let lastObserved: unknown = null;\n if (condition.kind === 'trace' || condition.kind === 'target') {\n return automationError('UNSUPPORTED', `${condition.kind} waits require an unavailable ${condition.kind} observation capability.`, { details: { capability: condition.kind, lastObserved } });\n }\n try {\n if (condition.kind === 'visible' || condition.kind === 'hidden' || condition.kind === 'attached' || condition.kind === 'detached') {\n await toPlaywrightLocator(page, condition.target).waitFor({ state: condition.kind, timeout: timeoutMs });\n } else if (condition.kind === 'enabled') {\n const locator = toPlaywrightLocator(page, condition.target);\n await locator.waitFor({ state: 'visible', timeout: timeoutMs });\n await page.waitForFunction((element) => !(element as HTMLInputElement).disabled && element.getAttribute('aria-disabled') !== 'true', await locator.elementHandle(), { timeout: timeoutMs });\n } else if (condition.kind === 'app_idle') {\n lastObserved = await readAutomationSnapshot(page);\n if (!(await waitForRendererIdle(page, { timeoutMs }))) throw new Error('Renderer did not become idle.');\n } else if (condition.kind === 'url') {\n while (!matchesUrl(lastObserved = page.url(), condition.value, condition.match)) {\n if (Date.now() - started >= timeoutMs) throw new Error('URL did not match.');\n await page.waitForTimeout(25);\n }\n } else if (condition.kind === 'route') {\n while (true) {\n const snapshot = await readAutomationSnapshot(page);\n lastObserved = snapshot?.currentRoute ?? null;\n const route = snapshot?.currentRoute;\n const includes = (wanted: Record<string, string> | undefined, actual: Record<string, string>) =>\n !wanted || Object.entries(wanted).every(([key, value]) => actual[key] === value);\n if (route?.page === condition.page && includes(condition.params, route.params) && includes(condition.query, route.query)) break;\n if (Date.now() - started >= timeoutMs) throw new Error('Route did not match.');\n await page.waitForTimeout(25);\n }\n } else if (condition.kind === 'scroll_edge') {\n const locator = condition.container.kind === 'locator' ? toPlaywrightLocator(page, condition.container.target) : null;\n await page.waitForFunction(({ element, edge }) => {\n const node = (element as HTMLElement | null) ?? document.scrollingElement ?? document.documentElement;\n return edge === 'top' ? node.scrollTop <= 0 : edge === 'bottom' ? node.scrollTop + node.clientHeight >= node.scrollHeight - 1 : edge === 'left' ? node.scrollLeft <= 0 : node.scrollLeft + node.clientWidth >= node.scrollWidth - 1;\n }, { element: locator ? await locator.elementHandle() : null, edge: condition.edge }, { timeout: timeoutMs });\n } else {\n const locator = condition.target ? toPlaywrightLocator(page, condition.target) : null;\n lastObserved = await page.evaluate(async ({ element, frames }) => {\n const target = element as Element | null;\n let previous = target?.getBoundingClientRect() ?? { x: 0, y: 0, width: innerWidth, height: innerHeight };\n let stable = 0;\n while (stable < frames) {\n await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));\n const next = target?.getBoundingClientRect() ?? { x: 0, y: 0, width: innerWidth, height: innerHeight };\n stable = next.x === previous.x && next.y === previous.y && next.width === previous.width && next.height === previous.height ? stable + 1 : 0;\n previous = next;\n }\n return { x: previous.x, y: previous.y, width: previous.width, height: previous.height, stableFrames: stable };\n }, { element: locator ? await locator.elementHandle() : null, frames: condition.kind === 'visual_stable' ? condition.frames ?? 3 : 3 });\n }\n return automationOk({ waitedMs: Date.now() - started });\n } catch (error) {\n return automationError('ACTION_FAILED', `Timed out waiting for ${condition.kind} after ${timeoutMs}ms.`, { details: { timeoutMs, lastObserved, cause: error instanceof Error ? error.message : String(error) } });\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/backend_bridge.ts"],"sourcesContent":["import { fork, type ChildProcess } from 'child_process';\nimport crypto from 'crypto';\nimport { getLogger } from '@noego/logger';\nimport type {\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n} from '../types/bridge';\n\nconst logger = getLogger('wood:bridge');\n\ninterface PendingCall {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: NodeJS.Timeout;\n}\n\nexport interface BridgeOptions {\n backendEntry: string;\n timeout?: number;\n onReady?: () => void;\n onPush?: (channel: string, data: unknown) => void;\n onElectronApi?: (id: string, api: string, args: unknown[]) => Promise<unknown>;\n onExit?: (code: number | null, signal: string | null) => void;\n}\n\ntype BridgeState = 'stopped' | 'starting' | 'ready' | 'restarting';\n\nexport class BackendBridge {\n private child: ChildProcess | null = null;\n private pending = new Map<string, PendingCall>();\n private readonly options: BridgeOptions;\n private readonly timeoutMs: number;\n private _state: BridgeState = 'stopped';\n\n constructor(options: BridgeOptions) {\n this.options = options;\n this.timeoutMs = options.timeout ?? 30_000;\n }\n\n get state(): BridgeState {\n return this._state;\n }\n\n /** Start the backend process and wait for the ready signal. */\n async start(): Promise<void> {\n this._state = 'starting';\n\n this.child = fork(this.options.backendEntry, [], {\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n });\n\n this.child.on('message', (msg: unknown) => this.onMessage(msg));\n this.child.on('exit', (code, signal) => {\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend process exited'));\n logger.debug(`backend exited code=${code} signal=${signal}`);\n this.options.onExit?.(code, signal);\n });\n\n this.child.stdout?.pipe(process.stdout);\n this.child.stderr?.pipe(process.stderr);\n\n await this.waitForReady();\n this.options.onReady?.();\n }\n\n /** Stop the backend process gracefully (SIGTERM then SIGKILL). */\n async stop(): Promise<void> {\n if (!this.child || this.child.killed) return;\n\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend is stopping'));\n\n return new Promise<void>((resolve) => {\n const killTimer = setTimeout(() => {\n if (this.child && !this.child.killed) {\n this.child.kill('SIGKILL');\n logger.warn('backend did not exit in time, sent SIGKILL');\n }\n resolve();\n }, 2000);\n\n this.child!.once('exit', () => {\n clearTimeout(killTimer);\n resolve();\n });\n\n this.child!.kill('SIGTERM');\n });\n }\n\n /** Restart the backend process. */\n async restart(): Promise<void> {\n this._state = 'restarting';\n logger.info('restarting backend');\n await this.stop();\n await this.start();\n }\n\n /** Send a request to the backend and return the result. */\n call(channel: string, data: unknown): Promise<unknown> {\n if (this._state !== 'ready') {\n return Promise.reject(new Error(`Backend not ready (state: ${this._state})`));\n }\n\n const id = crypto.randomUUID();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`Backend timeout: ${channel}`));\n }, this.timeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n\n this.child!.send({\n type: 'request',\n id,\n channel,\n data,\n } satisfies BridgeRequest);\n\n logger.debug(`call ${id}: ${channel}`);\n });\n }\n\n // -- Private --\n\n private waitForReady(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error('Backend failed to send ready signal within timeout'));\n }, this.timeoutMs);\n\n const readyHandler = (msg: unknown) => {\n if ((msg as BridgeReady)?.type === 'ready') {\n clearTimeout(timer);\n this.child?.removeListener('message', readyHandler);\n this._state = 'ready';\n logger.info('backend ready');\n resolve();\n }\n };\n\n this.child!.on('message', readyHandler);\n });\n }\n\n private onMessage(msg: unknown): void {\n const message = msg as BridgeResponse | BridgePush | BridgeElectronApi;\n\n if (message.type === 'response') {\n const resp = message as BridgeResponse;\n const entry = this.pending.get(resp.id);\n if (entry) {\n clearTimeout(entry.timer);\n this.pending.delete(resp.id);\n if (resp.error) {\n entry.reject(new Error(resp.error.message ?? 'Backend error'));\n } else {\n entry.resolve(resp.result);\n }\n }\n }\n\n if (message.type === 'push') {\n const push = message as BridgePush;\n this.options.onPush?.(push.channel, push.data);\n }\n\n if (message.type === 'electron-api') {\n this.handleElectronProxy(message as BridgeElectronApi);\n }\n }\n\n private async handleElectronProxy(msg: BridgeElectronApi): Promise<void> {\n if (!this.options.onElectronApi) return;\n\n try {\n const result = await this.options.onElectronApi(msg.id, msg.api, msg.args);\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n result,\n });\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n error: { message: error.message, name: error.name },\n });\n }\n }\n\n private rejectAllPending(error: Error): void {\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(error);\n }\n this.pending.clear();\n }\n}\n"],"mappings":"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","names":["crypto"]}
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/backend_bridge.ts"],"sourcesContent":["import { fork, type ChildProcess } from 'child_process';\nimport crypto from 'crypto';\nimport { getLogger } from '@noego/logger';\nimport type {\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n} from '../types/bridge.cjs';\n\nconst logger = getLogger('wood:bridge');\n\ninterface PendingCall {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: NodeJS.Timeout;\n}\n\nexport interface BridgeOptions {\n backendEntry: string;\n timeout?: number;\n onReady?: () => void;\n onPush?: (channel: string, data: unknown) => void;\n onElectronApi?: (id: string, api: string, args: unknown[]) => Promise<unknown>;\n onExit?: (code: number | null, signal: string | null) => void;\n}\n\ntype BridgeState = 'stopped' | 'starting' | 'ready' | 'restarting';\n\nexport class BackendBridge {\n private child: ChildProcess | null = null;\n private pending = new Map<string, PendingCall>();\n private readonly options: BridgeOptions;\n private readonly timeoutMs: number;\n private _state: BridgeState = 'stopped';\n\n constructor(options: BridgeOptions) {\n this.options = options;\n this.timeoutMs = options.timeout ?? 30_000;\n }\n\n get state(): BridgeState {\n return this._state;\n }\n\n /** Start the backend process and wait for the ready signal. */\n async start(): Promise<void> {\n this._state = 'starting';\n\n this.child = fork(this.options.backendEntry, [], {\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n });\n\n this.child.on('message', (msg: unknown) => this.onMessage(msg));\n this.child.on('exit', (code, signal) => {\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend process exited'));\n logger.debug(`backend exited code=${code} signal=${signal}`);\n this.options.onExit?.(code, signal);\n });\n\n this.child.stdout?.pipe(process.stdout);\n this.child.stderr?.pipe(process.stderr);\n\n await this.waitForReady();\n this.options.onReady?.();\n }\n\n /** Stop the backend process gracefully (SIGTERM then SIGKILL). */\n async stop(): Promise<void> {\n if (!this.child || this.child.killed) return;\n\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend is stopping'));\n\n return new Promise<void>((resolve) => {\n const killTimer = setTimeout(() => {\n if (this.child && !this.child.killed) {\n this.child.kill('SIGKILL');\n logger.warn('backend did not exit in time, sent SIGKILL');\n }\n resolve();\n }, 2000);\n\n this.child!.once('exit', () => {\n clearTimeout(killTimer);\n resolve();\n });\n\n this.child!.kill('SIGTERM');\n });\n }\n\n /** Restart the backend process. */\n async restart(): Promise<void> {\n this._state = 'restarting';\n logger.info('restarting backend');\n await this.stop();\n await this.start();\n }\n\n /** Send a request to the backend and return the result. */\n call(channel: string, data: unknown): Promise<unknown> {\n if (this._state !== 'ready') {\n return Promise.reject(new Error(`Backend not ready (state: ${this._state})`));\n }\n\n const id = crypto.randomUUID();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`Backend timeout: ${channel}`));\n }, this.timeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n\n this.child!.send({\n type: 'request',\n id,\n channel,\n data,\n } satisfies BridgeRequest);\n\n logger.debug(`call ${id}: ${channel}`);\n });\n }\n\n // -- Private --\n\n private waitForReady(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error('Backend failed to send ready signal within timeout'));\n }, this.timeoutMs);\n\n const readyHandler = (msg: unknown) => {\n if ((msg as BridgeReady)?.type === 'ready') {\n clearTimeout(timer);\n this.child?.removeListener('message', readyHandler);\n this._state = 'ready';\n logger.info('backend ready');\n resolve();\n }\n };\n\n this.child!.on('message', readyHandler);\n });\n }\n\n private onMessage(msg: unknown): void {\n const message = msg as BridgeResponse | BridgePush | BridgeElectronApi;\n\n if (message.type === 'response') {\n const resp = message as BridgeResponse;\n const entry = this.pending.get(resp.id);\n if (entry) {\n clearTimeout(entry.timer);\n this.pending.delete(resp.id);\n if (resp.error) {\n entry.reject(new Error(resp.error.message ?? 'Backend error'));\n } else {\n entry.resolve(resp.result);\n }\n }\n }\n\n if (message.type === 'push') {\n const push = message as BridgePush;\n this.options.onPush?.(push.channel, push.data);\n }\n\n if (message.type === 'electron-api') {\n this.handleElectronProxy(message as BridgeElectronApi);\n }\n }\n\n private async handleElectronProxy(msg: BridgeElectronApi): Promise<void> {\n if (!this.options.onElectronApi) return;\n\n try {\n const result = await this.options.onElectronApi(msg.id, msg.api, msg.args);\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n result,\n });\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n error: { message: error.message, name: error.name },\n });\n }\n }\n\n private rejectAllPending(error: Error): void {\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(error);\n }\n this.pending.clear();\n }\n}\n"],"mappings":"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","names":["crypto"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bridge/backend_bridge.ts"],"sourcesContent":["import { fork, type ChildProcess } from 'child_process';\nimport crypto from 'crypto';\nimport { getLogger } from '@noego/logger';\nimport type {\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n} from '../types/bridge';\n\nconst logger = getLogger('wood:bridge');\n\ninterface PendingCall {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: NodeJS.Timeout;\n}\n\nexport interface BridgeOptions {\n backendEntry: string;\n timeout?: number;\n onReady?: () => void;\n onPush?: (channel: string, data: unknown) => void;\n onElectronApi?: (id: string, api: string, args: unknown[]) => Promise<unknown>;\n onExit?: (code: number | null, signal: string | null) => void;\n}\n\ntype BridgeState = 'stopped' | 'starting' | 'ready' | 'restarting';\n\nexport class BackendBridge {\n private child: ChildProcess | null = null;\n private pending = new Map<string, PendingCall>();\n private readonly options: BridgeOptions;\n private readonly timeoutMs: number;\n private _state: BridgeState = 'stopped';\n\n constructor(options: BridgeOptions) {\n this.options = options;\n this.timeoutMs = options.timeout ?? 30_000;\n }\n\n get state(): BridgeState {\n return this._state;\n }\n\n /** Start the backend process and wait for the ready signal. */\n async start(): Promise<void> {\n this._state = 'starting';\n\n this.child = fork(this.options.backendEntry, [], {\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n });\n\n this.child.on('message', (msg: unknown) => this.onMessage(msg));\n this.child.on('exit', (code, signal) => {\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend process exited'));\n logger.debug(`backend exited code=${code} signal=${signal}`);\n this.options.onExit?.(code, signal);\n });\n\n this.child.stdout?.pipe(process.stdout);\n this.child.stderr?.pipe(process.stderr);\n\n await this.waitForReady();\n this.options.onReady?.();\n }\n\n /** Stop the backend process gracefully (SIGTERM then SIGKILL). */\n async stop(): Promise<void> {\n if (!this.child || this.child.killed) return;\n\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend is stopping'));\n\n return new Promise<void>((resolve) => {\n const killTimer = setTimeout(() => {\n if (this.child && !this.child.killed) {\n this.child.kill('SIGKILL');\n logger.warn('backend did not exit in time, sent SIGKILL');\n }\n resolve();\n }, 2000);\n\n this.child!.once('exit', () => {\n clearTimeout(killTimer);\n resolve();\n });\n\n this.child!.kill('SIGTERM');\n });\n }\n\n /** Restart the backend process. */\n async restart(): Promise<void> {\n this._state = 'restarting';\n logger.info('restarting backend');\n await this.stop();\n await this.start();\n }\n\n /** Send a request to the backend and return the result. */\n call(channel: string, data: unknown): Promise<unknown> {\n if (this._state !== 'ready') {\n return Promise.reject(new Error(`Backend not ready (state: ${this._state})`));\n }\n\n const id = crypto.randomUUID();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`Backend timeout: ${channel}`));\n }, this.timeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n\n this.child!.send({\n type: 'request',\n id,\n channel,\n data,\n } satisfies BridgeRequest);\n\n logger.debug(`call ${id}: ${channel}`);\n });\n }\n\n // -- Private --\n\n private waitForReady(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error('Backend failed to send ready signal within timeout'));\n }, this.timeoutMs);\n\n const readyHandler = (msg: unknown) => {\n if ((msg as BridgeReady)?.type === 'ready') {\n clearTimeout(timer);\n this.child?.removeListener('message', readyHandler);\n this._state = 'ready';\n logger.info('backend ready');\n resolve();\n }\n };\n\n this.child!.on('message', readyHandler);\n });\n }\n\n private onMessage(msg: unknown): void {\n const message = msg as BridgeResponse | BridgePush | BridgeElectronApi;\n\n if (message.type === 'response') {\n const resp = message as BridgeResponse;\n const entry = this.pending.get(resp.id);\n if (entry) {\n clearTimeout(entry.timer);\n this.pending.delete(resp.id);\n if (resp.error) {\n entry.reject(new Error(resp.error.message ?? 'Backend error'));\n } else {\n entry.resolve(resp.result);\n }\n }\n }\n\n if (message.type === 'push') {\n const push = message as BridgePush;\n this.options.onPush?.(push.channel, push.data);\n }\n\n if (message.type === 'electron-api') {\n this.handleElectronProxy(message as BridgeElectronApi);\n }\n }\n\n private async handleElectronProxy(msg: BridgeElectronApi): Promise<void> {\n if (!this.options.onElectronApi) return;\n\n try {\n const result = await this.options.onElectronApi(msg.id, msg.api, msg.args);\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n result,\n });\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n error: { message: error.message, name: error.name },\n });\n }\n }\n\n private rejectAllPending(error: Error): void {\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(error);\n }\n this.pending.clear();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/bridge/backend_bridge.ts"],"sourcesContent":["import { fork, type ChildProcess } from 'child_process';\nimport crypto from 'crypto';\nimport { getLogger } from '@noego/logger';\nimport type {\n BridgeRequest,\n BridgeResponse,\n BridgeReady,\n BridgePush,\n BridgeElectronApi,\n} from '../types/bridge.js';\n\nconst logger = getLogger('wood:bridge');\n\ninterface PendingCall {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: NodeJS.Timeout;\n}\n\nexport interface BridgeOptions {\n backendEntry: string;\n timeout?: number;\n onReady?: () => void;\n onPush?: (channel: string, data: unknown) => void;\n onElectronApi?: (id: string, api: string, args: unknown[]) => Promise<unknown>;\n onExit?: (code: number | null, signal: string | null) => void;\n}\n\ntype BridgeState = 'stopped' | 'starting' | 'ready' | 'restarting';\n\nexport class BackendBridge {\n private child: ChildProcess | null = null;\n private pending = new Map<string, PendingCall>();\n private readonly options: BridgeOptions;\n private readonly timeoutMs: number;\n private _state: BridgeState = 'stopped';\n\n constructor(options: BridgeOptions) {\n this.options = options;\n this.timeoutMs = options.timeout ?? 30_000;\n }\n\n get state(): BridgeState {\n return this._state;\n }\n\n /** Start the backend process and wait for the ready signal. */\n async start(): Promise<void> {\n this._state = 'starting';\n\n this.child = fork(this.options.backendEntry, [], {\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n });\n\n this.child.on('message', (msg: unknown) => this.onMessage(msg));\n this.child.on('exit', (code, signal) => {\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend process exited'));\n logger.debug(`backend exited code=${code} signal=${signal}`);\n this.options.onExit?.(code, signal);\n });\n\n this.child.stdout?.pipe(process.stdout);\n this.child.stderr?.pipe(process.stderr);\n\n await this.waitForReady();\n this.options.onReady?.();\n }\n\n /** Stop the backend process gracefully (SIGTERM then SIGKILL). */\n async stop(): Promise<void> {\n if (!this.child || this.child.killed) return;\n\n this._state = 'stopped';\n this.rejectAllPending(new Error('Backend is stopping'));\n\n return new Promise<void>((resolve) => {\n const killTimer = setTimeout(() => {\n if (this.child && !this.child.killed) {\n this.child.kill('SIGKILL');\n logger.warn('backend did not exit in time, sent SIGKILL');\n }\n resolve();\n }, 2000);\n\n this.child!.once('exit', () => {\n clearTimeout(killTimer);\n resolve();\n });\n\n this.child!.kill('SIGTERM');\n });\n }\n\n /** Restart the backend process. */\n async restart(): Promise<void> {\n this._state = 'restarting';\n logger.info('restarting backend');\n await this.stop();\n await this.start();\n }\n\n /** Send a request to the backend and return the result. */\n call(channel: string, data: unknown): Promise<unknown> {\n if (this._state !== 'ready') {\n return Promise.reject(new Error(`Backend not ready (state: ${this._state})`));\n }\n\n const id = crypto.randomUUID();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`Backend timeout: ${channel}`));\n }, this.timeoutMs);\n\n this.pending.set(id, { resolve, reject, timer });\n\n this.child!.send({\n type: 'request',\n id,\n channel,\n data,\n } satisfies BridgeRequest);\n\n logger.debug(`call ${id}: ${channel}`);\n });\n }\n\n // -- Private --\n\n private waitForReady(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(new Error('Backend failed to send ready signal within timeout'));\n }, this.timeoutMs);\n\n const readyHandler = (msg: unknown) => {\n if ((msg as BridgeReady)?.type === 'ready') {\n clearTimeout(timer);\n this.child?.removeListener('message', readyHandler);\n this._state = 'ready';\n logger.info('backend ready');\n resolve();\n }\n };\n\n this.child!.on('message', readyHandler);\n });\n }\n\n private onMessage(msg: unknown): void {\n const message = msg as BridgeResponse | BridgePush | BridgeElectronApi;\n\n if (message.type === 'response') {\n const resp = message as BridgeResponse;\n const entry = this.pending.get(resp.id);\n if (entry) {\n clearTimeout(entry.timer);\n this.pending.delete(resp.id);\n if (resp.error) {\n entry.reject(new Error(resp.error.message ?? 'Backend error'));\n } else {\n entry.resolve(resp.result);\n }\n }\n }\n\n if (message.type === 'push') {\n const push = message as BridgePush;\n this.options.onPush?.(push.channel, push.data);\n }\n\n if (message.type === 'electron-api') {\n this.handleElectronProxy(message as BridgeElectronApi);\n }\n }\n\n private async handleElectronProxy(msg: BridgeElectronApi): Promise<void> {\n if (!this.options.onElectronApi) return;\n\n try {\n const result = await this.options.onElectronApi(msg.id, msg.api, msg.args);\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n result,\n });\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.child?.send({\n type: 'electron-api-response',\n id: msg.id,\n error: { message: error.message, name: error.name },\n });\n }\n }\n\n private rejectAllPending(error: Error): void {\n for (const [, entry] of this.pending) {\n clearTimeout(entry.timer);\n entry.reject(error);\n }\n this.pending.clear();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/client/index.cjs
CHANGED
|
@@ -30,15 +30,20 @@ __export(client_exports, {
|
|
|
30
30
|
clearClientLoggersForTests: () => clearClientLoggersForTests,
|
|
31
31
|
clearClientNavigationForTests: () => clearClientNavigationForTests,
|
|
32
32
|
clearClientWindowControlsForTests: () => clearClientWindowControlsForTests,
|
|
33
|
+
clearRendererLogTransportForTests: () => clearRendererLogTransportForTests,
|
|
33
34
|
clearTraceHubForTests: () => import_tracing.clearTraceHubForTests,
|
|
35
|
+
configureRendererLogTransport: () => import_renderer_log_transport2.configureRendererLogTransport,
|
|
34
36
|
createLogger: () => createLogger,
|
|
35
37
|
createSvelteBoot: () => createSvelteBoot,
|
|
38
|
+
flushRendererLogs: () => import_renderer_log_transport2.flushRendererLogs,
|
|
36
39
|
getApp: () => getApp,
|
|
37
40
|
getContainer: () => getContainer,
|
|
38
41
|
getIpc: () => import_ipc.getIpc,
|
|
39
42
|
getNavigation: () => import_navigation.getNavigation,
|
|
43
|
+
getRendererBootConfig: () => getRendererBootConfig,
|
|
40
44
|
getWindowControls: () => getWindowControls,
|
|
41
45
|
getWoodAppEnv: () => import_app_env2.getWoodAppEnv,
|
|
46
|
+
setRendererLogSender: () => setRendererLogSender,
|
|
42
47
|
setRendererTraceTransport: () => import_tracing.setRendererTraceTransport,
|
|
43
48
|
startWood: () => startWood
|
|
44
49
|
});
|
|
@@ -51,7 +56,27 @@ var import_ipc = require("../ipc/index.js");
|
|
|
51
56
|
var import_app_env = require("./app_env.js");
|
|
52
57
|
var import_app_env2 = require("./app_env.js");
|
|
53
58
|
var import_tracing = require("../tracing/index.js");
|
|
59
|
+
var import_renderer_log_transport = require("./renderer_log_transport.js");
|
|
60
|
+
var import_renderer_log_transport2 = require("./renderer_log_transport.js");
|
|
54
61
|
var import_tracing2 = require("../tracing/index.js");
|
|
62
|
+
function clearRendererLogTransportForTests() {
|
|
63
|
+
rendererLogWiringDone = false;
|
|
64
|
+
appRendererLogSender = null;
|
|
65
|
+
rendererBootConfig = null;
|
|
66
|
+
(0, import_renderer_log_transport.clearRendererLogTransportForTests)();
|
|
67
|
+
}
|
|
68
|
+
let appRendererLogSender = null;
|
|
69
|
+
function setRendererLogSender(sender) {
|
|
70
|
+
const transport = (0, import_renderer_log_transport.getRendererLogTransport)();
|
|
71
|
+
transport.flush();
|
|
72
|
+
appRendererLogSender = sender;
|
|
73
|
+
rendererLogWiringDone = false;
|
|
74
|
+
ensureRendererLogWiring(transport);
|
|
75
|
+
}
|
|
76
|
+
function getRendererBootConfig() {
|
|
77
|
+
return rendererBootConfig;
|
|
78
|
+
}
|
|
79
|
+
let rendererBootConfig = null;
|
|
55
80
|
const CLIENT_CONTAINER_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.client.container");
|
|
56
81
|
const CLIENT_APP_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.client.app");
|
|
57
82
|
const CLIENT_WINDOW_CONTROLS_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.client.window-controls");
|
|
@@ -330,24 +355,49 @@ class RendererLogger {
|
|
|
330
355
|
}
|
|
331
356
|
log(level, rawMessage, context) {
|
|
332
357
|
const message = stringifyLogMessage(rawMessage);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
} catch {
|
|
337
|
-
writeConsole(level, this.loggerName, message, context);
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
if (typeof bridge.__log !== "function") {
|
|
341
|
-
writeConsole(level, this.loggerName, message, context);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
try {
|
|
345
|
-
bridge.__log(level, this.loggerName, message, context);
|
|
346
|
-
} catch {
|
|
347
|
-
writeConsole(level, this.loggerName, message, context);
|
|
348
|
-
}
|
|
358
|
+
const transport = (0, import_renderer_log_transport.getRendererLogTransport)();
|
|
359
|
+
ensureRendererLogWiring(transport);
|
|
360
|
+
transport.admit(level, this.loggerName, message, context);
|
|
349
361
|
}
|
|
350
362
|
}
|
|
363
|
+
let rendererLogWiringDone = false;
|
|
364
|
+
function ensureRendererLogWiring(transport) {
|
|
365
|
+
if (rendererLogWiringDone) return;
|
|
366
|
+
let bridge = null;
|
|
367
|
+
try {
|
|
368
|
+
bridge = resolveWoodBridge();
|
|
369
|
+
} catch {
|
|
370
|
+
bridge = null;
|
|
371
|
+
}
|
|
372
|
+
const preloadSend = bridge && typeof bridge.__logBatch === "function" ? bridge.__logBatch.bind(bridge) : null;
|
|
373
|
+
const appSend = appRendererLogSender;
|
|
374
|
+
if (appSend) {
|
|
375
|
+
transport.setSender((batch) => {
|
|
376
|
+
try {
|
|
377
|
+
appSend(batch);
|
|
378
|
+
} catch (error) {
|
|
379
|
+
if (!preloadSend) throw error;
|
|
380
|
+
preloadSend(batch);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
} else if (preloadSend) {
|
|
384
|
+
transport.setSender((batch) => preloadSend(batch));
|
|
385
|
+
} else {
|
|
386
|
+
transport.setSender(null);
|
|
387
|
+
}
|
|
388
|
+
const legacyLog = bridge && typeof bridge.__log === "function" ? bridge.__log.bind(bridge) : null;
|
|
389
|
+
transport.setFallback((record) => {
|
|
390
|
+
if (legacyLog) {
|
|
391
|
+
try {
|
|
392
|
+
legacyLog(record.level, record.logger, record.message, record.context);
|
|
393
|
+
return;
|
|
394
|
+
} catch {
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
writeConsole(record.level, record.logger, record.message, record.context);
|
|
398
|
+
});
|
|
399
|
+
rendererLogWiringDone = bridge !== null || appSend !== null;
|
|
400
|
+
}
|
|
351
401
|
function createLogger(name) {
|
|
352
402
|
const loggerName = name.trim() || "renderer";
|
|
353
403
|
const globalObj = globalThis;
|
|
@@ -370,11 +420,12 @@ function registerClientBuiltins(container) {
|
|
|
370
420
|
}
|
|
371
421
|
const traceConfiguration = new import_tracing.TraceProviderConfiguration();
|
|
372
422
|
traceConfiguration.configureRuntime("renderer");
|
|
373
|
-
|
|
374
|
-
container.registerFunction(
|
|
375
|
-
container.registerFunction(
|
|
376
|
-
container.registerFunction(
|
|
377
|
-
container.registerFunction(
|
|
423
|
+
const singleton = { loadAs: import_ioc.LoadAs.Singleton };
|
|
424
|
+
container.registerFunction(import_navigation.Navigation, () => (0, import_navigation.getNavigation)(), singleton);
|
|
425
|
+
container.registerFunction(App, () => getApp(), singleton);
|
|
426
|
+
container.registerFunction(import_ipc.Ipc, () => (0, import_ipc.getIpc)(), singleton);
|
|
427
|
+
container.registerFunction(WindowControls, () => getWindowControls(), singleton);
|
|
428
|
+
container.registerFunction(import_tracing.TraceProviderConfiguration, () => traceConfiguration, singleton);
|
|
378
429
|
}
|
|
379
430
|
function createClientContainerInstance() {
|
|
380
431
|
const container = new import_ioc.Container();
|
|
@@ -436,6 +487,7 @@ async function startWood(mountRoot, target) {
|
|
|
436
487
|
if (typeof bridge.__woodConfig === "function") {
|
|
437
488
|
const config = await bridge.__woodConfig();
|
|
438
489
|
rendererTraceConfig = config;
|
|
490
|
+
rendererBootConfig = config && typeof config === "object" ? Object.freeze({ ...config }) : null;
|
|
439
491
|
(0, import_app_env.setWoodAppEnv)(config?.appEnv);
|
|
440
492
|
const traceConfiguration = container.instance ? await container.instance(import_tracing.TraceProviderConfiguration) : null;
|
|
441
493
|
if (typeof config?.rendererTraceEnabled === "boolean") {
|
|
@@ -471,15 +523,20 @@ function createSvelteBoot(mountRoot) {
|
|
|
471
523
|
clearClientLoggersForTests,
|
|
472
524
|
clearClientNavigationForTests,
|
|
473
525
|
clearClientWindowControlsForTests,
|
|
526
|
+
clearRendererLogTransportForTests,
|
|
474
527
|
clearTraceHubForTests,
|
|
528
|
+
configureRendererLogTransport,
|
|
475
529
|
createLogger,
|
|
476
530
|
createSvelteBoot,
|
|
531
|
+
flushRendererLogs,
|
|
477
532
|
getApp,
|
|
478
533
|
getContainer,
|
|
479
534
|
getIpc,
|
|
480
535
|
getNavigation,
|
|
536
|
+
getRendererBootConfig,
|
|
481
537
|
getWindowControls,
|
|
482
538
|
getWoodAppEnv,
|
|
539
|
+
setRendererLogSender,
|
|
483
540
|
setRendererTraceTransport,
|
|
484
541
|
startWood
|
|
485
542
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts"],"sourcesContent":["import './global_polyfill.cjs';\nimport 'reflect-metadata';\nimport { Container } from '@noego/ioc';\nimport {\n Navigation,\n getNavigation,\n clearNavigationForTests as clearNavigationSingletonForTests,\n} from '../navigation/index.js';\nimport { Ipc, getIpc } from '../ipc/index.js';\nimport { setWoodAppEnv } from './app_env.js';\nexport { getWoodAppEnv, type WoodAppEnv } from './app_env.js';\nimport {\n TraceProviderConfiguration,\n clearTraceHubForTests,\n emitRendererTrace,\n setRendererTraceTransport,\n} from '../tracing/index.js';\nexport type {\n ControllerEvents,\n ControllerInput,\n ControllerLifecycle,\n ControllerState,\n PageController,\n} from './controller_contract.js';\n\nconst CLIENT_CONTAINER_SYMBOL = Symbol.for('@noego/wood.client.container');\nconst CLIENT_APP_SYMBOL = Symbol.for('@noego/wood.client.app');\nconst CLIENT_WINDOW_CONTROLS_SYMBOL = Symbol.for('@noego/wood.client.window-controls');\nconst CLIENT_LOGGER_REGISTRY_SYMBOL = Symbol.for('@noego/wood.client.logger-registry');\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\nexport const WOOD_INTERNAL_BRIDGE_KEY = INTERNAL_BRIDGE_GLOBAL_KEY;\n\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\ntype WoodBridgeRpcFunction = (data?: unknown) => Promise<unknown>;\ntype WoodBridgeLike = Record<string, unknown> & {\n __rpcManifest?: WoodRpcManifestEntry[];\n __window?: {\n current?: () => Promise<unknown>;\n open?: (windowId: string, options?: Record<string, unknown>) => Promise<unknown>;\n close?: (windowId?: string) => Promise<unknown>;\n focus?: (windowId: string) => Promise<unknown>;\n minimize?: (windowId?: string) => Promise<unknown>;\n maximize?: (windowId?: string) => Promise<unknown>;\n };\n __log?: (\n level: string,\n logger: string,\n message: string,\n context?: unknown,\n ) => void;\n __woodConfig?: () => Promise<unknown>;\n __trace?: (event: unknown) => void;\n};\n\ntype GlobalWithClientContainer = typeof globalThis & {\n [CLIENT_CONTAINER_SYMBOL]?: any;\n};\n\ntype GlobalWithClientApp = typeof globalThis & {\n [CLIENT_APP_SYMBOL]?: object;\n};\n\ntype GlobalWithWindowControls = typeof globalThis & {\n [CLIENT_WINDOW_CONTROLS_SYMBOL]?: WindowControls;\n};\n\ntype GlobalWithLoggerRegistry = typeof globalThis & {\n [CLIENT_LOGGER_REGISTRY_SYMBOL]?: Map<string, RendererLogger>;\n};\n\ninterface WoodContainerRegistration {\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\nexport class App {\n [controllerName: string]: unknown;\n}\n\nfunction resolveWoodBridge(): WoodBridgeLike {\n const globalObj = globalThis as typeof globalThis & {\n [INTERNAL_BRIDGE_GLOBAL_KEY]?: unknown;\n wood?: unknown;\n window?: {\n [INTERNAL_BRIDGE_GLOBAL_KEY]?: unknown;\n wood?: unknown;\n };\n };\n\n const bridge = globalObj[INTERNAL_BRIDGE_GLOBAL_KEY]\n ?? globalObj.window?.[INTERNAL_BRIDGE_GLOBAL_KEY]\n ?? globalObj.wood\n ?? globalObj.window?.wood;\n if (!bridge || typeof bridge !== 'object') {\n throw new Error(\n `Wood bridge is not available on globalThis.${INTERNAL_BRIDGE_GLOBAL_KEY}.`,\n );\n }\n\n return bridge as WoodBridgeLike;\n}\n\nfunction resolveRpcManifest(bridge: WoodBridgeLike): WoodRpcManifestEntry[] {\n const manifest = bridge.__rpcManifest;\n if (!Array.isArray(manifest)) {\n throw new Error(\n 'Wood bridge is missing \"__rpcManifest\". Regenerate preload with the latest @noego/wood.',\n );\n }\n\n return manifest;\n}\n\nfunction resolveBridgeFunction(\n bridge: WoodBridgeLike,\n pathSegments: string[],\n operationKey: string,\n): WoodBridgeRpcFunction {\n let current: unknown = bridge;\n\n for (const segment of pathSegments) {\n if (!current || typeof current !== 'object') {\n throw new Error(\n `Wood bridge operation \"${operationKey}\" is missing path \"${pathSegments.join('.')}\".`,\n );\n }\n current = (current as Record<string, unknown>)[segment];\n }\n\n if (typeof current !== 'function') {\n throw new Error(\n `Wood bridge path \"${pathSegments.join('.')}\" for \"${operationKey}\" is not callable.`,\n );\n }\n\n return current as WoodBridgeRpcFunction;\n}\n\nfunction assertSerializable(value: unknown, operationKey: string): void {\n if (typeof structuredClone !== 'function') {\n return;\n }\n\n try {\n structuredClone(value);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(\n `App RPC \"${operationKey}\" payload is not serializable: ${reason}`,\n );\n }\n}\n\nfunction extractTraceConversationId(value: unknown): number | string | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n\n const record = value as Record<string, unknown>;\n if (typeof record.conversationId === 'number' || typeof record.conversationId === 'string') {\n return record.conversationId;\n }\n if (typeof record.threadId === 'number' || typeof record.threadId === 'string') {\n return record.threadId;\n }\n\n return undefined;\n}\n\nfunction validateManifestEntry(entry: WoodRpcManifestEntry, index: number): void {\n if (!entry.channel || !entry.controller || !entry.action) {\n throw new Error(`Invalid Wood RPC manifest entry at index ${index}.`);\n }\n if (!Array.isArray(entry.path) || entry.path.length === 0) {\n throw new Error(\n `Invalid Wood RPC manifest path for \"${entry.controller}.${entry.action}\".`,\n );\n }\n}\n\nfunction createAppInstance(): App {\n const bridge = resolveWoodBridge();\n const manifest = resolveRpcManifest(bridge);\n const app: Record<string, Record<string, (...args: unknown[]) => Promise<unknown>>> = {};\n\n manifest.forEach((entry, index) => {\n validateManifestEntry(entry, index);\n\n const operationKey = `${entry.controller}.${entry.action}`;\n const invoke = resolveBridgeFunction(bridge, entry.path, operationKey);\n\n if (!app[entry.controller]) {\n app[entry.controller] = {};\n }\n\n if (app[entry.controller][entry.action]) {\n throw new Error(\n `Duplicate RPC action \"${operationKey}\" in Wood manifest. Actions must be unique per controller.`,\n );\n }\n\n app[entry.controller][entry.action] = (...args: unknown[]): Promise<unknown> => {\n if (entry.hasInput) {\n if (args.length !== 1) {\n throw new Error(\n `App RPC \"${operationKey}\" expects exactly one payload argument.`,\n );\n }\n assertSerializable(args[0], operationKey);\n const conversationId = extractTraceConversationId(args[0]);\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.request',\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n hasInput: entry.hasInput,\n },\n });\n return invoke(args[0])\n .then((result) => {\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.response',\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'ok',\n },\n });\n return result;\n })\n .catch((error) => {\n emitRendererTrace('error', {\n source: 'wood.client.app',\n type: 'rpc.response',\n message: error instanceof Error ? error.message : String(error),\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'error',\n },\n });\n throw error;\n });\n }\n\n if (args.length !== 0) {\n throw new Error(\n `App RPC \"${operationKey}\" expects no arguments.`,\n );\n }\n\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.request',\n payload: {\n operationKey,\n channel: entry.channel,\n hasInput: entry.hasInput,\n },\n });\n return invoke()\n .then((result) => {\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.response',\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'ok',\n },\n });\n return result;\n })\n .catch((error) => {\n emitRendererTrace('error', {\n source: 'wood.client.app',\n type: 'rpc.response',\n message: error instanceof Error ? error.message : String(error),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'error',\n },\n });\n throw error;\n });\n };\n });\n\n return app as unknown as App;\n}\n\nexport function getApp<TApp extends object = App>(): TApp {\n const globalObj = globalThis as GlobalWithClientApp;\n if (!globalObj[CLIENT_APP_SYMBOL]) {\n globalObj[CLIENT_APP_SYMBOL] = createAppInstance();\n }\n return globalObj[CLIENT_APP_SYMBOL] as TApp;\n}\n\n/** Test-only helper to clear the client App singleton. */\nexport function clearClientAppForTests(): void {\n const globalObj = globalThis as GlobalWithClientApp;\n delete globalObj[CLIENT_APP_SYMBOL];\n}\n\nfunction resolveWindowControlsBridgeMethod<T>(\n method: keyof NonNullable<WoodBridgeLike['__window']>,\n): T {\n const bridge = resolveWoodBridge();\n const fn = bridge.__window?.[method];\n if (typeof fn !== 'function') {\n throw new Error(`Wood bridge does not expose \"__window.${String(method)}\".`);\n }\n return fn as unknown as T;\n}\n\nexport class WindowControls {\n async open(windowId: string, options?: Record<string, unknown>): Promise<void> {\n const open = resolveWindowControlsBridgeMethod<\n (id: string, opts?: Record<string, unknown>) => Promise<unknown>\n >('open');\n await open(windowId, options);\n }\n\n async close(windowId?: string): Promise<void> {\n const close = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('close');\n await close(windowId);\n }\n\n async focus(windowId: string): Promise<void> {\n const focus = resolveWindowControlsBridgeMethod<\n (id: string) => Promise<unknown>\n >('focus');\n await focus(windowId);\n }\n\n async minimize(windowId?: string): Promise<void> {\n const minimize = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('minimize');\n await minimize(windowId);\n }\n\n async maximize(windowId?: string): Promise<void> {\n const maximize = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('maximize');\n await maximize(windowId);\n }\n}\n\nexport function getWindowControls(): WindowControls {\n const globalObj = globalThis as GlobalWithWindowControls;\n if (!globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL]) {\n globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL] = new WindowControls();\n }\n return globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL] as WindowControls;\n}\n\n/** Test-only helper to clear the client WindowControls singleton. */\nexport function clearClientWindowControlsForTests(): void {\n const globalObj = globalThis as GlobalWithWindowControls;\n delete globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL];\n}\n\ntype RendererLogLevel = 'debug' | 'info' | 'warn' | 'error' | (string & {});\n\nfunction stringifyLogMessage(message: unknown): string {\n if (typeof message === 'string') return message;\n if (message instanceof Error) return message.message;\n return String(message);\n}\n\nfunction writeConsole(level: RendererLogLevel, logger: string, message: string, context?: unknown): void {\n const prefix = `[${logger}] ${message}`;\n switch (level) {\n case 'debug':\n console.debug(prefix, context);\n return;\n case 'warn':\n console.warn(prefix, context);\n return;\n case 'error':\n console.error(prefix, context);\n return;\n default:\n console.info(prefix, context);\n }\n}\n\nclass RendererLogger {\n constructor(private readonly loggerName: string) {}\n\n debug(message: unknown, context?: unknown): void {\n this.log('debug', message, context);\n }\n\n info(message: unknown, context?: unknown): void {\n this.log('info', message, context);\n }\n\n warn(message: unknown, context?: unknown): void {\n this.log('warn', message, context);\n }\n\n error(message: unknown, context?: unknown): void {\n this.log('error', message, context);\n }\n\n logAt(level: RendererLogLevel, rawMessage: unknown, context?: unknown): void {\n this.log(level, rawMessage, context);\n }\n\n private log(level: RendererLogLevel, rawMessage: unknown, context?: unknown): void {\n const message = stringifyLogMessage(rawMessage);\n\n let bridge: WoodBridgeLike;\n try {\n bridge = resolveWoodBridge();\n } catch {\n writeConsole(level, this.loggerName, message, context);\n return;\n }\n\n if (typeof bridge.__log !== 'function') {\n writeConsole(level, this.loggerName, message, context);\n return;\n }\n\n try {\n bridge.__log(level, this.loggerName, message, context);\n } catch {\n writeConsole(level, this.loggerName, message, context);\n }\n }\n}\n\ntype RendererLoggerShape = {\n logAt(level: RendererLogLevel, message: unknown, context?: unknown): void;\n debug(message: unknown, context?: unknown): void;\n info(message: unknown, context?: unknown): void;\n warn(message: unknown, context?: unknown): void;\n error(message: unknown, context?: unknown): void;\n};\n\nexport function createLogger(name: string): RendererLoggerShape {\n const loggerName = name.trim() || 'renderer';\n const globalObj = globalThis as GlobalWithLoggerRegistry;\n if (!globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]) {\n globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL] = new Map<string, RendererLogger>();\n }\n\n const existing = globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]?.get(loggerName);\n if (existing) return existing;\n\n const logger = new RendererLogger(loggerName);\n globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]?.set(loggerName, logger);\n return logger;\n}\n\n/** Test-only helper to clear client logger singletons. */\nexport function clearClientLoggersForTests(): void {\n const globalObj = globalThis as GlobalWithLoggerRegistry;\n delete globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL];\n}\n\nfunction registerClientBuiltins(container: WoodContainerRegistration): void {\n if (typeof container.registerFunction !== 'function') {\n return;\n }\n\n const traceConfiguration = new TraceProviderConfiguration();\n traceConfiguration.configureRuntime('renderer');\n\n container.registerFunction(Navigation, () => getNavigation());\n container.registerFunction(App, () => getApp());\n container.registerFunction(Ipc, () => getIpc());\n container.registerFunction(WindowControls, () => getWindowControls());\n container.registerFunction(TraceProviderConfiguration, () => traceConfiguration);\n}\n\nfunction createClientContainerInstance(): any {\n const container = new Container();\n registerClientBuiltins(container as WoodContainerRegistration);\n return container;\n}\n\n/**\n * Return a process-global client container instance.\n *\n * - First call creates the container and stores it on a symbol.\n * - Later calls return the same container instance.\n */\nexport function getContainer(): any {\n const globalObj = globalThis as GlobalWithClientContainer;\n if (!globalObj[CLIENT_CONTAINER_SYMBOL]) {\n globalObj[CLIENT_CONTAINER_SYMBOL] = createClientContainerInstance();\n }\n return globalObj[CLIENT_CONTAINER_SYMBOL];\n}\n\n/** Test-only helper to clear the client container singleton. */\nexport function clearClientContainerForTests(): void {\n const globalObj = globalThis as GlobalWithClientContainer;\n delete globalObj[CLIENT_CONTAINER_SYMBOL];\n}\n\n/** Test-only helper to clear the client navigation singleton. */\nexport function clearClientNavigationForTests(): void {\n clearNavigationSingletonForTests();\n}\n\n/** Clamp a menu position so it stays within viewport bounds. */\nexport function clampMenuPosition(\n x: number,\n y: number,\n menuWidth: number,\n menuHeight: number,\n): { x: number; y: number } {\n const vw = typeof window !== 'undefined' ? window.innerWidth : Infinity;\n const vh = typeof window !== 'undefined' ? window.innerHeight : Infinity;\n return {\n x: Math.min(x, Math.max(0, vw - menuWidth)),\n y: Math.min(y, Math.max(0, vh - menuHeight)),\n };\n}\n\nfunction resolveTarget(target: Element | null): Element {\n if (!target) {\n throw new Error('Missing renderer mount target');\n }\n return target;\n}\n\ntype RendererTraceBootstrapConfiguration = {\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: string;\n rendererTraceBatchEnabled?: boolean;\n appEnv?: string;\n};\n\nfunction configureRendererTraceTransport(config: RendererTraceBootstrapConfiguration | null): void {\n const globalObj = globalThis as Record<string, unknown>;\n if (config?.rendererTraceBatchEnabled) {\n const batchGlobal = globalObj.__NOEGO_WOOD_TRACE_BATCH__ as\n | { send?: (data: unknown) => unknown }\n | undefined;\n if (batchGlobal && typeof batchGlobal.send === 'function') {\n const sender = batchGlobal.send.bind(batchGlobal);\n setRendererTraceTransport((payload: unknown) => {\n sender(payload);\n });\n return;\n }\n }\n\n const traceGlobal = globalObj.__NOEGO_TRACE__ as\n | { send?: (data: unknown) => void }\n | undefined;\n if (traceGlobal && typeof traceGlobal.send === 'function') {\n const sender = traceGlobal.send.bind(traceGlobal);\n setRendererTraceTransport((payload: unknown) => sender(payload));\n }\n}\n\n/**\n * Start a Wood renderer app by mounting it to a target element.\n * Usage:\n * import { app } from './generated/app.cjs';\n * startWood(app, document.getElementById('app'));\n */\nexport async function startWood<T>(\n mountRoot: (target: Element) => T,\n target: Element | null,\n): Promise<T> {\n // Ensure container singleton exists and registers built-in client tokens.\n const container = getContainer();\n // Ensure navigation singleton exists at first client boot.\n getNavigation();\n\n // Fetch framework config from the main process and apply renderer trace\n // controls before the first render.\n let rendererTraceConfig: RendererTraceBootstrapConfiguration | null = null;\n try {\n const bridge = resolveWoodBridge();\n if (typeof bridge.__woodConfig === 'function') {\n const config = await bridge.__woodConfig() as RendererTraceBootstrapConfiguration | null;\n rendererTraceConfig = config;\n setWoodAppEnv(config?.appEnv);\n const traceConfiguration = container.instance\n ? await container.instance(TraceProviderConfiguration)\n : null;\n if (typeof config?.rendererTraceEnabled === 'boolean') {\n traceConfiguration?.configureEnabled(config.rendererTraceEnabled);\n }\n const level = config?.rendererTraceMinLevel;\n if (typeof level === 'string' && level.trim().length > 0) {\n traceConfiguration?.configureMinLevel(level);\n }\n }\n } catch {\n // Config fetch is best-effort; fall back to defaults.\n }\n\n try {\n configureRendererTraceTransport(rendererTraceConfig);\n } catch {\n // Trace transport selection is best-effort; the internal IPC bridge remains available.\n }\n\n return mountRoot(resolveTarget(target));\n}\n\n/**\n * Backward-compatible helper that returns a target-aware boot function.\n * Usage:\n * const boot = createSvelteBoot(app);\n * const mounted = boot(document.getElementById('app'));\n */\nexport function createSvelteBoot<T>(\n mountRoot: (target: Element) => T,\n) {\n return (target: Element | null): T => mountRoot(resolveTarget(target));\n}\n\nexport { getNavigation };\nexport { Ipc, getIpc };\nexport { clearTraceHubForTests };\nexport { setRendererTraceTransport };\nexport { TraceProvider, TraceProviderConfiguration } from '../tracing/index.js';\nexport type {\n FrameworkTracer,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"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","names":["import_app_env","import_tracing","clearNavigationSingletonForTests"]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts"],"sourcesContent":["import './global_polyfill.cjs';\nimport 'reflect-metadata';\nimport { Container, LoadAs } from '@noego/ioc';\nimport {\n Navigation,\n getNavigation,\n clearNavigationForTests as clearNavigationSingletonForTests,\n} from '../navigation/index.js';\nimport { Ipc, getIpc } from '../ipc/index.js';\nimport { setWoodAppEnv } from './app_env.js';\nexport { getWoodAppEnv, type WoodAppEnv } from './app_env.js';\nimport {\n TraceProviderConfiguration,\n clearTraceHubForTests,\n emitRendererTrace,\n setRendererTraceTransport,\n} from '../tracing/index.js';\nexport type {\n ControllerEvents,\n ControllerInput,\n ControllerLifecycle,\n ControllerState,\n PageController,\n} from './controller_contract.js';\nimport {\n RendererLogTransport,\n getRendererLogTransport,\n clearRendererLogTransportForTests as clearRendererLogTransportSingletonForTests,\n} from './renderer_log_transport.js';\nexport {\n configureRendererLogTransport,\n flushRendererLogs,\n type RendererLogTransportConfig,\n} from './renderer_log_transport.js';\n\n/** Resets the renderer log transport singleton, its bridge wiring latch, and any app sender. */\nexport function clearRendererLogTransportForTests(): void {\n rendererLogWiringDone = false;\n appRendererLogSender = null;\n rendererBootConfig = null;\n clearRendererLogTransportSingletonForTests();\n}\n\n/** An app-installed outlet for admitted renderer log batches (e.g. a WebSocket to a log host). */\nexport type RendererLogSender = (batch: unknown) => void;\n\nlet appRendererLogSender: RendererLogSender | null = null;\n\n/**\n * Installs (or with `null`, removes) an app-owned batch sender that takes\n * precedence over the preload `__logBatch` IPC path. Records already buffered\n * are flushed through the previous outlet first so nothing is reordered or\n * lost across the swap. A sender that throws falls back to the preload/legacy\n * chain for that batch, exactly like the default outlet.\n */\nexport function setRendererLogSender(sender: RendererLogSender | null): void {\n const transport = getRendererLogTransport();\n transport.flush();\n appRendererLogSender = sender;\n rendererLogWiringDone = false;\n ensureRendererLogWiring(transport);\n}\n\n/** The most recent `__woodConfig` payload received in `startWood`, or null before boot. */\nexport function getRendererBootConfig(): Readonly<Record<string, unknown>> | null {\n return rendererBootConfig;\n}\n\nlet rendererBootConfig: Readonly<Record<string, unknown>> | null = null;\n\nconst CLIENT_CONTAINER_SYMBOL = Symbol.for('@noego/wood.client.container');\nconst CLIENT_APP_SYMBOL = Symbol.for('@noego/wood.client.app');\nconst CLIENT_WINDOW_CONTROLS_SYMBOL = Symbol.for('@noego/wood.client.window-controls');\nconst CLIENT_LOGGER_REGISTRY_SYMBOL = Symbol.for('@noego/wood.client.logger-registry');\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\nexport const WOOD_INTERNAL_BRIDGE_KEY = INTERNAL_BRIDGE_GLOBAL_KEY;\n\nexport interface WoodRpcManifestEntry {\n channel: string;\n controller: string;\n action: string;\n path: string[];\n hasInput: boolean;\n}\n\ntype WoodBridgeRpcFunction = (data?: unknown) => Promise<unknown>;\ntype WoodBridgeLike = Record<string, unknown> & {\n __rpcManifest?: WoodRpcManifestEntry[];\n __window?: {\n current?: () => Promise<unknown>;\n open?: (windowId: string, options?: Record<string, unknown>) => Promise<unknown>;\n close?: (windowId?: string) => Promise<unknown>;\n focus?: (windowId: string) => Promise<unknown>;\n minimize?: (windowId?: string) => Promise<unknown>;\n maximize?: (windowId?: string) => Promise<unknown>;\n };\n __log?: (\n level: string,\n logger: string,\n message: string,\n context?: unknown,\n ) => void;\n __logBatch?: (batch: unknown) => void;\n __woodConfig?: () => Promise<unknown>;\n __trace?: (event: unknown) => void;\n};\n\ntype GlobalWithClientContainer = typeof globalThis & {\n [CLIENT_CONTAINER_SYMBOL]?: any;\n};\n\ntype GlobalWithClientApp = typeof globalThis & {\n [CLIENT_APP_SYMBOL]?: object;\n};\n\ntype GlobalWithWindowControls = typeof globalThis & {\n [CLIENT_WINDOW_CONTROLS_SYMBOL]?: WindowControls;\n};\n\ntype GlobalWithLoggerRegistry = typeof globalThis & {\n [CLIENT_LOGGER_REGISTRY_SYMBOL]?: Map<string, RendererLogger>;\n};\n\ninterface WoodContainerRegistration {\n registerFunction?(\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ): void;\n}\n\nexport class App {\n [controllerName: string]: unknown;\n}\n\nfunction resolveWoodBridge(): WoodBridgeLike {\n const globalObj = globalThis as typeof globalThis & {\n [INTERNAL_BRIDGE_GLOBAL_KEY]?: unknown;\n wood?: unknown;\n window?: {\n [INTERNAL_BRIDGE_GLOBAL_KEY]?: unknown;\n wood?: unknown;\n };\n };\n\n const bridge = globalObj[INTERNAL_BRIDGE_GLOBAL_KEY]\n ?? globalObj.window?.[INTERNAL_BRIDGE_GLOBAL_KEY]\n ?? globalObj.wood\n ?? globalObj.window?.wood;\n if (!bridge || typeof bridge !== 'object') {\n throw new Error(\n `Wood bridge is not available on globalThis.${INTERNAL_BRIDGE_GLOBAL_KEY}.`,\n );\n }\n\n return bridge as WoodBridgeLike;\n}\n\nfunction resolveRpcManifest(bridge: WoodBridgeLike): WoodRpcManifestEntry[] {\n const manifest = bridge.__rpcManifest;\n if (!Array.isArray(manifest)) {\n throw new Error(\n 'Wood bridge is missing \"__rpcManifest\". Regenerate preload with the latest @noego/wood.',\n );\n }\n\n return manifest;\n}\n\nfunction resolveBridgeFunction(\n bridge: WoodBridgeLike,\n pathSegments: string[],\n operationKey: string,\n): WoodBridgeRpcFunction {\n let current: unknown = bridge;\n\n for (const segment of pathSegments) {\n if (!current || typeof current !== 'object') {\n throw new Error(\n `Wood bridge operation \"${operationKey}\" is missing path \"${pathSegments.join('.')}\".`,\n );\n }\n current = (current as Record<string, unknown>)[segment];\n }\n\n if (typeof current !== 'function') {\n throw new Error(\n `Wood bridge path \"${pathSegments.join('.')}\" for \"${operationKey}\" is not callable.`,\n );\n }\n\n return current as WoodBridgeRpcFunction;\n}\n\nfunction assertSerializable(value: unknown, operationKey: string): void {\n if (typeof structuredClone !== 'function') {\n return;\n }\n\n try {\n structuredClone(value);\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n throw new Error(\n `App RPC \"${operationKey}\" payload is not serializable: ${reason}`,\n );\n }\n}\n\nfunction extractTraceConversationId(value: unknown): number | string | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n\n const record = value as Record<string, unknown>;\n if (typeof record.conversationId === 'number' || typeof record.conversationId === 'string') {\n return record.conversationId;\n }\n if (typeof record.threadId === 'number' || typeof record.threadId === 'string') {\n return record.threadId;\n }\n\n return undefined;\n}\n\nfunction validateManifestEntry(entry: WoodRpcManifestEntry, index: number): void {\n if (!entry.channel || !entry.controller || !entry.action) {\n throw new Error(`Invalid Wood RPC manifest entry at index ${index}.`);\n }\n if (!Array.isArray(entry.path) || entry.path.length === 0) {\n throw new Error(\n `Invalid Wood RPC manifest path for \"${entry.controller}.${entry.action}\".`,\n );\n }\n}\n\nfunction createAppInstance(): App {\n const bridge = resolveWoodBridge();\n const manifest = resolveRpcManifest(bridge);\n const app: Record<string, Record<string, (...args: unknown[]) => Promise<unknown>>> = {};\n\n manifest.forEach((entry, index) => {\n validateManifestEntry(entry, index);\n\n const operationKey = `${entry.controller}.${entry.action}`;\n const invoke = resolveBridgeFunction(bridge, entry.path, operationKey);\n\n if (!app[entry.controller]) {\n app[entry.controller] = {};\n }\n\n if (app[entry.controller][entry.action]) {\n throw new Error(\n `Duplicate RPC action \"${operationKey}\" in Wood manifest. Actions must be unique per controller.`,\n );\n }\n\n app[entry.controller][entry.action] = (...args: unknown[]): Promise<unknown> => {\n if (entry.hasInput) {\n if (args.length !== 1) {\n throw new Error(\n `App RPC \"${operationKey}\" expects exactly one payload argument.`,\n );\n }\n assertSerializable(args[0], operationKey);\n const conversationId = extractTraceConversationId(args[0]);\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.request',\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n hasInput: entry.hasInput,\n },\n });\n return invoke(args[0])\n .then((result) => {\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.response',\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'ok',\n },\n });\n return result;\n })\n .catch((error) => {\n emitRendererTrace('error', {\n source: 'wood.client.app',\n type: 'rpc.response',\n message: error instanceof Error ? error.message : String(error),\n ...(conversationId !== undefined ? { conversationId } : {}),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'error',\n },\n });\n throw error;\n });\n }\n\n if (args.length !== 0) {\n throw new Error(\n `App RPC \"${operationKey}\" expects no arguments.`,\n );\n }\n\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.request',\n payload: {\n operationKey,\n channel: entry.channel,\n hasInput: entry.hasInput,\n },\n });\n return invoke()\n .then((result) => {\n emitRendererTrace('debug', {\n source: 'wood.client.app',\n type: 'rpc.response',\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'ok',\n },\n });\n return result;\n })\n .catch((error) => {\n emitRendererTrace('error', {\n source: 'wood.client.app',\n type: 'rpc.response',\n message: error instanceof Error ? error.message : String(error),\n payload: {\n operationKey,\n channel: entry.channel,\n outcome: 'error',\n },\n });\n throw error;\n });\n };\n });\n\n return app as unknown as App;\n}\n\nexport function getApp<TApp extends object = App>(): TApp {\n const globalObj = globalThis as GlobalWithClientApp;\n if (!globalObj[CLIENT_APP_SYMBOL]) {\n globalObj[CLIENT_APP_SYMBOL] = createAppInstance();\n }\n return globalObj[CLIENT_APP_SYMBOL] as TApp;\n}\n\n/** Test-only helper to clear the client App singleton. */\nexport function clearClientAppForTests(): void {\n const globalObj = globalThis as GlobalWithClientApp;\n delete globalObj[CLIENT_APP_SYMBOL];\n}\n\nfunction resolveWindowControlsBridgeMethod<T>(\n method: keyof NonNullable<WoodBridgeLike['__window']>,\n): T {\n const bridge = resolveWoodBridge();\n const fn = bridge.__window?.[method];\n if (typeof fn !== 'function') {\n throw new Error(`Wood bridge does not expose \"__window.${String(method)}\".`);\n }\n return fn as unknown as T;\n}\n\nexport class WindowControls {\n async open(windowId: string, options?: Record<string, unknown>): Promise<void> {\n const open = resolveWindowControlsBridgeMethod<\n (id: string, opts?: Record<string, unknown>) => Promise<unknown>\n >('open');\n await open(windowId, options);\n }\n\n async close(windowId?: string): Promise<void> {\n const close = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('close');\n await close(windowId);\n }\n\n async focus(windowId: string): Promise<void> {\n const focus = resolveWindowControlsBridgeMethod<\n (id: string) => Promise<unknown>\n >('focus');\n await focus(windowId);\n }\n\n async minimize(windowId?: string): Promise<void> {\n const minimize = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('minimize');\n await minimize(windowId);\n }\n\n async maximize(windowId?: string): Promise<void> {\n const maximize = resolveWindowControlsBridgeMethod<\n (id?: string) => Promise<unknown>\n >('maximize');\n await maximize(windowId);\n }\n}\n\nexport function getWindowControls(): WindowControls {\n const globalObj = globalThis as GlobalWithWindowControls;\n if (!globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL]) {\n globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL] = new WindowControls();\n }\n return globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL] as WindowControls;\n}\n\n/** Test-only helper to clear the client WindowControls singleton. */\nexport function clearClientWindowControlsForTests(): void {\n const globalObj = globalThis as GlobalWithWindowControls;\n delete globalObj[CLIENT_WINDOW_CONTROLS_SYMBOL];\n}\n\ntype RendererLogLevel = 'debug' | 'info' | 'warn' | 'error' | (string & {});\n\nfunction stringifyLogMessage(message: unknown): string {\n if (typeof message === 'string') return message;\n if (message instanceof Error) return message.message;\n return String(message);\n}\n\nfunction writeConsole(level: RendererLogLevel, logger: string, message: string, context?: unknown): void {\n const prefix = `[${logger}] ${message}`;\n switch (level) {\n case 'debug':\n console.debug(prefix, context);\n return;\n case 'warn':\n console.warn(prefix, context);\n return;\n case 'error':\n console.error(prefix, context);\n return;\n default:\n console.info(prefix, context);\n }\n}\n\nclass RendererLogger {\n constructor(private readonly loggerName: string) {}\n\n debug(message: unknown, context?: unknown): void {\n this.log('debug', message, context);\n }\n\n info(message: unknown, context?: unknown): void {\n this.log('info', message, context);\n }\n\n warn(message: unknown, context?: unknown): void {\n this.log('warn', message, context);\n }\n\n error(message: unknown, context?: unknown): void {\n this.log('error', message, context);\n }\n\n logAt(level: RendererLogLevel, rawMessage: unknown, context?: unknown): void {\n this.log(level, rawMessage, context);\n }\n\n private log(level: RendererLogLevel, rawMessage: unknown, context?: unknown): void {\n const message = stringifyLogMessage(rawMessage);\n\n const transport = getRendererLogTransport();\n ensureRendererLogWiring(transport);\n transport.admit(level, this.loggerName, message, context);\n }\n}\n\nlet rendererLogWiringDone = false;\n\n/**\n * Lazily binds the renderer log pipe's outlet to the preload bridge: batches\n * ride __logBatch (admitted records, one IPC message per flush); the per-entry\n * legacy __log channel and finally the console act as fallbacks when the\n * bridge predates batching or is absent (tests, plain browsers).\n */\nfunction ensureRendererLogWiring(transport: RendererLogTransport): void {\n if (rendererLogWiringDone) return;\n\n let bridge: WoodBridgeLike | null = null;\n try {\n bridge = resolveWoodBridge();\n } catch {\n bridge = null;\n }\n\n const preloadSend = bridge && typeof bridge.__logBatch === 'function'\n ? bridge.__logBatch.bind(bridge)\n : null;\n const appSend = appRendererLogSender;\n\n if (appSend) {\n // App sender wins; a throw here degrades to the preload batch path for\n // that batch, then to the per-record fallback if that throws too.\n transport.setSender((batch) => {\n try {\n appSend(batch);\n } catch (error) {\n if (!preloadSend) throw error;\n preloadSend(batch);\n }\n });\n } else if (preloadSend) {\n transport.setSender((batch) => preloadSend(batch));\n } else {\n transport.setSender(null);\n }\n\n const legacyLog = bridge && typeof bridge.__log === 'function' ? bridge.__log.bind(bridge) : null;\n transport.setFallback((record) => {\n if (legacyLog) {\n try {\n legacyLog(record.level, record.logger, record.message, record.context);\n return;\n } catch {\n // fall through to console\n }\n }\n writeConsole(record.level, record.logger, record.message, record.context);\n });\n\n // Only latch once a bridge was found (or an app sender makes the bridge\n // optional); keep retrying while both are absent so a late-injected bridge\n // (tests, slow preload) still gets wired.\n rendererLogWiringDone = bridge !== null || appSend !== null;\n}\n\ntype RendererLoggerShape = {\n logAt(level: RendererLogLevel, message: unknown, context?: unknown): void;\n debug(message: unknown, context?: unknown): void;\n info(message: unknown, context?: unknown): void;\n warn(message: unknown, context?: unknown): void;\n error(message: unknown, context?: unknown): void;\n};\n\nexport function createLogger(name: string): RendererLoggerShape {\n const loggerName = name.trim() || 'renderer';\n const globalObj = globalThis as GlobalWithLoggerRegistry;\n if (!globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]) {\n globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL] = new Map<string, RendererLogger>();\n }\n\n const existing = globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]?.get(loggerName);\n if (existing) return existing;\n\n const logger = new RendererLogger(loggerName);\n globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL]?.set(loggerName, logger);\n return logger;\n}\n\n/** Test-only helper to clear client logger singletons. */\nexport function clearClientLoggersForTests(): void {\n const globalObj = globalThis as GlobalWithLoggerRegistry;\n delete globalObj[CLIENT_LOGGER_REGISTRY_SYMBOL];\n}\n\nfunction registerClientBuiltins(container: WoodContainerRegistration): void {\n if (typeof container.registerFunction !== 'function') {\n return;\n }\n\n const traceConfiguration = new TraceProviderConfiguration();\n traceConfiguration.configureRuntime('renderer');\n\n // Explicit Singleton lifetime: these factories return renderer-root\n // globals, and registerFunction defaults to Transient — which ioc >= 0.5's\n // captive-lifetime validation rejects under singleton dependents.\n const singleton = { loadAs: LoadAs.Singleton };\n container.registerFunction(Navigation, () => getNavigation(), singleton);\n container.registerFunction(App, () => getApp(), singleton);\n container.registerFunction(Ipc, () => getIpc(), singleton);\n container.registerFunction(WindowControls, () => getWindowControls(), singleton);\n container.registerFunction(TraceProviderConfiguration, () => traceConfiguration, singleton);\n}\n\nfunction createClientContainerInstance(): any {\n const container = new Container();\n registerClientBuiltins(container as WoodContainerRegistration);\n return container;\n}\n\n/**\n * Return a process-global client container instance.\n *\n * - First call creates the container and stores it on a symbol.\n * - Later calls return the same container instance.\n */\nexport function getContainer(): any {\n const globalObj = globalThis as GlobalWithClientContainer;\n if (!globalObj[CLIENT_CONTAINER_SYMBOL]) {\n globalObj[CLIENT_CONTAINER_SYMBOL] = createClientContainerInstance();\n }\n return globalObj[CLIENT_CONTAINER_SYMBOL];\n}\n\n/** Test-only helper to clear the client container singleton. */\nexport function clearClientContainerForTests(): void {\n const globalObj = globalThis as GlobalWithClientContainer;\n delete globalObj[CLIENT_CONTAINER_SYMBOL];\n}\n\n/** Test-only helper to clear the client navigation singleton. */\nexport function clearClientNavigationForTests(): void {\n clearNavigationSingletonForTests();\n}\n\n/** Clamp a menu position so it stays within viewport bounds. */\nexport function clampMenuPosition(\n x: number,\n y: number,\n menuWidth: number,\n menuHeight: number,\n): { x: number; y: number } {\n const vw = typeof window !== 'undefined' ? window.innerWidth : Infinity;\n const vh = typeof window !== 'undefined' ? window.innerHeight : Infinity;\n return {\n x: Math.min(x, Math.max(0, vw - menuWidth)),\n y: Math.min(y, Math.max(0, vh - menuHeight)),\n };\n}\n\nfunction resolveTarget(target: Element | null): Element {\n if (!target) {\n throw new Error('Missing renderer mount target');\n }\n return target;\n}\n\ntype RendererTraceBootstrapConfiguration = {\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: string;\n rendererTraceBatchEnabled?: boolean;\n appEnv?: string;\n};\n\nfunction configureRendererTraceTransport(config: RendererTraceBootstrapConfiguration | null): void {\n const globalObj = globalThis as Record<string, unknown>;\n if (config?.rendererTraceBatchEnabled) {\n const batchGlobal = globalObj.__NOEGO_WOOD_TRACE_BATCH__ as\n | { send?: (data: unknown) => unknown }\n | undefined;\n if (batchGlobal && typeof batchGlobal.send === 'function') {\n const sender = batchGlobal.send.bind(batchGlobal);\n setRendererTraceTransport((payload: unknown) => {\n sender(payload);\n });\n return;\n }\n }\n\n const traceGlobal = globalObj.__NOEGO_TRACE__ as\n | { send?: (data: unknown) => void }\n | undefined;\n if (traceGlobal && typeof traceGlobal.send === 'function') {\n const sender = traceGlobal.send.bind(traceGlobal);\n setRendererTraceTransport((payload: unknown) => sender(payload));\n }\n}\n\n/**\n * Start a Wood renderer app by mounting it to a target element.\n * Usage:\n * import { app } from './generated/app.cjs';\n * startWood(app, document.getElementById('app'));\n */\nexport async function startWood<T>(\n mountRoot: (target: Element) => T,\n target: Element | null,\n): Promise<T> {\n // Ensure container singleton exists and registers built-in client tokens.\n const container = getContainer();\n // Ensure navigation singleton exists at first client boot.\n getNavigation();\n\n // Fetch framework config from the main process and apply renderer trace\n // controls before the first render.\n let rendererTraceConfig: RendererTraceBootstrapConfiguration | null = null;\n try {\n const bridge = resolveWoodBridge();\n if (typeof bridge.__woodConfig === 'function') {\n const config = await bridge.__woodConfig() as RendererTraceBootstrapConfiguration | null;\n rendererTraceConfig = config;\n rendererBootConfig = config && typeof config === 'object'\n ? Object.freeze({ ...(config as Record<string, unknown>) })\n : null;\n setWoodAppEnv(config?.appEnv);\n const traceConfiguration = container.instance\n ? await container.instance(TraceProviderConfiguration)\n : null;\n if (typeof config?.rendererTraceEnabled === 'boolean') {\n traceConfiguration?.configureEnabled(config.rendererTraceEnabled);\n }\n const level = config?.rendererTraceMinLevel;\n if (typeof level === 'string' && level.trim().length > 0) {\n traceConfiguration?.configureMinLevel(level);\n }\n }\n } catch {\n // Config fetch is best-effort; fall back to defaults.\n }\n\n try {\n configureRendererTraceTransport(rendererTraceConfig);\n } catch {\n // Trace transport selection is best-effort; the internal IPC bridge remains available.\n }\n\n return mountRoot(resolveTarget(target));\n}\n\n/**\n * Backward-compatible helper that returns a target-aware boot function.\n * Usage:\n * const boot = createSvelteBoot(app);\n * const mounted = boot(document.getElementById('app'));\n */\nexport function createSvelteBoot<T>(\n mountRoot: (target: Element) => T,\n) {\n return (target: Element | null): T => mountRoot(resolveTarget(target));\n}\n\nexport { getNavigation };\nexport { Ipc, getIpc };\nexport { clearTraceHubForTests };\nexport { setRendererTraceTransport };\nexport { TraceProvider, TraceProviderConfiguration } from '../tracing/index.js';\nexport type {\n FrameworkTracer,\n TraceEvent,\n TraceInput,\n TraceLevel,\n TraceProcess,\n TraceProviderMode,\n TraceRuntime,\n TraceWaitOptions,\n} from '../tracing/index.js';\n"],"mappings":"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","names":["import_app_env","import_renderer_log_transport","import_tracing","clearRendererLogTransportSingletonForTests","clearNavigationSingletonForTests"]}
|
package/dist/client/index.d.cts
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
export { getNavigation } from '../navigation/index.cjs';
|
|
2
2
|
export { Ipc, getIpc } from '../ipc/index.cjs';
|
|
3
3
|
export { getWoodAppEnv } from './app_env.cjs';
|
|
4
|
-
export { a as TraceEvent, b as TraceInput, c as TraceLevel, d as TraceProcess, f as TraceWaitOptions, i as clearTraceHubForTests,
|
|
4
|
+
export { a as TraceEvent, b as TraceInput, c as TraceLevel, d as TraceProcess, f as TraceWaitOptions, i as clearTraceHubForTests, n as setRendererTraceTransport } from '../trace_hub-Cpo_nVze.cjs';
|
|
5
5
|
export { FrameworkTracer, TraceProvider, TraceProviderConfiguration, TraceProviderMode, TraceRuntime } from '../tracing/trace_provider.cjs';
|
|
6
6
|
export { ControllerEvents, ControllerInput, ControllerState, PageController } from './controller_contract.cjs';
|
|
7
|
+
export { RendererLogTransportConfig, configureRendererLogTransport, flushRendererLogs } from './renderer_log_transport.cjs';
|
|
7
8
|
export { ControllerLifecycle } from '../controller/controller_lifecycle.cjs';
|
|
8
9
|
export { WoodAppEnv } from '../runtime/app_env.cjs';
|
|
10
|
+
import '../navigation/automation_introspection.cjs';
|
|
9
11
|
import '../ipc/shared.cjs';
|
|
10
12
|
import 'rxjs';
|
|
11
|
-
import '@noego/
|
|
13
|
+
import '@noego/logger';
|
|
12
14
|
|
|
15
|
+
/** Resets the renderer log transport singleton, its bridge wiring latch, and any app sender. */
|
|
16
|
+
declare function clearRendererLogTransportForTests(): void;
|
|
17
|
+
/** An app-installed outlet for admitted renderer log batches (e.g. a WebSocket to a log host). */
|
|
18
|
+
type RendererLogSender = (batch: unknown) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Installs (or with `null`, removes) an app-owned batch sender that takes
|
|
21
|
+
* precedence over the preload `__logBatch` IPC path. Records already buffered
|
|
22
|
+
* are flushed through the previous outlet first so nothing is reordered or
|
|
23
|
+
* lost across the swap. A sender that throws falls back to the preload/legacy
|
|
24
|
+
* chain for that batch, exactly like the default outlet.
|
|
25
|
+
*/
|
|
26
|
+
declare function setRendererLogSender(sender: RendererLogSender | null): void;
|
|
27
|
+
/** The most recent `__woodConfig` payload received in `startWood`, or null before boot. */
|
|
28
|
+
declare function getRendererBootConfig(): Readonly<Record<string, unknown>> | null;
|
|
13
29
|
declare const WOOD_INTERNAL_BRIDGE_KEY = "__NOEGO_WOOD_BRIDGE__";
|
|
14
30
|
interface WoodRpcManifestEntry {
|
|
15
31
|
channel: string;
|
|
@@ -76,4 +92,4 @@ declare function startWood<T>(mountRoot: (target: Element) => T, target: Element
|
|
|
76
92
|
*/
|
|
77
93
|
declare function createSvelteBoot<T>(mountRoot: (target: Element) => T): (target: Element | null) => T;
|
|
78
94
|
|
|
79
|
-
export { App, WOOD_INTERNAL_BRIDGE_KEY, WindowControls, type WoodRpcManifestEntry, clampMenuPosition, clearClientAppForTests, clearClientContainerForTests, clearClientLoggersForTests, clearClientNavigationForTests, clearClientWindowControlsForTests, createLogger, createSvelteBoot, getApp, getContainer, getWindowControls, startWood };
|
|
95
|
+
export { App, type RendererLogSender, WOOD_INTERNAL_BRIDGE_KEY, WindowControls, type WoodRpcManifestEntry, clampMenuPosition, clearClientAppForTests, clearClientContainerForTests, clearClientLoggersForTests, clearClientNavigationForTests, clearClientWindowControlsForTests, clearRendererLogTransportForTests, createLogger, createSvelteBoot, getApp, getContainer, getRendererBootConfig, getWindowControls, setRendererLogSender, startWood };
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
export { getNavigation } from '../navigation/index.js';
|
|
2
2
|
export { Ipc, getIpc } from '../ipc/index.js';
|
|
3
3
|
export { getWoodAppEnv } from './app_env.js';
|
|
4
|
-
export { a as TraceEvent, b as TraceInput, c as TraceLevel, d as TraceProcess, f as TraceWaitOptions, i as clearTraceHubForTests,
|
|
4
|
+
export { a as TraceEvent, b as TraceInput, c as TraceLevel, d as TraceProcess, f as TraceWaitOptions, i as clearTraceHubForTests, n as setRendererTraceTransport } from '../trace_hub-Cpo_nVze.js';
|
|
5
5
|
export { FrameworkTracer, TraceProvider, TraceProviderConfiguration, TraceProviderMode, TraceRuntime } from '../tracing/trace_provider.js';
|
|
6
6
|
export { ControllerEvents, ControllerInput, ControllerState, PageController } from './controller_contract.js';
|
|
7
|
+
export { RendererLogTransportConfig, configureRendererLogTransport, flushRendererLogs } from './renderer_log_transport.js';
|
|
7
8
|
export { ControllerLifecycle } from '../controller/controller_lifecycle.js';
|
|
8
9
|
export { WoodAppEnv } from '../runtime/app_env.js';
|
|
10
|
+
import '../navigation/automation_introspection.js';
|
|
9
11
|
import '../ipc/shared.js';
|
|
10
12
|
import 'rxjs';
|
|
11
|
-
import '@noego/
|
|
13
|
+
import '@noego/logger';
|
|
12
14
|
|
|
15
|
+
/** Resets the renderer log transport singleton, its bridge wiring latch, and any app sender. */
|
|
16
|
+
declare function clearRendererLogTransportForTests(): void;
|
|
17
|
+
/** An app-installed outlet for admitted renderer log batches (e.g. a WebSocket to a log host). */
|
|
18
|
+
type RendererLogSender = (batch: unknown) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Installs (or with `null`, removes) an app-owned batch sender that takes
|
|
21
|
+
* precedence over the preload `__logBatch` IPC path. Records already buffered
|
|
22
|
+
* are flushed through the previous outlet first so nothing is reordered or
|
|
23
|
+
* lost across the swap. A sender that throws falls back to the preload/legacy
|
|
24
|
+
* chain for that batch, exactly like the default outlet.
|
|
25
|
+
*/
|
|
26
|
+
declare function setRendererLogSender(sender: RendererLogSender | null): void;
|
|
27
|
+
/** The most recent `__woodConfig` payload received in `startWood`, or null before boot. */
|
|
28
|
+
declare function getRendererBootConfig(): Readonly<Record<string, unknown>> | null;
|
|
13
29
|
declare const WOOD_INTERNAL_BRIDGE_KEY = "__NOEGO_WOOD_BRIDGE__";
|
|
14
30
|
interface WoodRpcManifestEntry {
|
|
15
31
|
channel: string;
|
|
@@ -76,4 +92,4 @@ declare function startWood<T>(mountRoot: (target: Element) => T, target: Element
|
|
|
76
92
|
*/
|
|
77
93
|
declare function createSvelteBoot<T>(mountRoot: (target: Element) => T): (target: Element | null) => T;
|
|
78
94
|
|
|
79
|
-
export { App, WOOD_INTERNAL_BRIDGE_KEY, WindowControls, type WoodRpcManifestEntry, clampMenuPosition, clearClientAppForTests, clearClientContainerForTests, clearClientLoggersForTests, clearClientNavigationForTests, clearClientWindowControlsForTests, createLogger, createSvelteBoot, getApp, getContainer, getWindowControls, startWood };
|
|
95
|
+
export { App, type RendererLogSender, WOOD_INTERNAL_BRIDGE_KEY, WindowControls, type WoodRpcManifestEntry, clampMenuPosition, clearClientAppForTests, clearClientContainerForTests, clearClientLoggersForTests, clearClientNavigationForTests, clearClientWindowControlsForTests, clearRendererLogTransportForTests, createLogger, createSvelteBoot, getApp, getContainer, getRendererBootConfig, getWindowControls, setRendererLogSender, startWood };
|