@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,123 @@
|
|
|
1
|
+
import { createLogPipe } from "@noego/logger";
|
|
2
|
+
import { createRecordBatch } from "@noego/trace/stream";
|
|
3
|
+
const TRANSPORT_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.client.renderer-log-transport");
|
|
4
|
+
const DEFAULT_BUFFER = { mode: "buffered", intervalMs: 500, maxRecords: 500 };
|
|
5
|
+
function randomSuffix() {
|
|
6
|
+
return Math.random().toString(36).slice(2, 10);
|
|
7
|
+
}
|
|
8
|
+
class RendererLogTransport {
|
|
9
|
+
constructor(config = {}) {
|
|
10
|
+
this.sequence = 0;
|
|
11
|
+
this.sender = null;
|
|
12
|
+
this.fallback = null;
|
|
13
|
+
const c = globalThis.crypto;
|
|
14
|
+
this.producerId = `renderer:${c && typeof c.randomUUID === "function" ? c.randomUUID() : randomSuffix()}`;
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.pipe = this.buildPipe();
|
|
17
|
+
}
|
|
18
|
+
/** Rebuilds the pipe with new buffering config; pending records are flushed first. */
|
|
19
|
+
configure(config) {
|
|
20
|
+
this.pipe.flush();
|
|
21
|
+
void this.pipe.close();
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.pipe = this.buildPipe();
|
|
24
|
+
}
|
|
25
|
+
/** Installs the batch sender (the preload bridge's __logBatch). */
|
|
26
|
+
setSender(sender) {
|
|
27
|
+
this.sender = sender;
|
|
28
|
+
}
|
|
29
|
+
/** Installs the per-record fallback used when no batch sender is available. */
|
|
30
|
+
setFallback(fallback) {
|
|
31
|
+
this.fallback = fallback;
|
|
32
|
+
}
|
|
33
|
+
/** Admits one renderer log call: stamps identity + time, enters the pipe. */
|
|
34
|
+
admit(level, logger, message, context) {
|
|
35
|
+
const record = Object.freeze({
|
|
36
|
+
id: this.nextId(),
|
|
37
|
+
occurredAtMs: Date.now(),
|
|
38
|
+
producerId: this.producerId,
|
|
39
|
+
sequence: ++this.sequence,
|
|
40
|
+
level,
|
|
41
|
+
logger,
|
|
42
|
+
message,
|
|
43
|
+
service: "renderer",
|
|
44
|
+
environment: "renderer",
|
|
45
|
+
...context !== void 0 ? { context: sanitizeContext(context) } : {}
|
|
46
|
+
});
|
|
47
|
+
this.pipe.accept(record);
|
|
48
|
+
return record;
|
|
49
|
+
}
|
|
50
|
+
/** Drains buffered records across the boundary now. */
|
|
51
|
+
flush() {
|
|
52
|
+
this.pipe.flush();
|
|
53
|
+
}
|
|
54
|
+
buildPipe() {
|
|
55
|
+
const pipe = createLogPipe({
|
|
56
|
+
buffer: this.config.buffer ?? DEFAULT_BUFFER,
|
|
57
|
+
flushOnLevels: this.config.flushOnLevels ?? ["error"],
|
|
58
|
+
name: "renderer-log-ipc"
|
|
59
|
+
});
|
|
60
|
+
pipe.to((records) => this.send(records));
|
|
61
|
+
return pipe;
|
|
62
|
+
}
|
|
63
|
+
send(records) {
|
|
64
|
+
if (this.sender) {
|
|
65
|
+
try {
|
|
66
|
+
this.sender(createRecordBatch(records));
|
|
67
|
+
return;
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (this.fallback) {
|
|
72
|
+
for (const record of records) this.fallback(record);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
nextId() {
|
|
76
|
+
const c = globalThis.crypto;
|
|
77
|
+
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
78
|
+
return `${this.producerId}-${this.sequence + 1}-${randomSuffix()}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function sanitizeContext(value) {
|
|
82
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
83
|
+
try {
|
|
84
|
+
const json = JSON.stringify(value, (_key, val) => {
|
|
85
|
+
if (typeof val === "bigint") return val.toString();
|
|
86
|
+
if (typeof val === "object" && val !== null) {
|
|
87
|
+
if (seen.has(val)) return "[Circular]";
|
|
88
|
+
seen.add(val);
|
|
89
|
+
}
|
|
90
|
+
if (val instanceof Error) {
|
|
91
|
+
return { name: val.name, message: val.message, stack: val.stack };
|
|
92
|
+
}
|
|
93
|
+
return val;
|
|
94
|
+
});
|
|
95
|
+
return json === void 0 ? void 0 : JSON.parse(json);
|
|
96
|
+
} catch {
|
|
97
|
+
return "[Unserializable]";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function getRendererLogTransport() {
|
|
101
|
+
const globalObj = globalThis;
|
|
102
|
+
if (!globalObj[TRANSPORT_SYMBOL]) {
|
|
103
|
+
globalObj[TRANSPORT_SYMBOL] = new RendererLogTransport();
|
|
104
|
+
}
|
|
105
|
+
return globalObj[TRANSPORT_SYMBOL];
|
|
106
|
+
}
|
|
107
|
+
function configureRendererLogTransport(config) {
|
|
108
|
+
getRendererLogTransport().configure(config);
|
|
109
|
+
}
|
|
110
|
+
function flushRendererLogs() {
|
|
111
|
+
getRendererLogTransport().flush();
|
|
112
|
+
}
|
|
113
|
+
function clearRendererLogTransportForTests() {
|
|
114
|
+
delete globalThis[TRANSPORT_SYMBOL];
|
|
115
|
+
}
|
|
116
|
+
export {
|
|
117
|
+
RendererLogTransport,
|
|
118
|
+
clearRendererLogTransportForTests,
|
|
119
|
+
configureRendererLogTransport,
|
|
120
|
+
flushRendererLogs,
|
|
121
|
+
getRendererLogTransport
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=renderer_log_transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/renderer_log_transport.ts"],"sourcesContent":["import { createLogPipe, type LogPipe, type LogPipeBuffer, type LogRecord } from '@noego/logger';\nimport { createRecordBatch } from '@noego/trace/stream';\n\nconst TRANSPORT_SYMBOL = Symbol.for('@noego/wood.client.renderer-log-transport');\n\n/**\n * Per-pipe buffering configuration for renderer logs crossing the IPC\n * boundary. Batching is a property of the pipe, not of the record: records\n * are admitted (identity + occurredAtMs stamped) the moment they are logged,\n * and buffering only affects when they travel.\n */\nexport interface RendererLogTransportConfig {\n buffer?: LogPipeBuffer;\n /** Levels that flush the pipe immediately (default ['error']). */\n flushOnLevels?: readonly string[];\n}\n\nexport type RendererLogBatchSender = (batch: unknown) => void;\n\ntype FallbackWriter = (record: LogRecord) => void;\n\nconst DEFAULT_BUFFER: LogPipeBuffer = { mode: 'buffered', intervalMs: 500, maxRecords: 500 };\n\nfunction randomSuffix(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\n/**\n * The renderer's admission point and IPC-facing pipe.\n *\n * Admission happens here, in the renderer, at creation time: each record gets\n * this window's producerId, a strictly increasing sequence, and occurredAtMs\n * stamped when the log call ran. Everything downstream — the pipe's buffer,\n * the batch envelope, the main-process receiver, the database — transports\n * the frozen record unchanged.\n */\nexport class RendererLogTransport {\n private readonly producerId: string;\n private sequence = 0;\n private pipe: LogPipe;\n private sender: RendererLogBatchSender | null = null;\n private fallback: FallbackWriter | null = null;\n private config: RendererLogTransportConfig;\n\n constructor(config: RendererLogTransportConfig = {}) {\n const c = globalThis.crypto;\n this.producerId = `renderer:${c && typeof c.randomUUID === 'function' ? c.randomUUID() : randomSuffix()}`;\n this.config = config;\n this.pipe = this.buildPipe();\n }\n\n /** Rebuilds the pipe with new buffering config; pending records are flushed first. */\n configure(config: RendererLogTransportConfig): void {\n this.pipe.flush();\n void this.pipe.close();\n this.config = config;\n this.pipe = this.buildPipe();\n }\n\n /** Installs the batch sender (the preload bridge's __logBatch). */\n setSender(sender: RendererLogBatchSender | null): void {\n this.sender = sender;\n }\n\n /** Installs the per-record fallback used when no batch sender is available. */\n setFallback(fallback: FallbackWriter | null): void {\n this.fallback = fallback;\n }\n\n /** Admits one renderer log call: stamps identity + time, enters the pipe. */\n admit(level: string, logger: string, message: string, context?: unknown): LogRecord {\n const record = Object.freeze({\n id: this.nextId(),\n occurredAtMs: Date.now(),\n producerId: this.producerId,\n sequence: ++this.sequence,\n level,\n logger,\n message,\n service: 'renderer',\n environment: 'renderer',\n ...(context !== undefined ? { context: sanitizeContext(context) } : {}),\n });\n this.pipe.accept(record);\n return record;\n }\n\n /** Drains buffered records across the boundary now. */\n flush(): void {\n this.pipe.flush();\n }\n\n private buildPipe(): LogPipe {\n const pipe = createLogPipe({\n buffer: this.config.buffer ?? DEFAULT_BUFFER,\n flushOnLevels: this.config.flushOnLevels ?? ['error'],\n name: 'renderer-log-ipc',\n });\n pipe.to((records) => this.send(records));\n return pipe;\n }\n\n private send(records: readonly LogRecord[]): void {\n if (this.sender) {\n try {\n this.sender(createRecordBatch(records));\n return;\n } catch {\n // Fall through to per-record fallback below.\n }\n }\n if (this.fallback) {\n for (const record of records) this.fallback(record);\n }\n }\n\n private nextId(): string {\n const c = globalThis.crypto;\n if (c && typeof c.randomUUID === 'function') return c.randomUUID();\n return `${this.producerId}-${this.sequence + 1}-${randomSuffix()}`;\n }\n}\n\n/**\n * Context crossing IPC must survive structured clone: snapshot through JSON\n * with circular/bigint/Error handling. The original object stays untouched.\n */\nfunction sanitizeContext(value: unknown): unknown {\n const seen = new WeakSet<object>();\n try {\n const json = JSON.stringify(value, (_key, val: unknown) => {\n if (typeof val === 'bigint') return val.toString();\n if (typeof val === 'object' && val !== null) {\n if (seen.has(val)) return '[Circular]';\n seen.add(val);\n }\n if (val instanceof Error) {\n return { name: val.name, message: val.message, stack: val.stack };\n }\n return val;\n });\n return json === undefined ? undefined : JSON.parse(json);\n } catch {\n return '[Unserializable]';\n }\n}\n\ntype GlobalWithTransport = typeof globalThis & {\n [TRANSPORT_SYMBOL]?: RendererLogTransport;\n};\n\nexport function getRendererLogTransport(): RendererLogTransport {\n const globalObj = globalThis as GlobalWithTransport;\n if (!globalObj[TRANSPORT_SYMBOL]) {\n globalObj[TRANSPORT_SYMBOL] = new RendererLogTransport();\n }\n return globalObj[TRANSPORT_SYMBOL];\n}\n\n/** Reconfigures the renderer→main log pipe (buffer interval, flush levels). */\nexport function configureRendererLogTransport(config: RendererLogTransportConfig): void {\n getRendererLogTransport().configure(config);\n}\n\n/** Flushes all buffered renderer logs across the IPC boundary now. */\nexport function flushRendererLogs(): void {\n getRendererLogTransport().flush();\n}\n\nexport function clearRendererLogTransportForTests(): void {\n delete (globalThis as GlobalWithTransport)[TRANSPORT_SYMBOL];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -28,7 +28,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var controller_registration_generator_exports = {};
|
|
30
30
|
__export(controller_registration_generator_exports, {
|
|
31
|
-
|
|
31
|
+
controllerFileCandidates: () => controllerFileCandidates,
|
|
32
|
+
generateControllerRegistration: () => generateControllerRegistration,
|
|
33
|
+
resolveControllerFile: () => resolveControllerFile
|
|
32
34
|
});
|
|
33
35
|
module.exports = __toCommonJS(controller_registration_generator_exports);
|
|
34
36
|
var import_fs = require("fs");
|
|
@@ -48,6 +50,13 @@ const INDEX_CANDIDATES = [
|
|
|
48
50
|
"index.ts",
|
|
49
51
|
"index.js"
|
|
50
52
|
];
|
|
53
|
+
function controllerFileCandidates(controllerName, controllersDir) {
|
|
54
|
+
const basePath = import_path.default.resolve(controllersDir, controllerName);
|
|
55
|
+
return [
|
|
56
|
+
...CANDIDATE_SUFFIXES.map((suffix) => basePath + suffix),
|
|
57
|
+
...INDEX_CANDIDATES.map((indexFile) => import_path.default.resolve(controllersDir, controllerName, indexFile))
|
|
58
|
+
];
|
|
59
|
+
}
|
|
51
60
|
function resolveControllerFile(controllerName, controllersDir) {
|
|
52
61
|
const basePath = import_path.default.resolve(controllersDir, controllerName);
|
|
53
62
|
for (const suffix of CANDIDATE_SUFFIXES) {
|
|
@@ -138,6 +147,8 @@ Ensure each controller file exists with one of these suffixes: .ts, .controller.
|
|
|
138
147
|
}
|
|
139
148
|
// Annotate the CommonJS export names for ESM import in node:
|
|
140
149
|
0 && (module.exports = {
|
|
141
|
-
|
|
150
|
+
controllerFileCandidates,
|
|
151
|
+
generateControllerRegistration,
|
|
152
|
+
resolveControllerFile
|
|
142
153
|
});
|
|
143
154
|
//# sourceMappingURL=controller_registration_generator.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/controller_registration_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { OperationDef } from '../types/index.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nconst CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS = [\n 'To change controller registration, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and the matching controller files.',\n] as const;\n\n/**\n * Candidate file extensions to search when resolving a controller name to a file.\n * Matches the order used by ControllerResolver.resolveClass().\n */\nconst CANDIDATE_SUFFIXES = [\n '.ts',\n '.controller.ts',\n '.js',\n '.controller.js',\n] as const;\n\nconst INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\n/**\n * Resolve a controller name to a file path on disk.\n * Returns the first candidate that exists, or undefined if none match.\n */\
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/controller_registration_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { OperationDef } from '../types/index.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nconst CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS = [\n 'To change controller registration, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and the matching controller files.',\n] as const;\n\n/**\n * Candidate file extensions to search when resolving a controller name to a file.\n * Matches the order used by ControllerResolver.resolveClass().\n */\nconst CANDIDATE_SUFFIXES = [\n '.ts',\n '.controller.ts',\n '.js',\n '.controller.js',\n] as const;\n\nconst INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\n/**\n * Every file a controller identity may live at, in resolution order —\n * shared by codegen and by test-time auto-binding so both agree on where an\n * identity resolves and on what to report when it does not.\n */\nexport function controllerFileCandidates(controllerName: string, controllersDir: string): string[] {\n const basePath = path.resolve(controllersDir, controllerName);\n return [\n ...CANDIDATE_SUFFIXES.map((suffix) => basePath + suffix),\n ...INDEX_CANDIDATES.map((indexFile) => path.resolve(controllersDir, controllerName, indexFile)),\n ];\n}\n\n/**\n * Resolve a controller name to a file path on disk.\n * Returns the first candidate that exists, or undefined if none match.\n */\nexport function resolveControllerFile(controllerName: string, controllersDir: string): string | undefined {\n const basePath = path.resolve(controllersDir, controllerName);\n\n for (const suffix of CANDIDATE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) return candidate;\n }\n\n for (const indexFile of INDEX_CANDIDATES) {\n const candidate = path.resolve(controllersDir, controllerName, indexFile);\n if (existsSync(candidate)) return candidate;\n }\n\n return undefined;\n}\n\n/**\n * Compute a relative import path from the generated file's directory to the\n * resolved controller file. Strips `.ts` extensions since TypeScript imports\n * should not include them.\n */\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n // Ensure the path starts with ./ or ../\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n // Strip .ts extension (TypeScript convention)\n if (rel.endsWith('.ts')) {\n rel = rel.slice(0, -3);\n }\n\n // Normalize path separators to forward slashes (Windows compat)\n return rel.replace(/\\\\/g, '/');\n}\n\n/**\n * Convert a controller name to a valid PascalCase identifier for the import.\n * e.g. \"chat\" -> \"ChatController\", \"multi_agent\" -> \"MultiAgentController\"\n */\nfunction toControllerClassName(controllerName: string): string {\n const pascal = controllerName\n .split(/[_\\-.]/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return pascal + 'Controller';\n}\n\n/**\n * Extract all unique controller names from a set of parsed operations.\n */\nfunction extractControllerNames(operations: Map<string, OperationDef>): string[] {\n const names = new Set<string>();\n\n operations.forEach((op) => {\n names.add(op.controller);\n });\n\n return Array.from(names).sort();\n}\n\nexport interface ControllerRegistrationOptions {\n /** Directory where controller source files live */\n controllersDir: string;\n /** Directory where the generated file will be written */\n outDir: string;\n /** If true, unresolved controllers emit a warning comment instead of throwing. Default: false. */\n allowUnresolved?: boolean;\n}\n\n/**\n * Generate a TypeScript registration file that statically imports every\n * controller referenced in operations and exports a function to register\n * them with a WoodRouter.\n */\nexport function generateControllerRegistration(\n operations: Map<string, OperationDef>,\n options: ControllerRegistrationOptions,\n): string {\n const controllerNames = extractControllerNames(operations);\n const outDirResolved = path.resolve(options.outDir);\n\n const imports: string[] = [];\n const registrations: string[] = [];\n const unresolved: string[] = [];\n\n for (const name of controllerNames) {\n const filePath = resolveControllerFile(name, options.controllersDir);\n\n if (!filePath) {\n unresolved.push(name);\n continue;\n }\n\n const importPath = computeImportPath(outDirResolved, filePath);\n const className = toControllerClassName(name);\n\n imports.push(`import ${className} from '${importPath}';`);\n registrations.push(` router.registerController('${name}', ${className});`);\n }\n\n // Fail by default when controllers cannot be resolved\n if (unresolved.length > 0 && !options.allowUnresolved) {\n throw new Error(\n `Controller registration codegen failed: ${unresolved.length} controller(s) not found on disk:\\n` +\n unresolved.map(name => ` - \"${name}\" (searched in ${options.controllersDir})`).join('\\n') +\n `\\n\\nEnsure each controller file exists with one of these suffixes: .ts, .controller.ts, .js, .controller.js`\n );\n }\n\n const lines: string[] = [\n generatedFileNotice(CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS),\n '//',\n '// Static imports ensure all controllers are bundled and available at startup.',\n '// registerController() puts each class directly in the router\\'s cache.',\n ];\n\n if (unresolved.length > 0) {\n lines.push(\n '',\n '// WARNING: The following controllers could not be resolved on disk:',\n ...unresolved.map((name) => `// - ${name}`),\n );\n }\n\n // Static imports\n lines.push('');\n for (const imp of imports) {\n lines.push(imp);\n }\n\n // Registration function\n lines.push(\n '',\n 'export function registerControllers(router: { registerController(name: string, cls: any): void }) {',\n );\n for (const reg of registrations) {\n lines.push(reg);\n }\n lines.push(\n '}',\n '',\n );\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":["path"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { OperationDef } from '../types/operations.cjs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Every file a controller identity may live at, in resolution order —
|
|
5
|
+
* shared by codegen and by test-time auto-binding so both agree on where an
|
|
6
|
+
* identity resolves and on what to report when it does not.
|
|
7
|
+
*/
|
|
8
|
+
declare function controllerFileCandidates(controllerName: string, controllersDir: string): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a controller name to a file path on disk.
|
|
11
|
+
* Returns the first candidate that exists, or undefined if none match.
|
|
12
|
+
*/
|
|
13
|
+
declare function resolveControllerFile(controllerName: string, controllersDir: string): string | undefined;
|
|
3
14
|
interface ControllerRegistrationOptions {
|
|
4
15
|
/** Directory where controller source files live */
|
|
5
16
|
controllersDir: string;
|
|
@@ -15,4 +26,4 @@ interface ControllerRegistrationOptions {
|
|
|
15
26
|
*/
|
|
16
27
|
declare function generateControllerRegistration(operations: Map<string, OperationDef>, options: ControllerRegistrationOptions): string;
|
|
17
28
|
|
|
18
|
-
export { type ControllerRegistrationOptions, generateControllerRegistration };
|
|
29
|
+
export { type ControllerRegistrationOptions, controllerFileCandidates, generateControllerRegistration, resolveControllerFile };
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { OperationDef } from '../types/operations.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Every file a controller identity may live at, in resolution order —
|
|
5
|
+
* shared by codegen and by test-time auto-binding so both agree on where an
|
|
6
|
+
* identity resolves and on what to report when it does not.
|
|
7
|
+
*/
|
|
8
|
+
declare function controllerFileCandidates(controllerName: string, controllersDir: string): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a controller name to a file path on disk.
|
|
11
|
+
* Returns the first candidate that exists, or undefined if none match.
|
|
12
|
+
*/
|
|
13
|
+
declare function resolveControllerFile(controllerName: string, controllersDir: string): string | undefined;
|
|
3
14
|
interface ControllerRegistrationOptions {
|
|
4
15
|
/** Directory where controller source files live */
|
|
5
16
|
controllersDir: string;
|
|
@@ -15,4 +26,4 @@ interface ControllerRegistrationOptions {
|
|
|
15
26
|
*/
|
|
16
27
|
declare function generateControllerRegistration(operations: Map<string, OperationDef>, options: ControllerRegistrationOptions): string;
|
|
17
28
|
|
|
18
|
-
export { type ControllerRegistrationOptions, generateControllerRegistration };
|
|
29
|
+
export { type ControllerRegistrationOptions, controllerFileCandidates, generateControllerRegistration, resolveControllerFile };
|
|
@@ -15,6 +15,13 @@ const INDEX_CANDIDATES = [
|
|
|
15
15
|
"index.ts",
|
|
16
16
|
"index.js"
|
|
17
17
|
];
|
|
18
|
+
function controllerFileCandidates(controllerName, controllersDir) {
|
|
19
|
+
const basePath = path.resolve(controllersDir, controllerName);
|
|
20
|
+
return [
|
|
21
|
+
...CANDIDATE_SUFFIXES.map((suffix) => basePath + suffix),
|
|
22
|
+
...INDEX_CANDIDATES.map((indexFile) => path.resolve(controllersDir, controllerName, indexFile))
|
|
23
|
+
];
|
|
24
|
+
}
|
|
18
25
|
function resolveControllerFile(controllerName, controllersDir) {
|
|
19
26
|
const basePath = path.resolve(controllersDir, controllerName);
|
|
20
27
|
for (const suffix of CANDIDATE_SUFFIXES) {
|
|
@@ -104,6 +111,8 @@ Ensure each controller file exists with one of these suffixes: .ts, .controller.
|
|
|
104
111
|
return lines.join("\n");
|
|
105
112
|
}
|
|
106
113
|
export {
|
|
107
|
-
|
|
114
|
+
controllerFileCandidates,
|
|
115
|
+
generateControllerRegistration,
|
|
116
|
+
resolveControllerFile
|
|
108
117
|
};
|
|
109
118
|
//# sourceMappingURL=controller_registration_generator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/controller_registration_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { OperationDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS = [\n 'To change controller registration, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and the matching controller files.',\n] as const;\n\n/**\n * Candidate file extensions to search when resolving a controller name to a file.\n * Matches the order used by ControllerResolver.resolveClass().\n */\nconst CANDIDATE_SUFFIXES = [\n '.ts',\n '.controller.ts',\n '.js',\n '.controller.js',\n] as const;\n\nconst INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\n/**\n * Resolve a controller name to a file path on disk.\n * Returns the first candidate that exists, or undefined if none match.\n */\
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/controller_registration_generator.ts"],"sourcesContent":["import { existsSync } from 'fs';\nimport path from 'path';\nimport type { OperationDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS = [\n 'To change controller registration, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and the matching controller files.',\n] as const;\n\n/**\n * Candidate file extensions to search when resolving a controller name to a file.\n * Matches the order used by ControllerResolver.resolveClass().\n */\nconst CANDIDATE_SUFFIXES = [\n '.ts',\n '.controller.ts',\n '.js',\n '.controller.js',\n] as const;\n\nconst INDEX_CANDIDATES = [\n 'index.ts',\n 'index.js',\n] as const;\n\n/**\n * Every file a controller identity may live at, in resolution order —\n * shared by codegen and by test-time auto-binding so both agree on where an\n * identity resolves and on what to report when it does not.\n */\nexport function controllerFileCandidates(controllerName: string, controllersDir: string): string[] {\n const basePath = path.resolve(controllersDir, controllerName);\n return [\n ...CANDIDATE_SUFFIXES.map((suffix) => basePath + suffix),\n ...INDEX_CANDIDATES.map((indexFile) => path.resolve(controllersDir, controllerName, indexFile)),\n ];\n}\n\n/**\n * Resolve a controller name to a file path on disk.\n * Returns the first candidate that exists, or undefined if none match.\n */\nexport function resolveControllerFile(controllerName: string, controllersDir: string): string | undefined {\n const basePath = path.resolve(controllersDir, controllerName);\n\n for (const suffix of CANDIDATE_SUFFIXES) {\n const candidate = basePath + suffix;\n if (existsSync(candidate)) return candidate;\n }\n\n for (const indexFile of INDEX_CANDIDATES) {\n const candidate = path.resolve(controllersDir, controllerName, indexFile);\n if (existsSync(candidate)) return candidate;\n }\n\n return undefined;\n}\n\n/**\n * Compute a relative import path from the generated file's directory to the\n * resolved controller file. Strips `.ts` extensions since TypeScript imports\n * should not include them.\n */\nfunction computeImportPath(fromDir: string, toFile: string): string {\n let rel = path.relative(fromDir, toFile);\n\n // Ensure the path starts with ./ or ../\n if (!rel.startsWith('.')) {\n rel = './' + rel;\n }\n\n // Strip .ts extension (TypeScript convention)\n if (rel.endsWith('.ts')) {\n rel = rel.slice(0, -3);\n }\n\n // Normalize path separators to forward slashes (Windows compat)\n return rel.replace(/\\\\/g, '/');\n}\n\n/**\n * Convert a controller name to a valid PascalCase identifier for the import.\n * e.g. \"chat\" -> \"ChatController\", \"multi_agent\" -> \"MultiAgentController\"\n */\nfunction toControllerClassName(controllerName: string): string {\n const pascal = controllerName\n .split(/[_\\-.]/)\n .map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))\n .join('');\n\n return pascal + 'Controller';\n}\n\n/**\n * Extract all unique controller names from a set of parsed operations.\n */\nfunction extractControllerNames(operations: Map<string, OperationDef>): string[] {\n const names = new Set<string>();\n\n operations.forEach((op) => {\n names.add(op.controller);\n });\n\n return Array.from(names).sort();\n}\n\nexport interface ControllerRegistrationOptions {\n /** Directory where controller source files live */\n controllersDir: string;\n /** Directory where the generated file will be written */\n outDir: string;\n /** If true, unresolved controllers emit a warning comment instead of throwing. Default: false. */\n allowUnresolved?: boolean;\n}\n\n/**\n * Generate a TypeScript registration file that statically imports every\n * controller referenced in operations and exports a function to register\n * them with a WoodRouter.\n */\nexport function generateControllerRegistration(\n operations: Map<string, OperationDef>,\n options: ControllerRegistrationOptions,\n): string {\n const controllerNames = extractControllerNames(operations);\n const outDirResolved = path.resolve(options.outDir);\n\n const imports: string[] = [];\n const registrations: string[] = [];\n const unresolved: string[] = [];\n\n for (const name of controllerNames) {\n const filePath = resolveControllerFile(name, options.controllersDir);\n\n if (!filePath) {\n unresolved.push(name);\n continue;\n }\n\n const importPath = computeImportPath(outDirResolved, filePath);\n const className = toControllerClassName(name);\n\n imports.push(`import ${className} from '${importPath}';`);\n registrations.push(` router.registerController('${name}', ${className});`);\n }\n\n // Fail by default when controllers cannot be resolved\n if (unresolved.length > 0 && !options.allowUnresolved) {\n throw new Error(\n `Controller registration codegen failed: ${unresolved.length} controller(s) not found on disk:\\n` +\n unresolved.map(name => ` - \"${name}\" (searched in ${options.controllersDir})`).join('\\n') +\n `\\n\\nEnsure each controller file exists with one of these suffixes: .ts, .controller.ts, .js, .controller.js`\n );\n }\n\n const lines: string[] = [\n generatedFileNotice(CONTROLLER_REGISTRATION_SOURCE_INSTRUCTIONS),\n '//',\n '// Static imports ensure all controllers are bundled and available at startup.',\n '// registerController() puts each class directly in the router\\'s cache.',\n ];\n\n if (unresolved.length > 0) {\n lines.push(\n '',\n '// WARNING: The following controllers could not be resolved on disk:',\n ...unresolved.map((name) => `// - ${name}`),\n );\n }\n\n // Static imports\n lines.push('');\n for (const imp of imports) {\n lines.push(imp);\n }\n\n // Registration function\n lines.push(\n '',\n 'export function registerControllers(router: { registerController(name: string, cls: any): void }) {',\n );\n for (const reg of registrations) {\n lines.push(reg);\n }\n lines.push(\n '}',\n '',\n );\n\n return lines.join('\\n');\n}\n"],"mappings":"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","names":[]}
|
package/dist/codegen/index.d.cts
CHANGED
|
@@ -7,5 +7,6 @@ export { RuntimeGeneratorOptions, generateRuntime } from './runtime_generator.cj
|
|
|
7
7
|
export { RendererViewManifestGeneratorOptions, generateRendererViewManifest } from './renderer_view_manifest_generator.cjs';
|
|
8
8
|
export { RendererControllerRegistrationOptions, generateRendererControllerRegistration } from './renderer_controller_registration_generator.cjs';
|
|
9
9
|
export { RendererAppGeneratorOptions, generateRendererApp } from './renderer_app_generator.cjs';
|
|
10
|
+
import '../types/config.cjs';
|
|
10
11
|
import '../types/operations.cjs';
|
|
11
12
|
import '../types/views.cjs';
|
package/dist/codegen/index.d.ts
CHANGED
|
@@ -7,5 +7,6 @@ export { RuntimeGeneratorOptions, generateRuntime } from './runtime_generator.js
|
|
|
7
7
|
export { RendererViewManifestGeneratorOptions, generateRendererViewManifest } from './renderer_view_manifest_generator.js';
|
|
8
8
|
export { RendererControllerRegistrationOptions, generateRendererControllerRegistration } from './renderer_controller_registration_generator.js';
|
|
9
9
|
export { RendererAppGeneratorOptions, generateRendererApp } from './renderer_app_generator.js';
|
|
10
|
+
import '../types/config.js';
|
|
10
11
|
import '../types/operations.js';
|
|
11
12
|
import '../types/views.js';
|
|
@@ -21,6 +21,7 @@ __export(preload_generator_exports, {
|
|
|
21
21
|
generatePreload: () => generatePreload
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(preload_generator_exports);
|
|
24
|
+
var import_config_parser = require("../config/config_parser.cjs");
|
|
24
25
|
var import_generated_file_notice = require("./generated_file_notice.cjs");
|
|
25
26
|
const PRELOAD_SOURCE_INSTRUCTIONS = [
|
|
26
27
|
"To change IPC channels or preload bridge methods, edit the operations YAML configured by",
|
|
@@ -83,10 +84,11 @@ ${entries.join("\n")}
|
|
|
83
84
|
];`;
|
|
84
85
|
}
|
|
85
86
|
const INTERNAL_BRIDGE_GLOBAL_KEY = "__NOEGO_WOOD_BRIDGE__";
|
|
86
|
-
function generatePreload(operations) {
|
|
87
|
+
function generatePreload(operations, options = {}) {
|
|
87
88
|
const tree = buildNestedTree(operations);
|
|
88
89
|
const operationsCode = generateTreeCode(tree);
|
|
89
90
|
const rpcManifestCode = generateRpcManifestCode(operations);
|
|
91
|
+
const traceBatching = options.traceBatching ?? import_config_parser.RENDERER_TRACE_BATCHING_DEFAULTS;
|
|
90
92
|
return `${(0, import_generated_file_notice.generatedFileNotice)(PRELOAD_SOURCE_INSTRUCTIONS)}
|
|
91
93
|
import { contextBridge, ipcRenderer } from 'electron';
|
|
92
94
|
import {
|
|
@@ -159,6 +161,9 @@ ${operationsCode}
|
|
|
159
161
|
__log: (level: string, logger: string, message: string, context?: unknown) => {
|
|
160
162
|
ipcRenderer.send('__log', { level, logger, message, context });
|
|
161
163
|
},
|
|
164
|
+
__logBatch: (batch: unknown) => {
|
|
165
|
+
ipcRenderer.send('__log_batch', batch);
|
|
166
|
+
},
|
|
162
167
|
});
|
|
163
168
|
|
|
164
169
|
// Trace transport via MessagePort (activated when main process sends a port)
|
|
@@ -228,13 +233,15 @@ const __traceBatchPort: WoodTraceBatchPort = {
|
|
|
228
233
|
},
|
|
229
234
|
};
|
|
230
235
|
|
|
236
|
+
// Batching policy resolved from wood.config.yml observability configuration
|
|
237
|
+
// at generation time; this file embeds but does not own it.
|
|
231
238
|
const __traceBatchTransport = new RendererTraceBatchTransport({
|
|
232
239
|
producerId: __traceBatchProducerId,
|
|
233
|
-
maxQueuedEvents:
|
|
234
|
-
maxBatchEvents:
|
|
235
|
-
acknowledgementTimeoutMs:
|
|
236
|
-
retryLimit:
|
|
237
|
-
retryBaseDelayMs:
|
|
240
|
+
maxQueuedEvents: ${traceBatching.maxQueuedEvents},
|
|
241
|
+
maxBatchEvents: ${traceBatching.maxBatchEvents},
|
|
242
|
+
acknowledgementTimeoutMs: ${traceBatching.acknowledgementTimeoutMs},
|
|
243
|
+
retryLimit: ${traceBatching.retryLimit},
|
|
244
|
+
retryBaseDelayMs: ${traceBatching.retryBaseDelayMs},
|
|
238
245
|
now: () => Date.now(),
|
|
239
246
|
schedule: (work: () => void) => queueMicrotask(work),
|
|
240
247
|
delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/preload_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nconst PRELOAD_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels or preload bridge methods, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and regenerate with `wood dev` or `wood build`.',\n] as const;\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\n/**\n * Build a nested object tree from dot-path operation channels.\n * \"chat.message.send\" -> { chat: { message: { send: ... } } }\n */\nfunction buildNestedTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n\n const leaf = parts[parts.length - 1];\n current[leaf] = { __operation: op };\n }\n\n return tree;\n}\n\n/**\n * Generate TypeScript code for a nested tree node.\n */\nfunction generateTreeCode(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${key}: (data: unknown) =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}', data),`);\n } else {\n lines.push(`${indent}${key}: () =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}'),`);\n }\n } else {\n lines.push(`${indent}${key}: {`);\n lines.push(generateTreeCode(entry, indent + ' '));\n lines.push(`${indent}},`);\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction generateRpcManifestCode(operations: Map<string, OperationDef>): string {\n const entries = Array.from(operations.values())\n .sort((a, b) => a.channel.localeCompare(b.channel))\n .map((op) => {\n const payload = {\n channel: op.channel,\n controller: op.controller,\n action: op.action,\n path: op.channel.split('.'),\n hasInput: operationHasInput(op),\n };\n return ` ${JSON.stringify(payload)},`;\n });\n\n return `const __WOOD_RPC_MANIFEST = [\n${entries.join('\\n')}\n];`;\n}\n\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\n/**\n * Generate a complete preload.ts file from operations.\n */\nexport function generatePreload(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTree(operations);\n const operationsCode = generateTreeCode(tree);\n const rpcManifestCode = generateRpcManifestCode(operations);\n\n return `${generatedFileNotice(PRELOAD_SOURCE_INSTRUCTIONS)}\nimport { contextBridge, ipcRenderer } from 'electron';\nimport {\n RendererTraceBatchTransport,\n type WoodRendererTraceInput,\n type WoodTraceBatch,\n type WoodTraceBatchAcknowledgement,\n type WoodTraceBatchPort,\n} from '@noego/wood/trace-transport';\n\n${rpcManifestCode}\n\nconst __WOOD_INTERNAL_BRIDGE_KEY = '${INTERNAL_BRIDGE_GLOBAL_KEY}';\n\ncontextBridge.exposeInMainWorld(__WOOD_INTERNAL_BRIDGE_KEY, {\n${operationsCode}\n\n // Internal: backend controller/action RPC map for @Inject(App)\n __rpcManifest: __WOOD_RPC_MANIFEST,\n\n // Internal: loader data requests\n __load: (route: string, params: Record<string, string>) =>\n ipcRenderer.invoke('__load', { route, params }),\n\n // Internal: cross-window navigation\n __navigate: (windowId: string, route: string) =>\n ipcRenderer.invoke('__navigate', { windowId, route }),\n\n // Internal: window management\n __window: {\n current: () =>\n ipcRenderer.invoke('__window', { action: 'current' }),\n open: (windowId: string, options?: Record<string, unknown>) =>\n ipcRenderer.invoke('__window', { action: 'open', windowId, options }),\n close: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'close', windowId }),\n focus: (windowId: string) =>\n ipcRenderer.invoke('__window', { action: 'focus', windowId }),\n minimize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'minimize', windowId }),\n maximize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'maximize', windowId }),\n },\n\n // Internal: framework config (trace min level, etc)\n __woodConfig: () =>\n ipcRenderer.invoke('__woodConfig'),\n\n // Internal: debug metadata\n __debug: {\n current: () =>\n ipcRenderer.invoke('__debug', { action: 'current' }),\n },\n\n // Internal: context menu\n __contextMenu: {\n show: (data: unknown) =>\n ipcRenderer.invoke('__contextMenu', { action: 'show', ...data as Record<string, unknown> }),\n },\n\n // Push events from main process\n on: (channel: string, callback: (...args: unknown[]) => void) => {\n const subscription = (_event: unknown, ...args: unknown[]) => callback(...args);\n ipcRenderer.on(\\`__event:\\${channel}\\`, subscription);\n return () => ipcRenderer.removeListener(\\`__event:\\${channel}\\`, subscription);\n },\n __trace: (event: unknown) => {\n ipcRenderer.send('__trace', event);\n },\n __log: (level: string, logger: string, message: string, context?: unknown) => {\n ipcRenderer.send('__log', { level, logger, message, context });\n },\n});\n\n// Trace transport via MessagePort (activated when main process sends a port)\nlet __tracePort: MessagePort | null = null;\nconst __traceBuffer: unknown[] = [];\nconst __TRACE_BUFFER_CAPACITY = 256;\nlet __traceDroppedCapacity = 0;\n\nfunction __traceFlush(): void {\n while (__traceBuffer.length > 0 && __tracePort) {\n __tracePort.postMessage(__traceBuffer.shift());\n }\n}\n\nipcRenderer.on('__trace-port', (event) => {\n __tracePort = event.ports[0];\n __tracePort.start();\n __traceFlush();\n});\n\ncontextBridge.exposeInMainWorld('__NOEGO_TRACE__', {\n send: (data: unknown) => {\n if (__tracePort) {\n __tracePort.postMessage(data);\n } else if (__traceBuffer.length >= __TRACE_BUFFER_CAPACITY) {\n __traceDroppedCapacity += 1;\n } else {\n __traceBuffer.push(data);\n }\n },\n status: () => ({\n queuedEvents: __traceBuffer.length,\n droppedCapacity: __traceDroppedCapacity,\n }),\n});\n\nconst __traceBatchProducerId = typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : \\`wood-renderer-\\${Date.now()}-\\${Math.random().toString(16).slice(2)}\\`;\nlet __traceBatchListener: ((message: unknown) => void) | null = null;\n\nconst __traceBatchPort: WoodTraceBatchPort = {\n postMessage: (batch: WoodTraceBatch) => {\n void ipcRenderer.invoke('__traceBatch', batch)\n .then((acknowledgement: WoodTraceBatchAcknowledgement) => {\n __traceBatchListener?.(acknowledgement);\n })\n .catch((error: unknown) => {\n __traceBatchListener?.({\n kind: 'retryable',\n batchId: batch.batchId,\n reason: error instanceof Error ? error.message : String(error),\n retryAfterMs: 100,\n });\n });\n },\n subscribe: (listener: (message: unknown) => void) => {\n __traceBatchListener = listener;\n return () => {\n if (__traceBatchListener === listener) {\n __traceBatchListener = null;\n }\n };\n },\n close: () => {\n __traceBatchListener = null;\n },\n};\n\nconst __traceBatchTransport = new RendererTraceBatchTransport({\n producerId: __traceBatchProducerId,\n maxQueuedEvents: 256,\n maxBatchEvents: 32,\n acknowledgementTimeoutMs: 1_000,\n retryLimit: 3,\n retryBaseDelayMs: 25,\n now: () => Date.now(),\n schedule: (work: () => void) => queueMicrotask(work),\n delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),\n});\n__traceBatchTransport.attachPort(__traceBatchPort);\n\ncontextBridge.exposeInMainWorld('__NOEGO_WOOD_TRACE_BATCH__', {\n send: (event: WoodRendererTraceInput) => __traceBatchTransport.admit(event),\n status: () => __traceBatchTransport.status(),\n flush: (deadlineMs: number) => __traceBatchTransport.flush(deadlineMs),\n close: (deadlineMs: number) => __traceBatchTransport.close(deadlineMs),\n});\n\nipcRenderer.on('__woodTraceDrainRequest', (_event, payload: unknown) => {\n if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {\n return;\n }\n const requestId = Reflect.get(payload, 'requestId');\n const deadlineMs = Reflect.get(payload, 'deadlineMs');\n if (typeof requestId !== 'string'\n || typeof deadlineMs !== 'number'\n || !Number.isFinite(deadlineMs)) {\n return;\n }\n void __traceBatchTransport.close(deadlineMs).finally(() => {\n ipcRenderer.send('__woodTraceDrainAck', {\n requestId,\n status: __traceBatchTransport.status(),\n });\n });\n});\n\nglobalThis.addEventListener?.('pagehide', () => {\n void __traceBatchTransport.flush(Date.now() + 100);\n});\n`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mCAAoC;AAEpC,MAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AACF;AAEA,SAAS,kBAAkB,IAA2B;AACpD,SAAO;AAAA,IACL,GAAG,eACA,GAAG,YAAwC,SAAS,YACrD,OAAO,KAAM,GAAG,YAAwD,cAAc,CAAC,CAAC,EAAE,SAAS;AAAA,EACvG;AACF;AAMA,SAAS,gBAAgB,YAAgE;AACvF,QAAM,OAAgC,CAAC;AAEvC,aAAW,CAAC,SAAS,EAAE,KAAK,YAAY;AACtC,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,QAAI,UAAmC;AAEvC,aAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,UAAI,CAAC,QAAQ,MAAM,CAAC,CAAC,EAAG,SAAQ,MAAM,CAAC,CAAC,IAAI,CAAC;AAC7C,gBAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC5B;AAEA,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,YAAQ,IAAI,IAAI,EAAE,aAAa,GAAG;AAAA,EACpC;AAEA,SAAO;AACT;AAKA,SAAS,iBAAiB,MAA+B,SAAiB,MAAc;AACtF,QAAM,QAAkB,CAAC;AAEzB,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,UAAM,QAAQ;AACd,QAAI,MAAM,aAAa;AACrB,YAAM,KAAK,MAAM;AACjB,YAAM,WAAW,kBAAkB,EAAE;AAErC,UAAI,UAAU;AACZ,cAAM,KAAK,GAAG,MAAM,GAAG,GAAG,sBAAsB;AAChD,cAAM,KAAK,GAAG,MAAM,yBAAyB,GAAG,OAAO,WAAW;AAAA,MACpE,OAAO;AACL,cAAM,KAAK,GAAG,MAAM,GAAG,GAAG,SAAS;AACnC,cAAM,KAAK,GAAG,MAAM,yBAAyB,GAAG,OAAO,KAAK;AAAA,MAC9D;AAAA,IACF,OAAO;AACL,YAAM,KAAK,GAAG,MAAM,GAAG,GAAG,KAAK;AAC/B,YAAM,KAAK,iBAAiB,OAAO,SAAS,IAAI,CAAC;AACjD,YAAM,KAAK,GAAG,MAAM,IAAI;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,wBAAwB,YAA+C;AAC9E,QAAM,UAAU,MAAM,KAAK,WAAW,OAAO,CAAC,EAC3C,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,OAAO,CAAC,EACjD,IAAI,CAAC,OAAO;AACX,UAAM,UAAU;AAAA,MACd,SAAS,GAAG;AAAA,MACZ,YAAY,GAAG;AAAA,MACf,QAAQ,GAAG;AAAA,MACX,MAAM,GAAG,QAAQ,MAAM,GAAG;AAAA,MAC1B,UAAU,kBAAkB,EAAE;AAAA,IAChC;AACA,WAAO,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,EACrC,CAAC;AAEH,SAAO;AAAA,EACP,QAAQ,KAAK,IAAI,CAAC;AAAA;AAEpB;AAEA,MAAM,6BAA6B;AAK5B,SAAS,gBAAgB,YAA+C;AAC7E,QAAM,OAAO,gBAAgB,UAAU;AACvC,QAAM,iBAAiB,iBAAiB,IAAI;AAC5C,QAAM,kBAAkB,wBAAwB,UAAU;AAE1D,SAAO,OAAG,kDAAoB,2BAA2B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU1D,eAAe;AAAA;AAAA,sCAEqB,0BAA0B;AAAA;AAAA;AAAA,EAG9D,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyKhB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/preload_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.cjs';\nimport type { RendererTraceBatchingConfig } from '../types/config.cjs';\nimport { RENDERER_TRACE_BATCHING_DEFAULTS } from '../config/config_parser.cjs';\nimport { generatedFileNotice } from './generated_file_notice.cjs';\n\nexport type GeneratePreloadOptions = {\n /**\n * Renderer→main IPC trace batching policy resolved from\n * wood.config.yml `observability.trace.rendererToMain.batching`.\n * The generated preload embeds these values but does not own them.\n */\n traceBatching?: RendererTraceBatchingConfig;\n};\n\nconst PRELOAD_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels or preload bridge methods, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and regenerate with `wood dev` or `wood build`.',\n] as const;\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\n/**\n * Build a nested object tree from dot-path operation channels.\n * \"chat.message.send\" -> { chat: { message: { send: ... } } }\n */\nfunction buildNestedTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n\n const leaf = parts[parts.length - 1];\n current[leaf] = { __operation: op };\n }\n\n return tree;\n}\n\n/**\n * Generate TypeScript code for a nested tree node.\n */\nfunction generateTreeCode(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${key}: (data: unknown) =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}', data),`);\n } else {\n lines.push(`${indent}${key}: () =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}'),`);\n }\n } else {\n lines.push(`${indent}${key}: {`);\n lines.push(generateTreeCode(entry, indent + ' '));\n lines.push(`${indent}},`);\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction generateRpcManifestCode(operations: Map<string, OperationDef>): string {\n const entries = Array.from(operations.values())\n .sort((a, b) => a.channel.localeCompare(b.channel))\n .map((op) => {\n const payload = {\n channel: op.channel,\n controller: op.controller,\n action: op.action,\n path: op.channel.split('.'),\n hasInput: operationHasInput(op),\n };\n return ` ${JSON.stringify(payload)},`;\n });\n\n return `const __WOOD_RPC_MANIFEST = [\n${entries.join('\\n')}\n];`;\n}\n\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\n/**\n * Generate a complete preload.ts file from operations.\n */\nexport function generatePreload(\n operations: Map<string, OperationDef>,\n options: GeneratePreloadOptions = {},\n): string {\n const tree = buildNestedTree(operations);\n const operationsCode = generateTreeCode(tree);\n const rpcManifestCode = generateRpcManifestCode(operations);\n const traceBatching = options.traceBatching ?? RENDERER_TRACE_BATCHING_DEFAULTS;\n\n return `${generatedFileNotice(PRELOAD_SOURCE_INSTRUCTIONS)}\nimport { contextBridge, ipcRenderer } from 'electron';\nimport {\n RendererTraceBatchTransport,\n type WoodRendererTraceInput,\n type WoodTraceBatch,\n type WoodTraceBatchAcknowledgement,\n type WoodTraceBatchPort,\n} from '@noego/wood/trace-transport';\n\n${rpcManifestCode}\n\nconst __WOOD_INTERNAL_BRIDGE_KEY = '${INTERNAL_BRIDGE_GLOBAL_KEY}';\n\ncontextBridge.exposeInMainWorld(__WOOD_INTERNAL_BRIDGE_KEY, {\n${operationsCode}\n\n // Internal: backend controller/action RPC map for @Inject(App)\n __rpcManifest: __WOOD_RPC_MANIFEST,\n\n // Internal: loader data requests\n __load: (route: string, params: Record<string, string>) =>\n ipcRenderer.invoke('__load', { route, params }),\n\n // Internal: cross-window navigation\n __navigate: (windowId: string, route: string) =>\n ipcRenderer.invoke('__navigate', { windowId, route }),\n\n // Internal: window management\n __window: {\n current: () =>\n ipcRenderer.invoke('__window', { action: 'current' }),\n open: (windowId: string, options?: Record<string, unknown>) =>\n ipcRenderer.invoke('__window', { action: 'open', windowId, options }),\n close: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'close', windowId }),\n focus: (windowId: string) =>\n ipcRenderer.invoke('__window', { action: 'focus', windowId }),\n minimize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'minimize', windowId }),\n maximize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'maximize', windowId }),\n },\n\n // Internal: framework config (trace min level, etc)\n __woodConfig: () =>\n ipcRenderer.invoke('__woodConfig'),\n\n // Internal: debug metadata\n __debug: {\n current: () =>\n ipcRenderer.invoke('__debug', { action: 'current' }),\n },\n\n // Internal: context menu\n __contextMenu: {\n show: (data: unknown) =>\n ipcRenderer.invoke('__contextMenu', { action: 'show', ...data as Record<string, unknown> }),\n },\n\n // Push events from main process\n on: (channel: string, callback: (...args: unknown[]) => void) => {\n const subscription = (_event: unknown, ...args: unknown[]) => callback(...args);\n ipcRenderer.on(\\`__event:\\${channel}\\`, subscription);\n return () => ipcRenderer.removeListener(\\`__event:\\${channel}\\`, subscription);\n },\n __trace: (event: unknown) => {\n ipcRenderer.send('__trace', event);\n },\n __log: (level: string, logger: string, message: string, context?: unknown) => {\n ipcRenderer.send('__log', { level, logger, message, context });\n },\n __logBatch: (batch: unknown) => {\n ipcRenderer.send('__log_batch', batch);\n },\n});\n\n// Trace transport via MessagePort (activated when main process sends a port)\nlet __tracePort: MessagePort | null = null;\nconst __traceBuffer: unknown[] = [];\nconst __TRACE_BUFFER_CAPACITY = 256;\nlet __traceDroppedCapacity = 0;\n\nfunction __traceFlush(): void {\n while (__traceBuffer.length > 0 && __tracePort) {\n __tracePort.postMessage(__traceBuffer.shift());\n }\n}\n\nipcRenderer.on('__trace-port', (event) => {\n __tracePort = event.ports[0];\n __tracePort.start();\n __traceFlush();\n});\n\ncontextBridge.exposeInMainWorld('__NOEGO_TRACE__', {\n send: (data: unknown) => {\n if (__tracePort) {\n __tracePort.postMessage(data);\n } else if (__traceBuffer.length >= __TRACE_BUFFER_CAPACITY) {\n __traceDroppedCapacity += 1;\n } else {\n __traceBuffer.push(data);\n }\n },\n status: () => ({\n queuedEvents: __traceBuffer.length,\n droppedCapacity: __traceDroppedCapacity,\n }),\n});\n\nconst __traceBatchProducerId = typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : \\`wood-renderer-\\${Date.now()}-\\${Math.random().toString(16).slice(2)}\\`;\nlet __traceBatchListener: ((message: unknown) => void) | null = null;\n\nconst __traceBatchPort: WoodTraceBatchPort = {\n postMessage: (batch: WoodTraceBatch) => {\n void ipcRenderer.invoke('__traceBatch', batch)\n .then((acknowledgement: WoodTraceBatchAcknowledgement) => {\n __traceBatchListener?.(acknowledgement);\n })\n .catch((error: unknown) => {\n __traceBatchListener?.({\n kind: 'retryable',\n batchId: batch.batchId,\n reason: error instanceof Error ? error.message : String(error),\n retryAfterMs: 100,\n });\n });\n },\n subscribe: (listener: (message: unknown) => void) => {\n __traceBatchListener = listener;\n return () => {\n if (__traceBatchListener === listener) {\n __traceBatchListener = null;\n }\n };\n },\n close: () => {\n __traceBatchListener = null;\n },\n};\n\n// Batching policy resolved from wood.config.yml observability configuration\n// at generation time; this file embeds but does not own it.\nconst __traceBatchTransport = new RendererTraceBatchTransport({\n producerId: __traceBatchProducerId,\n maxQueuedEvents: ${traceBatching.maxQueuedEvents},\n maxBatchEvents: ${traceBatching.maxBatchEvents},\n acknowledgementTimeoutMs: ${traceBatching.acknowledgementTimeoutMs},\n retryLimit: ${traceBatching.retryLimit},\n retryBaseDelayMs: ${traceBatching.retryBaseDelayMs},\n now: () => Date.now(),\n schedule: (work: () => void) => queueMicrotask(work),\n delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),\n});\n__traceBatchTransport.attachPort(__traceBatchPort);\n\ncontextBridge.exposeInMainWorld('__NOEGO_WOOD_TRACE_BATCH__', {\n send: (event: WoodRendererTraceInput) => __traceBatchTransport.admit(event),\n status: () => __traceBatchTransport.status(),\n flush: (deadlineMs: number) => __traceBatchTransport.flush(deadlineMs),\n close: (deadlineMs: number) => __traceBatchTransport.close(deadlineMs),\n});\n\nipcRenderer.on('__woodTraceDrainRequest', (_event, payload: unknown) => {\n if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {\n return;\n }\n const requestId = Reflect.get(payload, 'requestId');\n const deadlineMs = Reflect.get(payload, 'deadlineMs');\n if (typeof requestId !== 'string'\n || typeof deadlineMs !== 'number'\n || !Number.isFinite(deadlineMs)) {\n return;\n }\n void __traceBatchTransport.close(deadlineMs).finally(() => {\n ipcRenderer.send('__woodTraceDrainAck', {\n requestId,\n status: __traceBatchTransport.status(),\n });\n });\n});\n\nglobalThis.addEventListener?.('pagehide', () => {\n void __traceBatchTransport.flush(Date.now() + 100);\n});\n`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import { RendererTraceBatchingConfig } from '../types/config.cjs';
|
|
1
2
|
import { OperationDef } from '../types/operations.cjs';
|
|
2
3
|
|
|
4
|
+
type GeneratePreloadOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Renderer→main IPC trace batching policy resolved from
|
|
7
|
+
* wood.config.yml `observability.trace.rendererToMain.batching`.
|
|
8
|
+
* The generated preload embeds these values but does not own them.
|
|
9
|
+
*/
|
|
10
|
+
traceBatching?: RendererTraceBatchingConfig;
|
|
11
|
+
};
|
|
3
12
|
/**
|
|
4
13
|
* Generate a complete preload.ts file from operations.
|
|
5
14
|
*/
|
|
6
|
-
declare function generatePreload(operations: Map<string, OperationDef
|
|
15
|
+
declare function generatePreload(operations: Map<string, OperationDef>, options?: GeneratePreloadOptions): string;
|
|
7
16
|
|
|
8
|
-
export { generatePreload };
|
|
17
|
+
export { type GeneratePreloadOptions, generatePreload };
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
+
import { RendererTraceBatchingConfig } from '../types/config.js';
|
|
1
2
|
import { OperationDef } from '../types/operations.js';
|
|
2
3
|
|
|
4
|
+
type GeneratePreloadOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Renderer→main IPC trace batching policy resolved from
|
|
7
|
+
* wood.config.yml `observability.trace.rendererToMain.batching`.
|
|
8
|
+
* The generated preload embeds these values but does not own them.
|
|
9
|
+
*/
|
|
10
|
+
traceBatching?: RendererTraceBatchingConfig;
|
|
11
|
+
};
|
|
3
12
|
/**
|
|
4
13
|
* Generate a complete preload.ts file from operations.
|
|
5
14
|
*/
|
|
6
|
-
declare function generatePreload(operations: Map<string, OperationDef
|
|
15
|
+
declare function generatePreload(operations: Map<string, OperationDef>, options?: GeneratePreloadOptions): string;
|
|
7
16
|
|
|
8
|
-
export { generatePreload };
|
|
17
|
+
export { type GeneratePreloadOptions, generatePreload };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RENDERER_TRACE_BATCHING_DEFAULTS } from "../config/config_parser.js";
|
|
1
2
|
import { generatedFileNotice } from "./generated_file_notice.js";
|
|
2
3
|
const PRELOAD_SOURCE_INSTRUCTIONS = [
|
|
3
4
|
"To change IPC channels or preload bridge methods, edit the operations YAML configured by",
|
|
@@ -60,10 +61,11 @@ ${entries.join("\n")}
|
|
|
60
61
|
];`;
|
|
61
62
|
}
|
|
62
63
|
const INTERNAL_BRIDGE_GLOBAL_KEY = "__NOEGO_WOOD_BRIDGE__";
|
|
63
|
-
function generatePreload(operations) {
|
|
64
|
+
function generatePreload(operations, options = {}) {
|
|
64
65
|
const tree = buildNestedTree(operations);
|
|
65
66
|
const operationsCode = generateTreeCode(tree);
|
|
66
67
|
const rpcManifestCode = generateRpcManifestCode(operations);
|
|
68
|
+
const traceBatching = options.traceBatching ?? RENDERER_TRACE_BATCHING_DEFAULTS;
|
|
67
69
|
return `${generatedFileNotice(PRELOAD_SOURCE_INSTRUCTIONS)}
|
|
68
70
|
import { contextBridge, ipcRenderer } from 'electron';
|
|
69
71
|
import {
|
|
@@ -136,6 +138,9 @@ ${operationsCode}
|
|
|
136
138
|
__log: (level: string, logger: string, message: string, context?: unknown) => {
|
|
137
139
|
ipcRenderer.send('__log', { level, logger, message, context });
|
|
138
140
|
},
|
|
141
|
+
__logBatch: (batch: unknown) => {
|
|
142
|
+
ipcRenderer.send('__log_batch', batch);
|
|
143
|
+
},
|
|
139
144
|
});
|
|
140
145
|
|
|
141
146
|
// Trace transport via MessagePort (activated when main process sends a port)
|
|
@@ -205,13 +210,15 @@ const __traceBatchPort: WoodTraceBatchPort = {
|
|
|
205
210
|
},
|
|
206
211
|
};
|
|
207
212
|
|
|
213
|
+
// Batching policy resolved from wood.config.yml observability configuration
|
|
214
|
+
// at generation time; this file embeds but does not own it.
|
|
208
215
|
const __traceBatchTransport = new RendererTraceBatchTransport({
|
|
209
216
|
producerId: __traceBatchProducerId,
|
|
210
|
-
maxQueuedEvents:
|
|
211
|
-
maxBatchEvents:
|
|
212
|
-
acknowledgementTimeoutMs:
|
|
213
|
-
retryLimit:
|
|
214
|
-
retryBaseDelayMs:
|
|
217
|
+
maxQueuedEvents: ${traceBatching.maxQueuedEvents},
|
|
218
|
+
maxBatchEvents: ${traceBatching.maxBatchEvents},
|
|
219
|
+
acknowledgementTimeoutMs: ${traceBatching.acknowledgementTimeoutMs},
|
|
220
|
+
retryLimit: ${traceBatching.retryLimit},
|
|
221
|
+
retryBaseDelayMs: ${traceBatching.retryBaseDelayMs},
|
|
215
222
|
now: () => Date.now(),
|
|
216
223
|
schedule: (work: () => void) => queueMicrotask(work),
|
|
217
224
|
delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/codegen/preload_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nconst PRELOAD_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels or preload bridge methods, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and regenerate with `wood dev` or `wood build`.',\n] as const;\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\n/**\n * Build a nested object tree from dot-path operation channels.\n * \"chat.message.send\" -> { chat: { message: { send: ... } } }\n */\nfunction buildNestedTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n\n const leaf = parts[parts.length - 1];\n current[leaf] = { __operation: op };\n }\n\n return tree;\n}\n\n/**\n * Generate TypeScript code for a nested tree node.\n */\nfunction generateTreeCode(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${key}: (data: unknown) =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}', data),`);\n } else {\n lines.push(`${indent}${key}: () =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}'),`);\n }\n } else {\n lines.push(`${indent}${key}: {`);\n lines.push(generateTreeCode(entry, indent + ' '));\n lines.push(`${indent}},`);\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction generateRpcManifestCode(operations: Map<string, OperationDef>): string {\n const entries = Array.from(operations.values())\n .sort((a, b) => a.channel.localeCompare(b.channel))\n .map((op) => {\n const payload = {\n channel: op.channel,\n controller: op.controller,\n action: op.action,\n path: op.channel.split('.'),\n hasInput: operationHasInput(op),\n };\n return ` ${JSON.stringify(payload)},`;\n });\n\n return `const __WOOD_RPC_MANIFEST = [\n${entries.join('\\n')}\n];`;\n}\n\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\n/**\n * Generate a complete preload.ts file from operations.\n */\nexport function generatePreload(operations: Map<string, OperationDef>): string {\n const tree = buildNestedTree(operations);\n const operationsCode = generateTreeCode(tree);\n const rpcManifestCode = generateRpcManifestCode(operations);\n\n return `${generatedFileNotice(PRELOAD_SOURCE_INSTRUCTIONS)}\nimport { contextBridge, ipcRenderer } from 'electron';\nimport {\n RendererTraceBatchTransport,\n type WoodRendererTraceInput,\n type WoodTraceBatch,\n type WoodTraceBatchAcknowledgement,\n type WoodTraceBatchPort,\n} from '@noego/wood/trace-transport';\n\n${rpcManifestCode}\n\nconst __WOOD_INTERNAL_BRIDGE_KEY = '${INTERNAL_BRIDGE_GLOBAL_KEY}';\n\ncontextBridge.exposeInMainWorld(__WOOD_INTERNAL_BRIDGE_KEY, {\n${operationsCode}\n\n // Internal: backend controller/action RPC map for @Inject(App)\n __rpcManifest: __WOOD_RPC_MANIFEST,\n\n // Internal: loader data requests\n __load: (route: string, params: Record<string, string>) =>\n ipcRenderer.invoke('__load', { route, params }),\n\n // Internal: cross-window navigation\n __navigate: (windowId: string, route: string) =>\n ipcRenderer.invoke('__navigate', { windowId, route }),\n\n // Internal: window management\n __window: {\n current: () =>\n ipcRenderer.invoke('__window', { action: 'current' }),\n open: (windowId: string, options?: Record<string, unknown>) =>\n ipcRenderer.invoke('__window', { action: 'open', windowId, options }),\n close: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'close', windowId }),\n focus: (windowId: string) =>\n ipcRenderer.invoke('__window', { action: 'focus', windowId }),\n minimize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'minimize', windowId }),\n maximize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'maximize', windowId }),\n },\n\n // Internal: framework config (trace min level, etc)\n __woodConfig: () =>\n ipcRenderer.invoke('__woodConfig'),\n\n // Internal: debug metadata\n __debug: {\n current: () =>\n ipcRenderer.invoke('__debug', { action: 'current' }),\n },\n\n // Internal: context menu\n __contextMenu: {\n show: (data: unknown) =>\n ipcRenderer.invoke('__contextMenu', { action: 'show', ...data as Record<string, unknown> }),\n },\n\n // Push events from main process\n on: (channel: string, callback: (...args: unknown[]) => void) => {\n const subscription = (_event: unknown, ...args: unknown[]) => callback(...args);\n ipcRenderer.on(\\`__event:\\${channel}\\`, subscription);\n return () => ipcRenderer.removeListener(\\`__event:\\${channel}\\`, subscription);\n },\n __trace: (event: unknown) => {\n ipcRenderer.send('__trace', event);\n },\n __log: (level: string, logger: string, message: string, context?: unknown) => {\n ipcRenderer.send('__log', { level, logger, message, context });\n },\n});\n\n// Trace transport via MessagePort (activated when main process sends a port)\nlet __tracePort: MessagePort | null = null;\nconst __traceBuffer: unknown[] = [];\nconst __TRACE_BUFFER_CAPACITY = 256;\nlet __traceDroppedCapacity = 0;\n\nfunction __traceFlush(): void {\n while (__traceBuffer.length > 0 && __tracePort) {\n __tracePort.postMessage(__traceBuffer.shift());\n }\n}\n\nipcRenderer.on('__trace-port', (event) => {\n __tracePort = event.ports[0];\n __tracePort.start();\n __traceFlush();\n});\n\ncontextBridge.exposeInMainWorld('__NOEGO_TRACE__', {\n send: (data: unknown) => {\n if (__tracePort) {\n __tracePort.postMessage(data);\n } else if (__traceBuffer.length >= __TRACE_BUFFER_CAPACITY) {\n __traceDroppedCapacity += 1;\n } else {\n __traceBuffer.push(data);\n }\n },\n status: () => ({\n queuedEvents: __traceBuffer.length,\n droppedCapacity: __traceDroppedCapacity,\n }),\n});\n\nconst __traceBatchProducerId = typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : \\`wood-renderer-\\${Date.now()}-\\${Math.random().toString(16).slice(2)}\\`;\nlet __traceBatchListener: ((message: unknown) => void) | null = null;\n\nconst __traceBatchPort: WoodTraceBatchPort = {\n postMessage: (batch: WoodTraceBatch) => {\n void ipcRenderer.invoke('__traceBatch', batch)\n .then((acknowledgement: WoodTraceBatchAcknowledgement) => {\n __traceBatchListener?.(acknowledgement);\n })\n .catch((error: unknown) => {\n __traceBatchListener?.({\n kind: 'retryable',\n batchId: batch.batchId,\n reason: error instanceof Error ? error.message : String(error),\n retryAfterMs: 100,\n });\n });\n },\n subscribe: (listener: (message: unknown) => void) => {\n __traceBatchListener = listener;\n return () => {\n if (__traceBatchListener === listener) {\n __traceBatchListener = null;\n }\n };\n },\n close: () => {\n __traceBatchListener = null;\n },\n};\n\nconst __traceBatchTransport = new RendererTraceBatchTransport({\n producerId: __traceBatchProducerId,\n maxQueuedEvents: 256,\n maxBatchEvents: 32,\n acknowledgementTimeoutMs: 1_000,\n retryLimit: 3,\n retryBaseDelayMs: 25,\n now: () => Date.now(),\n schedule: (work: () => void) => queueMicrotask(work),\n delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),\n});\n__traceBatchTransport.attachPort(__traceBatchPort);\n\ncontextBridge.exposeInMainWorld('__NOEGO_WOOD_TRACE_BATCH__', {\n send: (event: WoodRendererTraceInput) => __traceBatchTransport.admit(event),\n status: () => __traceBatchTransport.status(),\n flush: (deadlineMs: number) => __traceBatchTransport.flush(deadlineMs),\n close: (deadlineMs: number) => __traceBatchTransport.close(deadlineMs),\n});\n\nipcRenderer.on('__woodTraceDrainRequest', (_event, payload: unknown) => {\n if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {\n return;\n }\n const requestId = Reflect.get(payload, 'requestId');\n const deadlineMs = Reflect.get(payload, 'deadlineMs');\n if (typeof requestId !== 'string'\n || typeof deadlineMs !== 'number'\n || !Number.isFinite(deadlineMs)) {\n return;\n }\n void __traceBatchTransport.close(deadlineMs).finally(() => {\n ipcRenderer.send('__woodTraceDrainAck', {\n requestId,\n status: __traceBatchTransport.status(),\n });\n });\n});\n\nglobalThis.addEventListener?.('pagehide', () => {\n void __traceBatchTransport.flush(Date.now() + 100);\n});\n`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/codegen/preload_generator.ts"],"sourcesContent":["import type { OperationDef } from '../types/index.js';\nimport type { RendererTraceBatchingConfig } from '../types/config.js';\nimport { RENDERER_TRACE_BATCHING_DEFAULTS } from '../config/config_parser.js';\nimport { generatedFileNotice } from './generated_file_notice.js';\n\nexport type GeneratePreloadOptions = {\n /**\n * Renderer→main IPC trace batching policy resolved from\n * wood.config.yml `observability.trace.rendererToMain.batching`.\n * The generated preload embeds these values but does not own them.\n */\n traceBatching?: RendererTraceBatchingConfig;\n};\n\nconst PRELOAD_SOURCE_INSTRUCTIONS = [\n 'To change IPC channels or preload bridge methods, edit the operations YAML configured by',\n 'wood.config.yml main.openapi and regenerate with `wood dev` or `wood build`.',\n] as const;\n\nfunction operationHasInput(op: OperationDef): boolean {\n return Boolean(\n op.inputSchema &&\n (op.inputSchema as Record<string, unknown>).type === 'object' &&\n Object.keys((op.inputSchema as Record<string, Record<string, unknown>>).properties ?? {}).length > 0,\n );\n}\n\n/**\n * Build a nested object tree from dot-path operation channels.\n * \"chat.message.send\" -> { chat: { message: { send: ... } } }\n */\nfunction buildNestedTree(operations: Map<string, OperationDef>): Record<string, unknown> {\n const tree: Record<string, unknown> = {};\n\n for (const [channel, op] of operations) {\n const parts = channel.split('.');\n let current: Record<string, unknown> = tree;\n\n for (let i = 0; i < parts.length - 1; i++) {\n if (!current[parts[i]]) current[parts[i]] = {};\n current = current[parts[i]] as Record<string, unknown>;\n }\n\n const leaf = parts[parts.length - 1];\n current[leaf] = { __operation: op };\n }\n\n return tree;\n}\n\n/**\n * Generate TypeScript code for a nested tree node.\n */\nfunction generateTreeCode(node: Record<string, unknown>, indent: string = ' '): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(node)) {\n const entry = value as Record<string, unknown>;\n if (entry.__operation) {\n const op = entry.__operation as OperationDef;\n const hasInput = operationHasInput(op);\n\n if (hasInput) {\n lines.push(`${indent}${key}: (data: unknown) =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}', data),`);\n } else {\n lines.push(`${indent}${key}: () =>`);\n lines.push(`${indent} ipcRenderer.invoke('${op.channel}'),`);\n }\n } else {\n lines.push(`${indent}${key}: {`);\n lines.push(generateTreeCode(entry, indent + ' '));\n lines.push(`${indent}},`);\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction generateRpcManifestCode(operations: Map<string, OperationDef>): string {\n const entries = Array.from(operations.values())\n .sort((a, b) => a.channel.localeCompare(b.channel))\n .map((op) => {\n const payload = {\n channel: op.channel,\n controller: op.controller,\n action: op.action,\n path: op.channel.split('.'),\n hasInput: operationHasInput(op),\n };\n return ` ${JSON.stringify(payload)},`;\n });\n\n return `const __WOOD_RPC_MANIFEST = [\n${entries.join('\\n')}\n];`;\n}\n\nconst INTERNAL_BRIDGE_GLOBAL_KEY = '__NOEGO_WOOD_BRIDGE__';\n\n/**\n * Generate a complete preload.ts file from operations.\n */\nexport function generatePreload(\n operations: Map<string, OperationDef>,\n options: GeneratePreloadOptions = {},\n): string {\n const tree = buildNestedTree(operations);\n const operationsCode = generateTreeCode(tree);\n const rpcManifestCode = generateRpcManifestCode(operations);\n const traceBatching = options.traceBatching ?? RENDERER_TRACE_BATCHING_DEFAULTS;\n\n return `${generatedFileNotice(PRELOAD_SOURCE_INSTRUCTIONS)}\nimport { contextBridge, ipcRenderer } from 'electron';\nimport {\n RendererTraceBatchTransport,\n type WoodRendererTraceInput,\n type WoodTraceBatch,\n type WoodTraceBatchAcknowledgement,\n type WoodTraceBatchPort,\n} from '@noego/wood/trace-transport';\n\n${rpcManifestCode}\n\nconst __WOOD_INTERNAL_BRIDGE_KEY = '${INTERNAL_BRIDGE_GLOBAL_KEY}';\n\ncontextBridge.exposeInMainWorld(__WOOD_INTERNAL_BRIDGE_KEY, {\n${operationsCode}\n\n // Internal: backend controller/action RPC map for @Inject(App)\n __rpcManifest: __WOOD_RPC_MANIFEST,\n\n // Internal: loader data requests\n __load: (route: string, params: Record<string, string>) =>\n ipcRenderer.invoke('__load', { route, params }),\n\n // Internal: cross-window navigation\n __navigate: (windowId: string, route: string) =>\n ipcRenderer.invoke('__navigate', { windowId, route }),\n\n // Internal: window management\n __window: {\n current: () =>\n ipcRenderer.invoke('__window', { action: 'current' }),\n open: (windowId: string, options?: Record<string, unknown>) =>\n ipcRenderer.invoke('__window', { action: 'open', windowId, options }),\n close: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'close', windowId }),\n focus: (windowId: string) =>\n ipcRenderer.invoke('__window', { action: 'focus', windowId }),\n minimize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'minimize', windowId }),\n maximize: (windowId?: string) =>\n ipcRenderer.invoke('__window', { action: 'maximize', windowId }),\n },\n\n // Internal: framework config (trace min level, etc)\n __woodConfig: () =>\n ipcRenderer.invoke('__woodConfig'),\n\n // Internal: debug metadata\n __debug: {\n current: () =>\n ipcRenderer.invoke('__debug', { action: 'current' }),\n },\n\n // Internal: context menu\n __contextMenu: {\n show: (data: unknown) =>\n ipcRenderer.invoke('__contextMenu', { action: 'show', ...data as Record<string, unknown> }),\n },\n\n // Push events from main process\n on: (channel: string, callback: (...args: unknown[]) => void) => {\n const subscription = (_event: unknown, ...args: unknown[]) => callback(...args);\n ipcRenderer.on(\\`__event:\\${channel}\\`, subscription);\n return () => ipcRenderer.removeListener(\\`__event:\\${channel}\\`, subscription);\n },\n __trace: (event: unknown) => {\n ipcRenderer.send('__trace', event);\n },\n __log: (level: string, logger: string, message: string, context?: unknown) => {\n ipcRenderer.send('__log', { level, logger, message, context });\n },\n __logBatch: (batch: unknown) => {\n ipcRenderer.send('__log_batch', batch);\n },\n});\n\n// Trace transport via MessagePort (activated when main process sends a port)\nlet __tracePort: MessagePort | null = null;\nconst __traceBuffer: unknown[] = [];\nconst __TRACE_BUFFER_CAPACITY = 256;\nlet __traceDroppedCapacity = 0;\n\nfunction __traceFlush(): void {\n while (__traceBuffer.length > 0 && __tracePort) {\n __tracePort.postMessage(__traceBuffer.shift());\n }\n}\n\nipcRenderer.on('__trace-port', (event) => {\n __tracePort = event.ports[0];\n __tracePort.start();\n __traceFlush();\n});\n\ncontextBridge.exposeInMainWorld('__NOEGO_TRACE__', {\n send: (data: unknown) => {\n if (__tracePort) {\n __tracePort.postMessage(data);\n } else if (__traceBuffer.length >= __TRACE_BUFFER_CAPACITY) {\n __traceDroppedCapacity += 1;\n } else {\n __traceBuffer.push(data);\n }\n },\n status: () => ({\n queuedEvents: __traceBuffer.length,\n droppedCapacity: __traceDroppedCapacity,\n }),\n});\n\nconst __traceBatchProducerId = typeof globalThis.crypto?.randomUUID === 'function'\n ? globalThis.crypto.randomUUID()\n : \\`wood-renderer-\\${Date.now()}-\\${Math.random().toString(16).slice(2)}\\`;\nlet __traceBatchListener: ((message: unknown) => void) | null = null;\n\nconst __traceBatchPort: WoodTraceBatchPort = {\n postMessage: (batch: WoodTraceBatch) => {\n void ipcRenderer.invoke('__traceBatch', batch)\n .then((acknowledgement: WoodTraceBatchAcknowledgement) => {\n __traceBatchListener?.(acknowledgement);\n })\n .catch((error: unknown) => {\n __traceBatchListener?.({\n kind: 'retryable',\n batchId: batch.batchId,\n reason: error instanceof Error ? error.message : String(error),\n retryAfterMs: 100,\n });\n });\n },\n subscribe: (listener: (message: unknown) => void) => {\n __traceBatchListener = listener;\n return () => {\n if (__traceBatchListener === listener) {\n __traceBatchListener = null;\n }\n };\n },\n close: () => {\n __traceBatchListener = null;\n },\n};\n\n// Batching policy resolved from wood.config.yml observability configuration\n// at generation time; this file embeds but does not own it.\nconst __traceBatchTransport = new RendererTraceBatchTransport({\n producerId: __traceBatchProducerId,\n maxQueuedEvents: ${traceBatching.maxQueuedEvents},\n maxBatchEvents: ${traceBatching.maxBatchEvents},\n acknowledgementTimeoutMs: ${traceBatching.acknowledgementTimeoutMs},\n retryLimit: ${traceBatching.retryLimit},\n retryBaseDelayMs: ${traceBatching.retryBaseDelayMs},\n now: () => Date.now(),\n schedule: (work: () => void) => queueMicrotask(work),\n delay: (durationMs: number) => new Promise((resolve) => setTimeout(resolve, durationMs)),\n});\n__traceBatchTransport.attachPort(__traceBatchPort);\n\ncontextBridge.exposeInMainWorld('__NOEGO_WOOD_TRACE_BATCH__', {\n send: (event: WoodRendererTraceInput) => __traceBatchTransport.admit(event),\n status: () => __traceBatchTransport.status(),\n flush: (deadlineMs: number) => __traceBatchTransport.flush(deadlineMs),\n close: (deadlineMs: number) => __traceBatchTransport.close(deadlineMs),\n});\n\nipcRenderer.on('__woodTraceDrainRequest', (_event, payload: unknown) => {\n if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {\n return;\n }\n const requestId = Reflect.get(payload, 'requestId');\n const deadlineMs = Reflect.get(payload, 'deadlineMs');\n if (typeof requestId !== 'string'\n || typeof deadlineMs !== 'number'\n || !Number.isFinite(deadlineMs)) {\n return;\n }\n void __traceBatchTransport.close(deadlineMs).finally(() => {\n ipcRenderer.send('__woodTraceDrainAck', {\n requestId,\n status: __traceBatchTransport.status(),\n });\n });\n});\n\nglobalThis.addEventListener?.('pagehide', () => {\n void __traceBatchTransport.flush(Date.now() + 100);\n});\n`;\n}\n"],"mappings":"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","names":[]}
|