@agentick/core 0.0.1
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/LICENSE +21 -0
- package/README.md +875 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/.tsbuildinfo.build +1 -0
- package/dist/agent.d.ts +32 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +26 -0
- package/dist/agent.js.map +1 -0
- package/dist/agentick-instance.d.ts +285 -0
- package/dist/agentick-instance.d.ts.map +1 -0
- package/dist/agentick-instance.js +700 -0
- package/dist/agentick-instance.js.map +1 -0
- package/dist/aidk-instance.d.ts +294 -0
- package/dist/aidk-instance.d.ts.map +1 -0
- package/dist/aidk-instance.js +340 -0
- package/dist/aidk-instance.js.map +1 -0
- package/dist/app/session-store.d.ts +57 -0
- package/dist/app/session-store.d.ts.map +1 -0
- package/dist/app/session-store.js +87 -0
- package/dist/app/session-store.js.map +1 -0
- package/dist/app/session.d.ts +209 -0
- package/dist/app/session.d.ts.map +1 -0
- package/dist/app/session.js +2131 -0
- package/dist/app/session.js.map +1 -0
- package/dist/app/sqlite-session-store.d.ts +60 -0
- package/dist/app/sqlite-session-store.d.ts.map +1 -0
- package/dist/app/sqlite-session-store.js +234 -0
- package/dist/app/sqlite-session-store.js.map +1 -0
- package/dist/app/types.d.ts +1461 -0
- package/dist/app/types.d.ts.map +1 -0
- package/dist/app/types.js +14 -0
- package/dist/app/types.js.map +1 -0
- package/dist/app.d.ts +79 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +83 -0
- package/dist/app.js.map +1 -0
- package/dist/channels/adapters/index.d.ts +2 -0
- package/dist/channels/adapters/index.d.ts.map +1 -0
- package/dist/channels/adapters/index.js +2 -0
- package/dist/channels/adapters/index.js.map +1 -0
- package/dist/channels/adapters/redis.d.ts +77 -0
- package/dist/channels/adapters/redis.d.ts.map +1 -0
- package/dist/channels/adapters/redis.js +259 -0
- package/dist/channels/adapters/redis.js.map +1 -0
- package/dist/channels/index.d.ts +38 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +38 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/service.d.ts +684 -0
- package/dist/channels/service.d.ts.map +1 -0
- package/dist/channels/service.js +870 -0
- package/dist/channels/service.js.map +1 -0
- package/dist/channels/transports/index.d.ts +4 -0
- package/dist/channels/transports/index.d.ts.map +1 -0
- package/dist/channels/transports/index.js +4 -0
- package/dist/channels/transports/index.js.map +1 -0
- package/dist/channels/transports/socketio.d.ts +98 -0
- package/dist/channels/transports/socketio.d.ts.map +1 -0
- package/dist/channels/transports/socketio.js +246 -0
- package/dist/channels/transports/socketio.js.map +1 -0
- package/dist/channels/transports/streamable-http.d.ts +107 -0
- package/dist/channels/transports/streamable-http.d.ts.map +1 -0
- package/dist/channels/transports/streamable-http.js +353 -0
- package/dist/channels/transports/streamable-http.js.map +1 -0
- package/dist/channels/transports/websocket.d.ts +117 -0
- package/dist/channels/transports/websocket.d.ts.map +1 -0
- package/dist/channels/transports/websocket.js +416 -0
- package/dist/channels/transports/websocket.js.map +1 -0
- package/dist/com/index.d.ts +29 -0
- package/dist/com/index.d.ts.map +1 -0
- package/dist/com/index.js +29 -0
- package/dist/com/index.js.map +1 -0
- package/dist/com/object-model.d.ts +634 -0
- package/dist/com/object-model.d.ts.map +1 -0
- package/dist/com/object-model.js +963 -0
- package/dist/com/object-model.js.map +1 -0
- package/dist/com/types.d.ts +192 -0
- package/dist/com/types.d.ts.map +1 -0
- package/dist/com/types.js +1 -0
- package/dist/com/types.js.map +1 -0
- package/dist/compiler/collector.d.ts +16 -0
- package/dist/compiler/collector.d.ts.map +1 -0
- package/dist/compiler/collector.js +388 -0
- package/dist/compiler/collector.js.map +1 -0
- package/dist/compiler/content-block-registry.d.ts +11 -0
- package/dist/compiler/content-block-registry.d.ts.map +1 -0
- package/dist/compiler/content-block-registry.js +312 -0
- package/dist/compiler/content-block-registry.js.map +1 -0
- package/dist/compiler/extractors.d.ts +68 -0
- package/dist/compiler/extractors.d.ts.map +1 -0
- package/dist/compiler/extractors.js +547 -0
- package/dist/compiler/extractors.js.map +1 -0
- package/dist/compiler/fiber-compiler.d.ts +203 -0
- package/dist/compiler/fiber-compiler.d.ts.map +1 -0
- package/dist/compiler/fiber-compiler.js +498 -0
- package/dist/compiler/fiber-compiler.js.map +1 -0
- package/dist/compiler/fiber.d.ts +61 -0
- package/dist/compiler/fiber.d.ts.map +1 -0
- package/dist/compiler/fiber.js +244 -0
- package/dist/compiler/fiber.js.map +1 -0
- package/dist/compiler/index.d.ts +18 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +38 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/compiler/scheduler.d.ts +95 -0
- package/dist/compiler/scheduler.d.ts.map +1 -0
- package/dist/compiler/scheduler.js +138 -0
- package/dist/compiler/scheduler.js.map +1 -0
- package/dist/compiler/structure-renderer.d.ts +42 -0
- package/dist/compiler/structure-renderer.d.ts.map +1 -0
- package/dist/compiler/structure-renderer.js +189 -0
- package/dist/compiler/structure-renderer.js.map +1 -0
- package/dist/compiler/types.d.ts +96 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/compiler/types.js +19 -0
- package/dist/compiler/types.js.map +1 -0
- package/dist/component/component-hooks.d.ts +68 -0
- package/dist/component/component-hooks.d.ts.map +1 -0
- package/dist/component/component-hooks.js +112 -0
- package/dist/component/component-hooks.js.map +1 -0
- package/dist/component/component.d.ts +314 -0
- package/dist/component/component.d.ts.map +1 -0
- package/dist/component/component.js +64 -0
- package/dist/component/component.js.map +1 -0
- package/dist/component/index.d.ts +47 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +47 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/tentickle-component.d.ts +185 -0
- package/dist/component/tentickle-component.d.ts.map +1 -0
- package/dist/component/tentickle-component.js +182 -0
- package/dist/component/tentickle-component.js.map +1 -0
- package/dist/content/index.d.ts +12 -0
- package/dist/content/index.d.ts.map +1 -0
- package/dist/content/index.js +17 -0
- package/dist/content/index.js.map +1 -0
- package/dist/context/index.d.ts +51 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +69 -0
- package/dist/context/index.js.map +1 -0
- package/dist/core/channel-helpers.d.ts +31 -0
- package/dist/core/channel-helpers.d.ts.map +1 -0
- package/dist/core/channel-helpers.js +62 -0
- package/dist/core/channel-helpers.js.map +1 -0
- package/dist/core/channel.d.ts +164 -0
- package/dist/core/channel.d.ts.map +1 -0
- package/dist/core/channel.js +199 -0
- package/dist/core/channel.js.map +1 -0
- package/dist/core/context.d.ts +412 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +290 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/event-buffer.d.ts +212 -0
- package/dist/core/event-buffer.d.ts.map +1 -0
- package/dist/core/event-buffer.js +346 -0
- package/dist/core/event-buffer.js.map +1 -0
- package/dist/core/execution-helpers.d.ts +179 -0
- package/dist/core/execution-helpers.d.ts.map +1 -0
- package/dist/core/execution-helpers.js +212 -0
- package/dist/core/execution-helpers.js.map +1 -0
- package/dist/core/execution-tracker.d.ts +53 -0
- package/dist/core/execution-tracker.d.ts.map +1 -0
- package/dist/core/execution-tracker.js +309 -0
- package/dist/core/execution-tracker.js.map +1 -0
- package/dist/core/index.d.ts +58 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +58 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +341 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +346 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/metrics-helpers.d.ts +40 -0
- package/dist/core/metrics-helpers.d.ts.map +1 -0
- package/dist/core/metrics-helpers.js +72 -0
- package/dist/core/metrics-helpers.js.map +1 -0
- package/dist/core/otel-provider.d.ts +54 -0
- package/dist/core/otel-provider.d.ts.map +1 -0
- package/dist/core/otel-provider.js +107 -0
- package/dist/core/otel-provider.js.map +1 -0
- package/dist/core/procedure-graph.d.ts +136 -0
- package/dist/core/procedure-graph.d.ts.map +1 -0
- package/dist/core/procedure-graph.js +272 -0
- package/dist/core/procedure-graph.js.map +1 -0
- package/dist/core/procedure.d.ts +755 -0
- package/dist/core/procedure.d.ts.map +1 -0
- package/dist/core/procedure.js +899 -0
- package/dist/core/procedure.js.map +1 -0
- package/dist/core/stream.d.ts +106 -0
- package/dist/core/stream.d.ts.map +1 -0
- package/dist/core/stream.js +186 -0
- package/dist/core/stream.js.map +1 -0
- package/dist/core/telemetry.d.ts +182 -0
- package/dist/core/telemetry.d.ts.map +1 -0
- package/dist/core/telemetry.js +124 -0
- package/dist/core/telemetry.js.map +1 -0
- package/dist/engine/client-tool-coordinator.d.ts +50 -0
- package/dist/engine/client-tool-coordinator.d.ts.map +1 -0
- package/dist/engine/client-tool-coordinator.js +121 -0
- package/dist/engine/client-tool-coordinator.js.map +1 -0
- package/dist/engine/engine-events.d.ts +117 -0
- package/dist/engine/engine-events.d.ts.map +1 -0
- package/dist/engine/engine-events.js +178 -0
- package/dist/engine/engine-events.js.map +1 -0
- package/dist/engine/engine-response.d.ts +48 -0
- package/dist/engine/engine-response.d.ts.map +1 -0
- package/dist/engine/engine-response.js +2 -0
- package/dist/engine/engine-response.js.map +1 -0
- package/dist/engine/execution-graph.d.ts +104 -0
- package/dist/engine/execution-graph.d.ts.map +1 -0
- package/dist/engine/execution-graph.js +257 -0
- package/dist/engine/execution-graph.js.map +1 -0
- package/dist/engine/execution-handle.d.ts +212 -0
- package/dist/engine/execution-handle.d.ts.map +1 -0
- package/dist/engine/execution-handle.js +602 -0
- package/dist/engine/execution-handle.js.map +1 -0
- package/dist/engine/execution-types.d.ts +248 -0
- package/dist/engine/execution-types.d.ts.map +1 -0
- package/dist/engine/execution-types.js +23 -0
- package/dist/engine/execution-types.js.map +1 -0
- package/dist/engine/index.d.ts +21 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +23 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/tool-confirmation-coordinator.d.ts +74 -0
- package/dist/engine/tool-confirmation-coordinator.d.ts.map +1 -0
- package/dist/engine/tool-confirmation-coordinator.js +137 -0
- package/dist/engine/tool-confirmation-coordinator.js.map +1 -0
- package/dist/engine/tool-executor.d.ts +127 -0
- package/dist/engine/tool-executor.d.ts.map +1 -0
- package/dist/engine/tool-executor.js +363 -0
- package/dist/engine/tool-executor.js.map +1 -0
- package/dist/hibernation/index.d.ts +126 -0
- package/dist/hibernation/index.d.ts.map +1 -0
- package/dist/hibernation/index.js +127 -0
- package/dist/hibernation/index.js.map +1 -0
- package/dist/hooks/base-hook-registry.d.ts +41 -0
- package/dist/hooks/base-hook-registry.d.ts.map +1 -0
- package/dist/hooks/base-hook-registry.js +76 -0
- package/dist/hooks/base-hook-registry.js.map +1 -0
- package/dist/hooks/com-state.d.ts +40 -0
- package/dist/hooks/com-state.d.ts.map +1 -0
- package/dist/hooks/com-state.js +90 -0
- package/dist/hooks/com-state.js.map +1 -0
- package/dist/hooks/context-info.d.ts +139 -0
- package/dist/hooks/context-info.d.ts.map +1 -0
- package/dist/hooks/context-info.js +115 -0
- package/dist/hooks/context-info.js.map +1 -0
- package/dist/hooks/context-internal.d.ts +21 -0
- package/dist/hooks/context-internal.d.ts.map +1 -0
- package/dist/hooks/context-internal.js +20 -0
- package/dist/hooks/context-internal.js.map +1 -0
- package/dist/hooks/context.d.ts +64 -0
- package/dist/hooks/context.d.ts.map +1 -0
- package/dist/hooks/context.js +83 -0
- package/dist/hooks/context.js.map +1 -0
- package/dist/hooks/data.d.ts +33 -0
- package/dist/hooks/data.d.ts.map +1 -0
- package/dist/hooks/data.js +84 -0
- package/dist/hooks/data.js.map +1 -0
- package/dist/hooks/formatter-context.d.ts +34 -0
- package/dist/hooks/formatter-context.d.ts.map +1 -0
- package/dist/hooks/formatter-context.js +34 -0
- package/dist/hooks/formatter-context.js.map +1 -0
- package/dist/hooks/hook-registry.d.ts +45 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hooks/hook-registry.js +109 -0
- package/dist/hooks/hook-registry.js.map +1 -0
- package/dist/hooks/index.d.ts +20 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +47 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/knob.d.ts +87 -0
- package/dist/hooks/knob.d.ts.map +1 -0
- package/dist/hooks/knob.js +129 -0
- package/dist/hooks/knob.js.map +1 -0
- package/dist/hooks/knobs-component.d.ts +70 -0
- package/dist/hooks/knobs-component.d.ts.map +1 -0
- package/dist/hooks/knobs-component.js +300 -0
- package/dist/hooks/knobs-component.js.map +1 -0
- package/dist/hooks/lifecycle.d.ts +158 -0
- package/dist/hooks/lifecycle.d.ts.map +1 -0
- package/dist/hooks/lifecycle.js +217 -0
- package/dist/hooks/lifecycle.js.map +1 -0
- package/dist/hooks/message-context.d.ts +101 -0
- package/dist/hooks/message-context.d.ts.map +1 -0
- package/dist/hooks/message-context.js +145 -0
- package/dist/hooks/message-context.js.map +1 -0
- package/dist/hooks/policy-context.d.ts.map +1 -0
- package/dist/hooks/runtime-context.d.ts +122 -0
- package/dist/hooks/runtime-context.d.ts.map +1 -0
- package/dist/hooks/runtime-context.js +149 -0
- package/dist/hooks/runtime-context.js.map +1 -0
- package/dist/hooks/signal.d.ts +267 -0
- package/dist/hooks/signal.d.ts.map +1 -0
- package/dist/hooks/signal.js +825 -0
- package/dist/hooks/signal.js.map +1 -0
- package/dist/hooks/types.d.ts +179 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +5 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx/components/agent.d.ts +64 -0
- package/dist/jsx/components/agent.d.ts.map +1 -0
- package/dist/jsx/components/agent.js +80 -0
- package/dist/jsx/components/agent.js.map +1 -0
- package/dist/jsx/components/complete.d.ts +65 -0
- package/dist/jsx/components/complete.d.ts.map +1 -0
- package/dist/jsx/components/complete.js +64 -0
- package/dist/jsx/components/complete.js.map +1 -0
- package/dist/jsx/components/content.d.ts +98 -0
- package/dist/jsx/components/content.d.ts.map +1 -0
- package/dist/jsx/components/content.js +51 -0
- package/dist/jsx/components/content.js.map +1 -0
- package/dist/jsx/components/harness.d.ts +118 -0
- package/dist/jsx/components/harness.d.ts.map +1 -0
- package/dist/jsx/components/harness.js +117 -0
- package/dist/jsx/components/harness.js.map +1 -0
- package/dist/jsx/components/index.d.ts +11 -0
- package/dist/jsx/components/index.d.ts.map +1 -0
- package/dist/jsx/components/index.js +11 -0
- package/dist/jsx/components/index.js.map +1 -0
- package/dist/jsx/components/markdown.d.ts +31 -0
- package/dist/jsx/components/markdown.d.ts.map +1 -0
- package/dist/jsx/components/markdown.js +17 -0
- package/dist/jsx/components/markdown.js.map +1 -0
- package/dist/jsx/components/messages.d.ts +283 -0
- package/dist/jsx/components/messages.d.ts.map +1 -0
- package/dist/jsx/components/messages.js +257 -0
- package/dist/jsx/components/messages.js.map +1 -0
- package/dist/jsx/components/model.d.ts +94 -0
- package/dist/jsx/components/model.d.ts.map +1 -0
- package/dist/jsx/components/model.js +96 -0
- package/dist/jsx/components/model.js.map +1 -0
- package/dist/jsx/components/primitives.d.ts +117 -0
- package/dist/jsx/components/primitives.d.ts.map +1 -0
- package/dist/jsx/components/primitives.js +83 -0
- package/dist/jsx/components/primitives.js.map +1 -0
- package/dist/jsx/components/renderer.d.ts +24 -0
- package/dist/jsx/components/renderer.d.ts.map +1 -0
- package/dist/jsx/components/renderer.js +11 -0
- package/dist/jsx/components/renderer.js.map +1 -0
- package/dist/jsx/components/semantic.d.ts +155 -0
- package/dist/jsx/components/semantic.d.ts.map +1 -0
- package/dist/jsx/components/semantic.js +39 -0
- package/dist/jsx/components/semantic.js.map +1 -0
- package/dist/jsx/components/timeline.d.ts +157 -0
- package/dist/jsx/components/timeline.d.ts.map +1 -0
- package/dist/jsx/components/timeline.js +357 -0
- package/dist/jsx/components/timeline.js.map +1 -0
- package/dist/jsx/components/token-budget.d.ts +70 -0
- package/dist/jsx/components/token-budget.d.ts.map +1 -0
- package/dist/jsx/components/token-budget.js +135 -0
- package/dist/jsx/components/token-budget.js.map +1 -0
- package/dist/jsx/components/xml.d.ts +27 -0
- package/dist/jsx/components/xml.d.ts.map +1 -0
- package/dist/jsx/components/xml.js +17 -0
- package/dist/jsx/components/xml.js.map +1 -0
- package/dist/jsx/index.d.ts +58 -0
- package/dist/jsx/index.d.ts.map +1 -0
- package/dist/jsx/index.js +59 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/jsx-runtime.d.ts +370 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-runtime.js +79 -0
- package/dist/jsx/jsx-runtime.js.map +1 -0
- package/dist/jsx/jsx-types.d.ts +23 -0
- package/dist/jsx/jsx-types.d.ts.map +1 -0
- package/dist/jsx/jsx-types.js +1 -0
- package/dist/jsx/jsx-types.js.map +1 -0
- package/dist/mcp/client.d.ts +46 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +138 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/component.d.ts +95 -0
- package/dist/mcp/component.d.ts.map +1 -0
- package/dist/mcp/component.js +185 -0
- package/dist/mcp/component.js.map +1 -0
- package/dist/mcp/create-mcp-tool.d.ts +191 -0
- package/dist/mcp/create-mcp-tool.d.ts.map +1 -0
- package/dist/mcp/create-mcp-tool.js +228 -0
- package/dist/mcp/create-mcp-tool.js.map +1 -0
- package/dist/mcp/index.d.ts +49 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +48 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/service.d.ts +39 -0
- package/dist/mcp/service.d.ts.map +1 -0
- package/dist/mcp/service.js +77 -0
- package/dist/mcp/service.js.map +1 -0
- package/dist/mcp/tool.d.ts +55 -0
- package/dist/mcp/tool.d.ts.map +1 -0
- package/dist/mcp/tool.js +119 -0
- package/dist/mcp/tool.js.map +1 -0
- package/dist/mcp/types.d.ts +72 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +6 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/middleware/defaults.d.ts +9 -0
- package/dist/middleware/defaults.d.ts.map +1 -0
- package/dist/middleware/defaults.js +47 -0
- package/dist/middleware/defaults.js.map +1 -0
- package/dist/model/adapter-helpers.d.ts +161 -0
- package/dist/model/adapter-helpers.d.ts.map +1 -0
- package/dist/model/adapter-helpers.js +351 -0
- package/dist/model/adapter-helpers.js.map +1 -0
- package/dist/model/adapter.d.ts +399 -0
- package/dist/model/adapter.d.ts.map +1 -0
- package/dist/model/adapter.js +497 -0
- package/dist/model/adapter.js.map +1 -0
- package/dist/model/index.d.ts +54 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +55 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/model-hooks.d.ts +45 -0
- package/dist/model/model-hooks.d.ts.map +1 -0
- package/dist/model/model-hooks.js +24 -0
- package/dist/model/model-hooks.js.map +1 -0
- package/dist/model/model.d.ts +302 -0
- package/dist/model/model.d.ts.map +1 -0
- package/dist/model/model.js +20 -0
- package/dist/model/model.js.map +1 -0
- package/dist/model/simple-adapter.d.ts +176 -0
- package/dist/model/simple-adapter.d.ts.map +1 -0
- package/dist/model/simple-adapter.js +264 -0
- package/dist/model/simple-adapter.js.map +1 -0
- package/dist/model/stream-accumulator.d.ts +284 -0
- package/dist/model/stream-accumulator.d.ts.map +1 -0
- package/dist/model/stream-accumulator.js +532 -0
- package/dist/model/stream-accumulator.js.map +1 -0
- package/dist/model/utils/index.d.ts +2 -0
- package/dist/model/utils/index.d.ts.map +1 -0
- package/dist/model/utils/index.js +2 -0
- package/dist/model/utils/index.js.map +1 -0
- package/dist/model/utils/language-model.d.ts +26 -0
- package/dist/model/utils/language-model.d.ts.map +1 -0
- package/dist/model/utils/language-model.js +706 -0
- package/dist/model/utils/language-model.js.map +1 -0
- package/dist/procedure/index.d.ts +20 -0
- package/dist/procedure/index.d.ts.map +1 -0
- package/dist/procedure/index.js +19 -0
- package/dist/procedure/index.js.map +1 -0
- package/dist/reconciler/devtools-bridge.d.ts +40 -0
- package/dist/reconciler/devtools-bridge.d.ts.map +1 -0
- package/dist/reconciler/devtools-bridge.js +79 -0
- package/dist/reconciler/devtools-bridge.js.map +1 -0
- package/dist/reconciler/host-config.d.ts +39 -0
- package/dist/reconciler/host-config.d.ts.map +1 -0
- package/dist/reconciler/host-config.js +195 -0
- package/dist/reconciler/host-config.js.map +1 -0
- package/dist/reconciler/index.d.ts +7 -0
- package/dist/reconciler/index.d.ts.map +1 -0
- package/dist/reconciler/index.js +7 -0
- package/dist/reconciler/index.js.map +1 -0
- package/dist/reconciler/reconciler.d.ts +47 -0
- package/dist/reconciler/reconciler.d.ts.map +1 -0
- package/dist/reconciler/reconciler.js +89 -0
- package/dist/reconciler/reconciler.js.map +1 -0
- package/dist/reconciler/types.d.ts +86 -0
- package/dist/reconciler/types.d.ts.map +1 -0
- package/dist/reconciler/types.js +37 -0
- package/dist/reconciler/types.js.map +1 -0
- package/dist/renderers/base.d.ts +98 -0
- package/dist/renderers/base.d.ts.map +1 -0
- package/dist/renderers/base.js +82 -0
- package/dist/renderers/base.js.map +1 -0
- package/dist/renderers/index.d.ts +31 -0
- package/dist/renderers/index.d.ts.map +1 -0
- package/dist/renderers/index.js +31 -0
- package/dist/renderers/index.js.map +1 -0
- package/dist/renderers/markdown.d.ts +48 -0
- package/dist/renderers/markdown.d.ts.map +1 -0
- package/dist/renderers/markdown.js +432 -0
- package/dist/renderers/markdown.js.map +1 -0
- package/dist/renderers/types.d.ts +7 -0
- package/dist/renderers/types.d.ts.map +1 -0
- package/dist/renderers/types.js +7 -0
- package/dist/renderers/types.js.map +1 -0
- package/dist/renderers/xml.d.ts +49 -0
- package/dist/renderers/xml.d.ts.map +1 -0
- package/dist/renderers/xml.js +444 -0
- package/dist/renderers/xml.js.map +1 -0
- package/dist/state/boundary.d.ts +347 -0
- package/dist/state/boundary.d.ts.map +1 -0
- package/dist/state/boundary.js +341 -0
- package/dist/state/boundary.js.map +1 -0
- package/dist/state/context.d.ts +138 -0
- package/dist/state/context.d.ts.map +1 -0
- package/dist/state/context.js +139 -0
- package/dist/state/context.js.map +1 -0
- package/dist/state/hooks.d.ts +798 -0
- package/dist/state/hooks.d.ts.map +1 -0
- package/dist/state/hooks.js +1437 -0
- package/dist/state/hooks.js.map +1 -0
- package/dist/state/index.d.ts +72 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +73 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/signal.d.ts +223 -0
- package/dist/state/signal.d.ts.map +1 -0
- package/dist/state/signal.js +699 -0
- package/dist/state/signal.js.map +1 -0
- package/dist/state/use-state.d.ts +210 -0
- package/dist/state/use-state.d.ts.map +1 -0
- package/dist/state/use-state.js +327 -0
- package/dist/state/use-state.js.map +1 -0
- package/dist/tentickle-instance.d.ts +285 -0
- package/dist/tentickle-instance.d.ts.map +1 -0
- package/dist/tentickle-instance.js +700 -0
- package/dist/tentickle-instance.js.map +1 -0
- package/dist/testing/act.d.ts +59 -0
- package/dist/testing/act.d.ts.map +1 -0
- package/dist/testing/act.js +92 -0
- package/dist/testing/act.js.map +1 -0
- package/dist/testing/async-helpers.d.ts +99 -0
- package/dist/testing/async-helpers.d.ts.map +1 -0
- package/dist/testing/async-helpers.js +193 -0
- package/dist/testing/async-helpers.js.map +1 -0
- package/dist/testing/compile-agent.d.ts +101 -0
- package/dist/testing/compile-agent.d.ts.map +1 -0
- package/dist/testing/compile-agent.js +136 -0
- package/dist/testing/compile-agent.js.map +1 -0
- package/dist/testing/index.d.ts +57 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +59 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-app.d.ts +163 -0
- package/dist/testing/mock-app.d.ts.map +1 -0
- package/dist/testing/mock-app.js +393 -0
- package/dist/testing/mock-app.js.map +1 -0
- package/dist/testing/mocks.d.ts +142 -0
- package/dist/testing/mocks.d.ts.map +1 -0
- package/dist/testing/mocks.js +191 -0
- package/dist/testing/mocks.js.map +1 -0
- package/dist/testing/render-agent.d.ts +146 -0
- package/dist/testing/render-agent.d.ts.map +1 -0
- package/dist/testing/render-agent.js +200 -0
- package/dist/testing/render-agent.js.map +1 -0
- package/dist/testing/test-adapter.d.ts +157 -0
- package/dist/testing/test-adapter.d.ts.map +1 -0
- package/dist/testing/test-adapter.js +297 -0
- package/dist/testing/test-adapter.js.map +1 -0
- package/dist/testing/test-model.d.ts +132 -0
- package/dist/testing/test-model.d.ts.map +1 -0
- package/dist/testing/test-model.js +260 -0
- package/dist/testing/test-model.js.map +1 -0
- package/dist/tool/index.d.ts +61 -0
- package/dist/tool/index.d.ts.map +1 -0
- package/dist/tool/index.js +63 -0
- package/dist/tool/index.js.map +1 -0
- package/dist/tool/tool-hooks.d.ts +45 -0
- package/dist/tool/tool-hooks.d.ts.map +1 -0
- package/dist/tool/tool-hooks.js +35 -0
- package/dist/tool/tool-hooks.js.map +1 -0
- package/dist/tool/tool.d.ts +403 -0
- package/dist/tool/tool.d.ts.map +1 -0
- package/dist/tool/tool.js +176 -0
- package/dist/tool/tool.js.map +1 -0
- package/dist/types.d.ts +442 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +97 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/abort-utils.d.ts +5 -0
- package/dist/utils/abort-utils.d.ts.map +1 -0
- package/dist/utils/abort-utils.js +50 -0
- package/dist/utils/abort-utils.js.map +1 -0
- package/dist/utils/classify-error.d.ts +19 -0
- package/dist/utils/classify-error.d.ts.map +1 -0
- package/dist/utils/classify-error.js +77 -0
- package/dist/utils/classify-error.js.map +1 -0
- package/dist/utils/index.d.ts +21 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/normalization.d.ts +6 -0
- package/dist/utils/normalization.d.ts.map +1 -0
- package/dist/utils/normalization.js +103 -0
- package/dist/utils/normalization.js.map +1 -0
- package/dist/utils/registry.d.ts +15 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +28 -0
- package/dist/utils/registry.js.map +1 -0
- package/dist/utils/schema.d.ts +7 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +13 -0
- package/dist/utils/schema.js.map +1 -0
- package/dist/utils/token-estimate.d.ts +87 -0
- package/dist/utils/token-estimate.d.ts.map +1 -0
- package/dist/utils/token-estimate.js +199 -0
- package/dist/utils/token-estimate.js.map +1 -0
- package/dist/v2/reconciler/host-config.d.ts +31 -0
- package/dist/v2/reconciler/host-config.d.ts.map +1 -0
- package/dist/v2/reconciler/host-config.js +197 -0
- package/dist/v2/reconciler/host-config.js.map +1 -0
- package/dist/v2/reconciler/index.d.ts +7 -0
- package/dist/v2/reconciler/index.d.ts.map +1 -0
- package/dist/v2/reconciler/index.js +7 -0
- package/dist/v2/reconciler/index.js.map +1 -0
- package/dist/v2/reconciler/reconciler.d.ts +39 -0
- package/dist/v2/reconciler/reconciler.d.ts.map +1 -0
- package/dist/v2/reconciler/reconciler.js +54 -0
- package/dist/v2/reconciler/reconciler.js.map +1 -0
- package/dist/v2/reconciler/types.d.ts +64 -0
- package/dist/v2/reconciler/types.d.ts.map +1 -0
- package/dist/v2/reconciler/types.js +20 -0
- package/dist/v2/reconciler/types.js.map +1 -0
- package/dist/v2/renderers/index.d.ts +7 -0
- package/dist/v2/renderers/index.d.ts.map +1 -0
- package/dist/v2/renderers/index.js +7 -0
- package/dist/v2/renderers/index.js.map +1 -0
- package/dist/v2/renderers/markdown.d.ts +16 -0
- package/dist/v2/renderers/markdown.d.ts.map +1 -0
- package/dist/v2/renderers/markdown.js +65 -0
- package/dist/v2/renderers/markdown.js.map +1 -0
- package/dist/v2/renderers/types.d.ts +26 -0
- package/dist/v2/renderers/types.d.ts.map +1 -0
- package/dist/v2/renderers/types.js +6 -0
- package/dist/v2/renderers/types.js.map +1 -0
- package/dist/v2/renderers/xml.d.ts +17 -0
- package/dist/v2/renderers/xml.d.ts.map +1 -0
- package/dist/v2/renderers/xml.js +73 -0
- package/dist/v2/renderers/xml.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
import { ChannelSession, Context, } from "@agentick/kernel";
|
|
2
|
+
import { NotFoundError, ValidationError } from "@agentick/shared";
|
|
3
|
+
// Re-export channel types from Kernel so Engine users don't need to import from Kernel
|
|
4
|
+
export { Channel, ChannelSession, } from "@agentick/kernel";
|
|
5
|
+
/**
|
|
6
|
+
* Channel Service - Low-level channel infrastructure.
|
|
7
|
+
*
|
|
8
|
+
* ## Architecture
|
|
9
|
+
*
|
|
10
|
+
* ```
|
|
11
|
+
* ┌─────────────────────────────────────────────────────────────────────┐
|
|
12
|
+
* │ Application Layer (recommended) │
|
|
13
|
+
* │ └── ChannelRouter - declarative handlers, context registry, │
|
|
14
|
+
* │ auto-notifications, scoped publishing │
|
|
15
|
+
* ├─────────────────────────────────────────────────────────────────────┤
|
|
16
|
+
* │ Service Layer (escape hatch) │
|
|
17
|
+
* │ └── ChannelService - sessions, direct publish/subscribe, │
|
|
18
|
+
* │ transport & adapter management │
|
|
19
|
+
* ├─────────────────────────────────────────────────────────────────────┤
|
|
20
|
+
* │ Infrastructure Layer │
|
|
21
|
+
* │ ├── Transport - external communication (SSE, WebSocket) │
|
|
22
|
+
* │ └── Adapter - multi-instance distribution (Redis pub/sub) │
|
|
23
|
+
* └─────────────────────────────────────────────────────────────────────┘
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Usage
|
|
27
|
+
*
|
|
28
|
+
* **Recommended:** Use `ChannelRouter` for application code.
|
|
29
|
+
* - Register routers with engine: `createEngine({ channels: { routers: [...] } })`
|
|
30
|
+
* - Handle events via `channelService.handleEvent()`
|
|
31
|
+
* - Components register via `router.registerContext()`
|
|
32
|
+
*
|
|
33
|
+
* **Escape hatch:** Direct `ChannelService` methods for advanced cases.
|
|
34
|
+
* - `subscribe()` - low-level channel subscription
|
|
35
|
+
* - `publish()` - low-level event publishing
|
|
36
|
+
*
|
|
37
|
+
* Sessions persist across multiple engine executions.
|
|
38
|
+
*/
|
|
39
|
+
export class ChannelService {
|
|
40
|
+
sessions = new Map();
|
|
41
|
+
sessionIdGenerator;
|
|
42
|
+
transport;
|
|
43
|
+
adapter;
|
|
44
|
+
sessionTimeout;
|
|
45
|
+
cleanupInterval;
|
|
46
|
+
adapterSubscriptions = new Map();
|
|
47
|
+
routerRegistry = new Map();
|
|
48
|
+
constructor(config = {}) {
|
|
49
|
+
this.sessionIdGenerator = config.sessionIdGenerator || ChannelSession.generateId;
|
|
50
|
+
this.transport = config.transport;
|
|
51
|
+
this.adapter = config.adapter;
|
|
52
|
+
this.sessionTimeout = config.sessionTimeout || 3600000; // 1 hour default
|
|
53
|
+
// Register channel routers
|
|
54
|
+
if (config.routers) {
|
|
55
|
+
for (const router of config.routers) {
|
|
56
|
+
if (!router.channel) {
|
|
57
|
+
throw ValidationError.required("channel");
|
|
58
|
+
}
|
|
59
|
+
this.routerRegistry.set(router.channel, router);
|
|
60
|
+
router.setChannelService(this);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Setup transport if provided
|
|
64
|
+
if (this.transport) {
|
|
65
|
+
this.setupTransport();
|
|
66
|
+
}
|
|
67
|
+
// Setup adapter if provided
|
|
68
|
+
if (this.adapter) {
|
|
69
|
+
this.setupAdapter();
|
|
70
|
+
}
|
|
71
|
+
// Start session cleanup interval
|
|
72
|
+
this.startCleanupInterval();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the transport adapter (for external access, e.g., HTTP routes).
|
|
76
|
+
*/
|
|
77
|
+
getTransport() {
|
|
78
|
+
return this.transport;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get a registered channel router by name.
|
|
82
|
+
*/
|
|
83
|
+
getRouter(channelName) {
|
|
84
|
+
return this.routerRegistry.get(channelName);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Handle an event by delegating to the appropriate registered router.
|
|
88
|
+
* Eliminates if-else chains in HTTP routes.
|
|
89
|
+
*
|
|
90
|
+
* @param channelName - Name of the channel
|
|
91
|
+
* @param request - Event type and payload
|
|
92
|
+
* @param context - Context passed to the handler
|
|
93
|
+
* @returns Result from the handler (for HTTP response body)
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* // In HTTP route - no if-else needed
|
|
98
|
+
* const result = await engine.channels?.handleEvent('todo-list',
|
|
99
|
+
* { type: 'create_task', payload },
|
|
100
|
+
* { userId, broadcast: true }
|
|
101
|
+
* );
|
|
102
|
+
* res.json({ success: true, ...result });
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
async handleEvent(channelName, request, rawContext) {
|
|
106
|
+
const router = this.getRouter(channelName);
|
|
107
|
+
if (!router) {
|
|
108
|
+
throw new NotFoundError("channel", channelName, `Unknown channel. Available channels: ${Array.from(this.routerRegistry.keys()).join(", ")}`);
|
|
109
|
+
}
|
|
110
|
+
// Let router transform context if it has buildContext
|
|
111
|
+
const context = router.buildContext ? router.buildContext(rawContext) : rawContext;
|
|
112
|
+
const event = {
|
|
113
|
+
channel: channelName,
|
|
114
|
+
type: request.type,
|
|
115
|
+
payload: request.payload,
|
|
116
|
+
metadata: {},
|
|
117
|
+
};
|
|
118
|
+
// console.log('handleEvent', channelName, request, context, router);
|
|
119
|
+
return router.handle(event, context);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get or create a session for the current context.
|
|
123
|
+
*/
|
|
124
|
+
getSession(ctx) {
|
|
125
|
+
const sessionId = this.sessionIdGenerator(ctx);
|
|
126
|
+
if (!this.sessions.has(sessionId)) {
|
|
127
|
+
const session = new ChannelSession(sessionId);
|
|
128
|
+
this.sessions.set(sessionId, session);
|
|
129
|
+
// Connect transport if available
|
|
130
|
+
if (this.transport) {
|
|
131
|
+
this.transport.connect(sessionId).catch((err) => {
|
|
132
|
+
console.error(`Failed to connect transport for session ${sessionId}:`, err);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const session = this.sessions.get(sessionId);
|
|
137
|
+
session.lastActivity = Date.now();
|
|
138
|
+
return session;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get or create a channel within the current session.
|
|
142
|
+
*/
|
|
143
|
+
getChannel(ctx, channelName) {
|
|
144
|
+
const session = this.getSession(ctx);
|
|
145
|
+
const channel = session.getChannel(channelName);
|
|
146
|
+
// Subscribe to adapter if this is a new channel
|
|
147
|
+
// Use synchronous placeholder to prevent duplicate subscriptions from concurrent calls
|
|
148
|
+
if (this.adapter && !this.adapterSubscriptions.has(channelName)) {
|
|
149
|
+
// Set placeholder immediately to prevent race condition
|
|
150
|
+
// The placeholder is a no-op function that will be replaced with the real unsubscribe
|
|
151
|
+
this.adapterSubscriptions.set(channelName, () => { });
|
|
152
|
+
this.adapter
|
|
153
|
+
.subscribe(channelName, (event) => {
|
|
154
|
+
// Only forward if event didn't originate from this instance
|
|
155
|
+
// (prevent feedback loop)
|
|
156
|
+
if (event.metadata?.source !== "local") {
|
|
157
|
+
channel.publish(event);
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
.then((unsubscribe) => {
|
|
161
|
+
// Replace placeholder with actual unsubscribe function
|
|
162
|
+
this.adapterSubscriptions.set(channelName, unsubscribe);
|
|
163
|
+
})
|
|
164
|
+
.catch((err) => {
|
|
165
|
+
// Remove placeholder on failure so retry is possible
|
|
166
|
+
this.adapterSubscriptions.delete(channelName);
|
|
167
|
+
console.error(`Failed to subscribe adapter to channel ${channelName}:`, err);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return channel;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Low-level: Publish an event to a channel.
|
|
174
|
+
*
|
|
175
|
+
* **Prefer using ChannelRouter.publisher() for application code.**
|
|
176
|
+
* This is an escape hatch for advanced use cases.
|
|
177
|
+
*/
|
|
178
|
+
publish(ctx, channelName, event) {
|
|
179
|
+
const session = this.getSession(ctx);
|
|
180
|
+
const channel = session.getChannel(channelName);
|
|
181
|
+
const fullEvent = {
|
|
182
|
+
...event,
|
|
183
|
+
channel: channelName,
|
|
184
|
+
metadata: {
|
|
185
|
+
...event.metadata,
|
|
186
|
+
executionId: ctx.traceId,
|
|
187
|
+
sessionId: session.id, // Always include sessionId in metadata
|
|
188
|
+
sourceConnectionId: session.id, // For excludeSender (broadcast) support
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
// Publish to local channel
|
|
192
|
+
channel.publish(fullEvent);
|
|
193
|
+
// Forward to transport if available
|
|
194
|
+
if (this.transport) {
|
|
195
|
+
this.transport.send(fullEvent).catch((err) => {
|
|
196
|
+
console.error(`Failed to send event via transport:`, err);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Forward to adapter if available
|
|
200
|
+
if (this.adapter) {
|
|
201
|
+
this.adapter.publish(fullEvent).catch((err) => {
|
|
202
|
+
console.error(`Failed to publish event via adapter:`, err);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Low-level: Subscribe to events on a channel with a handler function.
|
|
208
|
+
*
|
|
209
|
+
* **Prefer using ChannelRouter for application code.**
|
|
210
|
+
* This is an escape hatch for advanced use cases.
|
|
211
|
+
*/
|
|
212
|
+
subscribe(ctx, channelName, handler) {
|
|
213
|
+
const channel = this.getChannel(ctx, channelName);
|
|
214
|
+
return channel.subscribe(handler);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Low-level: Subscribe to multiple channels at once.
|
|
218
|
+
*
|
|
219
|
+
* **Prefer using ChannelRouter for application code.**
|
|
220
|
+
* This is an escape hatch for advanced use cases.
|
|
221
|
+
*
|
|
222
|
+
* @param ctx - Engine context
|
|
223
|
+
* @param channelNames - Array of channel names to subscribe to, or '*' for all channels
|
|
224
|
+
* @param handler - Handler function that receives events from any subscribed channel
|
|
225
|
+
* @returns Unsubscribe function
|
|
226
|
+
*/
|
|
227
|
+
subscribeToChannels(ctx, channelNames, handler) {
|
|
228
|
+
const session = this.getSession(ctx);
|
|
229
|
+
const unsubscribers = [];
|
|
230
|
+
if (channelNames === "*") {
|
|
231
|
+
// Subscribe to all existing channels
|
|
232
|
+
for (const channel of session.channels.values()) {
|
|
233
|
+
unsubscribers.push(channel.subscribe(handler));
|
|
234
|
+
}
|
|
235
|
+
// For future channels, we'll subscribe when they're accessed via getChannel
|
|
236
|
+
// This is handled by subscribing to the session's channel creation
|
|
237
|
+
// Note: This is a best-effort approach - channels created outside getChannel won't be subscribed
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
// Subscribe to specific channels
|
|
241
|
+
for (const channelName of channelNames) {
|
|
242
|
+
const channel = session.getChannel(channelName);
|
|
243
|
+
unsubscribers.push(channel.subscribe(handler));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Return combined unsubscribe function
|
|
247
|
+
return () => {
|
|
248
|
+
for (const unsubscribe of unsubscribers) {
|
|
249
|
+
unsubscribe();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Low-level: Subscribe to events filtered by session ID.
|
|
255
|
+
*
|
|
256
|
+
* **Prefer using ChannelRouter for application code.**
|
|
257
|
+
* This is an escape hatch for advanced use cases.
|
|
258
|
+
*
|
|
259
|
+
* @param ctx - Engine context
|
|
260
|
+
* @param channelName - Channel name to subscribe to, or '*' for all channels
|
|
261
|
+
* @param handler - Handler function that receives filtered events
|
|
262
|
+
* @param options - Optional filter options
|
|
263
|
+
* @returns Unsubscribe function
|
|
264
|
+
*/
|
|
265
|
+
subscribeFiltered(ctx, channelName, handler, options) {
|
|
266
|
+
const session = this.getSession(ctx);
|
|
267
|
+
const targetSessionId = options?.sessionId || session.id;
|
|
268
|
+
// Create filtered handler
|
|
269
|
+
const filteredHandler = (event) => {
|
|
270
|
+
// Filter by sessionId
|
|
271
|
+
const eventSessionId = event.metadata?.["sessionId"];
|
|
272
|
+
if (eventSessionId !== targetSessionId) {
|
|
273
|
+
return; // Skip events not for this session
|
|
274
|
+
}
|
|
275
|
+
// Apply additional channel filter if provided
|
|
276
|
+
if (options?.channelFilter && !options.channelFilter(event.channel)) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
// Call original handler
|
|
280
|
+
handler(event);
|
|
281
|
+
};
|
|
282
|
+
// Subscribe using filtered handler
|
|
283
|
+
if (channelName === "*") {
|
|
284
|
+
return this.subscribeToChannels(ctx, "*", filteredHandler);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
return this.subscribe(ctx, channelName, filteredHandler);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Wait for a response on a channel (for bidirectional communication).
|
|
292
|
+
*/
|
|
293
|
+
async waitForResponse(ctx, channelName, requestId, timeoutMs) {
|
|
294
|
+
const channel = this.getChannel(ctx, channelName);
|
|
295
|
+
return channel.waitForResponse(requestId, timeoutMs);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Setup transport handlers.
|
|
299
|
+
* Forwards events received from transport to local channels.
|
|
300
|
+
*/
|
|
301
|
+
setupTransport() {
|
|
302
|
+
if (!this.transport)
|
|
303
|
+
return;
|
|
304
|
+
// Forward received events to appropriate channels
|
|
305
|
+
this.transport.onReceive((event) => {
|
|
306
|
+
// Extract session ID from event metadata
|
|
307
|
+
const sessionId = event.metadata?.["sessionId"];
|
|
308
|
+
if (!sessionId) {
|
|
309
|
+
console.warn("Received transport event without sessionId in metadata");
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
// Find session and channel
|
|
313
|
+
const session = this.sessions.get(sessionId);
|
|
314
|
+
if (!session) {
|
|
315
|
+
console.warn(`Received transport event for unknown session: ${sessionId}`);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// Publish to local channel
|
|
319
|
+
const channel = session.getChannel(event.channel);
|
|
320
|
+
channel.publish(event);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Setup adapter handlers.
|
|
325
|
+
* Subscribes to channels via adapter and forwards events to local channels.
|
|
326
|
+
*/
|
|
327
|
+
async setupAdapter() {
|
|
328
|
+
if (!this.adapter)
|
|
329
|
+
return;
|
|
330
|
+
// We'll subscribe to channels on-demand when they're created
|
|
331
|
+
// This is handled in getChannel() - we check if adapter exists and subscribe
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Start cleanup interval for expired sessions.
|
|
335
|
+
*/
|
|
336
|
+
startCleanupInterval() {
|
|
337
|
+
if (this.cleanupInterval) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
this.cleanupInterval = setInterval(() => {
|
|
341
|
+
const now = Date.now();
|
|
342
|
+
for (const [sessionId, session] of this.sessions.entries()) {
|
|
343
|
+
if (now - session.lastActivity > this.sessionTimeout) {
|
|
344
|
+
this.destroySession(sessionId);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}, 60000); // Check every minute
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Destroy a session and cleanup resources.
|
|
351
|
+
*/
|
|
352
|
+
destroySession(sessionId) {
|
|
353
|
+
const session = this.sessions.get(sessionId);
|
|
354
|
+
if (session) {
|
|
355
|
+
session.destroy();
|
|
356
|
+
this.sessions.delete(sessionId);
|
|
357
|
+
// Disconnect transport if available
|
|
358
|
+
if (this.transport) {
|
|
359
|
+
this.transport.disconnect().catch((err) => {
|
|
360
|
+
console.error(`Failed to disconnect transport for session ${sessionId}:`, err);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Cleanup all sessions and resources.
|
|
367
|
+
*/
|
|
368
|
+
destroy() {
|
|
369
|
+
// Clear cleanup interval
|
|
370
|
+
if (this.cleanupInterval) {
|
|
371
|
+
clearInterval(this.cleanupInterval);
|
|
372
|
+
}
|
|
373
|
+
// Destroy all sessions
|
|
374
|
+
for (const sessionId of this.sessions.keys()) {
|
|
375
|
+
this.destroySession(sessionId);
|
|
376
|
+
}
|
|
377
|
+
// Close transport (sends proper close events to clients)
|
|
378
|
+
if (this.transport) {
|
|
379
|
+
this.transport.closeAll();
|
|
380
|
+
}
|
|
381
|
+
// Close adapter if available
|
|
382
|
+
if (this.adapter?.close) {
|
|
383
|
+
this.adapter.close().catch((err) => {
|
|
384
|
+
console.error("Failed to close adapter during cleanup:", err);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
// Unsubscribe from all adapter subscriptions
|
|
388
|
+
for (const unsubscribe of this.adapterSubscriptions.values()) {
|
|
389
|
+
unsubscribe();
|
|
390
|
+
}
|
|
391
|
+
this.adapterSubscriptions.clear();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
export class ChannelRouter {
|
|
395
|
+
channel;
|
|
396
|
+
config;
|
|
397
|
+
handlers = new Map();
|
|
398
|
+
defaultHandler;
|
|
399
|
+
errorHandler;
|
|
400
|
+
/**
|
|
401
|
+
* Registry of execution contexts.
|
|
402
|
+
* Key format: `${executionId}:${scopeKey}`
|
|
403
|
+
* Allows multiple executions to register for same scope, each with own callbacks.
|
|
404
|
+
*/
|
|
405
|
+
contextRegistry = new Map();
|
|
406
|
+
constructor(channel, config = {}) {
|
|
407
|
+
this.channel = channel;
|
|
408
|
+
this.config = config;
|
|
409
|
+
}
|
|
410
|
+
// =========================================================================
|
|
411
|
+
// Getters for lazy-initialized dependencies
|
|
412
|
+
// =========================================================================
|
|
413
|
+
getTransport() {
|
|
414
|
+
if (this.config.transport) {
|
|
415
|
+
return typeof this.config.transport === "function"
|
|
416
|
+
? this.config.transport()
|
|
417
|
+
: this.config.transport;
|
|
418
|
+
}
|
|
419
|
+
const service = this.getChannelService();
|
|
420
|
+
const transport = service?.getTransport?.();
|
|
421
|
+
if (transport) {
|
|
422
|
+
this.setTransport(transport);
|
|
423
|
+
return transport;
|
|
424
|
+
}
|
|
425
|
+
throw ValidationError.required(`ChannelRouter[${this.channel}].transport`);
|
|
426
|
+
}
|
|
427
|
+
getChannelService() {
|
|
428
|
+
const service = this.config.channelService;
|
|
429
|
+
if (!service) {
|
|
430
|
+
throw ValidationError.required(`ChannelRouter[${this.channel}].channelService`);
|
|
431
|
+
}
|
|
432
|
+
return typeof service === "function" ? service() : service;
|
|
433
|
+
}
|
|
434
|
+
setChannelService(service) {
|
|
435
|
+
this.config.channelService = service;
|
|
436
|
+
// If router doesn't have transport configured, get it from the service
|
|
437
|
+
if (!this.config.transport) {
|
|
438
|
+
const transport = service?.getTransport?.();
|
|
439
|
+
if (transport) {
|
|
440
|
+
this.setTransport(transport);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
setTransport(transport) {
|
|
445
|
+
this.config.transport = transport;
|
|
446
|
+
}
|
|
447
|
+
setScope(scope) {
|
|
448
|
+
this.config.scope = scope;
|
|
449
|
+
}
|
|
450
|
+
setContextBuilder(contextBuilder) {
|
|
451
|
+
this.config.contextBuilder = contextBuilder;
|
|
452
|
+
}
|
|
453
|
+
// =========================================================================
|
|
454
|
+
// Handler Registration (Fluent API)
|
|
455
|
+
// =========================================================================
|
|
456
|
+
/**
|
|
457
|
+
* Register a handler for a specific event type.
|
|
458
|
+
* Handler receives (event, context) where context is built from the request
|
|
459
|
+
* via contextBuilder or passed directly to handle().
|
|
460
|
+
*/
|
|
461
|
+
on(eventType, handler) {
|
|
462
|
+
this.handlers.set(eventType, handler);
|
|
463
|
+
return this;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Register a default handler for unmatched event types.
|
|
467
|
+
*/
|
|
468
|
+
default(handler) {
|
|
469
|
+
this.defaultHandler = handler;
|
|
470
|
+
return this;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Register an error handler.
|
|
474
|
+
*/
|
|
475
|
+
onError(handler) {
|
|
476
|
+
this.errorHandler = handler;
|
|
477
|
+
return this;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Handle an incoming event.
|
|
481
|
+
* Called by ChannelService.handleEvent() or directly.
|
|
482
|
+
* Auto-notifies registered execution contexts after handler returns.
|
|
483
|
+
*
|
|
484
|
+
* @param event - The channel event to handle
|
|
485
|
+
* @param context - Context for the handler (required)
|
|
486
|
+
* @returns Result from the handler, or undefined if no handler matched
|
|
487
|
+
*/
|
|
488
|
+
async handle(event, context) {
|
|
489
|
+
const handler = this.handlers.get(event.type) || this.defaultHandler;
|
|
490
|
+
if (!handler) {
|
|
491
|
+
return undefined;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
const result = await handler(event, context);
|
|
495
|
+
// Auto-notify all registered execution contexts for this scope
|
|
496
|
+
this.notifyRegisteredContexts(context, event, result);
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
499
|
+
catch (error) {
|
|
500
|
+
if (this.errorHandler) {
|
|
501
|
+
this.errorHandler(error, event);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
console.error(`ChannelRouter[${this.channel}] error handling ${event.type}:`, error);
|
|
505
|
+
}
|
|
506
|
+
throw error;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Build the context for the handler.
|
|
511
|
+
*/
|
|
512
|
+
buildContext(data) {
|
|
513
|
+
return this.config.contextBuilder?.(data) ?? data;
|
|
514
|
+
}
|
|
515
|
+
// =========================================================================
|
|
516
|
+
// Context Registry - Per-execution context registration
|
|
517
|
+
// =========================================================================
|
|
518
|
+
/**
|
|
519
|
+
* Check if value is a ScopeMapping (object with string values, not an array or function)
|
|
520
|
+
*/
|
|
521
|
+
isScopeMapping(value) {
|
|
522
|
+
return (typeof value === "object" &&
|
|
523
|
+
value !== null &&
|
|
524
|
+
!Array.isArray(value) &&
|
|
525
|
+
typeof value !== "function");
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Extract scope keys from channel context based on scope config.
|
|
529
|
+
* Returns array of fully qualified keys like 'prefix:value'.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* // scope: { user: 'userId' }, ctx: { userId: 'alice' }
|
|
533
|
+
* // → ['user:alice']
|
|
534
|
+
*
|
|
535
|
+
* // scope: [{ user: 'userId' }, { thread: 'threadId' }], ctx: { userId: 'alice', threadId: '123' }
|
|
536
|
+
* // → ['user:alice', 'thread:123']
|
|
537
|
+
*
|
|
538
|
+
* // scope: (ctx) => `user:${ctx.userId}`, ctx: { userId: 'alice' }
|
|
539
|
+
* // → ['user:alice']
|
|
540
|
+
*/
|
|
541
|
+
getScopeKeys(channelContext) {
|
|
542
|
+
const scope = this.config.scope;
|
|
543
|
+
const ctx = channelContext;
|
|
544
|
+
if (!scope) {
|
|
545
|
+
return ["default"];
|
|
546
|
+
}
|
|
547
|
+
// Function: (ctx) => 'user:alice' or ['user:alice', 'thread:123']
|
|
548
|
+
if (typeof scope === "function") {
|
|
549
|
+
const scopeFn = scope;
|
|
550
|
+
const result = scopeFn(ctx);
|
|
551
|
+
return Array.isArray(result) ? result : [result];
|
|
552
|
+
}
|
|
553
|
+
// ScopeMapping: { user: 'userId' }
|
|
554
|
+
if (this.isScopeMapping(scope)) {
|
|
555
|
+
return this.extractKeysFromMapping(scope, ctx);
|
|
556
|
+
}
|
|
557
|
+
// ScopeMapping[]: [{ user: 'userId' }, { thread: 'threadId' }]
|
|
558
|
+
if (Array.isArray(scope)) {
|
|
559
|
+
const keys = [];
|
|
560
|
+
for (const item of scope) {
|
|
561
|
+
if (this.isScopeMapping(item)) {
|
|
562
|
+
keys.push(...this.extractKeysFromMapping(item, ctx));
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return keys.length > 0 ? keys : ["default"];
|
|
566
|
+
}
|
|
567
|
+
return ["default"];
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Extract scope keys from a single ScopeMapping.
|
|
571
|
+
*/
|
|
572
|
+
extractKeysFromMapping(mapping, ctx) {
|
|
573
|
+
const keys = [];
|
|
574
|
+
for (const [prefix, field] of Object.entries(mapping)) {
|
|
575
|
+
const value = ctx[field];
|
|
576
|
+
if (value) {
|
|
577
|
+
keys.push(`${prefix}:${value}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return keys;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Register an execution's context with this channel.
|
|
584
|
+
* When channel events are handled, the onEvent callback is automatically invoked
|
|
585
|
+
* with the event and handler result.
|
|
586
|
+
*
|
|
587
|
+
* @param ctx - Engine context (provides executionHandle for auto-cleanup)
|
|
588
|
+
* @param channelContext - The context to register (used for scope matching)
|
|
589
|
+
* @param onEvent - Callback invoked after handler returns (receives event + result)
|
|
590
|
+
* @returns ChannelPublisher for publishing events
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* ```typescript
|
|
594
|
+
* // In component onMount
|
|
595
|
+
* const publisher = channel.registerContext(ctx, { userId }, (event, result) => {
|
|
596
|
+
* if (result?.success) ctx.setState('tasks', result.tasks);
|
|
597
|
+
* });
|
|
598
|
+
* publisher.to(userId).broadcast({ type: 'state_changed', payload });
|
|
599
|
+
*
|
|
600
|
+
* // In component onUnmount
|
|
601
|
+
* channel.unregisterContext(ctx);
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
registerContext(ctx, channelContext, onEvent) {
|
|
605
|
+
const executionId = ctx.executionHandle?.pid;
|
|
606
|
+
if (!executionId) {
|
|
607
|
+
console.warn(`ChannelRouter[${this.channel}]: Cannot register context without execution handle`);
|
|
608
|
+
return this.createPublisher(); // Return publisher anyway for API consistency
|
|
609
|
+
}
|
|
610
|
+
// Get all scope keys for this context (may be multiple with scope mappings)
|
|
611
|
+
const scopeKeys = this.getScopeKeys(channelContext);
|
|
612
|
+
// Register for each scope key
|
|
613
|
+
for (const scopeKey of scopeKeys) {
|
|
614
|
+
const fullKey = `${executionId}:${scopeKey}`;
|
|
615
|
+
// Overwrite if already registered (same execution + scope)
|
|
616
|
+
this.contextRegistry.set(fullKey, {
|
|
617
|
+
executionId,
|
|
618
|
+
context: channelContext,
|
|
619
|
+
onEvent,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
// Auto-cleanup on execution end (fail-safe)
|
|
623
|
+
const cleanupHandler = () => {
|
|
624
|
+
this.cleanupExecution(executionId);
|
|
625
|
+
};
|
|
626
|
+
// Hook into execution completion/cancellation
|
|
627
|
+
ctx.executionHandle?.once("completed", cleanupHandler);
|
|
628
|
+
ctx.executionHandle?.once("abort", cleanupHandler);
|
|
629
|
+
// Return publisher for this channel
|
|
630
|
+
return this.createPublisher();
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Unregister all contexts for an execution.
|
|
634
|
+
* Alternative to storing the returned function from registerContext.
|
|
635
|
+
*
|
|
636
|
+
* @param ctx - Engine context to unregister
|
|
637
|
+
*/
|
|
638
|
+
unregisterContext(ctx) {
|
|
639
|
+
const executionId = ctx.executionHandle?.pid;
|
|
640
|
+
if (!executionId)
|
|
641
|
+
return;
|
|
642
|
+
// Remove all entries for this execution
|
|
643
|
+
for (const [key] of this.contextRegistry) {
|
|
644
|
+
if (key.startsWith(`${executionId}:`)) {
|
|
645
|
+
this.contextRegistry.delete(key);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Clean up all contexts for a specific execution ID.
|
|
651
|
+
* Called as a fail-safe when execution ends.
|
|
652
|
+
*
|
|
653
|
+
* @param executionId - The execution ID to clean up
|
|
654
|
+
*/
|
|
655
|
+
cleanupExecution(executionId) {
|
|
656
|
+
for (const [key] of this.contextRegistry) {
|
|
657
|
+
if (key.startsWith(`${executionId}:`)) {
|
|
658
|
+
this.contextRegistry.delete(key);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Extract the scope key from a registry key.
|
|
664
|
+
* Registry keys are formatted as `${executionId}:${scopeKey}`.
|
|
665
|
+
* We find the first colon and take everything after it as the scopeKey.
|
|
666
|
+
*/
|
|
667
|
+
extractScopeKeyFromRegistryKey(registryKey) {
|
|
668
|
+
const colonIndex = registryKey.indexOf(":");
|
|
669
|
+
if (colonIndex === -1) {
|
|
670
|
+
return registryKey;
|
|
671
|
+
}
|
|
672
|
+
return registryKey.substring(colonIndex + 1);
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Execute a callback for each registered context matching scope(s).
|
|
676
|
+
* Scope keys are derived from the provided context (or explicit scopeKey).
|
|
677
|
+
* Deduplicates by executionId - each execution's callback runs at most once.
|
|
678
|
+
*
|
|
679
|
+
* @param scopeKeyOrContext - Either explicit scope key or context to derive scope from
|
|
680
|
+
* @param fn - Callback to execute for each matching context
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```typescript
|
|
684
|
+
* // Using context (scope derived automatically, supports multiple scopes)
|
|
685
|
+
* channel.forEachContext(ctx, (regCtx) => regCtx.onUpdate?.(result.notes));
|
|
686
|
+
*
|
|
687
|
+
* // Using explicit scope key (single key)
|
|
688
|
+
* channel.forEachContext('user:alice', (regCtx) => regCtx.onUpdate?.(result.notes));
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
forEachContext(scopeKeyOrContext, fn) {
|
|
692
|
+
const scopeKeys = typeof scopeKeyOrContext === "string"
|
|
693
|
+
? [scopeKeyOrContext]
|
|
694
|
+
: this.getScopeKeys(scopeKeyOrContext);
|
|
695
|
+
const processedExecutions = new Set();
|
|
696
|
+
for (const scopeKey of scopeKeys) {
|
|
697
|
+
for (const [key, { executionId, context }] of this.contextRegistry) {
|
|
698
|
+
// Extract scope key from registry key and compare exactly
|
|
699
|
+
// This prevents 'malicious_user:alice' from matching 'user:alice'
|
|
700
|
+
const registeredScopeKey = this.extractScopeKeyFromRegistryKey(key);
|
|
701
|
+
if (registeredScopeKey === scopeKey && !processedExecutions.has(executionId)) {
|
|
702
|
+
processedExecutions.add(executionId);
|
|
703
|
+
try {
|
|
704
|
+
fn(context);
|
|
705
|
+
}
|
|
706
|
+
catch (error) {
|
|
707
|
+
console.error(`ChannelRouter[${this.channel}]: Error in forEachContext callback:`, error);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Notify all registered contexts for matching scopes with an event and result.
|
|
715
|
+
* Called automatically by handle() after handler returns.
|
|
716
|
+
* Deduplicates by executionId - each execution's callback runs at most once.
|
|
717
|
+
*
|
|
718
|
+
* @param context - Context to derive scope from
|
|
719
|
+
* @param event - The channel event
|
|
720
|
+
* @param result - The handler's result
|
|
721
|
+
*/
|
|
722
|
+
notifyRegisteredContexts(context, event, result) {
|
|
723
|
+
const scopeKeys = this.getScopeKeys(context);
|
|
724
|
+
const notifiedExecutions = new Set();
|
|
725
|
+
for (const scopeKey of scopeKeys) {
|
|
726
|
+
for (const [key, { executionId, onEvent }] of this.contextRegistry) {
|
|
727
|
+
// Extract scope key from registry key and compare exactly
|
|
728
|
+
// This prevents 'malicious_user:alice' from matching 'user:alice'
|
|
729
|
+
const registeredScopeKey = this.extractScopeKeyFromRegistryKey(key);
|
|
730
|
+
if (registeredScopeKey === scopeKey && !notifiedExecutions.has(executionId) && onEvent) {
|
|
731
|
+
notifiedExecutions.add(executionId);
|
|
732
|
+
try {
|
|
733
|
+
onEvent(event, result);
|
|
734
|
+
}
|
|
735
|
+
catch (error) {
|
|
736
|
+
console.error(`ChannelRouter[${this.channel}]: Error in onEvent callback:`, error);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Get the number of registered contexts (for debugging/monitoring).
|
|
744
|
+
*/
|
|
745
|
+
getRegisteredContextCount() {
|
|
746
|
+
return this.contextRegistry.size;
|
|
747
|
+
}
|
|
748
|
+
// =========================================================================
|
|
749
|
+
// Publishing Methods
|
|
750
|
+
// =========================================================================
|
|
751
|
+
/**
|
|
752
|
+
* Resolve a value or getter function.
|
|
753
|
+
*/
|
|
754
|
+
resolve(valueOrGetter) {
|
|
755
|
+
return typeof valueOrGetter === "function" ? valueOrGetter() : valueOrGetter;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Get the scope prefix for a given scope key.
|
|
759
|
+
* If scopeKey is provided, uses that key from the mapping.
|
|
760
|
+
* Otherwise uses the first key from the mapping.
|
|
761
|
+
*
|
|
762
|
+
* Note: Function scopes are not supported for publishing via .scope()/.to() -
|
|
763
|
+
* use mapping syntax instead: { user: 'userId' }
|
|
764
|
+
*/
|
|
765
|
+
getScopePrefix(scopeKey) {
|
|
766
|
+
const scope = this.config.scope;
|
|
767
|
+
if (!scope)
|
|
768
|
+
return undefined;
|
|
769
|
+
// Function scope - can't select by key for publishing
|
|
770
|
+
// (functions are for context matching, not room prefix selection)
|
|
771
|
+
if (typeof scope === "function") {
|
|
772
|
+
return undefined;
|
|
773
|
+
}
|
|
774
|
+
// Get the mapping (flatten if array)
|
|
775
|
+
const mapping = Array.isArray(scope)
|
|
776
|
+
? scope.reduce((acc, m) => ({ ...acc, ...m }), {})
|
|
777
|
+
: scope;
|
|
778
|
+
// If scopeKey provided, use it; otherwise use first key
|
|
779
|
+
if (scopeKey) {
|
|
780
|
+
return scopeKey in mapping ? scopeKey : undefined;
|
|
781
|
+
}
|
|
782
|
+
const keys = Object.keys(mapping);
|
|
783
|
+
return keys.length > 0 ? keys[0] : undefined;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Create a scoped publisher (has scope prefix set, needs .to(id)).
|
|
787
|
+
*/
|
|
788
|
+
createScopedPublisherForKey(scopePrefix) {
|
|
789
|
+
return {
|
|
790
|
+
to: (idGetter) => {
|
|
791
|
+
return this.createBoundPublisherForPrefix(scopePrefix, idGetter);
|
|
792
|
+
},
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Create a bound publisher for a specific scope prefix.
|
|
797
|
+
*/
|
|
798
|
+
createBoundPublisherForPrefix(scopePrefix, idGetter) {
|
|
799
|
+
return {
|
|
800
|
+
send: async (event) => {
|
|
801
|
+
const id = this.resolve(idGetter);
|
|
802
|
+
await this.sendInternalWithPrefix(scopePrefix, id, event);
|
|
803
|
+
},
|
|
804
|
+
broadcast: async (event, options) => {
|
|
805
|
+
const id = this.resolve(idGetter);
|
|
806
|
+
await this.sendInternalWithPrefix(scopePrefix, id, event, {
|
|
807
|
+
excludeSender: true,
|
|
808
|
+
sourceConnectionId: options?.sourceConnectionId,
|
|
809
|
+
});
|
|
810
|
+
},
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Internal send with explicit scope prefix and id.
|
|
815
|
+
*/
|
|
816
|
+
async sendInternalWithPrefix(scopePrefix, id, event, options) {
|
|
817
|
+
const transport = this.getTransport();
|
|
818
|
+
const room = `${scopePrefix}:${id}`;
|
|
819
|
+
const sourceConnectionId = options?.sourceConnectionId ??
|
|
820
|
+
Context.tryGet()?.metadata?.["sessionId"];
|
|
821
|
+
await transport.send({
|
|
822
|
+
channel: this.channel,
|
|
823
|
+
type: event.type,
|
|
824
|
+
payload: event.payload,
|
|
825
|
+
target: {
|
|
826
|
+
rooms: [room],
|
|
827
|
+
excludeSender: options?.excludeSender,
|
|
828
|
+
},
|
|
829
|
+
metadata: {
|
|
830
|
+
timestamp: Date.now(),
|
|
831
|
+
source: `ChannelRouter:${this.channel}`,
|
|
832
|
+
sourceConnectionId,
|
|
833
|
+
},
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Create a publisher interface for this channel.
|
|
838
|
+
*/
|
|
839
|
+
createPublisher() {
|
|
840
|
+
return {
|
|
841
|
+
scope: (scopeKey) => {
|
|
842
|
+
const prefix = this.getScopePrefix(scopeKey);
|
|
843
|
+
if (!prefix) {
|
|
844
|
+
throw new NotFoundError("scope", scopeKey, `ChannelRouter[${this.channel}]: Unknown scope key`);
|
|
845
|
+
}
|
|
846
|
+
return this.createScopedPublisherForKey(prefix);
|
|
847
|
+
},
|
|
848
|
+
to: (idGetter) => {
|
|
849
|
+
const prefix = this.getScopePrefix();
|
|
850
|
+
if (!prefix) {
|
|
851
|
+
throw ValidationError.required(`ChannelRouter[${this.channel}].scope`);
|
|
852
|
+
}
|
|
853
|
+
return this.createBoundPublisherForPrefix(prefix, idGetter);
|
|
854
|
+
},
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Get a publisher without subscribing (for services that only publish).
|
|
859
|
+
*/
|
|
860
|
+
publisher() {
|
|
861
|
+
return this.createPublisher();
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Factory function to create a ChannelRouter with common defaults.
|
|
866
|
+
*/
|
|
867
|
+
export function createChannelRouter(channel, config = {}) {
|
|
868
|
+
return new ChannelRouter(channel, config);
|
|
869
|
+
}
|
|
870
|
+
//# sourceMappingURL=service.js.map
|