@codemation/core 0.10.2 → 0.11.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +183 -0
  2. package/dist/CostCatalogContract-DZgcUBE4.d.cts +19 -0
  3. package/dist/{EngineRuntimeRegistration.types-ClLuY1FG.d.ts → EngineRuntimeRegistration.types-BQbS9_gs.d.ts} +2 -2
  4. package/dist/{EngineRuntimeRegistration.types-BryWi2mA.d.cts → EngineRuntimeRegistration.types-Cggm5GVY.d.cts} +8 -2
  5. package/dist/{InMemoryRunDataFactory-DeXNJt1O.d.cts → InMemoryRunDataFactory-C7YItvHG.d.cts} +9 -19
  6. package/dist/{InMemoryRunEventBusRegistry-sM4z4n_i.js → InMemoryRunEventBusRegistry-Bwunvt1T.js} +1 -1
  7. package/dist/{InMemoryRunEventBusRegistry-sM4z4n_i.js.map → InMemoryRunEventBusRegistry-Bwunvt1T.js.map} +1 -1
  8. package/dist/{InMemoryRunEventBusRegistry-VM3OWnHo.cjs → InMemoryRunEventBusRegistry-Sa86VxuV.cjs} +1 -1
  9. package/dist/{InMemoryRunEventBusRegistry-VM3OWnHo.cjs.map → InMemoryRunEventBusRegistry-Sa86VxuV.cjs.map} +1 -1
  10. package/dist/ItemsInputNormalizer-C_dpn76M.d.cts +407 -0
  11. package/dist/ItemsInputNormalizer-CwdOhSAK.cjs +43 -0
  12. package/dist/ItemsInputNormalizer-CwdOhSAK.cjs.map +1 -0
  13. package/dist/ItemsInputNormalizer-D-MH8MBs.js +36 -0
  14. package/dist/ItemsInputNormalizer-D-MH8MBs.js.map +1 -0
  15. package/dist/ItemsInputNormalizer-_Mfcd3YU.d.ts +321 -0
  16. package/dist/RunIntentService-BVur7x9n.d.ts +285 -0
  17. package/dist/RunIntentService-CEF-sFfI.d.cts +206 -0
  18. package/dist/{RunIntentService-BqNjrksF.d.cts → agentMcpTypes-ZiNbNsEi.d.cts} +1717 -1809
  19. package/dist/bootstrap/index.cjs +4 -2
  20. package/dist/bootstrap/index.d.cts +8 -3
  21. package/dist/bootstrap/index.d.ts +6 -4
  22. package/dist/bootstrap/index.js +4 -2
  23. package/dist/{bootstrap-DtjQtuvi.cjs → bootstrap-BxuTFTLB.cjs} +41 -34
  24. package/dist/bootstrap-BxuTFTLB.cjs.map +1 -0
  25. package/dist/{bootstrap-BfFKGzyj.js → bootstrap-D_Yyi0wL.js} +9 -2
  26. package/dist/bootstrap-D_Yyi0wL.js.map +1 -0
  27. package/dist/browser.cjs +16 -0
  28. package/dist/browser.d.cts +4 -0
  29. package/dist/browser.d.ts +3 -0
  30. package/dist/browser.js +4 -0
  31. package/dist/contracts-CK0x6w_G.cjs +74 -0
  32. package/dist/contracts-CK0x6w_G.cjs.map +1 -0
  33. package/dist/contracts-DXdfTdpW.js +50 -0
  34. package/dist/contracts-DXdfTdpW.js.map +1 -0
  35. package/dist/contracts.cjs +6 -0
  36. package/dist/contracts.d.cts +5 -0
  37. package/dist/contracts.d.ts +2 -0
  38. package/dist/contracts.js +3 -0
  39. package/dist/di-0Wop7z1y.js +376 -0
  40. package/dist/di-0Wop7z1y.js.map +1 -0
  41. package/dist/di-BlEKdoZS.cjs +489 -0
  42. package/dist/di-BlEKdoZS.cjs.map +1 -0
  43. package/dist/executionPersistenceContracts-BgZMRsTa.d.cts +275 -0
  44. package/dist/{index-CJQtTY_M.d.ts → index-62Ba9f7D.d.ts} +114 -320
  45. package/dist/{RunIntentService-CI-F8qQ7.d.ts → index-zWGtEhrf.d.ts} +1811 -1914
  46. package/dist/index.cjs +76 -71
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +112 -656
  49. package/dist/index.d.ts +5 -3
  50. package/dist/index.js +52 -50
  51. package/dist/index.js.map +1 -1
  52. package/dist/params-B5SENSzZ.d.cts +44 -0
  53. package/dist/{runtime-_ywksLa6.cjs → runtime-DBzq5YBi.cjs} +125 -489
  54. package/dist/runtime-DBzq5YBi.cjs.map +1 -0
  55. package/dist/{runtime-DbMjpb5d.js → runtime-cxmUkk0l.js} +117 -369
  56. package/dist/runtime-cxmUkk0l.js.map +1 -0
  57. package/dist/testing.cjs +23 -21
  58. package/dist/testing.cjs.map +1 -1
  59. package/dist/testing.d.cts +4 -3
  60. package/dist/testing.d.ts +3 -2
  61. package/dist/testing.js +5 -3
  62. package/dist/testing.js.map +1 -1
  63. package/package.json +12 -17
  64. package/src/ai/AgentConnectionNodeCollector.ts +47 -5
  65. package/src/authoring/defineNode.types.ts +21 -1
  66. package/src/authoring/definePollingTrigger.types.ts +20 -0
  67. package/src/binaries/UnavailableBinaryStorage.ts +6 -0
  68. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +9 -0
  69. package/src/browser.ts +1 -0
  70. package/src/contracts/AgentBindError.ts +11 -0
  71. package/src/contracts/CodemationTelemetryAttributeNames.ts +4 -0
  72. package/src/contracts/NoOpAgentMcpIntegration.ts +13 -0
  73. package/src/contracts/agentMcpTypes.ts +64 -0
  74. package/src/contracts/index.ts +4 -0
  75. package/src/contracts/mcpTypes.ts +29 -0
  76. package/src/contracts/runTypes.ts +8 -0
  77. package/src/contracts/runtimeTypes.ts +4 -0
  78. package/src/contracts/workflowTypes.ts +21 -0
  79. package/src/contracts.ts +3 -0
  80. package/src/credentials/OAuthFlowExecutor.types.ts +45 -0
  81. package/src/di/CoreTokens.ts +7 -0
  82. package/src/execution/InProcessRetryRunner.ts +31 -5
  83. package/src/execution/NodeExecutor.ts +27 -7
  84. package/src/execution/NodeRunStateWriter.ts +2 -0
  85. package/src/index.ts +10 -0
  86. package/src/orchestration/RunContinuationService.ts +6 -2
  87. package/src/runStorage/InMemoryBinaryStorageRegistry.ts +10 -0
  88. package/src/scheduler/InlineDrivingScheduler.ts +26 -22
  89. package/src/types/index.ts +1 -0
  90. package/src/validation/WorkflowEdgePortError.types.ts +16 -0
  91. package/src/validation/WorkflowEdgePortValidator.ts +52 -0
  92. package/src/workflow/definition/ConnectionInvocationIdFactory.ts +4 -3
  93. package/src/workflow/definition/ConnectionNodeIdFactory.ts +25 -0
  94. package/src/workflow/definition/NodeIterationIdFactory.ts +5 -3
  95. package/src/workflowSnapshots/WorkflowSnapshotCodec.ts +42 -10
  96. package/tsdown.config.ts +1 -1
  97. package/dist/bootstrap-BfFKGzyj.js.map +0 -1
  98. package/dist/bootstrap-DtjQtuvi.cjs.map +0 -1
  99. package/dist/runtime-DbMjpb5d.js.map +0 -1
  100. package/dist/runtime-_ywksLa6.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,188 @@
