@aotui/runtime 1.0.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/dist/adapters/aotui-driven-source.d.ts +106 -0
- package/dist/adapters/aotui-driven-source.js +549 -0
- package/dist/adapters/aotui-driven-source.js.map +1 -0
- package/dist/adapters/bridge/index.d.ts +94 -0
- package/dist/adapters/bridge/index.js +199 -0
- package/dist/adapters/bridge/index.js.map +1 -0
- package/dist/adapters/index.d.ts +7 -0
- package/dist/adapters/index.js +8 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/session/index.d.ts +7 -0
- package/dist/adapters/session/index.js +2 -0
- package/dist/adapters/session/index.js.map +1 -0
- package/dist/adapters/session/session.d.ts +46 -0
- package/dist/adapters/session/session.js +76 -0
- package/dist/adapters/session/session.js.map +1 -0
- package/dist/adapters/session/types.d.ts +52 -0
- package/dist/adapters/session/types.js +7 -0
- package/dist/adapters/session/types.js.map +1 -0
- package/dist/adapters/system-instruction.d.ts +9 -0
- package/dist/adapters/system-instruction.js +434 -0
- package/dist/adapters/system-instruction.js.map +1 -0
- package/dist/benchmarks/dom-engine-comparison.d.ts +1 -0
- package/dist/benchmarks/dom-engine-comparison.js +84 -0
- package/dist/benchmarks/dom-engine-comparison.js.map +1 -0
- package/dist/benchmarks/shadow-dom-check.d.ts +1 -0
- package/dist/benchmarks/shadow-dom-check.js +44 -0
- package/dist/benchmarks/shadow-dom-check.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +314 -0
- package/dist/cli.js.map +1 -0
- package/dist/engine/app/config.d.ts +81 -0
- package/dist/engine/app/config.js +32 -0
- package/dist/engine/app/config.js.map +1 -0
- package/dist/engine/app/index.d.ts +14 -0
- package/dist/engine/app/index.js +33 -0
- package/dist/engine/app/index.js.map +1 -0
- package/dist/engine/app/manager.d.ts +194 -0
- package/dist/engine/app/manager.js +340 -0
- package/dist/engine/app/manager.js.map +1 -0
- package/dist/engine/app/registry.d.ts +138 -0
- package/dist/engine/app/registry.js +473 -0
- package/dist/engine/app/registry.js.map +1 -0
- package/dist/engine/app/worker-app-host.service.d.ts +62 -0
- package/dist/engine/app/worker-app-host.service.js +189 -0
- package/dist/engine/app/worker-app-host.service.js.map +1 -0
- package/dist/engine/app/worker-host.d.ts +139 -0
- package/dist/engine/app/worker-host.js +397 -0
- package/dist/engine/app/worker-host.js.map +1 -0
- package/dist/engine/app/worker-pool.d.ts +45 -0
- package/dist/engine/app/worker-pool.js +122 -0
- package/dist/engine/app/worker-pool.js.map +1 -0
- package/dist/engine/app/worker-sandbox.d.ts +152 -0
- package/dist/engine/app/worker-sandbox.js +290 -0
- package/dist/engine/app/worker-sandbox.js.map +1 -0
- package/dist/engine/core/desktop-logger.d.ts +69 -0
- package/dist/engine/core/desktop-logger.js +124 -0
- package/dist/engine/core/desktop-logger.js.map +1 -0
- package/dist/engine/core/desktop.d.ts +208 -0
- package/dist/engine/core/desktop.js +351 -0
- package/dist/engine/core/desktop.js.map +1 -0
- package/dist/engine/core/index.d.ts +12 -0
- package/dist/engine/core/index.js +28 -0
- package/dist/engine/core/index.js.map +1 -0
- package/dist/engine/core/llm-output-channel.d.ts +45 -0
- package/dist/engine/core/llm-output-channel.js +122 -0
- package/dist/engine/core/llm-output-channel.js.map +1 -0
- package/dist/engine/core/manager.d.ts +59 -0
- package/dist/engine/core/manager.js +131 -0
- package/dist/engine/core/manager.js.map +1 -0
- package/dist/engine/core/operation-log-buffer.d.ts +79 -0
- package/dist/engine/core/operation-log-buffer.js +108 -0
- package/dist/engine/core/operation-log-buffer.js.map +1 -0
- package/dist/engine/core/operation-log-formatter.d.ts +44 -0
- package/dist/engine/core/operation-log-formatter.js +180 -0
- package/dist/engine/core/operation-log-formatter.js.map +1 -0
- package/dist/engine/core/services/lock.service.d.ts +33 -0
- package/dist/engine/core/services/lock.service.js +99 -0
- package/dist/engine/core/services/lock.service.js.map +1 -0
- package/dist/engine/core/signal-bus.d.ts +84 -0
- package/dist/engine/core/signal-bus.js +160 -0
- package/dist/engine/core/signal-bus.js.map +1 -0
- package/dist/engine/core/signal-service.d.ts +42 -0
- package/dist/engine/core/signal-service.js +58 -0
- package/dist/engine/core/signal-service.js.map +1 -0
- package/dist/engine/system/dispatcher.d.ts +18 -0
- package/dist/engine/system/dispatcher.js +48 -0
- package/dist/engine/system/dispatcher.js.map +1 -0
- package/dist/engine/system/index.d.ts +10 -0
- package/dist/engine/system/index.js +20 -0
- package/dist/engine/system/index.js.map +1 -0
- package/dist/engine/system/operations/index.d.ts +26 -0
- package/dist/engine/system/operations/index.js +38 -0
- package/dist/engine/system/operations/index.js.map +1 -0
- package/dist/engine/system/operations/registry.d.ts +62 -0
- package/dist/engine/system/operations/registry.js +101 -0
- package/dist/engine/system/operations/registry.js.map +1 -0
- package/dist/engine/system/operations/system/close-app.d.ts +13 -0
- package/dist/engine/system/operations/system/close-app.js +43 -0
- package/dist/engine/system/operations/system/close-app.js.map +1 -0
- package/dist/engine/system/operations/system/dismount-view.d.ts +13 -0
- package/dist/engine/system/operations/system/dismount-view.js +48 -0
- package/dist/engine/system/operations/system/dismount-view.js.map +1 -0
- package/dist/engine/system/operations/system/index.d.ts +6 -0
- package/dist/engine/system/operations/system/index.js +7 -0
- package/dist/engine/system/operations/system/index.js.map +1 -0
- package/dist/engine/system/operations/system/open-app.d.ts +13 -0
- package/dist/engine/system/operations/system/open-app.js +43 -0
- package/dist/engine/system/operations/system/open-app.js.map +1 -0
- package/dist/engine/system/registry.d.ts +36 -0
- package/dist/engine/system/registry.js +101 -0
- package/dist/engine/system/registry.js.map +1 -0
- package/dist/engine/view/index.d.ts +13 -0
- package/dist/engine/view/index.js +20 -0
- package/dist/engine/view/index.js.map +1 -0
- package/dist/engine/view/manager.d.ts +42 -0
- package/dist/engine/view/manager.js +57 -0
- package/dist/engine/view/manager.js.map +1 -0
- package/dist/engine/view/snapshot/builder.d.ts +34 -0
- package/dist/engine/view/snapshot/builder.js +119 -0
- package/dist/engine/view/snapshot/builder.js.map +1 -0
- package/dist/engine/view/snapshot/formatter.d.ts +76 -0
- package/dist/engine/view/snapshot/formatter.js +297 -0
- package/dist/engine/view/snapshot/formatter.js.map +1 -0
- package/dist/engine/view/snapshot/index.d.ts +8 -0
- package/dist/engine/view/snapshot/index.js +8 -0
- package/dist/engine/view/snapshot/index.js.map +1 -0
- package/dist/engine/view/snapshot/templates.d.ts +41 -0
- package/dist/engine/view/snapshot/templates.js +317 -0
- package/dist/engine/view/snapshot/templates.js.map +1 -0
- package/dist/engine/view/transformer/__tests__/visitors/test-utils.d.ts +1 -0
- package/dist/engine/view/transformer/__tests__/visitors/test-utils.js +14 -0
- package/dist/engine/view/transformer/__tests__/visitors/test-utils.js.map +1 -0
- package/dist/engine/view/transformer/helpers.d.ts +19 -0
- package/dist/engine/view/transformer/helpers.js +32 -0
- package/dist/engine/view/transformer/helpers.js.map +1 -0
- package/dist/engine/view/transformer/index.d.ts +40 -0
- package/dist/engine/view/transformer/index.js +38 -0
- package/dist/engine/view/transformer/index.js.map +1 -0
- package/dist/engine/view/transformer/pure.d.ts +17 -0
- package/dist/engine/view/transformer/pure.js +124 -0
- package/dist/engine/view/transformer/pure.js.map +1 -0
- package/dist/engine/view/transformer/types.d.ts +31 -0
- package/dist/engine/view/transformer/types.js +16 -0
- package/dist/engine/view/transformer/types.js.map +1 -0
- package/dist/engine/view/transformer/visitors/application.visitor.d.ts +8 -0
- package/dist/engine/view/transformer/visitors/application.visitor.js +37 -0
- package/dist/engine/view/transformer/visitors/application.visitor.js.map +1 -0
- package/dist/engine/view/transformer/visitors/html.visitor.d.ts +8 -0
- package/dist/engine/view/transformer/visitors/html.visitor.js +161 -0
- package/dist/engine/view/transformer/visitors/html.visitor.js.map +1 -0
- package/dist/engine/view/transformer/visitors/index.d.ts +12 -0
- package/dist/engine/view/transformer/visitors/index.js +27 -0
- package/dist/engine/view/transformer/visitors/index.js.map +1 -0
- package/dist/engine/view/transformer/visitors/interface.d.ts +53 -0
- package/dist/engine/view/transformer/visitors/interface.js +8 -0
- package/dist/engine/view/transformer/visitors/interface.js.map +1 -0
- package/dist/engine/view/transformer/visitors/operation.visitor.d.ts +9 -0
- package/dist/engine/view/transformer/visitors/operation.visitor.js +122 -0
- package/dist/engine/view/transformer/visitors/operation.visitor.js.map +1 -0
- package/dist/engine/view/transformer/visitors/view-link.visitor.d.ts +15 -0
- package/dist/engine/view/transformer/visitors/view-link.visitor.js +98 -0
- package/dist/engine/view/transformer/visitors/view-link.visitor.js.map +1 -0
- package/dist/engine/view/transformer/visitors/view.visitor.d.ts +8 -0
- package/dist/engine/view/transformer/visitors/view.visitor.js +43 -0
- package/dist/engine/view/transformer/visitors/view.visitor.js.map +1 -0
- package/dist/engine/view/types.d.ts +70 -0
- package/dist/engine/view/types.js +17 -0
- package/dist/engine/view/types.js.map +1 -0
- package/dist/facades/facades.d.ts +40 -0
- package/dist/facades/facades.js +66 -0
- package/dist/facades/facades.js.map +1 -0
- package/dist/facades/index.d.ts +13 -0
- package/dist/facades/index.js +15 -0
- package/dist/facades/index.js.map +1 -0
- package/dist/factory/createKernel.d.ts +37 -0
- package/dist/factory/createKernel.js +42 -0
- package/dist/factory/createKernel.js.map +1 -0
- package/dist/factory/index.d.ts +9 -0
- package/dist/factory/index.js +10 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/browser.d.ts +20 -0
- package/dist/internal/browser.js +20 -0
- package/dist/internal/browser.js.map +1 -0
- package/dist/kernel/index.d.ts +120 -0
- package/dist/kernel/index.js +328 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/spi/app/aoapp.d.ts +86 -0
- package/dist/spi/app/aoapp.js +39 -0
- package/dist/spi/app/aoapp.js.map +1 -0
- package/dist/spi/app/app-config.interface.d.ts +9 -0
- package/dist/spi/app/app-config.interface.js +2 -0
- package/dist/spi/app/app-config.interface.js.map +1 -0
- package/dist/spi/app/app-factory.interface.d.ts +78 -0
- package/dist/spi/app/app-factory.interface.js +49 -0
- package/dist/spi/app/app-factory.interface.js.map +1 -0
- package/dist/spi/app/app-kernel.interface.d.ts +139 -0
- package/dist/spi/app/app-kernel.interface.js +2 -0
- package/dist/spi/app/app-kernel.interface.js.map +1 -0
- package/dist/spi/app/app.interface.d.ts +84 -0
- package/dist/spi/app/app.interface.js +8 -0
- package/dist/spi/app/app.interface.js.map +1 -0
- package/dist/spi/app/index.d.ts +26 -0
- package/dist/spi/app/index.js +13 -0
- package/dist/spi/app/index.js.map +1 -0
- package/dist/spi/app/public-types.d.ts +309 -0
- package/dist/spi/app/public-types.js +17 -0
- package/dist/spi/app/public-types.js.map +1 -0
- package/dist/spi/app/ref-exporter.interface.d.ts +23 -0
- package/dist/spi/app/ref-exporter.interface.js +10 -0
- package/dist/spi/app/ref-exporter.interface.js.map +1 -0
- package/dist/spi/app/store.interface.d.ts +45 -0
- package/dist/spi/app/store.interface.js +11 -0
- package/dist/spi/app/store.interface.js.map +1 -0
- package/dist/spi/app/view-context-core.interface.d.ts +50 -0
- package/dist/spi/app/view-context-core.interface.js +8 -0
- package/dist/spi/app/view-context-core.interface.js.map +1 -0
- package/dist/spi/app/view-context-ext.interface.d.ts +79 -0
- package/dist/spi/app/view-context-ext.interface.js +19 -0
- package/dist/spi/app/view-context-ext.interface.js.map +1 -0
- package/dist/spi/app/view-factory.interface.d.ts +46 -0
- package/dist/spi/app/view-factory.interface.js +2 -0
- package/dist/spi/app/view-factory.interface.js.map +1 -0
- package/dist/spi/app/view-link.types.d.ts +136 -0
- package/dist/spi/app/view-link.types.js +19 -0
- package/dist/spi/app/view-link.types.js.map +1 -0
- package/dist/spi/app/view-tree.interface.d.ts +254 -0
- package/dist/spi/app/view-tree.interface.js +13 -0
- package/dist/spi/app/view-tree.interface.js.map +1 -0
- package/dist/spi/app/view.interface.d.ts +122 -0
- package/dist/spi/app/view.interface.js +15 -0
- package/dist/spi/app/view.interface.js.map +1 -0
- package/dist/spi/bridge/bridge.interface.d.ts +118 -0
- package/dist/spi/bridge/bridge.interface.js +32 -0
- package/dist/spi/bridge/bridge.interface.js.map +1 -0
- package/dist/spi/bridge/index.d.ts +8 -0
- package/dist/spi/bridge/index.js +9 -0
- package/dist/spi/bridge/index.js.map +1 -0
- package/dist/spi/component-factory.interface.d.ts +123 -0
- package/dist/spi/component-factory.interface.js +15 -0
- package/dist/spi/component-factory.interface.js.map +1 -0
- package/dist/spi/config/define-config.d.ts +31 -0
- package/dist/spi/config/define-config.js +72 -0
- package/dist/spi/config/define-config.js.map +1 -0
- package/dist/spi/config/domains/bridge.config.d.ts +21 -0
- package/dist/spi/config/domains/bridge.config.js +10 -0
- package/dist/spi/config/domains/bridge.config.js.map +1 -0
- package/dist/spi/config/domains/lock.config.d.ts +20 -0
- package/dist/spi/config/domains/lock.config.js +10 -0
- package/dist/spi/config/domains/lock.config.js.map +1 -0
- package/dist/spi/config/domains/logger.config.d.ts +28 -0
- package/dist/spi/config/domains/logger.config.js +11 -0
- package/dist/spi/config/domains/logger.config.js.map +1 -0
- package/dist/spi/config/domains/snapshot.config.d.ts +20 -0
- package/dist/spi/config/domains/snapshot.config.js +10 -0
- package/dist/spi/config/domains/snapshot.config.js.map +1 -0
- package/dist/spi/config/domains/transform.config.d.ts +28 -0
- package/dist/spi/config/domains/transform.config.js +11 -0
- package/dist/spi/config/domains/transform.config.js.map +1 -0
- package/dist/spi/config/domains/worker.config.d.ts +54 -0
- package/dist/spi/config/domains/worker.config.js +15 -0
- package/dist/spi/config/domains/worker.config.js.map +1 -0
- package/dist/spi/config/index.d.ts +16 -0
- package/dist/spi/config/index.js +18 -0
- package/dist/spi/config/index.js.map +1 -0
- package/dist/spi/config/types.d.ts +38 -0
- package/dist/spi/config/types.js +7 -0
- package/dist/spi/config/types.js.map +1 -0
- package/dist/spi/config/validate.d.ts +12 -0
- package/dist/spi/config/validate.js +90 -0
- package/dist/spi/config/validate.js.map +1 -0
- package/dist/spi/core/errors.d.ts +117 -0
- package/dist/spi/core/errors.js +233 -0
- package/dist/spi/core/errors.js.map +1 -0
- package/dist/spi/core/id-factory.d.ts +85 -0
- package/dist/spi/core/id-factory.js +119 -0
- package/dist/spi/core/id-factory.js.map +1 -0
- package/dist/spi/core/index.d.ts +21 -0
- package/dist/spi/core/index.js +25 -0
- package/dist/spi/core/index.js.map +1 -0
- package/dist/spi/core/llm-output.d.ts +74 -0
- package/dist/spi/core/llm-output.js +12 -0
- package/dist/spi/core/llm-output.js.map +1 -0
- package/dist/spi/core/operation-log.d.ts +133 -0
- package/dist/spi/core/operation-log.js +13 -0
- package/dist/spi/core/operation-log.js.map +1 -0
- package/dist/spi/core/operations.d.ts +198 -0
- package/dist/spi/core/operations.js +13 -0
- package/dist/spi/core/operations.js.map +1 -0
- package/dist/spi/core/signals.d.ts +16 -0
- package/dist/spi/core/signals.js +7 -0
- package/dist/spi/core/signals.js.map +1 -0
- package/dist/spi/core/snapshot.d.ts +77 -0
- package/dist/spi/core/snapshot.js +18 -0
- package/dist/spi/core/snapshot.js.map +1 -0
- package/dist/spi/core/tool-call.d.ts +60 -0
- package/dist/spi/core/tool-call.js +10 -0
- package/dist/spi/core/tool-call.js.map +1 -0
- package/dist/spi/core/types.d.ts +68 -0
- package/dist/spi/core/types.js +8 -0
- package/dist/spi/core/types.js.map +1 -0
- package/dist/spi/index.d.ts +31 -0
- package/dist/spi/index.js +57 -0
- package/dist/spi/index.js.map +1 -0
- package/dist/spi/runtime/app-host.interface.d.ts +142 -0
- package/dist/spi/runtime/app-host.interface.js +10 -0
- package/dist/spi/runtime/app-host.interface.js.map +1 -0
- package/dist/spi/runtime/app-installer.interface.d.ts +33 -0
- package/dist/spi/runtime/app-installer.interface.js +2 -0
- package/dist/spi/runtime/app-installer.interface.js.map +1 -0
- package/dist/spi/runtime/context.interface.d.ts +10 -0
- package/dist/spi/runtime/context.interface.js +2 -0
- package/dist/spi/runtime/context.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-context.interface.d.ts +45 -0
- package/dist/spi/runtime/desktop-context.interface.js +10 -0
- package/dist/spi/runtime/desktop-context.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-dom.interface.d.ts +48 -0
- package/dist/spi/runtime/desktop-dom.interface.js +13 -0
- package/dist/spi/runtime/desktop-dom.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-lifecycle.interface.d.ts +23 -0
- package/dist/spi/runtime/desktop-lifecycle.interface.js +2 -0
- package/dist/spi/runtime/desktop-lifecycle.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-lock.interface.d.ts +50 -0
- package/dist/spi/runtime/desktop-lock.interface.js +2 -0
- package/dist/spi/runtime/desktop-lock.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-manager.interface.d.ts +22 -0
- package/dist/spi/runtime/desktop-manager.interface.js +13 -0
- package/dist/spi/runtime/desktop-manager.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-repository.interface.d.ts +8 -0
- package/dist/spi/runtime/desktop-repository.interface.js +2 -0
- package/dist/spi/runtime/desktop-repository.interface.js.map +1 -0
- package/dist/spi/runtime/desktop-state-accessor.interface.d.ts +22 -0
- package/dist/spi/runtime/desktop-state-accessor.interface.js +2 -0
- package/dist/spi/runtime/desktop-state-accessor.interface.js.map +1 -0
- package/dist/spi/runtime/dispatcher.interface.d.ts +34 -0
- package/dist/spi/runtime/dispatcher.interface.js +10 -0
- package/dist/spi/runtime/dispatcher.interface.js.map +1 -0
- package/dist/spi/runtime/index.d.ts +28 -0
- package/dist/spi/runtime/index.js +11 -0
- package/dist/spi/runtime/index.js.map +1 -0
- package/dist/spi/runtime/kernel.interface.d.ts +221 -0
- package/dist/spi/runtime/kernel.interface.js +7 -0
- package/dist/spi/runtime/kernel.interface.js.map +1 -0
- package/dist/spi/runtime/llm-output-channel.interface.d.ts +81 -0
- package/dist/spi/runtime/llm-output-channel.interface.js +12 -0
- package/dist/spi/runtime/llm-output-channel.interface.js.map +1 -0
- package/dist/spi/runtime/signal.interface.d.ts +80 -0
- package/dist/spi/runtime/signal.interface.js +9 -0
- package/dist/spi/runtime/signal.interface.js.map +1 -0
- package/dist/spi/runtime/snapshot.interface.d.ts +126 -0
- package/dist/spi/runtime/snapshot.interface.js +14 -0
- package/dist/spi/runtime/snapshot.interface.js.map +1 -0
- package/dist/spi/runtime/transformer.interface.d.ts +47 -0
- package/dist/spi/runtime/transformer.interface.js +10 -0
- package/dist/spi/runtime/transformer.interface.js.map +1 -0
- package/dist/spi/runtime/worker-message.interface.d.ts +80 -0
- package/dist/spi/runtime/worker-message.interface.js +49 -0
- package/dist/spi/runtime/worker-message.interface.js.map +1 -0
- package/dist/spi/runtime/worker-runtime.interface.d.ts +177 -0
- package/dist/spi/runtime/worker-runtime.interface.js +14 -0
- package/dist/spi/runtime/worker-runtime.interface.js.map +1 -0
- package/dist/spi/worker-protocol/index.d.ts +26 -0
- package/dist/spi/worker-protocol/index.js +29 -0
- package/dist/spi/worker-protocol/index.js.map +1 -0
- package/dist/spi/worker-protocol/messages.d.ts +257 -0
- package/dist/spi/worker-protocol/messages.js +42 -0
- package/dist/spi/worker-protocol/messages.js.map +1 -0
- package/dist/spi/worker-protocol/types.d.ts +12 -0
- package/dist/spi/worker-protocol/types.js +16 -0
- package/dist/spi/worker-protocol/types.js.map +1 -0
- package/dist/worker-runtime/app-kernel/AppKernel.d.ts +178 -0
- package/dist/worker-runtime/app-kernel/AppKernel.js +622 -0
- package/dist/worker-runtime/app-kernel/AppKernel.js.map +1 -0
- package/dist/worker-runtime/app-kernel/index.d.ts +23 -0
- package/dist/worker-runtime/app-kernel/index.js +23 -0
- package/dist/worker-runtime/app-kernel/index.js.map +1 -0
- package/dist/worker-runtime/app-kernel/view-registry.d.ts +85 -0
- package/dist/worker-runtime/app-kernel/view-registry.js +119 -0
- package/dist/worker-runtime/app-kernel/view-registry.js.map +1 -0
- package/dist/worker-runtime/app-kernel/view-tree.d.ts +222 -0
- package/dist/worker-runtime/app-kernel/view-tree.js +682 -0
- package/dist/worker-runtime/app-kernel/view-tree.js.map +1 -0
- package/dist/worker-runtime/index.d.ts +16 -0
- package/dist/worker-runtime/index.js +731 -0
- package/dist/worker-runtime/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AOTUI Runtime - ViewTree Implementation
|
|
3
|
+
*
|
|
4
|
+
* [方案 B] 从 @aotui/sdk 迁移到 @aotui/runtime/worker-runtime。
|
|
5
|
+
*
|
|
6
|
+
* 这是 IViewTree 的实现,管理 App 内部的 View 层级结构。
|
|
7
|
+
* 作为 Worker Kernel 的一部分,负责:
|
|
8
|
+
* - 添加/移除 Views
|
|
9
|
+
* - 挂载/卸载 Views
|
|
10
|
+
* - 渲染树结构
|
|
11
|
+
* - 操作路由
|
|
12
|
+
*
|
|
13
|
+
* @module @aotui/runtime/worker-runtime/app-kernel
|
|
14
|
+
*/
|
|
15
|
+
import { AOTUIError } from '../../spi/core/errors.js';
|
|
16
|
+
// Maximum tree depth to prevent stack overflow
|
|
17
|
+
const MAX_TREE_DEPTH = 20;
|
|
18
|
+
/**
|
|
19
|
+
* ViewTree Implementation
|
|
20
|
+
*
|
|
21
|
+
* Runtime's own implementation of the IViewTree interface.
|
|
22
|
+
* This is used by AppKernel to manage the App's view hierarchy.
|
|
23
|
+
*/
|
|
24
|
+
export class ViewTree {
|
|
25
|
+
nodes = new Map();
|
|
26
|
+
_rootId = null;
|
|
27
|
+
contextFactory;
|
|
28
|
+
/**
|
|
29
|
+
* @param contextFactory - Factory function to create ViewContext for each View
|
|
30
|
+
*/
|
|
31
|
+
constructor(contextFactory) {
|
|
32
|
+
this.contextFactory = contextFactory;
|
|
33
|
+
}
|
|
34
|
+
get rootId() {
|
|
35
|
+
return this._rootId;
|
|
36
|
+
}
|
|
37
|
+
getNode(viewId) {
|
|
38
|
+
return this.nodes.get(viewId);
|
|
39
|
+
}
|
|
40
|
+
getView(viewId) {
|
|
41
|
+
return this.nodes.get(viewId)?.view;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Add View to tree
|
|
45
|
+
*
|
|
46
|
+
* Includes depth checking and cycle detection.
|
|
47
|
+
*/
|
|
48
|
+
addView(view, parentId) {
|
|
49
|
+
// Check if already exists
|
|
50
|
+
if (this.nodes.has(view.id)) {
|
|
51
|
+
throw new AOTUIError('VIEW_DUPLICATE', { viewId: view.id });
|
|
52
|
+
}
|
|
53
|
+
// Validate parent exists
|
|
54
|
+
if (parentId !== null && !this.nodes.has(parentId)) {
|
|
55
|
+
throw new AOTUIError('VIEW_PARENT_NOT_FOUND', { parentId });
|
|
56
|
+
}
|
|
57
|
+
// Check depth limit
|
|
58
|
+
if (parentId !== null) {
|
|
59
|
+
const depth = this.getDepth(parentId);
|
|
60
|
+
if (depth >= MAX_TREE_DEPTH) {
|
|
61
|
+
throw new AOTUIError('CONFIG_INVALID', {
|
|
62
|
+
reason: `Tree depth would exceed ${MAX_TREE_DEPTH}. Current depth at parent ${parentId}: ${depth}`
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Create node (using internal mutable type)
|
|
67
|
+
const node = {
|
|
68
|
+
view,
|
|
69
|
+
parentId,
|
|
70
|
+
childIds: [],
|
|
71
|
+
mounted: false
|
|
72
|
+
};
|
|
73
|
+
this.nodes.set(view.id, node);
|
|
74
|
+
// Set root or add to parent's children
|
|
75
|
+
if (parentId === null) {
|
|
76
|
+
if (this._rootId !== null) {
|
|
77
|
+
throw new AOTUIError('VIEW_ROOT_EXISTS', {});
|
|
78
|
+
}
|
|
79
|
+
this._rootId = view.id;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const parent = this.nodes.get(parentId);
|
|
83
|
+
if (!parent) {
|
|
84
|
+
throw new AOTUIError('VIEW_PARENT_NOT_FOUND', { parentId });
|
|
85
|
+
}
|
|
86
|
+
if (!parent.childIds.includes(view.id)) {
|
|
87
|
+
parent.childIds.push(view.id);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Calculate node depth (distance from root to this node)
|
|
93
|
+
*/
|
|
94
|
+
getDepth(viewId) {
|
|
95
|
+
let depth = 0;
|
|
96
|
+
let currentId = viewId;
|
|
97
|
+
const visited = new Set();
|
|
98
|
+
while (currentId !== null) {
|
|
99
|
+
// Cycle detection - should never happen but defensive programming
|
|
100
|
+
if (visited.has(currentId)) {
|
|
101
|
+
throw new AOTUIError('INTERNAL_ERROR', {
|
|
102
|
+
message: `Cycle detected in view tree at ${currentId}. This indicates a bug in ViewTree implementation.`
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
visited.add(currentId);
|
|
106
|
+
const node = this.nodes.get(currentId);
|
|
107
|
+
if (!node)
|
|
108
|
+
break;
|
|
109
|
+
currentId = node.parentId;
|
|
110
|
+
depth++;
|
|
111
|
+
}
|
|
112
|
+
return depth;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Remove View (and its subtree)
|
|
116
|
+
*/
|
|
117
|
+
removeView(viewId) {
|
|
118
|
+
const node = this.nodes.get(viewId);
|
|
119
|
+
if (!node)
|
|
120
|
+
return;
|
|
121
|
+
// Recursively remove all children
|
|
122
|
+
for (const childId of [...node.childIds]) {
|
|
123
|
+
this.removeView(childId);
|
|
124
|
+
}
|
|
125
|
+
// Remove from parent's children list
|
|
126
|
+
if (node.parentId !== null) {
|
|
127
|
+
const parent = this.nodes.get(node.parentId);
|
|
128
|
+
if (parent) {
|
|
129
|
+
parent.childIds = parent.childIds.filter(id => id !== viewId);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Clear root if this is root
|
|
133
|
+
if (this._rootId === viewId) {
|
|
134
|
+
this._rootId = null;
|
|
135
|
+
}
|
|
136
|
+
// Remove node
|
|
137
|
+
this.nodes.delete(viewId);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Mount View
|
|
141
|
+
*/
|
|
142
|
+
async mountView(viewId) {
|
|
143
|
+
const node = this.nodes.get(viewId);
|
|
144
|
+
if (!node) {
|
|
145
|
+
throw new AOTUIError('VIEW_NOT_FOUND', { viewId });
|
|
146
|
+
}
|
|
147
|
+
if (node.mounted) {
|
|
148
|
+
return; // Already mounted, idempotent
|
|
149
|
+
}
|
|
150
|
+
// Mount parent first if not mounted
|
|
151
|
+
if (node.parentId !== null) {
|
|
152
|
+
const parent = this.nodes.get(node.parentId);
|
|
153
|
+
if (parent && !parent.mounted) {
|
|
154
|
+
await this.mountView(node.parentId);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Create context and call onMount
|
|
158
|
+
const context = this.contextFactory(viewId);
|
|
159
|
+
await node.view.onMount(context);
|
|
160
|
+
node.mounted = true;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Dismount View
|
|
164
|
+
*/
|
|
165
|
+
async dismountView(viewId) {
|
|
166
|
+
const node = this.nodes.get(viewId);
|
|
167
|
+
if (!node) {
|
|
168
|
+
throw new AOTUIError('VIEW_NOT_FOUND', { viewId });
|
|
169
|
+
}
|
|
170
|
+
if (!node.mounted) {
|
|
171
|
+
return; // Already dismounted, idempotent
|
|
172
|
+
}
|
|
173
|
+
// Dismount all children first (from leaves)
|
|
174
|
+
for (const childId of [...node.childIds]) {
|
|
175
|
+
await this.dismountView(childId);
|
|
176
|
+
}
|
|
177
|
+
// Call onDismount
|
|
178
|
+
await node.view.onDismount();
|
|
179
|
+
node.mounted = false;
|
|
180
|
+
// [Orphan Cleanup] If this view has no corresponding ViewLink (mountableEntry),
|
|
181
|
+
// it's an orphan and should be removed from the tree.
|
|
182
|
+
// This happens when data moves (e.g., todo from pending to done) and the
|
|
183
|
+
// ViewLink at the original position no longer exists.
|
|
184
|
+
// V2 Update: Check uniqueIdBindings as well?
|
|
185
|
+
// Actually, V2 views are NEVER in mountableEntries (V1 only).
|
|
186
|
+
// So V2 views should ALWAYS be removed on dismount.
|
|
187
|
+
const isLegacyMountable = this.mountableEntries.has(viewId);
|
|
188
|
+
console.log(`[ViewTree] dismountView: isLegacyMountable=${isLegacyMountable}`);
|
|
189
|
+
if (!isLegacyMountable) {
|
|
190
|
+
console.log(`[ViewTree] dismountView: Removing orphan/V2 view ${viewId}`);
|
|
191
|
+
this.removeView(viewId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Get all mounted Views
|
|
196
|
+
*/
|
|
197
|
+
getMountedViews() {
|
|
198
|
+
return Array.from(this.nodes.values())
|
|
199
|
+
.filter(n => n.mounted)
|
|
200
|
+
.map(n => n.view);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get View's full path (from root to this node)
|
|
204
|
+
*/
|
|
205
|
+
getPath(viewId) {
|
|
206
|
+
const path = [];
|
|
207
|
+
let currentId = viewId;
|
|
208
|
+
while (currentId !== null) {
|
|
209
|
+
path.unshift(currentId);
|
|
210
|
+
const node = this.nodes.get(currentId);
|
|
211
|
+
currentId = node?.parentId ?? null;
|
|
212
|
+
}
|
|
213
|
+
return path;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get child Views
|
|
217
|
+
*/
|
|
218
|
+
getChildren(viewId) {
|
|
219
|
+
const node = this.nodes.get(viewId);
|
|
220
|
+
if (!node)
|
|
221
|
+
return [];
|
|
222
|
+
return node.childIds
|
|
223
|
+
.map(id => this.nodes.get(id)?.view)
|
|
224
|
+
.filter((v) => v !== undefined);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Render View Tree state
|
|
228
|
+
*
|
|
229
|
+
* [RFC-007] Output format:
|
|
230
|
+
* ## Application View Tree
|
|
231
|
+
* - [Navigation](view:view_0, mounted)
|
|
232
|
+
* - [Conversations](view:view_1, mounted)
|
|
233
|
+
* ↳ [Contact Detail](link:CD_0)
|
|
234
|
+
*
|
|
235
|
+
* Only mounted views are shown. Unmounted ViewLinks use link: protocol.
|
|
236
|
+
*/
|
|
237
|
+
renderTree() {
|
|
238
|
+
if (this._rootId === null) {
|
|
239
|
+
return '## Application View Tree\n- No views registered.';
|
|
240
|
+
}
|
|
241
|
+
// [RFC-007] Only render if root is mounted
|
|
242
|
+
const rootNode = this.nodes.get(this._rootId);
|
|
243
|
+
if (!rootNode || !rootNode.mounted) {
|
|
244
|
+
return '## Application View Tree\n- No views mounted.';
|
|
245
|
+
}
|
|
246
|
+
const lines = ['## Application View Tree'];
|
|
247
|
+
this.renderNodeV2(this._rootId, 0, lines);
|
|
248
|
+
return lines.join('\n');
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* [RFC-007] Enhanced node renderer - only mounted views
|
|
252
|
+
*/
|
|
253
|
+
renderNodeV2(viewId, depth, lines) {
|
|
254
|
+
const node = this.nodes.get(viewId);
|
|
255
|
+
if (!node || !node.mounted)
|
|
256
|
+
return; // [RFC-007] Only show mounted
|
|
257
|
+
const indent = ' '.repeat(depth);
|
|
258
|
+
const name = node.view.displayName || node.view.name || viewId;
|
|
259
|
+
// [RFC-007] Only "mounted" status is shown
|
|
260
|
+
lines.push(`${indent}- [${name}](view:${viewId}, mounted)`);
|
|
261
|
+
// Render mounted child nodes first
|
|
262
|
+
for (const childId of node.childIds) {
|
|
263
|
+
const childNode = this.nodes.get(childId);
|
|
264
|
+
if (childNode && childNode.mounted) {
|
|
265
|
+
this.renderNodeV2(childId, depth + 1, lines);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// [RFC-007] Render unmounted ViewLinks as sub-items
|
|
269
|
+
const links = this.getLinksInParent(viewId);
|
|
270
|
+
for (const link of links) {
|
|
271
|
+
// Check if this link is bound to a mounted view (skip if already rendered)
|
|
272
|
+
const boundViewId = this.getBoundViewId(link.viewType, link.uniqueId);
|
|
273
|
+
if (boundViewId) {
|
|
274
|
+
const boundNode = this.nodes.get(boundViewId);
|
|
275
|
+
if (boundNode && boundNode.mounted) {
|
|
276
|
+
continue; // Already rendered as mounted view
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Render as unmounted ViewLink with link: protocol
|
|
280
|
+
const linkIndent = ' '.repeat(depth + 1);
|
|
281
|
+
const label = link.label || link.viewType || 'View';
|
|
282
|
+
lines.push(`${linkIndent}↳ [${label}](link:${link.linkId})`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* @deprecated Use renderNodeV2 for RFC-007 compliance
|
|
287
|
+
*/
|
|
288
|
+
renderNode(viewId, depth, lines) {
|
|
289
|
+
const node = this.nodes.get(viewId);
|
|
290
|
+
if (!node)
|
|
291
|
+
return;
|
|
292
|
+
const indent = ' '.repeat(depth);
|
|
293
|
+
const status = node.mounted ? ', mounted' : '';
|
|
294
|
+
const name = node.view.name || viewId;
|
|
295
|
+
lines.push(`${indent}- [${name}](view:${viewId}${status})`);
|
|
296
|
+
// Render instantiated children
|
|
297
|
+
for (const childId of node.childIds) {
|
|
298
|
+
// Check if this child is an instantiated view or just a mountable placeholder
|
|
299
|
+
if (this.nodes.has(childId)) {
|
|
300
|
+
this.renderNode(childId, depth + 1, lines);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// It's a mountable view (not yet instantiated)
|
|
304
|
+
const entry = this.mountableEntries.get(childId);
|
|
305
|
+
if (entry) {
|
|
306
|
+
const childIndent = ' '.repeat(depth + 1);
|
|
307
|
+
// Use factory's name or generate from factory function
|
|
308
|
+
const mountableName = entry.label || `View ${childId}`;
|
|
309
|
+
lines.push(`${childIndent}- [${mountableName}](view:${childId})`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Render all mounted View contents
|
|
316
|
+
*
|
|
317
|
+
* SDK View components output HTML with view attribute (e.g., <div view="Chat">),
|
|
318
|
+
* Transformer will convert to <view> tag.
|
|
319
|
+
*/
|
|
320
|
+
renderMountedViews() {
|
|
321
|
+
const mountedViews = this.getMountedViews();
|
|
322
|
+
return mountedViews.map(view => {
|
|
323
|
+
// view.render() returns SDK-rendered HTML (with view attribute)
|
|
324
|
+
// Transformer will recognize view attribute and convert to <view> tag
|
|
325
|
+
return view.render();
|
|
326
|
+
}).join('\n\n');
|
|
327
|
+
}
|
|
328
|
+
// ═══════════════════════════════════════════════════════════════
|
|
329
|
+
// Mountable View API (ViewLink Redesign)
|
|
330
|
+
// ═══════════════════════════════════════════════════════════════
|
|
331
|
+
mountableEntries = new Map();
|
|
332
|
+
/**
|
|
333
|
+
* Register a mountable view (unmounted state)
|
|
334
|
+
*
|
|
335
|
+
* Called by ViewLink. The view is NOT created yet - only the factory and props
|
|
336
|
+
* are cached. When Agent calls mount_view, we use these to create the actual View.
|
|
337
|
+
*
|
|
338
|
+
* @param viewId - Pre-generated view ID (from FunctionalApp)
|
|
339
|
+
* @param parentId - Parent view ID (where the ViewLink is rendered)
|
|
340
|
+
* @param factory - View factory function
|
|
341
|
+
* @param props - Props to pass when mounted
|
|
342
|
+
* @param label - Display label (optional)
|
|
343
|
+
*/
|
|
344
|
+
registerMountableView(viewId, parentId, factory, props, label) {
|
|
345
|
+
const entry = {
|
|
346
|
+
factory,
|
|
347
|
+
props,
|
|
348
|
+
parentId,
|
|
349
|
+
label
|
|
350
|
+
};
|
|
351
|
+
this.mountableEntries.set(viewId, entry);
|
|
352
|
+
// Add to parent's children (for tree rendering)
|
|
353
|
+
const parent = this.nodes.get(parentId);
|
|
354
|
+
if (parent) {
|
|
355
|
+
if (!parent.childIds.includes(viewId)) {
|
|
356
|
+
parent.childIds.push(viewId);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Unregister a mountable view
|
|
362
|
+
*
|
|
363
|
+
* Called when ViewLink is removed from React tree.
|
|
364
|
+
*
|
|
365
|
+
* IMPORTANT: If the view has already been mounted (via mount_view),
|
|
366
|
+
* we should NOT remove it from the tree. Only clean up the mountable entry.
|
|
367
|
+
*/
|
|
368
|
+
unregisterMountableView(viewId) {
|
|
369
|
+
const entry = this.mountableEntries.get(viewId);
|
|
370
|
+
if (!entry)
|
|
371
|
+
return;
|
|
372
|
+
// Check if this view has been mounted as an actual View
|
|
373
|
+
const node = this.nodes.get(viewId);
|
|
374
|
+
if (node && node.mounted) {
|
|
375
|
+
// View is mounted - DO NOT remove it!
|
|
376
|
+
// Just clean up the mountable entry, keep the actual view in the tree
|
|
377
|
+
this.mountableEntries.delete(viewId);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
// View is not mounted - safe to remove from parent's children
|
|
381
|
+
const parent = this.nodes.get(entry.parentId);
|
|
382
|
+
if (parent) {
|
|
383
|
+
parent.childIds = parent.childIds.filter(id => id !== viewId);
|
|
384
|
+
}
|
|
385
|
+
// If it exists as an unmounted node, remove it
|
|
386
|
+
if (this.nodes.has(viewId)) {
|
|
387
|
+
this.removeView(viewId);
|
|
388
|
+
}
|
|
389
|
+
this.mountableEntries.delete(viewId);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Get mountable entry (factory + props) for a view ID
|
|
393
|
+
*/
|
|
394
|
+
getMountableEntry(viewId) {
|
|
395
|
+
return this.mountableEntries.get(viewId);
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Mount a previously registered mountable view
|
|
399
|
+
*
|
|
400
|
+
* Called by Runtime when Agent invokes mount_view.
|
|
401
|
+
* Creates the actual View instance using cached factory and props.
|
|
402
|
+
*/
|
|
403
|
+
async mountMountableView(viewId) {
|
|
404
|
+
const entry = this.mountableEntries.get(viewId);
|
|
405
|
+
if (!entry) {
|
|
406
|
+
throw new AOTUIError('VIEW_MOUNTABLE_NOT_FOUND', { viewId });
|
|
407
|
+
}
|
|
408
|
+
// Check if already mounted as actual view
|
|
409
|
+
if (this.nodes.has(viewId)) {
|
|
410
|
+
// Already mounted, just ensure mounted flag
|
|
411
|
+
await this.mountView(viewId);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
// Create the actual View instance
|
|
415
|
+
// Defensive: Handle both Callable Factory (Proxy) and Object Factory
|
|
416
|
+
let view;
|
|
417
|
+
if (typeof entry.factory === 'function') {
|
|
418
|
+
view = entry.factory(viewId, entry.props);
|
|
419
|
+
}
|
|
420
|
+
else if (typeof entry.factory === 'object' && entry.factory !== null && 'create' in entry.factory) {
|
|
421
|
+
// Fallback for when Proxy mechanism fails or factory is passed as object
|
|
422
|
+
view = entry.factory.create(viewId, entry.props);
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
console.error('[ViewTree] Invalid factory:', entry.factory);
|
|
426
|
+
throw new AOTUIError('VIEW_INVALID_FACTORY', { viewId });
|
|
427
|
+
}
|
|
428
|
+
// Add to tree
|
|
429
|
+
this.addView(view, entry.parentId);
|
|
430
|
+
// Mount it
|
|
431
|
+
await this.mountView(viewId);
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Check if a view ID is a registered mountable view (not yet instantiated)
|
|
435
|
+
*/
|
|
436
|
+
isMountableView(viewId) {
|
|
437
|
+
return this.mountableEntries.has(viewId) && !this.nodes.has(viewId);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Get all mountable (unmounted) children of a view
|
|
441
|
+
*/
|
|
442
|
+
getMountableChildren(parentId) {
|
|
443
|
+
return Array.from(this.mountableEntries.entries())
|
|
444
|
+
.filter(([id, entry]) => entry.parentId === parentId && !this.nodes.has(id))
|
|
445
|
+
.map(([id]) => id);
|
|
446
|
+
}
|
|
447
|
+
// ═══════════════════════════════════════════════════════════════
|
|
448
|
+
// [RFC-006] ViewLink API - Decoupled ViewLink/View IDs
|
|
449
|
+
// ═══════════════════════════════════════════════════════════════
|
|
450
|
+
/**
|
|
451
|
+
* LinkEntry storage by parent view
|
|
452
|
+
* Map<parentViewId, Map<linkId, LinkEntry>>
|
|
453
|
+
*/
|
|
454
|
+
linksByParent = new Map();
|
|
455
|
+
/**
|
|
456
|
+
* LinkID counter by parent view and prefix
|
|
457
|
+
* Map<parentViewId, Map<prefix, counter>>
|
|
458
|
+
*/
|
|
459
|
+
linkIdCounters = new Map();
|
|
460
|
+
/**
|
|
461
|
+
* Binding: ViewType:UniqueId -> ViewID
|
|
462
|
+
* Used for cross-snapshot matching
|
|
463
|
+
*/
|
|
464
|
+
uniqueIdBindings = new Map();
|
|
465
|
+
/**
|
|
466
|
+
* Allocate a unique LinkID for a given prefix within a parent view
|
|
467
|
+
*/
|
|
468
|
+
allocateLinkId(parentId, prefix) {
|
|
469
|
+
let prefixCounters = this.linkIdCounters.get(parentId);
|
|
470
|
+
if (!prefixCounters) {
|
|
471
|
+
prefixCounters = new Map();
|
|
472
|
+
this.linkIdCounters.set(parentId, prefixCounters);
|
|
473
|
+
}
|
|
474
|
+
const current = prefixCounters.get(prefix) ?? 0;
|
|
475
|
+
prefixCounters.set(prefix, current + 1);
|
|
476
|
+
return `${prefix}_${current}`;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Register a ViewLink
|
|
480
|
+
*
|
|
481
|
+
* @param parentId - Parent View ID
|
|
482
|
+
* @param entry - Link entry data
|
|
483
|
+
*/
|
|
484
|
+
registerLink(parentId, entry) {
|
|
485
|
+
let links = this.linksByParent.get(parentId);
|
|
486
|
+
if (!links) {
|
|
487
|
+
links = new Map();
|
|
488
|
+
this.linksByParent.set(parentId, links);
|
|
489
|
+
}
|
|
490
|
+
// Check for duplicate LinkID
|
|
491
|
+
if (links.has(entry.linkId)) {
|
|
492
|
+
throw new AOTUIError('LINK_DUPLICATE', {
|
|
493
|
+
parentId,
|
|
494
|
+
linkId: entry.linkId
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
links.set(entry.linkId, entry);
|
|
498
|
+
// [DEBUG] Log registration
|
|
499
|
+
console.log(`[ViewTree] Registering link: ${entry.linkId}, factory type: ${typeof entry.factory}`);
|
|
500
|
+
if (typeof entry.factory !== 'function') {
|
|
501
|
+
console.error('[ViewTree] INVALID FACTORY REGISTRATION:', entry);
|
|
502
|
+
}
|
|
503
|
+
// Add to parent's children for tree rendering
|
|
504
|
+
const parent = this.nodes.get(parentId);
|
|
505
|
+
if (parent) {
|
|
506
|
+
const childId = entry.linkId; // For tree rendering only
|
|
507
|
+
if (!parent.childIds.includes(childId)) {
|
|
508
|
+
// We don't add unmounted links to childIds anymore
|
|
509
|
+
// They are rendered separately via linksByParent
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Unregister a ViewLink
|
|
515
|
+
*/
|
|
516
|
+
unregisterLink(parentId, linkId) {
|
|
517
|
+
const links = this.linksByParent.get(parentId);
|
|
518
|
+
if (!links)
|
|
519
|
+
return;
|
|
520
|
+
const entry = links.get(linkId);
|
|
521
|
+
if (!entry)
|
|
522
|
+
return;
|
|
523
|
+
// Check if a view was mounted from this link
|
|
524
|
+
const bindingKey = `${entry.viewType}:${entry.uniqueId}`;
|
|
525
|
+
const boundViewId = this.uniqueIdBindings.get(bindingKey);
|
|
526
|
+
if (boundViewId && this.nodes.has(boundViewId)) {
|
|
527
|
+
// View is mounted - keep it alive, just remove the link registration
|
|
528
|
+
// The view continues to exist until explicitly dismounted
|
|
529
|
+
}
|
|
530
|
+
links.delete(linkId);
|
|
531
|
+
if (links.size === 0) {
|
|
532
|
+
this.linksByParent.delete(parentId);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Get bound ViewID for a ViewType + UniqueID combination
|
|
537
|
+
*/
|
|
538
|
+
getBoundViewId(viewType, uniqueId) {
|
|
539
|
+
const bindingKey = `${viewType}:${uniqueId}`;
|
|
540
|
+
return this.uniqueIdBindings.get(bindingKey);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Mount a view via ViewLink
|
|
544
|
+
*
|
|
545
|
+
* Called when Agent executes mount(parent_view, link_id)
|
|
546
|
+
*
|
|
547
|
+
* @param parentId - Parent View ID
|
|
548
|
+
* @param linkId - Link ID
|
|
549
|
+
* @returns Mounted ViewID
|
|
550
|
+
*/
|
|
551
|
+
async mountByLink(parentId, linkId) {
|
|
552
|
+
const links = this.linksByParent.get(parentId);
|
|
553
|
+
if (!links) {
|
|
554
|
+
throw new AOTUIError('LINK_NOT_FOUND', { parentId, linkId });
|
|
555
|
+
}
|
|
556
|
+
const entry = links.get(linkId);
|
|
557
|
+
if (!entry) {
|
|
558
|
+
throw new AOTUIError('LINK_NOT_FOUND', { parentId, linkId });
|
|
559
|
+
}
|
|
560
|
+
// Check if already bound (idempotent)
|
|
561
|
+
const bindingKey = `${entry.viewType}:${entry.uniqueId}`;
|
|
562
|
+
const existingViewId = this.uniqueIdBindings.get(bindingKey);
|
|
563
|
+
if (existingViewId && this.nodes.has(existingViewId)) {
|
|
564
|
+
// Already mounted - ensure it's still mounted and return
|
|
565
|
+
const node = this.nodes.get(existingViewId);
|
|
566
|
+
if (node && !node.mounted) {
|
|
567
|
+
await this.mountView(existingViewId);
|
|
568
|
+
}
|
|
569
|
+
return existingViewId;
|
|
570
|
+
}
|
|
571
|
+
// Create new View - use mountable entry mechanism
|
|
572
|
+
// First, register as mountable entry (for compatibility with existing flow)
|
|
573
|
+
const viewId = `view_${this.nodes.size}`;
|
|
574
|
+
// Create the view instance
|
|
575
|
+
let view;
|
|
576
|
+
// console.log(`[ViewTree] Mounting link: ${linkId}, factory type: ${typeof entry.factory}`);
|
|
577
|
+
if (typeof entry.factory === 'function') {
|
|
578
|
+
view = entry.factory(viewId, entry.props);
|
|
579
|
+
}
|
|
580
|
+
else if (typeof entry.factory === 'object' && entry.factory !== null && typeof entry.factory.create === 'function') {
|
|
581
|
+
// Support Factory object
|
|
582
|
+
view = entry.factory.create(viewId, entry.props);
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
throw new AOTUIError('VIEW_INVALID_FACTORY', { viewId });
|
|
586
|
+
}
|
|
587
|
+
// Add view to tree
|
|
588
|
+
this.addView(view, parentId);
|
|
589
|
+
// Bind UniqueID to ViewID
|
|
590
|
+
this.uniqueIdBindings.set(bindingKey, viewId);
|
|
591
|
+
// Mount the view
|
|
592
|
+
await this.mountView(viewId);
|
|
593
|
+
return viewId;
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get all links in a parent view (for rendering)
|
|
597
|
+
*/
|
|
598
|
+
getLinksInParent(parentId) {
|
|
599
|
+
const links = this.linksByParent.get(parentId);
|
|
600
|
+
if (!links)
|
|
601
|
+
return [];
|
|
602
|
+
return Array.from(links.values());
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Reset link counters for a parent view
|
|
606
|
+
* Called at the start of each render cycle
|
|
607
|
+
*/
|
|
608
|
+
resetLinkCounters(parentId) {
|
|
609
|
+
this.linkIdCounters.delete(parentId);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Clear all links for a parent view
|
|
613
|
+
* Called when parent view is unmounted
|
|
614
|
+
*/
|
|
615
|
+
clearLinksForParent(parentId) {
|
|
616
|
+
this.linksByParent.delete(parentId);
|
|
617
|
+
this.linkIdCounters.delete(parentId);
|
|
618
|
+
}
|
|
619
|
+
// ═══════════════════════════════════════════════════════════════
|
|
620
|
+
// [RFC-027] Component Mode View Registration
|
|
621
|
+
// ═══════════════════════════════════════════════════════════════
|
|
622
|
+
/**
|
|
623
|
+
* Register a component-mode View (from SDK's View component)
|
|
624
|
+
*
|
|
625
|
+
* Component-mode Views:
|
|
626
|
+
* - Are registered directly without parent (flat structure)
|
|
627
|
+
* - Manage their own mounted state via React lifecycle
|
|
628
|
+
* - Don't participate in traditional ViewTree hierarchy
|
|
629
|
+
*
|
|
630
|
+
* This method unifies View storage, making ViewTree the single source of truth
|
|
631
|
+
* for both traditional-mode and component-mode Views.
|
|
632
|
+
*
|
|
633
|
+
* @param view - IView instance created by createInlineView()
|
|
634
|
+
*/
|
|
635
|
+
registerComponentView(view) {
|
|
636
|
+
if (this.nodes.has(view.id)) {
|
|
637
|
+
throw new AOTUIError('VIEW_DUPLICATE', { viewId: view.id });
|
|
638
|
+
}
|
|
639
|
+
// Create node without parent relationship
|
|
640
|
+
const node = {
|
|
641
|
+
view,
|
|
642
|
+
parentId: null, // ✅ Component-mode Views have no parent
|
|
643
|
+
childIds: [], // ✅ No children (flat structure)
|
|
644
|
+
mounted: true // ✅ Component manages its own mounted state
|
|
645
|
+
};
|
|
646
|
+
this.nodes.set(view.id, node);
|
|
647
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
648
|
+
console.log(`[ViewTree] Registered component-mode view ${view.id} (${view.name})`);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Unregister a component-mode View
|
|
653
|
+
*
|
|
654
|
+
* Called when SDK View component unmounts (via useLayoutEffect cleanup)
|
|
655
|
+
*
|
|
656
|
+
* @param viewId - View ID to unregister
|
|
657
|
+
*/
|
|
658
|
+
unregisterComponentView(viewId) {
|
|
659
|
+
const node = this.nodes.get(viewId);
|
|
660
|
+
if (!node) {
|
|
661
|
+
// Idempotent: already removed
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
// Safety check: Component-mode Views should not have children
|
|
665
|
+
if (node.childIds.length > 0) {
|
|
666
|
+
console.warn(`[ViewTree] Component-mode view ${viewId} has ${node.childIds.length} children. ` +
|
|
667
|
+
`This should not happen. Children:`, node.childIds);
|
|
668
|
+
}
|
|
669
|
+
// Remove from storage
|
|
670
|
+
this.nodes.delete(viewId);
|
|
671
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
672
|
+
console.log(`[ViewTree] Unregistered component-mode view ${viewId}`);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Factory function to create ViewTree instances.
|
|
678
|
+
*/
|
|
679
|
+
export function createViewTree(contextFactory) {
|
|
680
|
+
return new ViewTree(contextFactory);
|
|
681
|
+
}
|
|
682
|
+
//# sourceMappingURL=view-tree.js.map
|