1
1
  # @codemation/core
2
2
 
3
+ ## 0.11.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#154](https://github.com/MadeRelevant/codemation/pull/154) [`e0933eb`](https://github.com/MadeRelevant/codemation/commit/e0933ebc51806a9593f94758860c591b8346a7a5) Thanks [@cblokland90](https://github.com/cblokland90)! - fix: compile `./browser` and `./contracts` subpath exports (were shipping raw .ts, broke Turbopack consumers)
8
+
9
+ The `./browser` and `./contracts` subpaths in `@codemation/core` were pointing at raw TypeScript source files (`./src/browser.ts`, `./src/contracts.ts`). Turbopack (used by Next.js) and other browser bundlers refuse to process raw `.ts` from published npm packages, causing builds to fail with "Unknown module type" errors.
10
+
11
+ Both entry points are now compiled by tsdown and the exports map points at `./dist/browser.{js,cjs,d.ts}` and `./dist/contracts.{js,cjs,d.ts}`. A `development` condition retains the direct-source path for framework-author mode. API surface is unchanged.
12
+
13
+ ## 0.11.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 8285ec0: Add a `statusLabel` field to `ConnectionInvocationRecord` / `ConnectionInvocationAppendArgs` so connection invocations can carry a short human-readable description of what they are doing (e.g. `"calling search_messages"`). The engine-side `NodeRunStateWriter` persists it; the canvas-side mirror picks it up via the standard patch projection.
18
+
19
+ Wire per-MCP-tool-call lifecycle invocations through `AgentMcpIntegration`. `prepareMcpTools` now accepts an optional `appendMcpInvocation` callback (plus the agent activation / iteration / item / parent-invocation context). When the host-side `AgentMcpIntegrationImpl` wraps a tool's `execute`, it emits a `running` record with `statusLabel: "calling <toolName>"` and a matching `completed` or `failed` record; the existing telemetry span and 403 `NeedsReconsentEvent` paths are preserved. `@codemation/canvas-core` exposes a `CurrentStatusLabelSelector` and `WorkflowCanvasNodeData.currentStatusLabel`; `@codemation/canvas` renders the latest non-empty label as a sub-line under the node card. The two capabilities work together: MCP tool calls under an agent now stream the same invocation events the LLM and node-backed tool paths already emit, and the canvas surfaces the running label per-node.
20
+
21
+ - 8285ec0: Add optional `subjectName?: string` to `ConnectionInvocationRecord` and `ConnectionInvocationAppendArgs` — a stable identifier for the thing an invocation acts on that persists across status transitions. The MCP integration's `wrapToolExecutes` sets it to the tool name on every transition (running / completed / failed), so the inspector's tool-call timeline entries can render `"Tool call · <toolName>"` for MCP servers (which expose many tools through a single connection node) instead of an opaque `"Tool call"`.
22
+
23
+ For node-backed agent tools, the parent connection node id already encodes the tool name — `subjectName` stays unset there and the inspector renders the existing `"Tool call"` title unchanged.
24
+
25
+ `statusLabel` (the running-only sentence rendered on the canvas card sub-line) is unchanged; `subjectName` is the persistent structural sibling used by the inspector.
26
+
27
+ - 8285ec0: Export `McpServerDeclaration` and `McpServerTransport` from `@codemation/core` main entry point and contracts subpath.
28
+ - 7b50018: feat(core-nodes,msgraph,gmail): inspectorSummary on every built-in node
29
+
30
+ Implements `inspectorSummary()` on all built-in node and trigger config classes so the workflow
31
+ inspector panel introduced in #136 has content for every shipped node.
32
+ - `@codemation/core`: extends `definePollingTrigger` to accept and plumb an `inspectorSummary`
33
+ option, mirroring the existing `defineNode` / `defineBatchNode` pattern. Also extends
34
+ `defineRestNode` (in `@codemation/core-nodes`) with the same option.
35
+ - `@codemation/core-nodes`: `inspectorSummary()` on `HttpRequest`, `AIAgent`, `CronTrigger`,
36
+ `ManualTrigger`, `SubWorkflow`, `Callback`, `If`, `Switch`, `Filter`, `Split`, `Merge`,
37
+ `Wait`, `WebhookTrigger`, `TestTrigger`, `Aggregate`, `MapData`, `Assertion`.
38
+ - `@codemation/core-nodes-msgraph`: `inspectorSummary` option on all 17 mail/drive/excel nodes
39
+ plus the `onNewMsGraphMailTrigger` polling trigger.
40
+ - `@codemation/core-nodes-gmail`: `inspectorSummary()` on `OnNewGmailTrigger`.
41
+ Gmail action nodes (`SendGmailMessage`, `ReplyToGmailMessage`, `ModifyGmailLabels`) return
42
+ `undefined` — all their config is per-item via `inputSchema`, nothing to surface at design time.
43
+ - `@codemation/core`: `WorkflowSnapshotCodec.serializeConfig` now pre-serializes the result of
44
+ `inspectorSummary()` into the snapshot JSON as `_inspectorSummary` so the browser-side mapper
45
+ can surface the same rows without calling class methods.
46
+ - `@codemation/next-host`: `PersistedWorkflowSnapshotMapper` now reads `_inspectorSummary` from
47
+ the serialized config and includes it in the node DTO, maintaining parity with the live mapper.
48
+
49
+ - 8285ec0: Add LocalOAuthFlowExecutor for framework (OSS/standalone) mode. Reads clientId from the credential instance's publicConfig and clientSecret from its secret material; builds PKCE-protected consent URLs; exchanges auth codes and refresh tokens directly against the provider's token endpoint. Also patches OAuthFlowExecutor.refresh to accept typeId and instanceId alongside the material, since looking up the tokenUrl and app credentials requires the instance.
50
+ - 8285ec0: Remove the MCP credential bypass on AI agents. `AIAgent.mcpServers` is now a plain
51
+ `ReadonlyArray<string>` of server ids — the inline `{ credential }` field is gone. Each
52
+ declared server surfaces a standard credential slot on the agent node (key
53
+ `mcp:<serverId>`, label and accepted types from the MCP catalog) and binds through the
54
+ same `CredentialBinding` table as every other slot. At execute time the host resolves the
55
+ binding via `getBinding({ workflowId, agentNodeId, slotKey: mcp:<serverId> })`, then opens
56
+ the MCP pool with the resolved credential instance — no more reading the credential id
57
+ out of the workflow config.
58
+
59
+ Breaking — config shape change. Replace:
60
+
61
+ ```ts
62
+ mcpServers: {
63
+ gmail: {
64
+ credential: "<instanceId>";
65
+ }
66
+ }
67
+ ```
68
+
69
+ with:
70
+
71
+ ```ts
72
+ mcpServers: ["gmail"];
73
+ ```
74
+
75
+ Then bind the credential through the canvas credential dropdown before activating the
76
+ workflow, the same way trigger credentials are bound. The `McpServerBindings` /
77
+ `McpServerExplicitBinding` types are removed from `@codemation/core`;
78
+ `AgentMcpIntegration.prepareMcpTools` now takes `{ workflowId, agentNodeId, serverIds }`.
79
+
80
+ - 8285ec0: Replace `McpServerDeclaration.credentialKind` / `credentialTypeId` / `oauthAppKey` with `acceptedCredentialTypes?: ReadonlyArray<string>`, matching the `CredentialRequirement.acceptedTypes` shape. Absent or empty array means no credential required. Gmail MCP declaration now uses `["oauth.google.gmail"]`, the same type as the Gmail trigger node.
81
+ - 8285ec0: Add `McpServerDeclaration` type and `McpServerCatalog` service (Story 7).
82
+ - `@codemation/core` exports `McpServerDeclaration` and `McpServerTransport` from `packages/core/src/contracts/mcpTypes.ts`.
83
+ - `CodemationPlugin` gains an optional `mcpServers?: ReadonlyArray<McpServerDeclaration>` field.
84
+ - `CodemationConfig` gains an optional `mcpServers?: ReadonlyArray<McpServerDeclaration>` field (also threaded through `AppConfig` and `DefineCodemationAppOptions`).
85
+ - `McpServerCatalog` in `packages/host/src/mcp/` merges declarations from three sources (`plugin`, `config`, `controlPlane`) with deterministic precedence and validation (id regex, stdio gate, credential requirements).
86
+ - `CodemationPluginDiscovery.isPluginConfig` now recognises `mcpServers`-only plugins.
87
+ - Plugin registrar and app container factory wire catalog merge on startup.
88
+
89
+ - 8285ec0: MCP servers are now first-class agent connection slots with credential pickers.
90
+
91
+ `AgentConnectionNodeCollector.collect()` accepts an optional `mcpServerResolver` callback (Pattern A). When provided, each entry in `agentConfig.mcpServers` is resolved and emitted as a `"tools"` connection slot descriptor — identical pattern to tools. Each MCP slot gets a stable node id via `ConnectionNodeIdFactory.mcpConnectionNodeId()` and exposes `getCredentialRequirements()` from the resolved `McpServerDeclaration`.
92
+
93
+ `AIAgentConnectionWorkflowExpander` accepts the resolver in its constructor; `AppContainerFactory` wires `McpServerCatalog.get` there. MCP credential pickers are now visible on the canvas alongside tool slots.
94
+
95
+ Removes the `AIAgent.inspectorSummary()` band-aid that listed MCP server ids as plain text — those are now first-class connection nodes rendered on the canvas directly.
96
+
97
+ - 0082ab5: Adds an `inspectorSummary` hook on node configs (and `defineNode({ inspectorSummary })` for plugin-author nodes). Returns 2–6 short label/value pairs that describe what the node will do at design time — model + prompt for an agent, method + URL for an HTTP call, schedule + timezone for a cron, etc. Surfaced in the workflow editor's node-properties panel as a new "Configuration" section that renders before any run telemetry exists. Hidden when no rows are produced; node configs that don't implement the hook contribute nothing. Built-in nodes will fill these in across follow-up PRs.
98
+ - 8285ec0: Define `OAuthFlowExecutor` interface — the mode-agnostic contract for the OAuth dance (start → callback → token storage) and refresh. Implementations (local and managed) will register behind this single interface via DI.
99
+ - 8285ec0: Remove deprecated broker-era MCP fields: `NeedsReconsentEvent.oauthAppKey`, shorthand `McpServerBindings` string array form, and `AgentMcpIntegrationImpl.autoResolveCredential`. Explicit binding (`{ serverId: { credential: "<instanceId>" } }`) is now the only supported form — eliminating ambiguity when multiple credential instances of the same type exist.
100
+ - 8285ec0: feat(host/binary): S3BinaryStorage implementation + boot connectivity check (Sprint 15 Story 03)
101
+
102
+ Adds `S3BinaryStorage` — a Scaleway-compatible S3 implementation of `BinaryStorage` using
103
+ `@aws-sdk/client-s3` + `@aws-sdk/lib-storage` (multipart for large payloads). Key scheme:
104
+ `<workspaceId>/<runId>/<binaryId>`.
105
+
106
+ Runtime selection is controlled by `BINARY_STORAGE_KIND` env var (`"local"` default | `"s3"`).
107
+ When `"s3"`, all `BINARY_STORAGE_S3_*` vars are required and validated at boot. A `HeadBucket`
108
+ connectivity check fails loudly on startup if the bucket is unreachable.
109
+
110
+ Extends `BinaryStorage` interface (core) with `deleteMany(keys)` and `listByPrefix(prefix)` for
111
+ bulk-delete (1000-key S3 batching) and workspace-prefix enumeration (GDPR erasure). All existing
112
+ implementations (`InMemoryBinaryStorage`, `LocalFilesystemBinaryStorage`, `UnavailableBinaryStorage`)
113
+ updated with correct implementations.
114
+
115
+ - 8285ec0: feat(story-11): Wire MCP catalog into agent — explicit and shorthand binding, scope validation, pool integration, telemetry, and runtime 403 detection
116
+ - `@codemation/core`: `AgentMcpIntegration` interface + token, `McpServerBindings` types, `NeedsReconsentEvent`, `AgentBindError`, `NoOpAgentMcpIntegration` fallback, `CodemationTelemetryAttributeNames.mcpServerId/mcpToolName`
117
+ - `@codemation/core-nodes`: `AIAgentConfig` + `AIAgent` extended with `mcpServers` and `pinnedMcpTools`; `DeferredMetaToolStrategy.ownsToolName` covers MCP tools; `AIAgentNode` injects `AgentMcpIntegration` and strips AI SDK auto-execute from strategy tools
118
+ - `@codemation/host`: `AgentMcpIntegrationImpl` — resolves bindings, validates scopes, opens pool, wraps tool execute with telemetry spans and 403/permission error detection
119
+
120
+ ### Patch Changes
121
+
122
+ - 8285ec0: Fix workflow detail screen hydration mismatch caused by overlay siblings (tabs, run button, error banner, realtime badge) being rendered conditionally on controller state that diverges between SSR and a warm React Query client cache. Overlay siblings are now gated behind the same `hasMounted` flag as the canvas root.
123
+
124
+ Render AIAgent MCP-server attachments in the canvas. `WorkflowDefinitionMapper` (the server-side mapper that feeds `/api/workflows/:id`) now passes an `McpServerResolver` backed by the host's `McpServerCatalog` to `AgentConnectionNodeCollector.collect`, so virtual connection nodes for declared `mcpServers` are emitted alongside the LLM and tool children. The MCP descriptor itself carries `icon: "lucide:plug"` and `lucide:plug` is added to the curated `WorkflowCanvasLucideIconRegistry` so MCP servers render with a distinct icon on the synchronous zero-HTTP path.
125
+
126
+ - 8285ec0: test: push @codemation/core coverage to ≥90% (Sprint 16 Story 01)
127
+ - 8285ec0: Stop leaking `node:crypto` and `node:module` into canvas's browser bundle. `NodeIterationIdFactory` and `ConnectionInvocationIdFactory` now use `globalThis.crypto.randomUUID()` instead of importing `randomUUID` from `node:crypto`. Canvas's `tsdown` build is configured with `platform: "neutral"` so the dist no longer ships `createRequire(import.meta.url)` from `node:module`. Fixes consumer Turbopack OOMs when the canvas dist is included in a Next.js client bundle.
128
+ - e4d3e1a: perf(core): yield event loop between node activations in InlineDrivingScheduler
129
+
130
+ Switch `scheduleDrain` from `setTimeout(0)` to `setImmediate` and process one
131
+ activation per drain call instead of draining the entire queue in a while loop.
132
+ This ensures HTTP responses and WebSocket frames can flush to clients between
133
+ node activations — previously synchronous SQLite writes during a 20-node run
134
+ could block the proxy event loop for 3–4 s, making the canvas appear frozen
135
+ until the run completed.
136
+
137
+ - 8285ec0: MCP credential slots now live on the MCP connection node, matching ChatModel and Tool
138
+ connection nodes. Each declared `mcpServers` entry materializes an MCP connection node
139
+ and the credential slot is attached to that node with slot key `"credential"` (label
140
+ and accepted types derived from the MCP catalog declaration). The standard credential
141
+ slot traversal picks them up via `AgentConnectionNodeCollector` — no special-case path.
142
+
143
+ Removed the agent-owned `mcp:<serverId>` slot key. Removed the `mcpSlotKey(serverId)`
144
+ helper from `@codemation/core` (and its re-export from the type-only `contracts`
145
+ subpath). At runtime, `AgentMcpIntegration.prepareMcpTools` now resolves the binding at
146
+ `(workflowId, ConnectionNodeIdFactory.mcpConnectionNodeId(agentNodeId, serverId), "credential")`.
147
+
148
+ Gmail MCP `requiredScopes` trimmed to `["https://www.googleapis.com/auth/gmail.modify"]`
149
+ — `gmail.modify` is a superset of `gmail.readonly` + `gmail.send` for messages, threads,
150
+ drafts, and labels, so the previous list was redundant.
151
+
152
+ - e4d3e1a: perf(core): fail fast on unbound required credential slots before node execution
153
+
154
+ `NodeExecutor` now checks all required (non-optional) credential slots via
155
+ `ctx.getCredential` before entering the retry runner or calling the node's
156
+ `execute`. This means a misconfigured credential surfaces as an immediate error
157
+ without burning the retry budget or running any node setup work. The session is
158
+ created and cached during the pre-flight, so the node itself pays no extra cost
159
+ when it subsequently calls `getCredential`. Optional slots (`optional: true` in
160
+ `getCredentialRequirements`) are skipped.
161
+
162
+ Also adds a `shouldRetry` predicate to `InProcessRetryRunner.run` and uses it
163
+ in `NodeExecutor` to skip all retry delays when the node throws a
164
+ `CredentialUnboundError` (or an error whose `.cause` is one). Previously, nodes
165
+ like `AIAgent` that check credentials inside `execute` rather than via
166
+ `getCredentialRequirements` would burn their full retry budget (e.g. 3 × 2 s
167
+ for AI agents) before surfacing the "slot not bound" error.
168
+
169
+ - 8285ec0: fix: validate edge output ports against declared node ports at load time
170
+
171
+ Adds `WorkflowEdgePortValidator` to `@codemation/core`. The validator checks that every edge's `from.output` port is declared by the source node's `declaredOutputPorts`; nodes without declared ports are treated as unconstrained (legacy behaviour).
172
+
173
+ The validator is wired into `WorkflowDefinitionExportsResolver` in `@codemation/host`, which is the common chokepoint for both the `CodemationConsumerConfigLoader` and `CodemationConsumerAppResolver` load paths. On violation, all errors are reported at once so an agent can self-correct in a single pass.
174
+
175
+ `WorkflowElkPortInfoResolver` in `@codemation/canvas-core` is tightened to render _exactly_ the declared ports (plus the synthetic `error` port when applicable) when a node has `declaredOutputPorts`, preventing phantom handles from rogue edges on the canvas. Legacy nodes without declared ports continue to infer ports from edges as before.
176
+
177
+ Root cause: an LLM agent created an `If` workflow node (declares `["true", "false"]`) with a rogue edge using `output: "main"`, which the canvas unioned into the port list, producing a phantom third handle.
178
+
179
+ - 8285ec0: Sprint 14 coverage: tests for WhenBuilder DSL helper, InMemoryWorkflowExecutionRepository retention paths, DevTrackedProcessTreeKiller edge cases, ConsumerCliTsconfigPreparation resolution, ListenPortConflictDescriber ss fallback, RedisRunEventBus publish/subscribe/teardown, CodemationChatModelFactory HMAC signing, registerCoreNodes smoke, single-react-component-per-file rule branches, and CodemationAgentSkillsCli error/help paths. No production code changes.
180
+ - 8285ec0: Remove the `development` export condition from `@codemation/canvas`, `@codemation/core`, and `@codemation/host` package.json exports. Module resolution now consistently uses the built `dist/` regardless of `NODE_ENV`.
181
+
182
+ **Why:** the `development` condition is auto-applied by bundlers (Next.js dev mode, Vite dev, etc.) and was making every cross-repo monorepo consumer fall through to TypeScript source. For the framework's own `@codemation/next-host`, this was fine — turbo's `dev` already runs `tsdown --watch` on these packages so dist is always fresh in dev. For external consumers (notably the managed control plane), it caused multi-hundred-file recursive source compiles on every cold page load.
183
+
184
+ **Impact:** zero behavior change for normal users (they consume published `dist/`). Framework monorepo devs editing canvas/core/host source still see live updates as long as `tsdown --watch` is running for the package — which is what `pnpm dev` (turbo) orchestrates by default. If you're running an app in isolation without the package's watch task, you now need to start it explicitly.
185
+
3
186
  ## 0.10.2
4
187
 
5
188
  ### Patch Changes
@@ -0,0 +1,19 @@
1
+ import { ni as CostTrackingUsageRecord } from "./agentMcpTypes-ZiNbNsEi.cjs";
2
+
3
+ //#region src/contracts/CostCatalogContract.d.ts
4
+ interface CostCatalogEntry {
5
+ readonly component: CostTrackingUsageRecord["component"];
6
+ readonly provider: string;
7
+ readonly operation: string;
8
+ readonly pricingKey: string;
9
+ readonly usageUnit: string;
10
+ readonly currency: string;
11
+ readonly currencyScale: number;
12
+ readonly pricePerUnitMinor: number;
13
+ }
14
+ interface CostCatalog {
15
+ findEntry(args: CostTrackingUsageRecord): CostCatalogEntry | undefined;
16
+ }
17
+ //#endregion
18
+ export { CostCatalogEntry as n, CostCatalog as t };
19
+ //# sourceMappingURL=CostCatalogContract-DZgcUBE4.d.cts.map
@@ -1,4 +1,4 @@
1
- import { Mr as WebhookTriggerMatcher, Pr as WebhookTriggerRoutingDiagnostics, Ta as DependencyContainer, Wa as EngineExecutionLimitsPolicyConfig, _r as TriggerRuntimeDiagnostics, vn as WorkflowPolicyRuntimeDefaults } from "./RunIntentService-CI-F8qQ7.js";
1
+ import { Cn as EngineExecutionLimitsPolicyConfig, Dr as WorkflowPolicyRuntimeDefaults, Ei as TriggerRuntimeDiagnostics, Ui as WebhookTriggerRoutingDiagnostics, Vi as WebhookTriggerMatcher, in as DependencyContainer } from "./index-zWGtEhrf.js";
2
2
 
3
3
  //#region src/bootstrap/runtime/EngineRuntimeRegistration.types.d.ts
4
4
 
@@ -41,4 +41,4 @@ interface EngineRuntimeRegistrationOptions {
41
41
  }
42
42
  //#endregion
43
43
  export { TriggerRuntimeDiagnosticsProvider as n, WebhookTriggerMatcherProvider as r, EngineRuntimeRegistrationOptions as t };
44
- //# sourceMappingURL=EngineRuntimeRegistration.types-ClLuY1FG.d.ts.map
44
+ //# sourceMappingURL=EngineRuntimeRegistration.types-BQbS9_gs.d.ts.map
@@ -1,4 +1,5 @@
1
- import { Br as PersistedWorkflowTokenRegistryLike, Fi as NodeId, G as WorkflowDefinition, Jr as RunResult, M as ParentExecutionRef, Q as WorkflowPolicyRuntimeDefaults, Ri as WorkflowId, Rr as PersistedWorkflowSnapshot, Zt as TriggerRuntimeDiagnostics, ai as DependencyContainer, d as Items, fn as WebhookTriggerMatcher, mn as WebhookTriggerRoutingDiagnostics, r as Engine, rn as WorkflowRepository, wi as EngineExecutionLimitsPolicyConfig, y as NodeConfigBase, zr as PersistedWorkflowSnapshotNode } from "./RunIntentService-BqNjrksF.cjs";
1
+ import { A as RunResult, At as NodeConfigBase, Er as WebhookTriggerRoutingDiagnostics, Ii as NodeId, S as PersistedWorkflowTokenRegistryLike, St as Items, V as DependencyContainer, Wt as ParentExecutionRef, b as PersistedWorkflowSnapshot, hr as WorkflowRepository, lr as TriggerRuntimeDiagnostics, ot as EngineExecutionLimitsPolicyConfig, rn as WorkflowDefinition, un as WorkflowPolicyRuntimeDefaults, wr as WebhookTriggerMatcher, x as PersistedWorkflowSnapshotNode, zi as WorkflowId } from "./agentMcpTypes-ZiNbNsEi.cjs";
2
+ import { r as Engine } from "./RunIntentService-CEF-sFfI.cjs";
2
3
 
3
4
  //#region src/workflowSnapshots/WorkflowSnapshotCodec.d.ts
4
5
  declare class WorkflowSnapshotCodec {
@@ -7,6 +8,11 @@ declare class WorkflowSnapshotCodec {
7
8
  create(workflow: WorkflowDefinition): PersistedWorkflowSnapshot;
8
9
  hydrate(snapshotNode: PersistedWorkflowSnapshotNode, liveConfig: NodeConfigBase): NodeConfigBase;
9
10
  private serializeConfig;
11
+ /**
12
+ * Safely call `config.inspectorSummary()` and return a plain JSON-safe array, or undefined.
13
+ * Returns undefined if the method is absent, throws, or produces no valid rows.
14
+ */
15
+ private safeInspectorSummary;
10
16
  private injectTokenIds;
11
17
  private mergeValue;
12
18
  private mergeNestedValue;
@@ -72,4 +78,4 @@ interface EngineRuntimeRegistrationOptions {
72
78
  }
73
79
  //#endregion
74
80
  export { WorkflowSnapshotCodec as a, EngineWorkflowRunnerService as i, TriggerRuntimeDiagnosticsProvider as n, WebhookTriggerMatcherProvider as r, EngineRuntimeRegistrationOptions as t };
75
- //# sourceMappingURL=EngineRuntimeRegistration.types-BryWi2mA.d.cts.map
81
+ //# sourceMappingURL=EngineRuntimeRegistration.types-Cggm5GVY.d.cts.map
@@ -1,20 +1,5 @@
1
- import { $r as RunTestContext, Bt as NodeExecutionStatePublisher, Et as ExecutionContextFactory, F as RunDataSnapshot, Fi as NodeId, Ft as NodeBinaryAttachmentService, Hn as CostTrackingTelemetryFactory, I as RunId, It as NodeExecutionContext, Kn as CollectionsContext, M as ParentExecutionRef, N as PersistedRunPolicySnapshot, O as NodeOutputs, P as RunDataFactory, R as RunnableNodeConfig, Ri as WorkflowId, Tt as ExecutionContext, Wn as CostTrackingUsageRecord, _ as MutableRunData, _t as BinaryStorageReadResult, a as BinaryAttachment, bt as BinaryStorageWriteResult, dr as CredentialSessionService, gt as BinaryStorage, ht as BinaryBody, l as Item, pt as RetryPolicySpec, v as NodeActivationId, vn as ExecutionTelemetryFactory, vt as BinaryStorageStatResult, wt as ExecutionBinaryService } from "./RunIntentService-BqNjrksF.cjs";
1
+ import { An as BinaryStorageStatResult, Ar as ExecutionTelemetryFactory, Bt as NodeOutputs, Ci as CredentialSessionService, Dn as BinaryBody, F as RunTestContext, Gt as PersistedRunPolicySnapshot, Ii as NodeId, In as ExecutionBinaryService, Jn as NodeExecutionContext, Jt as RunId, Kt as RunDataFactory, Ln as ExecutionContext, Mn as BinaryStorageWriteResult, On as BinaryStorage, Ot as MutableRunData, Qn as NodeExecutionStatePublisher, Rn as ExecutionContextFactory, Tn as RetryPolicySpec, Wt as ParentExecutionRef, Xt as RunnableNodeConfig, bt as Item, ei as CostTrackingTelemetryFactory, gt as BinaryAttachment, ii as CollectionsContext, kn as BinaryStorageReadResult, kt as NodeActivationId, qn as NodeBinaryAttachmentService, qt as RunDataSnapshot, zi as WorkflowId } from "./agentMcpTypes-ZiNbNsEi.cjs";
2
2
 
3
- //#region src/contracts/CostCatalogContract.d.ts
4
- interface CostCatalogEntry {
5
- readonly component: CostTrackingUsageRecord["component"];
6
- readonly provider: string;
7
- readonly operation: string;
8
- readonly pricingKey: string;
9
- readonly usageUnit: string;
10
- readonly currency: string;
11
- readonly currencyScale: number;
12
- readonly pricePerUnitMinor: number;
13
- }
14
- interface CostCatalog {
15
- findEntry(args: CostTrackingUsageRecord): CostCatalogEntry | undefined;
16
- }
17
- //#endregion
18
3
  //#region src/execution/CredentialResolverFactory.d.ts
19
4
  declare class CredentialResolverFactory {
20
5
  private readonly credentialSessions;
@@ -31,6 +16,8 @@ declare class UnavailableBinaryStorage implements BinaryStorage {
31
16
  exists: false;
32
17
  }>;
33
18
  delete(): Promise<void>;
19
+ deleteMany(): Promise<void>;
20
+ listByPrefix(): Promise<ReadonlyArray<string>>;
34
21
  }
35
22
  //#endregion
36
23
  //#region src/binaries/DefaultExecutionBinaryServiceFactory.d.ts
@@ -86,9 +73,10 @@ declare class DefaultExecutionContextFactory implements ExecutionContextFactory
86
73
  declare class InProcessRetryRunner {
87
74
  private readonly sleeper;
88
75
  constructor(sleeper: AsyncSleeper);
89
- run<T>(policy: RetryPolicySpec | undefined, work: () => Promise<T>): Promise<T>;
76
+ run<T>(policy: RetryPolicySpec | undefined, work: () => Promise<T>, shouldRetry?: (error: unknown) => boolean, warn?: (message: string) => void): Promise<T>;
90
77
  private static delayAfterFailureMs;
91
78
  private static normalizePolicy;
79
+ private static clampMaxAttempts;
92
80
  private static assertPositiveInt;
93
81
  private static assertNonNegativeFinite;
94
82
  private static assertMultiplier;
@@ -122,6 +110,8 @@ declare class InMemoryBinaryStorage implements BinaryStorage {
122
110
  openReadStream(storageKey: string): Promise<BinaryStorageReadResult | undefined>;
123
111
  stat(storageKey: string): Promise<BinaryStorageStatResult>;
124
112
  delete(storageKey: string): Promise<void>;
113
+ deleteMany(storageKeys: ReadonlyArray<string>): Promise<void>;
114
+ listByPrefix(prefix: string): Promise<ReadonlyArray<string>>;
125
115
  }
126
116
  //#endregion
127
117
  //#region src/runStorage/InMemoryRunDataFactory.d.ts
@@ -129,5 +119,5 @@ declare class InMemoryRunDataFactory implements RunDataFactory {
129
119
  create(initial?: Record<NodeId, NodeOutputs>): MutableRunData;
130
120
  }
131
121
  //#endregion
132
- export { ItemExprResolver as a, DefaultAsyncSleeper as c, UnavailableBinaryStorage as d, CredentialResolverFactory as f, RunnableOutputBehaviorResolver as i, AsyncSleeper as l, CostCatalogEntry as m, InMemoryBinaryStorage as n, InProcessRetryRunner as o, CostCatalog as p, RunnableOutputBehavior as r, DefaultExecutionContextFactory as s, InMemoryRunDataFactory as t, DefaultExecutionBinaryService as u };
133
- //# sourceMappingURL=InMemoryRunDataFactory-DeXNJt1O.d.cts.map
122
+ export { ItemExprResolver as a, DefaultAsyncSleeper as c, UnavailableBinaryStorage as d, CredentialResolverFactory as f, RunnableOutputBehaviorResolver as i, AsyncSleeper as l, InMemoryBinaryStorage as n, InProcessRetryRunner as o, RunnableOutputBehavior as r, DefaultExecutionContextFactory as s, InMemoryRunDataFactory as t, DefaultExecutionBinaryService as u };
123
+ //# sourceMappingURL=InMemoryRunDataFactory-C7YItvHG.d.cts.map
@@ -38,4 +38,4 @@ var InMemoryRunEventBus = class {
38
38
 
39
39
  //#endregion
40
40
  export { InMemoryRunEventBus as t };
41
- //# sourceMappingURL=InMemoryRunEventBusRegistry-sM4z4n_i.js.map
41
+ //# sourceMappingURL=InMemoryRunEventBusRegistry-Bwunvt1T.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InMemoryRunEventBusRegistry-sM4z4n_i.js","names":["onClose: () => void"],"sources":["../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts"],"sourcesContent":["import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n"],"mappings":";AAEA,IAAa,+BAAb,MAA0E;CACxE,YAAY,AAAiBA,SAAqB;EAArB;;CAE7B,MAAM,QAAuB;AAC3B,OAAK,SAAS;;;;;;ACAlB,IAAa,sBAAb,MAAwD;CACtD,AAAiB,kCAAkB,IAAI,KAAgC;CACvE,AAAiB,wCAAwB,IAAI,KAAiD;CAE9F,MAAM,QAAQ,OAAgC;AAC5C,OAAK,MAAM,YAAY,KAAK,gBAAiB,UAAS,MAAM;AAC5D,OAAK,MAAM,YAAY,KAAK,sBAAsB,IAAI,MAAM,WAAW,IAAI,EAAE,CAAE,UAAS,MAAM;;CAGhG,MAAM,UAAU,SAAmE;AACjF,OAAK,gBAAgB,IAAI,QAAQ;AACjC,SAAO,IAAI,mCAAmC;AAC5C,QAAK,gBAAgB,OAAO,QAAQ;IACpC;;CAGJ,MAAM,oBAAoB,YAAwB,SAAmE;EACnH,MAAM,WAAW,KAAK,sBAAsB,IAAI,WAAW,oBAAI,IAAI,KAAgC;AACnG,WAAS,IAAI,QAAQ;AACrB,OAAK,sBAAsB,IAAI,YAAY,SAAS;AAEpD,SAAO,IAAI,mCAAmC;GAC5C,MAAM,YAAY,KAAK,sBAAsB,IAAI,WAAW;AAC5D,OAAI,CAAC,UAAW;AAChB,aAAU,OAAO,QAAQ;AACzB,OAAI,UAAU,SAAS,EAAG,MAAK,sBAAsB,OAAO,WAAW;IACvE"}
1
+ {"version":3,"file":"InMemoryRunEventBusRegistry-Bwunvt1T.js","names":["onClose: () => void"],"sources":["../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts"],"sourcesContent":["import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n"],"mappings":";AAEA,IAAa,+BAAb,MAA0E;CACxE,YAAY,AAAiBA,SAAqB;EAArB;;CAE7B,MAAM,QAAuB;AAC3B,OAAK,SAAS;;;;;;ACAlB,IAAa,sBAAb,MAAwD;CACtD,AAAiB,kCAAkB,IAAI,KAAgC;CACvE,AAAiB,wCAAwB,IAAI,KAAiD;CAE9F,MAAM,QAAQ,OAAgC;AAC5C,OAAK,MAAM,YAAY,KAAK,gBAAiB,UAAS,MAAM;AAC5D,OAAK,MAAM,YAAY,KAAK,sBAAsB,IAAI,MAAM,WAAW,IAAI,EAAE,CAAE,UAAS,MAAM;;CAGhG,MAAM,UAAU,SAAmE;AACjF,OAAK,gBAAgB,IAAI,QAAQ;AACjC,SAAO,IAAI,mCAAmC;AAC5C,QAAK,gBAAgB,OAAO,QAAQ;IACpC;;CAGJ,MAAM,oBAAoB,YAAwB,SAAmE;EACnH,MAAM,WAAW,KAAK,sBAAsB,IAAI,WAAW,oBAAI,IAAI,KAAgC;AACnG,WAAS,IAAI,QAAQ;AACrB,OAAK,sBAAsB,IAAI,YAAY,SAAS;AAEpD,SAAO,IAAI,mCAAmC;GAC5C,MAAM,YAAY,KAAK,sBAAsB,IAAI,WAAW;AAC5D,OAAI,CAAC,UAAW;AAChB,aAAU,OAAO,QAAQ;AACzB,OAAI,UAAU,SAAS,EAAG,MAAK,sBAAsB,OAAO,WAAW;IACvE"}
@@ -44,4 +44,4 @@ Object.defineProperty(exports, 'InMemoryRunEventBus', {
44
44
  return InMemoryRunEventBus;
45
45
  }
46
46
  });
47
- //# sourceMappingURL=InMemoryRunEventBusRegistry-VM3OWnHo.cjs.map
47
+ //# sourceMappingURL=InMemoryRunEventBusRegistry-Sa86VxuV.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"InMemoryRunEventBusRegistry-VM3OWnHo.cjs","names":["onClose: () => void"],"sources":["../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts"],"sourcesContent":["import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n"],"mappings":";;AAEA,IAAa,+BAAb,MAA0E;CACxE,YAAY,AAAiBA,SAAqB;EAArB;;CAE7B,MAAM,QAAuB;AAC3B,OAAK,SAAS;;;;;;ACAlB,IAAa,sBAAb,MAAwD;CACtD,AAAiB,kCAAkB,IAAI,KAAgC;CACvE,AAAiB,wCAAwB,IAAI,KAAiD;CAE9F,MAAM,QAAQ,OAAgC;AAC5C,OAAK,MAAM,YAAY,KAAK,gBAAiB,UAAS,MAAM;AAC5D,OAAK,MAAM,YAAY,KAAK,sBAAsB,IAAI,MAAM,WAAW,IAAI,EAAE,CAAE,UAAS,MAAM;;CAGhG,MAAM,UAAU,SAAmE;AACjF,OAAK,gBAAgB,IAAI,QAAQ;AACjC,SAAO,IAAI,mCAAmC;AAC5C,QAAK,gBAAgB,OAAO,QAAQ;IACpC;;CAGJ,MAAM,oBAAoB,YAAwB,SAAmE;EACnH,MAAM,WAAW,KAAK,sBAAsB,IAAI,WAAW,oBAAI,IAAI,KAAgC;AACnG,WAAS,IAAI,QAAQ;AACrB,OAAK,sBAAsB,IAAI,YAAY,SAAS;AAEpD,SAAO,IAAI,mCAAmC;GAC5C,MAAM,YAAY,KAAK,sBAAsB,IAAI,WAAW;AAC5D,OAAI,CAAC,UAAW;AAChB,aAAU,OAAO,QAAQ;AACzB,OAAI,UAAU,SAAS,EAAG,MAAK,sBAAsB,OAAO,WAAW;IACvE"}
1
+ {"version":3,"file":"InMemoryRunEventBusRegistry-Sa86VxuV.cjs","names":["onClose: () => void"],"sources":["../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts"],"sourcesContent":["import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n"],"mappings":";;AAEA,IAAa,+BAAb,MAA0E;CACxE,YAAY,AAAiBA,SAAqB;EAArB;;CAE7B,MAAM,QAAuB;AAC3B,OAAK,SAAS;;;;;;ACAlB,IAAa,sBAAb,MAAwD;CACtD,AAAiB,kCAAkB,IAAI,KAAgC;CACvE,AAAiB,wCAAwB,IAAI,KAAiD;CAE9F,MAAM,QAAQ,OAAgC;AAC5C,OAAK,MAAM,YAAY,KAAK,gBAAiB,UAAS,MAAM;AAC5D,OAAK,MAAM,YAAY,KAAK,sBAAsB,IAAI,MAAM,WAAW,IAAI,EAAE,CAAE,UAAS,MAAM;;CAGhG,MAAM,UAAU,SAAmE;AACjF,OAAK,gBAAgB,IAAI,QAAQ;AACjC,SAAO,IAAI,mCAAmC;AAC5C,QAAK,gBAAgB,OAAO,QAAQ;IACpC;;CAGJ,MAAM,oBAAoB,YAAwB,SAAmE;EACnH,MAAM,WAAW,KAAK,sBAAsB,IAAI,WAAW,oBAAI,IAAI,KAAgC;AACnG,WAAS,IAAI,QAAQ;AACrB,OAAK,sBAAsB,IAAI,YAAY,SAAS;AAEpD,SAAO,IAAI,mCAAmC;GAC5C,MAAM,YAAY,KAAK,sBAAsB,IAAI,WAAW;AAC5D,OAAI,CAAC,UAAW;AAChB,aAAU,OAAO,QAAQ;AACzB,OAAI,UAAU,SAAS,EAAG,MAAK,sBAAsB,OAAO,WAAW;IACvE"}