@codemation/core 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/{EngineRuntimeRegistration.types-Bjeo7Sfq.d.ts → EngineRuntimeRegistration.types-DU6MsjU9.d.ts} +2 -2
  3. package/dist/{EngineWorkflowRunnerService-Dd4yD31l.d.cts → EngineWorkflowRunnerService-BBkL4VQF.d.cts} +2 -2
  4. package/dist/{InMemoryRunDataFactory-OUzDmAHt.d.cts → InMemoryRunDataFactory-CsYEMJK2.d.cts} +11 -3
  5. package/dist/{RunIntentService-Bkg4oYrM.d.cts → RunIntentService-BvlTpmEb.d.cts} +224 -237
  6. package/dist/{RunIntentService-BAKikN8h.d.ts → RunIntentService-zbTchO9T.d.ts} +305 -259
  7. package/dist/bootstrap/index.cjs +2 -2
  8. package/dist/bootstrap/index.d.cts +19 -7
  9. package/dist/bootstrap/index.d.ts +3 -3
  10. package/dist/bootstrap/index.js +2 -2
  11. package/dist/{bootstrap-DwS5S7s9.cjs → bootstrap-DHH2uo-W.cjs} +4 -2
  12. package/dist/bootstrap-DHH2uo-W.cjs.map +1 -0
  13. package/dist/{bootstrap-BD6CobHl.js → bootstrap-DbUlOl11.js} +4 -2
  14. package/dist/bootstrap-DbUlOl11.js.map +1 -0
  15. package/dist/{index-uCm9l0nw.d.ts → index-CUt13qs1.d.ts} +62 -34
  16. package/dist/index.cjs +22 -15
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +108 -42
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +13 -16
  21. package/dist/index.js.map +1 -1
  22. package/dist/{runtime-Cy-3FTI_.js → runtime-BdH94eBR.js} +502 -123
  23. package/dist/runtime-BdH94eBR.js.map +1 -0
  24. package/dist/{runtime-ZJUpWmPH.cjs → runtime-feFn8OmG.cjs} +561 -122
  25. package/dist/runtime-feFn8OmG.cjs.map +1 -0
  26. package/dist/testing.cjs +40 -36
  27. package/dist/testing.cjs.map +1 -1
  28. package/dist/testing.d.cts +17 -26
  29. package/dist/testing.d.ts +17 -26
  30. package/dist/testing.js +40 -36
  31. package/dist/testing.js.map +1 -1
  32. package/dist/{workflowActivationPolicy-BzyzXLa_.cjs → workflowActivationPolicy-6V3OJD3N.cjs} +65 -19
  33. package/dist/workflowActivationPolicy-6V3OJD3N.cjs.map +1 -0
  34. package/dist/{workflowActivationPolicy-B8HzTk3o.js → workflowActivationPolicy-Td9HTOuD.js} +65 -19
  35. package/dist/workflowActivationPolicy-Td9HTOuD.js.map +1 -0
  36. package/package.json +2 -1
  37. package/src/ai/AgentConfigInspectorFactory.ts +4 -0
  38. package/src/ai/AgentMessageConfigNormalizerFactory.ts +7 -0
  39. package/src/ai/AgentToolFactory.ts +2 -2
  40. package/src/ai/AiHost.ts +11 -10
  41. package/src/ai/NodeBackedToolConfig.ts +1 -1
  42. package/src/authoring/defineNode.types.ts +48 -72
  43. package/src/authoring/index.ts +1 -1
  44. package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +8 -0
  45. package/src/contracts/emitPorts.ts +27 -0
  46. package/src/contracts/index.ts +3 -0
  47. package/src/contracts/itemMeta.ts +11 -0
  48. package/src/contracts/itemValue.ts +147 -0
  49. package/src/contracts/runtimeTypes.ts +39 -22
  50. package/src/contracts/workflowTypes.ts +26 -56
  51. package/src/execution/FanInMergeByOriginMerger.ts +67 -0
  52. package/src/execution/ItemValueResolver.ts +27 -0
  53. package/src/execution/NodeActivationRequestComposer.ts +25 -0
  54. package/src/execution/NodeActivationRequestInputPreparer.ts +57 -25
  55. package/src/execution/NodeExecutor.ts +199 -30
  56. package/src/execution/NodeOutputNormalizer.ts +90 -0
  57. package/src/execution/index.ts +2 -0
  58. package/src/index.ts +2 -0
  59. package/src/orchestration/NodeExecutionRequestHandlerService.ts +39 -18
  60. package/src/orchestration/RunContinuationService.ts +11 -17
  61. package/src/planning/CurrentStateFrontierPlanner.ts +20 -20
  62. package/src/planning/RunQueuePlanner.ts +56 -19
  63. package/src/planning/WorkflowTopologyPlanner.ts +57 -33
  64. package/src/testing/ItemHarnessNode.ts +4 -10
  65. package/src/testing/ItemHarnessNodeConfig.ts +7 -16
  66. package/src/testing/RegistrarEngineTestKitFactory.ts +2 -0
  67. package/src/testing/SubWorkflowRunnerTestNode.ts +28 -43
  68. package/src/testing/SwitchHarnessNode.ts +54 -0
  69. package/src/types/index.ts +3 -0
  70. package/src/workflow/dsl/ChainCursorResolver.ts +68 -23
  71. package/src/workflow/dsl/WorkflowBuilder.ts +3 -5
  72. package/src/workflow/dsl/workflowBuilderTypes.ts +5 -8
  73. package/src/workflowSnapshots/MissingRuntimeNode.ts +4 -4
  74. package/src/workflowSnapshots/MissingRuntimeNodeConfig.ts +2 -2
  75. package/src/workflowSnapshots/WorkflowSnapshotCodec.ts +16 -7
  76. package/dist/bootstrap-BD6CobHl.js.map +0 -1
  77. package/dist/bootstrap-DwS5S7s9.cjs.map +0 -1
  78. package/dist/runtime-Cy-3FTI_.js.map +0 -1
  79. package/dist/runtime-ZJUpWmPH.cjs.map +0 -1
  80. package/dist/workflowActivationPolicy-B8HzTk3o.js.map +0 -1
  81. package/dist/workflowActivationPolicy-BzyzXLa_.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","names":["name: string","inputSchema: ZodType<TIn>","runOne: (args: {\n input: TIn;\n item: Item<TWire>;\n itemIndex: number;\n items: Items<TWire>;\n ctx: NodeExecutionContext<ItemHarnessNodeConfig<TIn, TOut, TWire>>;\n }) => TOut | Promise<TOut>","opts: Readonly<{\n id?: string;\n mapInput?: ItemInputMapper<TWire, TIn>;\n }>","prefix: string","makeRunIdValue: () => string","makeActivationIdValue: () => string","name: string","args: Readonly<{\n workflowId: WorkflowId;\n startAt?: NodeId;\n id?: string;\n execution?: Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }>;\n }>","workflows: WorkflowRunnerService","out: Item[]","name: string","id?: string","container","tsyringeContainer","runToCompletion: RegistrarEngineTestKitHandle[\"runToCompletion\"]","runIntentStartToCompletion: RegistrarEngineTestKitHandle[\"runIntentStartToCompletion\"]"],"sources":["../src/testing/RejectingCredentialSessionService.ts","../src/testing/ItemHarnessNode.ts","../src/testing/ItemHarnessNodeConfig.ts","../src/testing/CapturingScheduler.ts","../src/testing/PrefixedSequentialIdGenerator.ts","../src/testing/EngineTestKitRunIdFactory.ts","../src/testing/InMemoryTriggerSetupStateRepository.ts","../src/testing/SubWorkflowRunnerTestNode.ts","../src/testing/WorkflowTestHarnessManualTrigger.ts","../src/testing/RegistrarEngineTestKitFactory.ts","../src/testing/WorkflowTestKitNodeRegistrationContextFactory.ts","../src/testing/WorkflowTestKitRunNodeWorkflowFactory.ts","../src/testing/WorkflowTestKitBuilder.ts"],"sourcesContent":["import type { CredentialSessionService } from \"../contracts/credentialTypes\";\n\n/**\n * Test harness default: rejects any credential lookup so missing bindings fail loudly.\n * Prefer registering a real {@link CredentialSessionService} in integration scenarios.\n */\nexport class RejectingCredentialSessionService implements CredentialSessionService {\n async getSession<TSession = unknown>(\n args: Readonly<{ workflowId: string; nodeId: string; slotKey: string }>,\n ): Promise<TSession> {\n throw new Error(\n `Credential sessions are unavailable for workflow ${args.workflowId} node ${args.nodeId} slot \"${args.slotKey}\". Register a real CredentialSessionService implementation before executing workflows.`,\n );\n }\n}\n","import type { Item, ItemNode, Items, NodeExecutionContext } from \"../types\";\n\nimport type { ItemHarnessNodeConfig } from \"./ItemHarnessNodeConfig\";\n\n/**\n * Item-mode harness node for engine tests (see {@link ItemHarnessNodeConfig}).\n */\nexport class ItemHarnessNode implements ItemNode<ItemHarnessNodeConfig<any, any, any>, unknown, unknown> {\n readonly kind = \"node\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n async executeOne(args: {\n input: unknown;\n item: Item;\n itemIndex: number;\n items: Items;\n ctx: NodeExecutionContext<ItemHarnessNodeConfig<any, any, any>>;\n }): Promise<unknown> {\n return await args.ctx.config.runOne({\n input: args.input as never,\n item: args.item,\n itemIndex: args.itemIndex,\n items: args.items,\n ctx: args.ctx,\n });\n }\n}\n","import type { ZodType } from \"zod\";\n\nimport type { TypeToken } from \"../di\";\nimport type { Item, ItemInputMapper, Items, NodeExecutionContext, RunnableNodeConfig } from \"../types\";\n\nimport { ItemHarnessNode } from \"./ItemHarnessNode\";\n\n/**\n * Item-mode harness node config for engine tests: engine applies {@link RunnableNodeConfig.inputSchema} +\n * optional {@link RunnableNodeConfig.mapInput}, then {@link ItemHarnessNode.executeOne} per item.\n */\nexport class ItemHarnessNodeConfig<TIn = unknown, TOut = unknown, TWire = TIn> implements RunnableNodeConfig<\n TIn,\n TOut,\n TWire\n> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = ItemHarnessNode;\n\n constructor(\n public readonly name: string,\n public readonly inputSchema: ZodType<TIn>,\n public readonly runOne: (args: {\n input: TIn;\n item: Item<TWire>;\n itemIndex: number;\n items: Items<TWire>;\n ctx: NodeExecutionContext<ItemHarnessNodeConfig<TIn, TOut, TWire>>;\n }) => TOut | Promise<TOut>,\n public readonly opts: Readonly<{\n id?: string;\n mapInput?: ItemInputMapper<TWire, TIn>;\n }> = {},\n ) {}\n\n get mapInput(): ItemInputMapper<TWire, TIn> | undefined {\n return this.opts.mapInput;\n }\n\n get id(): string | undefined {\n return this.opts.id;\n }\n}\n","import type { NodeExecutionRequest, NodeExecutionScheduler } from \"../types\";\n\n/**\n * Test scheduler that records enqueue requests without executing a real queue.\n */\nexport class CapturingScheduler implements NodeExecutionScheduler {\n lastRequest: NodeExecutionRequest | undefined;\n requests: NodeExecutionRequest[] = [];\n\n async enqueue(request: NodeExecutionRequest): Promise<{ receiptId: string }> {\n this.lastRequest = request;\n this.requests.push(request);\n return { receiptId: `receipt_${this.requests.length}` };\n }\n}\n","/**\n * Deterministic `run_1`, `act_1`-style ids for test harness factories.\n */\nexport class PrefixedSequentialIdGenerator {\n private n = 0;\n\n constructor(private readonly prefix: string) {}\n\n next(): string {\n this.n += 1;\n return `${this.prefix}${this.n}`;\n }\n\n asFn(): () => string {\n return () => this.next();\n }\n}\n","import type { RunIdFactory } from \"../types\";\n\n/**\n * @internal Test harness id factory shared by registrar kit wiring.\n */\nexport class EngineTestKitRunIdFactory implements RunIdFactory {\n private runCounter = 0;\n private activationCounter = 0;\n\n constructor(\n private readonly makeRunIdValue: () => string,\n private readonly makeActivationIdValue: () => string,\n ) {}\n\n makeRunId(): string {\n this.runCounter += 1;\n return this.makeRunIdValue();\n }\n\n makeActivationId(): string {\n this.activationCounter += 1;\n return this.makeActivationIdValue();\n }\n}\n","import type { PersistedTriggerSetupState, TriggerSetupStateRepository } from \"../types\";\n\nexport class InMemoryTriggerSetupStateRepository implements TriggerSetupStateRepository {\n private readonly statesByKey = new Map<string, PersistedTriggerSetupState>();\n\n async load(trigger: { workflowId: string; nodeId: string }): Promise<PersistedTriggerSetupState | undefined> {\n return this.statesByKey.get(this.toKey(trigger));\n }\n\n async save(state: PersistedTriggerSetupState): Promise<void> {\n this.statesByKey.set(this.toKey(state.trigger), state);\n }\n\n async delete(trigger: { workflowId: string; nodeId: string }): Promise<void> {\n this.statesByKey.delete(this.toKey(trigger));\n }\n\n private toKey(trigger: { workflowId: string; nodeId: string }): string {\n return `${trigger.workflowId}:${trigger.nodeId}`;\n }\n}\n","/* eslint-disable codemation/single-class-per-file -- Runnable config and implementation share a TypeToken pairing. */\nimport type { WorkflowRunnerService } from \"../contracts/runtimeTypes\";\nimport type { TypeToken } from \"../di\";\nimport type {\n Item,\n Items,\n NodeExecutionContext,\n NodeId,\n NodeOutputs,\n Node,\n RunnableNodeConfig,\n WorkflowId,\n} from \"../types\";\n\n/**\n * Test harness subworkflow runner (mirrors integration patterns; lives under {@link \"@codemation/core/testing\"}).\n */\nexport class SubWorkflowRunnerConfig<TInputJson = unknown, TOutputJson = unknown> implements RunnableNodeConfig<\n TInputJson,\n TOutputJson\n> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = SubWorkflowRunnerNode;\n\n constructor(\n public readonly name: string,\n public readonly args: Readonly<{\n workflowId: WorkflowId;\n startAt?: NodeId;\n id?: string;\n execution?: Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }>;\n }>,\n ) {}\n\n get id(): string | undefined {\n return this.args.id;\n }\n\n get execution(): Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }> | undefined {\n return this.args.execution;\n }\n\n get workflowId(): WorkflowId {\n return this.args.workflowId;\n }\n\n get startAt(): NodeId | undefined {\n return this.args.startAt;\n }\n}\n\nexport class SubWorkflowRunnerNode implements Node<SubWorkflowRunnerConfig<any, any>> {\n readonly kind = \"node\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n constructor(private readonly workflows: WorkflowRunnerService) {}\n\n async execute(items: Items, ctx: NodeExecutionContext<SubWorkflowRunnerConfig<any, any>>): Promise<NodeOutputs> {\n const out: Item[] = [];\n for (let i = 0; i < items.length; i++) {\n const current = items[i]!;\n const result = await this.workflows.runById({\n workflowId: ctx.config.workflowId,\n startAt: ctx.config.startAt,\n items: [current],\n parent: {\n runId: ctx.runId,\n workflowId: ctx.workflowId,\n nodeId: ctx.nodeId,\n subworkflowDepth: ctx.subworkflowDepth,\n engineMaxNodeActivations: ctx.engineMaxNodeActivations,\n engineMaxSubworkflowDepth: ctx.engineMaxSubworkflowDepth,\n },\n });\n if (result.status !== \"completed\") {\n throw new Error(`Subworkflow ${ctx.config.workflowId} did not complete (status=${result.status})`);\n }\n out.push(...result.outputs);\n }\n\n return { main: out };\n }\n}\n","/* eslint-disable codemation/single-class-per-file -- Trigger config and implementation share a TypeToken pairing. */\nimport type { TypeToken } from \"../di\";\nimport type {\n Items,\n NodeExecutionContext,\n NodeOutputs,\n TriggerNode,\n TriggerNodeConfig,\n TriggerSetupContext,\n} from \"../types\";\n\n/**\n * Minimal pass-through manual trigger for {@link WorkflowTestKit.runNode}; emits input items unchanged.\n */\nexport class WorkflowTestHarnessManualTriggerConfig implements TriggerNodeConfig<unknown> {\n readonly kind = \"trigger\" as const;\n readonly type: TypeToken<unknown> = WorkflowTestHarnessManualTriggerNode;\n\n constructor(\n public readonly name: string,\n public readonly id?: string,\n ) {}\n}\n\nexport class WorkflowTestHarnessManualTriggerNode implements TriggerNode<WorkflowTestHarnessManualTriggerConfig> {\n readonly kind = \"trigger\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n async setup(_ctx: TriggerSetupContext<WorkflowTestHarnessManualTriggerConfig>): Promise<undefined> {\n return undefined;\n }\n\n async execute(\n items: Items,\n _ctx: NodeExecutionContext<WorkflowTestHarnessManualTriggerConfig>,\n ): Promise<NodeOutputs> {\n return { main: items };\n }\n}\n","import type { DependencyContainer, InjectionToken } from \"tsyringe\";\nimport { container as tsyringeContainer } from \"tsyringe\";\n\nimport type { WorkflowRunnerService } from \"../contracts/runtimeTypes\";\nimport { CoreTokens } from \"../di\";\nimport { InMemoryRunEventBus } from \"../events/InMemoryRunEventBusRegistry\";\nimport { AllWorkflowsActiveWorkflowActivationPolicy } from \"../contracts/workflowActivationPolicy\";\nimport { RunIntentService } from \"../runtime/RunIntentService\";\nimport {\n DefaultDrivingScheduler,\n DefaultAsyncSleeper,\n DefaultExecutionContextFactory,\n Engine,\n EngineRuntimeRegistrar,\n EngineWorkflowRunnerService,\n HintOnlyOffloadPolicy,\n InProcessRetryRunner,\n InMemoryRunDataFactory,\n InMemoryWorkflowExecutionRepository,\n InlineDrivingScheduler,\n NodeExecutor,\n NodeInstanceFactory,\n PersistedWorkflowTokenRegistry,\n} from \"../bootstrap/index\";\nimport { InMemoryLiveWorkflowRepository } from \"../runtime/InMemoryLiveWorkflowRepository\";\nimport { EngineTestKitRunIdFactory } from \"./EngineTestKitRunIdFactory\";\nimport { InMemoryTriggerSetupStateRepository } from \"./InMemoryTriggerSetupStateRepository\";\nimport { RejectingCredentialSessionService } from \"./RejectingCredentialSessionService\";\nimport { CapturingScheduler } from \"./CapturingScheduler\";\nimport { PrefixedSequentialIdGenerator } from \"./PrefixedSequentialIdGenerator\";\nimport type { RegistrarEngineTestKitHandle, RegistrarEngineTestKitOptions } from \"./RegistrarEngineTestKit.types\";\nimport { ItemHarnessNode } from \"./ItemHarnessNode\";\nimport { SubWorkflowRunnerNode } from \"./SubWorkflowRunnerTestNode\";\nimport { WorkflowTestHarnessManualTriggerNode } from \"./WorkflowTestHarnessManualTrigger\";\n\nexport class RegistrarEngineTestKitFactory {\n static create(options: RegistrarEngineTestKitOptions = {}): RegistrarEngineTestKitHandle {\n const runStore = options.runStore ?? new InMemoryWorkflowExecutionRepository();\n const scheduler = options.scheduler ?? new CapturingScheduler();\n const offloadPolicy = options.offloadPolicy ?? new HintOnlyOffloadPolicy();\n const runIdGen = new PrefixedSequentialIdGenerator(\"run_\");\n const activationIdGen = new PrefixedSequentialIdGenerator(\"act_\");\n const makeRunId = options.makeRunId ?? runIdGen.asFn();\n const makeActivationId = options.makeActivationId ?? activationIdGen.asFn();\n const credentialSessions = options.credentialSessions ?? new RejectingCredentialSessionService();\n const eventBus = options.eventBus ?? new InMemoryRunEventBus();\n const triggerSetupStateRepository =\n options.triggerSetupStateRepository ?? new InMemoryTriggerSetupStateRepository();\n const liveWorkflowRepository = new InMemoryLiveWorkflowRepository();\n const runDataFactory = options.runDataFactory ?? new InMemoryRunDataFactory();\n const executionContextFactory = options.executionContextFactory ?? new DefaultExecutionContextFactory();\n const container = options.container ?? tsyringeContainer.createChildContainer();\n const dependencyContainer = container as DependencyContainer;\n const nodeResolver = container;\n const nodeExecutor = new NodeExecutor(\n new NodeInstanceFactory(nodeResolver),\n new InProcessRetryRunner(new DefaultAsyncSleeper()),\n );\n const activationScheduler = new DefaultDrivingScheduler(\n offloadPolicy,\n scheduler,\n new InlineDrivingScheduler(nodeExecutor),\n );\n\n for (const [token, value] of options.providers ?? new Map<InjectionToken<unknown>, unknown>()) {\n dependencyContainer.registerInstance(token, value);\n }\n\n dependencyContainer.registerInstance(CoreTokens.CredentialSessionService, credentialSessions);\n dependencyContainer.registerInstance(CoreTokens.LiveWorkflowRepository, liveWorkflowRepository);\n dependencyContainer.registerInstance(CoreTokens.WorkflowRepository, liveWorkflowRepository);\n dependencyContainer.registerInstance(CoreTokens.NodeResolver, nodeResolver);\n dependencyContainer.registerInstance(\n CoreTokens.RunIdFactory,\n new EngineTestKitRunIdFactory(makeRunId, makeActivationId),\n );\n dependencyContainer.registerInstance(\n CoreTokens.ActivationIdFactory,\n new EngineTestKitRunIdFactory(makeRunId, makeActivationId),\n );\n dependencyContainer.registerInstance(CoreTokens.WebhookBasePath, options.webhookBasePath ?? \"/webhooks\");\n dependencyContainer.registerInstance(CoreTokens.WorkflowExecutionRepository, runStore);\n dependencyContainer.registerInstance(CoreTokens.TriggerSetupStateRepository, triggerSetupStateRepository);\n dependencyContainer.registerInstance(CoreTokens.NodeActivationScheduler, activationScheduler);\n dependencyContainer.registerInstance(CoreTokens.RunDataFactory, runDataFactory);\n dependencyContainer.registerInstance(CoreTokens.ExecutionContextFactory, executionContextFactory);\n dependencyContainer.registerInstance(CoreTokens.RunEventBus, eventBus);\n dependencyContainer.registerInstance(\n CoreTokens.PersistedWorkflowTokenRegistry,\n new PersistedWorkflowTokenRegistry(),\n );\n dependencyContainer.registerInstance(\n CoreTokens.WorkflowActivationPolicy,\n new AllWorkflowsActiveWorkflowActivationPolicy(),\n );\n\n if (options.executionLimitsPolicy !== undefined) {\n dependencyContainer.registerInstance(CoreTokens.EngineExecutionLimitsPolicy, options.executionLimitsPolicy);\n }\n\n new EngineRuntimeRegistrar().register(dependencyContainer, options.registrarOptions ?? {});\n\n const engine = dependencyContainer.resolve(Engine);\n const runIntent = dependencyContainer.resolve(RunIntentService);\n const workflowRunner =\n options.workflowRunner ??\n (dependencyContainer.resolve(CoreTokens.WorkflowRunnerService) as EngineWorkflowRunnerService);\n dependencyContainer.registerInstance(\n SubWorkflowRunnerNode,\n new SubWorkflowRunnerNode(workflowRunner as WorkflowRunnerService),\n );\n dependencyContainer.registerInstance(ItemHarnessNode, new ItemHarnessNode());\n dependencyContainer.registerInstance(\n WorkflowTestHarnessManualTriggerNode,\n new WorkflowTestHarnessManualTriggerNode(),\n );\n\n const start = async (workflows: ReadonlyArray<import(\"../types\").WorkflowDefinition>): Promise<void> => {\n await engine.start([...workflows]);\n };\n\n const runToCompletion: RegistrarEngineTestKitHandle[\"runToCompletion\"] = async (args) => {\n const r0 = await engine.runWorkflow(args.wf, args.startAt, args.items, args.parent);\n if (r0.status !== \"pending\") return r0;\n return await engine.waitForCompletion(r0.runId);\n };\n\n const runIntentStartToCompletion: RegistrarEngineTestKitHandle[\"runIntentStartToCompletion\"] = async (args) => {\n const r0 = await runIntent.startWorkflow({\n workflow: args.wf,\n startAt: args.startAt,\n items: args.items,\n parent: args.parent,\n });\n if (r0.status !== \"pending\") return r0;\n return await engine.waitForCompletion(r0.runId);\n };\n\n return {\n engine,\n runIntent,\n liveWorkflowRepository,\n runStore,\n triggerSetupStateRepository,\n scheduler: scheduler as CapturingScheduler | import(\"../types\").NodeExecutionScheduler,\n offloadPolicy,\n workflowRunner,\n dependencyContainer,\n start,\n runToCompletion,\n runIntentStartToCompletion,\n makeRunId,\n makeActivationId,\n };\n }\n}\n","import type { DependencyContainer } from \"tsyringe\";\n\nimport type { TypeToken } from \"../di\";\n\nimport type { DefinedNodeRegistrationContext } from \"./WorkflowTestKit.types\";\n\nexport class WorkflowTestKitNodeRegistrationContextFactory {\n create(dependencyContainer: DependencyContainer): DefinedNodeRegistrationContext {\n return {\n registerNode<TValue>(token: TypeToken<TValue>, implementation?: TypeToken<TValue>) {\n dependencyContainer.register(token, {\n useClass: (implementation ?? token) as never,\n });\n },\n };\n }\n}\n","import type { RunnableNodeConfig, WorkflowDefinition, WorkflowId } from \"../types\";\nimport { WorkflowBuilder } from \"../workflow/dsl/WorkflowBuilder\";\n\nimport { WorkflowTestHarnessManualTriggerConfig } from \"./WorkflowTestHarnessManualTrigger\";\n\nconst defaultInlineWorkflowId = \"codemation.testing.workflowkit.inline\" as WorkflowId;\nconst defaultInlineWorkflowName = \"WorkflowTestKit inline\";\n\n/**\n * Builds the minimal trigger → runnable workflow used by {@link import(\"./WorkflowTestKit\").WorkflowTestKit.runNode}.\n */\nexport class WorkflowTestKitRunNodeWorkflowFactory {\n build(args: { node: RunnableNodeConfig; workflowId?: WorkflowId; workflowName?: string }): WorkflowDefinition {\n const workflowId = args.workflowId ?? defaultInlineWorkflowId;\n const workflowName = args.workflowName ?? defaultInlineWorkflowName;\n const trigger = new WorkflowTestHarnessManualTriggerConfig(\n \"WorkflowTestKit trigger\",\n \"workflowkit.harness.trigger\",\n );\n return new WorkflowBuilder({ id: workflowId, name: workflowName }).trigger(trigger).then(args.node).build();\n }\n\n defaultStartNodeId(): string {\n return \"workflowkit.harness.trigger\";\n }\n}\n","import type { DependencyContainer } from \"tsyringe\";\n\nimport type { Items, NodeId, RunnableNodeConfig, RunResult, WorkflowDefinition, WorkflowId } from \"../types\";\n\nimport { RegistrarEngineTestKitFactory } from \"./RegistrarEngineTestKitFactory\";\nimport type { EngineTestKitOptions, RegistrarEngineTestKitHandle } from \"./RegistrarEngineTestKit.types\";\nimport { WorkflowTestKitNodeRegistrationContextFactory } from \"./WorkflowTestKitNodeRegistrationContextFactory\";\nimport type { DefinedNodeRegistration } from \"./WorkflowTestKit.types\";\nimport { WorkflowTestKitRunNodeWorkflowFactory } from \"./WorkflowTestKitRunNodeWorkflowFactory\";\n\nexport type { DefinedNodeRegistration, DefinedNodeRegistrationContext } from \"./WorkflowTestKit.types\";\n\nexport type WorkflowTestKitOptions = EngineTestKitOptions;\n\nexport class WorkflowTestKit {\n private readonly handle: RegistrarEngineTestKitHandle;\n private readonly runNodeWorkflowFactory = new WorkflowTestKitRunNodeWorkflowFactory();\n private readonly nodeRegistrationContextFactory = new WorkflowTestKitNodeRegistrationContextFactory();\n\n constructor(options: WorkflowTestKitOptions = {}) {\n this.handle = RegistrarEngineTestKitFactory.create(options);\n }\n\n get dependencyContainer(): DependencyContainer {\n return this.handle.dependencyContainer;\n }\n\n get engine(): RegistrarEngineTestKitHandle[\"engine\"] {\n return this.handle.engine;\n }\n\n get workflowRunner(): RegistrarEngineTestKitHandle[\"workflowRunner\"] {\n return this.handle.workflowRunner;\n }\n\n get liveWorkflowRepository(): RegistrarEngineTestKitHandle[\"liveWorkflowRepository\"] {\n return this.handle.liveWorkflowRepository;\n }\n\n get runStore(): RegistrarEngineTestKitHandle[\"runStore\"] {\n return this.handle.runStore;\n }\n\n /**\n * Registers {@link import(\"../authoring/defineNode.types\").DefinedNode} implementations on the same DI container used by the engine\n * (same pattern as `plugin.register({ registerNode })` in the host).\n */\n registerDefinedNodes(definitions: ReadonlyArray<DefinedNodeRegistration>): void {\n const ctx = this.nodeRegistrationContextFactory.create(this.handle.dependencyContainer);\n for (const def of definitions) {\n def.register(ctx);\n }\n }\n\n async run(args: { workflow: WorkflowDefinition; items: Items; startAt?: NodeId }): Promise<RunResult> {\n await this.handle.start([args.workflow]);\n return await this.handle.workflowRunner.runById({\n workflowId: args.workflow.id,\n startAt: args.startAt,\n items: args.items,\n });\n }\n\n async runNode(args: {\n node: RunnableNodeConfig;\n items: Items;\n workflowId?: WorkflowId;\n workflowName?: string;\n }): Promise<RunResult> {\n const wf = this.runNodeWorkflowFactory.build(args);\n return await this.run({\n workflow: wf,\n items: args.items,\n startAt: this.runNodeWorkflowFactory.defaultStartNodeId(),\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"testing.js","names":["name: string","inputSchema: ZodType<TIn>","runOne: (args: {\n input: TIn;\n item: Item<TIn>;\n itemIndex: number;\n items: Items<TIn>;\n ctx: NodeExecutionContext<ItemHarnessNodeConfig<TIn, TOut>>;\n }) => TOut | Promise<TOut>","opts: Readonly<{\n id?: string;\n }>","prefix: string","makeRunIdValue: () => string","makeActivationIdValue: () => string","name: string","args: Readonly<{\n workflowId: WorkflowId;\n startAt?: NodeId;\n id?: string;\n execution?: Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }>;\n }>","workflows: WorkflowRunnerService","name: string","id?: string","container","tsyringeContainer","runToCompletion: RegistrarEngineTestKitHandle[\"runToCompletion\"]","runIntentStartToCompletion: RegistrarEngineTestKitHandle[\"runIntentStartToCompletion\"]"],"sources":["../src/testing/RejectingCredentialSessionService.ts","../src/testing/ItemHarnessNode.ts","../src/testing/ItemHarnessNodeConfig.ts","../src/testing/CapturingScheduler.ts","../src/testing/PrefixedSequentialIdGenerator.ts","../src/testing/EngineTestKitRunIdFactory.ts","../src/testing/InMemoryTriggerSetupStateRepository.ts","../src/testing/SubWorkflowRunnerTestNode.ts","../src/testing/WorkflowTestHarnessManualTrigger.ts","../src/testing/SwitchHarnessNode.ts","../src/testing/RegistrarEngineTestKitFactory.ts","../src/testing/WorkflowTestKitNodeRegistrationContextFactory.ts","../src/testing/WorkflowTestKitRunNodeWorkflowFactory.ts","../src/testing/WorkflowTestKitBuilder.ts"],"sourcesContent":["import type { CredentialSessionService } from \"../contracts/credentialTypes\";\n\n/**\n * Test harness default: rejects any credential lookup so missing bindings fail loudly.\n * Prefer registering a real {@link CredentialSessionService} in integration scenarios.\n */\nexport class RejectingCredentialSessionService implements CredentialSessionService {\n async getSession<TSession = unknown>(\n args: Readonly<{ workflowId: string; nodeId: string; slotKey: string }>,\n ): Promise<TSession> {\n throw new Error(\n `Credential sessions are unavailable for workflow ${args.workflowId} node ${args.nodeId} slot \"${args.slotKey}\". Register a real CredentialSessionService implementation before executing workflows.`,\n );\n }\n}\n","import type { Item, RunnableNode, RunnableNodeExecuteArgs } from \"../types\";\n\nimport type { ItemHarnessNodeConfig } from \"./ItemHarnessNodeConfig\";\n\n/**\n * Item-mode harness node for engine tests (see {@link ItemHarnessNodeConfig}).\n */\nexport class ItemHarnessNode implements RunnableNode<ItemHarnessNodeConfig<any, any>> {\n readonly kind = \"node\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n async execute(args: RunnableNodeExecuteArgs<ItemHarnessNodeConfig<any, any>>): Promise<unknown> {\n return await args.ctx.config.runOne({\n input: args.input as never,\n item: args.item as Item,\n itemIndex: args.itemIndex,\n items: args.items,\n ctx: args.ctx,\n });\n }\n}\n","import type { ZodType } from \"zod\";\n\nimport type { TypeToken } from \"../di\";\nimport type { Item, Items, NodeExecutionContext, RunnableNodeConfig } from \"../types\";\n\nimport { ItemHarnessNode } from \"./ItemHarnessNode\";\n\n/**\n * Item-mode harness node config for engine tests: engine applies {@link RunnableNodeConfig.inputSchema},\n * then {@link ItemHarnessNode.execute} per item.\n */\nexport class ItemHarnessNodeConfig<TIn = unknown, TOut = unknown> implements RunnableNodeConfig<TIn, TOut> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = ItemHarnessNode;\n\n constructor(\n public readonly name: string,\n public readonly inputSchema: ZodType<TIn>,\n public readonly runOne: (args: {\n input: TIn;\n item: Item<TIn>;\n itemIndex: number;\n items: Items<TIn>;\n ctx: NodeExecutionContext<ItemHarnessNodeConfig<TIn, TOut>>;\n }) => TOut | Promise<TOut>,\n public readonly opts: Readonly<{\n id?: string;\n }> = {},\n ) {}\n\n get id(): string | undefined {\n return this.opts.id;\n }\n}\n","import type { NodeExecutionRequest, NodeExecutionScheduler } from \"../types\";\n\n/**\n * Test scheduler that records enqueue requests without executing a real queue.\n */\nexport class CapturingScheduler implements NodeExecutionScheduler {\n lastRequest: NodeExecutionRequest | undefined;\n requests: NodeExecutionRequest[] = [];\n\n async enqueue(request: NodeExecutionRequest): Promise<{ receiptId: string }> {\n this.lastRequest = request;\n this.requests.push(request);\n return { receiptId: `receipt_${this.requests.length}` };\n }\n}\n","/**\n * Deterministic `run_1`, `act_1`-style ids for test harness factories.\n */\nexport class PrefixedSequentialIdGenerator {\n private n = 0;\n\n constructor(private readonly prefix: string) {}\n\n next(): string {\n this.n += 1;\n return `${this.prefix}${this.n}`;\n }\n\n asFn(): () => string {\n return () => this.next();\n }\n}\n","import type { RunIdFactory } from \"../types\";\n\n/**\n * @internal Test harness id factory shared by registrar kit wiring.\n */\nexport class EngineTestKitRunIdFactory implements RunIdFactory {\n private runCounter = 0;\n private activationCounter = 0;\n\n constructor(\n private readonly makeRunIdValue: () => string,\n private readonly makeActivationIdValue: () => string,\n ) {}\n\n makeRunId(): string {\n this.runCounter += 1;\n return this.makeRunIdValue();\n }\n\n makeActivationId(): string {\n this.activationCounter += 1;\n return this.makeActivationIdValue();\n }\n}\n","import type { PersistedTriggerSetupState, TriggerSetupStateRepository } from \"../types\";\n\nexport class InMemoryTriggerSetupStateRepository implements TriggerSetupStateRepository {\n private readonly statesByKey = new Map<string, PersistedTriggerSetupState>();\n\n async load(trigger: { workflowId: string; nodeId: string }): Promise<PersistedTriggerSetupState | undefined> {\n return this.statesByKey.get(this.toKey(trigger));\n }\n\n async save(state: PersistedTriggerSetupState): Promise<void> {\n this.statesByKey.set(this.toKey(state.trigger), state);\n }\n\n async delete(trigger: { workflowId: string; nodeId: string }): Promise<void> {\n this.statesByKey.delete(this.toKey(trigger));\n }\n\n private toKey(trigger: { workflowId: string; nodeId: string }): string {\n return `${trigger.workflowId}:${trigger.nodeId}`;\n }\n}\n","/* eslint-disable codemation/single-class-per-file -- Runnable config and implementation share a TypeToken pairing. */\nimport type { WorkflowRunnerService } from \"../contracts/runtimeTypes\";\nimport type { TypeToken } from \"../di\";\nimport type { Item, NodeId, RunnableNode, RunnableNodeConfig, RunnableNodeExecuteArgs, WorkflowId } from \"../types\";\nimport { emitPorts } from \"../contracts/emitPorts\";\n\n/**\n * Test harness subworkflow runner (mirrors integration patterns; lives under {@link \"@codemation/core/testing\"}).\n */\nexport class SubWorkflowRunnerConfig<TInputJson = unknown, TOutputJson = unknown> implements RunnableNodeConfig<\n TInputJson,\n TOutputJson\n> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = SubWorkflowRunnerNode;\n\n readonly workflowId: WorkflowId;\n readonly startAt: NodeId | undefined;\n\n constructor(\n public readonly name: string,\n public readonly args: Readonly<{\n workflowId: WorkflowId;\n startAt?: NodeId;\n id?: string;\n execution?: Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }>;\n }>,\n ) {\n this.workflowId = args.workflowId;\n this.startAt = args.startAt;\n }\n\n get id(): string | undefined {\n return this.args.id;\n }\n\n get execution(): Readonly<{ hint?: \"local\" | \"worker\"; queue?: string }> | undefined {\n return this.args.execution;\n }\n}\n\nexport class SubWorkflowRunnerNode implements RunnableNode<SubWorkflowRunnerConfig<any, any>> {\n readonly kind = \"node\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n constructor(private readonly workflows: WorkflowRunnerService) {}\n\n async execute(args: RunnableNodeExecuteArgs<SubWorkflowRunnerConfig<any, any>>): Promise<unknown> {\n const current = args.item as Item;\n const result = await this.workflows.runById({\n workflowId: args.ctx.config.workflowId,\n startAt: args.ctx.config.startAt,\n items: [current],\n parent: {\n runId: args.ctx.runId,\n workflowId: args.ctx.workflowId,\n nodeId: args.ctx.nodeId,\n subworkflowDepth: args.ctx.subworkflowDepth,\n engineMaxNodeActivations: args.ctx.engineMaxNodeActivations,\n engineMaxSubworkflowDepth: args.ctx.engineMaxSubworkflowDepth,\n },\n });\n if (result.status !== \"completed\") {\n throw new Error(`Subworkflow ${args.ctx.config.workflowId} did not complete (status=${result.status})`);\n }\n return emitPorts({ main: result.outputs });\n }\n}\n","/* eslint-disable codemation/single-class-per-file -- Trigger config and implementation share a TypeToken pairing. */\nimport type { TypeToken } from \"../di\";\nimport type {\n Items,\n NodeExecutionContext,\n NodeOutputs,\n TriggerNode,\n TriggerNodeConfig,\n TriggerSetupContext,\n} from \"../types\";\n\n/**\n * Minimal pass-through manual trigger for {@link WorkflowTestKit.runNode}; emits input items unchanged.\n */\nexport class WorkflowTestHarnessManualTriggerConfig implements TriggerNodeConfig<unknown> {\n readonly kind = \"trigger\" as const;\n readonly type: TypeToken<unknown> = WorkflowTestHarnessManualTriggerNode;\n\n constructor(\n public readonly name: string,\n public readonly id?: string,\n ) {}\n}\n\nexport class WorkflowTestHarnessManualTriggerNode implements TriggerNode<WorkflowTestHarnessManualTriggerConfig> {\n readonly kind = \"trigger\" as const;\n readonly outputPorts = [\"main\"] as const;\n\n async setup(_ctx: TriggerSetupContext<WorkflowTestHarnessManualTriggerConfig>): Promise<undefined> {\n return undefined;\n }\n\n async execute(\n items: Items,\n _ctx: NodeExecutionContext<WorkflowTestHarnessManualTriggerConfig>,\n ): Promise<NodeOutputs> {\n return { main: items };\n }\n}\n","import type { TypeToken } from \"../di\";\nimport type {\n Item,\n Items,\n NodeExecutionContext,\n RunnableNode,\n RunnableNodeConfig,\n RunnableNodeExecuteArgs,\n} from \"../types\";\nimport { emitPorts } from \"../contracts/emitPorts\";\n\nexport class SwitchHarnessNode implements RunnableNode<SwitchHarnessNodeConfig<any>> {\n readonly kind = \"node\" as const;\n readonly outputPorts = [] as const;\n\n async execute(args: RunnableNodeExecuteArgs<SwitchHarnessNodeConfig<any>>): Promise<unknown> {\n const key = await Promise.resolve(\n args.ctx.config.cfg.resolveCaseKey(args.item as Item, args.itemIndex, args.items, args.ctx),\n );\n const { cases, defaultCase } = args.ctx.config.cfg;\n const port = cases.includes(key) ? key : defaultCase;\n return emitPorts({\n [port]: [args.item],\n });\n }\n}\n\nexport class SwitchHarnessNodeConfig<TInputJson = unknown> implements RunnableNodeConfig<TInputJson, TInputJson> {\n readonly kind = \"node\" as const;\n readonly type: TypeToken<unknown> = SwitchHarnessNode;\n readonly lineageCarry = \"carryThrough\" as const;\n readonly declaredOutputPorts: ReadonlyArray<string>;\n\n constructor(\n public readonly name: string,\n public readonly cfg: Readonly<{\n cases: readonly string[];\n defaultCase: string;\n resolveCaseKey: (\n item: Item<TInputJson>,\n index: number,\n items: Items<TInputJson>,\n ctx: NodeExecutionContext<SwitchHarnessNodeConfig<TInputJson>>,\n ) => string | Promise<string>;\n }>,\n public readonly opts: Readonly<{ id?: string }> = {},\n ) {\n this.declaredOutputPorts = [...new Set([...cfg.cases, cfg.defaultCase])].sort();\n }\n\n get id(): string | undefined {\n return this.opts.id;\n }\n}\n","import type { DependencyContainer, InjectionToken } from \"tsyringe\";\nimport { container as tsyringeContainer } from \"tsyringe\";\n\nimport type { WorkflowRunnerService } from \"../contracts/runtimeTypes\";\nimport { CoreTokens } from \"../di\";\nimport { InMemoryRunEventBus } from \"../events/InMemoryRunEventBusRegistry\";\nimport { AllWorkflowsActiveWorkflowActivationPolicy } from \"../contracts/workflowActivationPolicy\";\nimport { RunIntentService } from \"../runtime/RunIntentService\";\nimport {\n DefaultDrivingScheduler,\n DefaultAsyncSleeper,\n DefaultExecutionContextFactory,\n Engine,\n EngineRuntimeRegistrar,\n EngineWorkflowRunnerService,\n HintOnlyOffloadPolicy,\n InProcessRetryRunner,\n InMemoryRunDataFactory,\n InMemoryWorkflowExecutionRepository,\n InlineDrivingScheduler,\n NodeExecutor,\n NodeInstanceFactory,\n PersistedWorkflowTokenRegistry,\n} from \"../bootstrap/index\";\nimport { InMemoryLiveWorkflowRepository } from \"../runtime/InMemoryLiveWorkflowRepository\";\nimport { EngineTestKitRunIdFactory } from \"./EngineTestKitRunIdFactory\";\nimport { InMemoryTriggerSetupStateRepository } from \"./InMemoryTriggerSetupStateRepository\";\nimport { RejectingCredentialSessionService } from \"./RejectingCredentialSessionService\";\nimport { CapturingScheduler } from \"./CapturingScheduler\";\nimport { PrefixedSequentialIdGenerator } from \"./PrefixedSequentialIdGenerator\";\nimport type { RegistrarEngineTestKitHandle, RegistrarEngineTestKitOptions } from \"./RegistrarEngineTestKit.types\";\nimport { ItemHarnessNode } from \"./ItemHarnessNode\";\nimport { SubWorkflowRunnerNode } from \"./SubWorkflowRunnerTestNode\";\nimport { WorkflowTestHarnessManualTriggerNode } from \"./WorkflowTestHarnessManualTrigger\";\nimport { SwitchHarnessNode } from \"./SwitchHarnessNode\";\n\nexport class RegistrarEngineTestKitFactory {\n static create(options: RegistrarEngineTestKitOptions = {}): RegistrarEngineTestKitHandle {\n const runStore = options.runStore ?? new InMemoryWorkflowExecutionRepository();\n const scheduler = options.scheduler ?? new CapturingScheduler();\n const offloadPolicy = options.offloadPolicy ?? new HintOnlyOffloadPolicy();\n const runIdGen = new PrefixedSequentialIdGenerator(\"run_\");\n const activationIdGen = new PrefixedSequentialIdGenerator(\"act_\");\n const makeRunId = options.makeRunId ?? runIdGen.asFn();\n const makeActivationId = options.makeActivationId ?? activationIdGen.asFn();\n const credentialSessions = options.credentialSessions ?? new RejectingCredentialSessionService();\n const eventBus = options.eventBus ?? new InMemoryRunEventBus();\n const triggerSetupStateRepository =\n options.triggerSetupStateRepository ?? new InMemoryTriggerSetupStateRepository();\n const liveWorkflowRepository = new InMemoryLiveWorkflowRepository();\n const runDataFactory = options.runDataFactory ?? new InMemoryRunDataFactory();\n const executionContextFactory = options.executionContextFactory ?? new DefaultExecutionContextFactory();\n const container = options.container ?? tsyringeContainer.createChildContainer();\n const dependencyContainer = container as DependencyContainer;\n const nodeResolver = container;\n const nodeExecutor = new NodeExecutor(\n new NodeInstanceFactory(nodeResolver),\n new InProcessRetryRunner(new DefaultAsyncSleeper()),\n );\n const activationScheduler = new DefaultDrivingScheduler(\n offloadPolicy,\n scheduler,\n new InlineDrivingScheduler(nodeExecutor),\n );\n\n for (const [token, value] of options.providers ?? new Map<InjectionToken<unknown>, unknown>()) {\n dependencyContainer.registerInstance(token, value);\n }\n\n dependencyContainer.registerInstance(CoreTokens.CredentialSessionService, credentialSessions);\n dependencyContainer.registerInstance(CoreTokens.LiveWorkflowRepository, liveWorkflowRepository);\n dependencyContainer.registerInstance(CoreTokens.WorkflowRepository, liveWorkflowRepository);\n dependencyContainer.registerInstance(CoreTokens.NodeResolver, nodeResolver);\n dependencyContainer.registerInstance(\n CoreTokens.RunIdFactory,\n new EngineTestKitRunIdFactory(makeRunId, makeActivationId),\n );\n dependencyContainer.registerInstance(\n CoreTokens.ActivationIdFactory,\n new EngineTestKitRunIdFactory(makeRunId, makeActivationId),\n );\n dependencyContainer.registerInstance(CoreTokens.WebhookBasePath, options.webhookBasePath ?? \"/webhooks\");\n dependencyContainer.registerInstance(CoreTokens.WorkflowExecutionRepository, runStore);\n dependencyContainer.registerInstance(CoreTokens.TriggerSetupStateRepository, triggerSetupStateRepository);\n dependencyContainer.registerInstance(CoreTokens.NodeActivationScheduler, activationScheduler);\n dependencyContainer.registerInstance(CoreTokens.RunDataFactory, runDataFactory);\n dependencyContainer.registerInstance(CoreTokens.ExecutionContextFactory, executionContextFactory);\n dependencyContainer.registerInstance(CoreTokens.RunEventBus, eventBus);\n dependencyContainer.registerInstance(\n CoreTokens.PersistedWorkflowTokenRegistry,\n new PersistedWorkflowTokenRegistry(),\n );\n dependencyContainer.registerInstance(\n CoreTokens.WorkflowActivationPolicy,\n new AllWorkflowsActiveWorkflowActivationPolicy(),\n );\n\n if (options.executionLimitsPolicy !== undefined) {\n dependencyContainer.registerInstance(CoreTokens.EngineExecutionLimitsPolicy, options.executionLimitsPolicy);\n }\n\n new EngineRuntimeRegistrar().register(dependencyContainer, options.registrarOptions ?? {});\n\n const engine = dependencyContainer.resolve(Engine);\n const runIntent = dependencyContainer.resolve(RunIntentService);\n const workflowRunner =\n options.workflowRunner ??\n (dependencyContainer.resolve(CoreTokens.WorkflowRunnerService) as EngineWorkflowRunnerService);\n dependencyContainer.registerInstance(\n SubWorkflowRunnerNode,\n new SubWorkflowRunnerNode(workflowRunner as WorkflowRunnerService),\n );\n dependencyContainer.registerInstance(ItemHarnessNode, new ItemHarnessNode());\n dependencyContainer.registerInstance(SwitchHarnessNode, new SwitchHarnessNode());\n dependencyContainer.registerInstance(\n WorkflowTestHarnessManualTriggerNode,\n new WorkflowTestHarnessManualTriggerNode(),\n );\n\n const start = async (workflows: ReadonlyArray<import(\"../types\").WorkflowDefinition>): Promise<void> => {\n await engine.start([...workflows]);\n };\n\n const runToCompletion: RegistrarEngineTestKitHandle[\"runToCompletion\"] = async (args) => {\n const r0 = await engine.runWorkflow(args.wf, args.startAt, args.items, args.parent);\n if (r0.status !== \"pending\") return r0;\n return await engine.waitForCompletion(r0.runId);\n };\n\n const runIntentStartToCompletion: RegistrarEngineTestKitHandle[\"runIntentStartToCompletion\"] = async (args) => {\n const r0 = await runIntent.startWorkflow({\n workflow: args.wf,\n startAt: args.startAt,\n items: args.items,\n parent: args.parent,\n });\n if (r0.status !== \"pending\") return r0;\n return await engine.waitForCompletion(r0.runId);\n };\n\n return {\n engine,\n runIntent,\n liveWorkflowRepository,\n runStore,\n triggerSetupStateRepository,\n scheduler: scheduler as CapturingScheduler | import(\"../types\").NodeExecutionScheduler,\n offloadPolicy,\n workflowRunner,\n dependencyContainer,\n start,\n runToCompletion,\n runIntentStartToCompletion,\n makeRunId,\n makeActivationId,\n };\n }\n}\n","import type { DependencyContainer } from \"tsyringe\";\n\nimport type { TypeToken } from \"../di\";\n\nimport type { DefinedNodeRegistrationContext } from \"./WorkflowTestKit.types\";\n\nexport class WorkflowTestKitNodeRegistrationContextFactory {\n create(dependencyContainer: DependencyContainer): DefinedNodeRegistrationContext {\n return {\n registerNode<TValue>(token: TypeToken<TValue>, implementation?: TypeToken<TValue>) {\n dependencyContainer.register(token, {\n useClass: (implementation ?? token) as never,\n });\n },\n };\n }\n}\n","import type { RunnableNodeConfig, WorkflowDefinition, WorkflowId } from \"../types\";\nimport { WorkflowBuilder } from \"../workflow/dsl/WorkflowBuilder\";\n\nimport { WorkflowTestHarnessManualTriggerConfig } from \"./WorkflowTestHarnessManualTrigger\";\n\nconst defaultInlineWorkflowId = \"codemation.testing.workflowkit.inline\" as WorkflowId;\nconst defaultInlineWorkflowName = \"WorkflowTestKit inline\";\n\n/**\n * Builds the minimal trigger → runnable workflow used by {@link import(\"./WorkflowTestKit\").WorkflowTestKit.runNode}.\n */\nexport class WorkflowTestKitRunNodeWorkflowFactory {\n build(args: { node: RunnableNodeConfig; workflowId?: WorkflowId; workflowName?: string }): WorkflowDefinition {\n const workflowId = args.workflowId ?? defaultInlineWorkflowId;\n const workflowName = args.workflowName ?? defaultInlineWorkflowName;\n const trigger = new WorkflowTestHarnessManualTriggerConfig(\n \"WorkflowTestKit trigger\",\n \"workflowkit.harness.trigger\",\n );\n return new WorkflowBuilder({ id: workflowId, name: workflowName }).trigger(trigger).then(args.node).build();\n }\n\n defaultStartNodeId(): string {\n return \"workflowkit.harness.trigger\";\n }\n}\n","import type { DependencyContainer } from \"tsyringe\";\n\nimport type { Items, NodeId, RunnableNodeConfig, RunResult, WorkflowDefinition, WorkflowId } from \"../types\";\n\nimport { RegistrarEngineTestKitFactory } from \"./RegistrarEngineTestKitFactory\";\nimport type { EngineTestKitOptions, RegistrarEngineTestKitHandle } from \"./RegistrarEngineTestKit.types\";\nimport { WorkflowTestKitNodeRegistrationContextFactory } from \"./WorkflowTestKitNodeRegistrationContextFactory\";\nimport type { DefinedNodeRegistration } from \"./WorkflowTestKit.types\";\nimport { WorkflowTestKitRunNodeWorkflowFactory } from \"./WorkflowTestKitRunNodeWorkflowFactory\";\n\nexport type { DefinedNodeRegistration, DefinedNodeRegistrationContext } from \"./WorkflowTestKit.types\";\n\nexport type WorkflowTestKitOptions = EngineTestKitOptions;\n\nexport class WorkflowTestKit {\n private readonly handle: RegistrarEngineTestKitHandle;\n private readonly runNodeWorkflowFactory = new WorkflowTestKitRunNodeWorkflowFactory();\n private readonly nodeRegistrationContextFactory = new WorkflowTestKitNodeRegistrationContextFactory();\n\n constructor(options: WorkflowTestKitOptions = {}) {\n this.handle = RegistrarEngineTestKitFactory.create(options);\n }\n\n get dependencyContainer(): DependencyContainer {\n return this.handle.dependencyContainer;\n }\n\n get engine(): RegistrarEngineTestKitHandle[\"engine\"] {\n return this.handle.engine;\n }\n\n get workflowRunner(): RegistrarEngineTestKitHandle[\"workflowRunner\"] {\n return this.handle.workflowRunner;\n }\n\n get liveWorkflowRepository(): RegistrarEngineTestKitHandle[\"liveWorkflowRepository\"] {\n return this.handle.liveWorkflowRepository;\n }\n\n get runStore(): RegistrarEngineTestKitHandle[\"runStore\"] {\n return this.handle.runStore;\n }\n\n /**\n * Registers {@link import(\"../authoring/defineNode.types\").DefinedNode} implementations on the same DI container used by the engine\n * (same pattern as `plugin.register({ registerNode })` in the host).\n */\n registerDefinedNodes(definitions: ReadonlyArray<DefinedNodeRegistration>): void {\n const ctx = this.nodeRegistrationContextFactory.create(this.handle.dependencyContainer);\n for (const def of definitions) {\n def.register(ctx);\n }\n }\n\n async run(args: { workflow: WorkflowDefinition; items: Items; startAt?: NodeId }): Promise<RunResult> {\n await this.handle.start([args.workflow]);\n return await this.handle.workflowRunner.runById({\n workflowId: args.workflow.id,\n startAt: args.startAt,\n items: args.items,\n });\n }\n\n async runNode(args: {\n node: RunnableNodeConfig;\n items: Items;\n workflowId?: WorkflowId;\n workflowName?: string;\n }): Promise<RunResult> {\n const wf = this.runNodeWorkflowFactory.build(args);\n return await this.run({\n workflow: wf,\n items: args.items,\n startAt: this.runNodeWorkflowFactory.defaultStartNodeId(),\n });\n }\n}\n"],"mappings":"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"}
@@ -42,56 +42,96 @@ var WhenBuilder = class WhenBuilder {
42
42
  //#endregion
43
43
  //#region src/workflow/dsl/ChainCursorResolver.ts
44
44
  var ChainCursor = class ChainCursor {
45
- constructor(wf, cursor, cursorOutput) {
45
+ constructor(wf, endpoints) {
46
46
  this.wf = wf;
47
- this.cursor = cursor;
48
- this.cursorOutput = cursorOutput;
47
+ this.endpoints = endpoints;
49
48
  }
50
49
  then(config) {
51
50
  const next = this.wf.add(config);
52
- this.wf.connect(this.cursor, next, this.cursorOutput);
53
- return new ChainCursor(this.wf, next, "main");
51
+ const inputPortHint = this.resolveSharedInputPortHint();
52
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output);
53
+ return new ChainCursor(this.wf, [{
54
+ node: next,
55
+ output: "main",
56
+ ...inputPortHint ? { inputPortHint } : {}
57
+ }]);
58
+ }
59
+ thenIntoInputHints(config) {
60
+ const next = this.wf.add(config);
61
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output, e.inputPortHint ?? "in");
62
+ return new ChainCursor(this.wf, [{
63
+ node: next,
64
+ output: "main"
65
+ }]);
54
66
  }
55
67
  when = ((arg1, steps, ...more) => {
68
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.when(...) is only supported from a single cursor endpoint");
69
+ const cursor = this.endpoints[0].node;
56
70
  if (typeof arg1 === "boolean") {
57
71
  const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
58
72
  const port = arg1 ? "true" : "false";
59
- const b = new WhenBuilder(this.wf, this.cursor, port);
73
+ const b = new WhenBuilder(this.wf, cursor, port);
60
74
  b.addBranch(list);
61
75
  return b;
62
76
  }
63
77
  const branches = arg1;
64
- const makeMerge = this.wf.options?.makeMergeNode;
65
- if (!makeMerge) throw new Error("WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".");
66
78
  const wfAny = this.wf;
67
79
  const buildBranch = (port, branchSteps) => {
68
80
  const list = branchSteps ?? [];
69
81
  let prev = null;
70
82
  for (const cfg of list) {
71
83
  const ref = wfAny.add(cfg);
72
- if (!prev) wfAny.connect(this.cursor, ref, port, "in");
84
+ if (!prev) wfAny.connect(cursor, ref, port, "in");
73
85
  else wfAny.connect(prev, ref, "main", "in");
74
86
  prev = ref;
75
87
  }
76
88
  if (!prev) return {
77
- end: this.cursor,
78
- endOutput: port
89
+ end: cursor,
90
+ endOutput: port,
91
+ inputPortHint: port
79
92
  };
80
93
  return {
81
94
  end: prev,
82
- endOutput: "main"
95
+ endOutput: "main",
96
+ inputPortHint: port
83
97
  };
84
98
  };
85
99
  const t = buildBranch("true", branches.true);
86
100
  const f = buildBranch("false", branches.false);
87
- const merge = wfAny.add(makeMerge("Merge (auto)"));
88
- wfAny.connect(t.end, merge, t.endOutput, "true");
89
- wfAny.connect(f.end, merge, f.endOutput, "false");
90
- return new ChainCursor(this.wf, merge, "main");
101
+ return new ChainCursor(this.wf, [{
102
+ node: t.end,
103
+ output: t.endOutput,
104
+ inputPortHint: t.inputPortHint
105
+ }, {
106
+ node: f.end,
107
+ output: f.endOutput,
108
+ inputPortHint: f.inputPortHint
109
+ }]);
91
110
  });
111
+ route(branches) {
112
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.route(...) is only supported from a single cursor endpoint");
113
+ const cursor = this.endpoints[0];
114
+ const nextEndpoints = [];
115
+ for (const [port, branchFactory] of Object.entries(branches)) {
116
+ if (!branchFactory) continue;
117
+ const builtBranch = branchFactory(new ChainCursor(this.wf, [{
118
+ node: cursor.node,
119
+ output: port,
120
+ inputPortHint: port
121
+ }]));
122
+ if (!builtBranch) continue;
123
+ nextEndpoints.push(...builtBranch.endpoints);
124
+ }
125
+ return new ChainCursor(this.wf, nextEndpoints);
126
+ }
92
127
  build() {
93
128
  return this.wf.build();
94
129
  }
130
+ resolveSharedInputPortHint() {
131
+ const first = this.endpoints[0]?.inputPortHint;
132
+ if (!first) return;
133
+ return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : void 0;
134
+ }
95
135
  };
96
136
 
97
137
  //#endregion
@@ -134,11 +174,17 @@ var WorkflowBuilder = class {
134
174
  }
135
175
  trigger(config) {
136
176
  const ref = this.add(config);
137
- return new ChainCursor(this, ref, "main");
177
+ return new ChainCursor(this, [{
178
+ node: ref,
179
+ output: "main"
180
+ }]);
138
181
  }
139
182
  start(config) {
140
183
  const ref = this.add(config);
141
- return new ChainCursor(this, ref, "main");
184
+ return new ChainCursor(this, [{
185
+ node: ref,
186
+ output: "main"
187
+ }]);
142
188
  }
143
189
  build() {
144
190
  return {
@@ -228,4 +274,4 @@ Object.defineProperty(exports, 'WorkflowBuilder', {
228
274
  return WorkflowBuilder;
229
275
  }
230
276
  });
231
- //# sourceMappingURL=workflowActivationPolicy-BzyzXLa_.cjs.map
277
+ //# sourceMappingURL=workflowActivationPolicy-6V3OJD3N.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflowActivationPolicy-6V3OJD3N.cjs","names":["wf: WorkflowBuilder","from: NodeRef","branchPort: OutputPortKey","created: NodeRef[]","prev: NodeRef | null","port: OutputPortKey","wf: WorkflowBuilder","endpoints: ReadonlyArray<ChainCursorEndpoint>","port: OutputPortKey","prev: NodeRef | null","nextEndpoints: ChainCursorEndpoint[]","meta: { id: WorkflowId; name: string }","options?: Readonly<Record<string, never>>","onClose: () => void"],"sources":["../src/workflow/dsl/WhenBuilder.ts","../src/workflow/dsl/ChainCursorResolver.ts","../src/workflow/dsl/WorkflowBuilder.ts","../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts","../src/contracts/workflowActivationPolicy.ts"],"sourcesContent":["import type { NodeId, NodeRef, OutputPortKey, UpstreamRefPlaceholder, WorkflowDefinition } from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport type { AnyRunnableNodeConfig, BooleanWhenOverloads, ValidStepSequence } from \"./workflowBuilderTypes\";\n\nexport class WhenBuilder<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly from: NodeRef,\n private readonly branchPort: OutputPortKey,\n ) {}\n\n addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(\n steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>,\n ): this {\n const created: NodeRef[] = [];\n\n let prev: NodeRef | null = null;\n for (const cfg of steps) {\n const ref = (this.wf as any).add(cfg) as NodeRef;\n created.push(ref);\n if (!prev) (this.wf as any).connect(this.from, ref, this.branchPort, \"in\");\n else (this.wf as any).connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n\n for (const cfg of steps) {\n const maybe = cfg as unknown as { upstreamRefs?: Array<{ nodeId: NodeId } | UpstreamRefPlaceholder> };\n if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;\n\n maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {\n if (typeof r !== \"string\") return r;\n const idx = parseInt(r.slice(1), 10);\n const nodeId = created[idx]?.id;\n return nodeId ? { nodeId } : { nodeId: r };\n });\n }\n\n return this;\n }\n\n readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> = (\n branch: boolean,\n steps: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> => {\n const list = Array.isArray(steps) ? steps : [steps, ...more];\n const port: OutputPortKey = branch ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.from, port);\n b.addBranch(list);\n return b;\n };\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n InputPortKey,\n NodeRef,\n OutputPortKey,\n RunnableNodeConfig,\n RunnableNodeOutputJson,\n WorkflowDefinition,\n} from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport { WhenBuilder } from \"./WhenBuilder\";\nimport type {\n AnyRunnableNodeConfig,\n BooleanWhenOverloads,\n BranchOutputGuard,\n BranchStepsArg,\n StepSequenceOutput,\n} from \"./workflowBuilderTypes\";\n\ntype ChainCursorEndpoint = Readonly<{ node: NodeRef; output: OutputPortKey; inputPortHint?: InputPortKey }>;\n\ntype ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {\n <\n TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n >(\n branches: Readonly<{\n true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;\n false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig>\n ? BranchStepsArg<TCurrentJson, TFalseSteps>\n : never;\n }> &\n BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>,\n ): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;\n};\n\nexport class ChainCursor<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly endpoints: ReadonlyArray<ChainCursorEndpoint>,\n ) {}\n\n then<TOutputJson, TConfig extends RunnableNodeConfig<TCurrentJson, TOutputJson>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n const inputPortHint = this.resolveSharedInputPortHint();\n for (const e of this.endpoints) {\n (this.wf as any).connect(e.node, next, e.output);\n }\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, [\n { node: next, output: \"main\", ...(inputPortHint ? { inputPortHint } : {}) },\n ]);\n }\n\n thenIntoInputHints<TOutputJson, TConfig extends RunnableNodeConfig<any, TOutputJson>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n for (const e of this.endpoints) {\n (this.wf as any).connect(e.node, next, e.output, e.inputPortHint ?? \"in\");\n }\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, [{ node: next, output: \"main\" }]);\n }\n\n readonly when: ChainCursorWhenOverloads<TCurrentJson> = ((\n arg1:\n | boolean\n | Readonly<{ true?: ReadonlyArray<AnyRunnableNodeConfig>; false?: ReadonlyArray<AnyRunnableNodeConfig> }>,\n steps?: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> | ChainCursor<TCurrentJson> => {\n if (this.endpoints.length !== 1) {\n throw new Error(\"ChainCursor.when(...) is only supported from a single cursor endpoint\");\n }\n const cursor = this.endpoints[0]!.node;\n\n if (typeof arg1 === \"boolean\") {\n const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;\n const port: OutputPortKey = arg1 ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, cursor, port);\n b.addBranch(list);\n return b;\n }\n\n const branches = arg1;\n const wfAny = this.wf as any;\n\n const buildBranch = (\n port: OutputPortKey,\n branchSteps: ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n ): Readonly<{ end: NodeRef; endOutput: OutputPortKey; inputPortHint: InputPortKey }> => {\n const list = branchSteps ?? [];\n let prev: NodeRef | null = null;\n for (const cfg of list) {\n const ref = wfAny.add(cfg) as NodeRef;\n if (!prev) wfAny.connect(cursor, ref, port, \"in\");\n else wfAny.connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n if (!prev) return { end: cursor, endOutput: port, inputPortHint: port };\n return { end: prev, endOutput: \"main\", inputPortHint: port };\n };\n\n const t = buildBranch(\"true\", branches.true);\n const f = buildBranch(\"false\", branches.false);\n return new ChainCursor<TCurrentJson>(this.wf, [\n { node: t.end, output: t.endOutput, inputPortHint: t.inputPortHint },\n { node: f.end, output: f.endOutput, inputPortHint: f.inputPortHint },\n ]);\n }) as ChainCursorWhenOverloads<TCurrentJson>;\n\n route<TNextJson>(\n branches: Readonly<\n Record<OutputPortKey, (branch: ChainCursor<TCurrentJson>) => ChainCursor<TNextJson> | undefined>\n >,\n ): ChainCursor<TNextJson> {\n if (this.endpoints.length !== 1) {\n throw new Error(\"ChainCursor.route(...) is only supported from a single cursor endpoint\");\n }\n const cursor = this.endpoints[0]!;\n const nextEndpoints: ChainCursorEndpoint[] = [];\n for (const [port, branchFactory] of Object.entries(branches)) {\n if (!branchFactory) {\n continue;\n }\n const branch = new ChainCursor<TCurrentJson>(this.wf, [{ node: cursor.node, output: port, inputPortHint: port }]);\n const builtBranch = branchFactory(branch);\n if (!builtBranch) {\n continue;\n }\n nextEndpoints.push(...builtBranch.endpoints);\n }\n return new ChainCursor<TNextJson>(this.wf, nextEndpoints);\n }\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n\n private resolveSharedInputPortHint(): InputPortKey | undefined {\n const first = this.endpoints[0]?.inputPortHint;\n if (!first) {\n return undefined;\n }\n return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : undefined;\n }\n}\n","import type {\n InputPortKey,\n NodeConfigBase,\n NodeDefinition,\n NodeRef,\n OutputPortKey,\n RunnableNodeOutputJson,\n TriggerNodeOutputJson,\n WorkflowDefinition,\n WorkflowId,\n} from \"../../types\";\n\nimport { ChainCursor } from \"./ChainCursorResolver\";\nimport type { AnyRunnableNodeConfig, AnyTriggerNodeConfig } from \"./workflowBuilderTypes\";\n\nexport class WorkflowBuilder {\n private readonly nodes: NodeDefinition[] = [];\n private readonly edges: WorkflowDefinition[\"edges\"] = [];\n private seq = 0;\n\n constructor(\n private readonly meta: { id: WorkflowId; name: string },\n private readonly options?: Readonly<Record<string, never>>,\n ) {}\n\n private add(config: NodeConfigBase): NodeRef {\n const tokenName = typeof config.type === \"function\" ? config.type.name : String(config.type);\n const id = config.id ?? `${tokenName}:${++this.seq}`;\n this.nodes.push({ id, kind: config.kind, type: config.type, name: config.name, config });\n return { id, kind: config.kind, name: config.name };\n }\n\n private connect(from: NodeRef, to: NodeRef, fromOutput: OutputPortKey = \"main\", toInput: InputPortKey = \"in\"): void {\n this.edges.push({ from: { nodeId: from.id, output: fromOutput }, to: { nodeId: to.id, input: toInput } });\n }\n\n trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<TriggerNodeOutputJson<TConfig>>(this, [{ node: ref, output: \"main\" }]);\n }\n\n start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this, [{ node: ref, output: \"main\" }]);\n }\n\n build(): WorkflowDefinition {\n return { ...this.meta, nodes: this.nodes, edges: this.edges };\n }\n}\n\nexport { ChainCursor } from \"./ChainCursorResolver\";\nexport { WhenBuilder } from \"./WhenBuilder\";\n","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","import type { WorkflowId } from \"./workflowTypes\";\n\n/**\n * Host-controlled policy: when false, trigger {@link TriggerNode} setup is skipped and webhook routes\n * for that workflow are not registered (see engine trigger runtime + webhook matcher).\n */\nexport interface WorkflowActivationPolicy {\n isActive(workflowId: WorkflowId): boolean;\n}\n\n/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */\nexport class AllWorkflowsActiveWorkflowActivationPolicy implements WorkflowActivationPolicy {\n isActive(_workflowId: WorkflowId): boolean {\n return true;\n }\n}\n"],"mappings":";;AAKA,IAAa,cAAb,MAAa,YAA0B;CACrC,YACE,AAAiBA,IACjB,AAAiBC,MACjB,AAAiBC,YACjB;EAHiB;EACA;EACA;;CAGnB,UACE,OACM;EACN,MAAMC,UAAqB,EAAE;EAE7B,IAAIC,OAAuB;AAC3B,OAAK,MAAM,OAAO,OAAO;GACvB,MAAM,MAAO,KAAK,GAAW,IAAI,IAAI;AACrC,WAAQ,KAAK,IAAI;AACjB,OAAI,CAAC,KAAM,CAAC,KAAK,GAAW,QAAQ,KAAK,MAAM,KAAK,KAAK,YAAY,KAAK;OACrE,CAAC,KAAK,GAAW,QAAQ,MAAM,KAAK,QAAQ,KAAK;AACtD,UAAO;;AAGT,OAAK,MAAM,OAAO,OAAO;GACvB,MAAM,QAAQ;AACd,OAAI,CAAC,MAAM,QAAQ,MAAM,aAAa,IAAI,MAAM,aAAa,WAAW,EAAG;AAE3E,SAAM,eAAe,MAAM,aAAa,KAAK,MAAM;AACjD,QAAI,OAAO,MAAM,SAAU,QAAO;IAElC,MAAM,SAAS,QADH,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,GACP;AAC7B,WAAO,SAAS,EAAE,QAAQ,GAAG,EAAE,QAAQ,GAAG;KAC1C;;AAGJ,SAAO;;CAGT,AAAS,QACP,QACA,OACA,GAAG,SAC2B;EAC9B,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,OAAO,GAAG,KAAK;EAC5D,MAAMC,OAAsB,SAAS,SAAS;EAC9C,MAAM,IAAI,IAAI,YAA0B,KAAK,IAAI,KAAK,MAAM,KAAK;AACjE,IAAE,UAAU,KAAK;AACjB,SAAO;;CAGT,QAA4B;AAC1B,SAAO,KAAK,GAAG,OAAO;;;;;;AClB1B,IAAa,cAAb,MAAa,YAA0B;CACrC,YACE,AAAiBC,IACjB,AAAiBC,WACjB;EAFiB;EACA;;CAGnB,KACE,QAC8C;EAC9C,MAAM,OAAQ,KAAK,GAAW,IAAI,OAAO;EACzC,MAAM,gBAAgB,KAAK,4BAA4B;AACvD,OAAK,MAAM,KAAK,KAAK,UACnB,CAAC,KAAK,GAAW,QAAQ,EAAE,MAAM,MAAM,EAAE,OAAO;AAElD,SAAO,IAAI,YAA6C,KAAK,IAAI,CAC/D;GAAE,MAAM;GAAM,QAAQ;GAAQ,GAAI,gBAAgB,EAAE,eAAe,GAAG,EAAE;GAAG,CAC5E,CAAC;;CAGJ,mBACE,QAC8C;EAC9C,MAAM,OAAQ,KAAK,GAAW,IAAI,OAAO;AACzC,OAAK,MAAM,KAAK,KAAK,UACnB,CAAC,KAAK,GAAW,QAAQ,EAAE,MAAM,MAAM,EAAE,QAAQ,EAAE,iBAAiB,KAAK;AAE3E,SAAO,IAAI,YAA6C,KAAK,IAAI,CAAC;GAAE,MAAM;GAAM,QAAQ;GAAQ,CAAC,CAAC;;CAGpG,AAAS,SACP,MAGA,OACA,GAAG,SACuD;AAC1D,MAAI,KAAK,UAAU,WAAW,EAC5B,OAAM,IAAI,MAAM,wEAAwE;EAE1F,MAAM,SAAS,KAAK,UAAU,GAAI;AAElC,MAAI,OAAO,SAAS,WAAW;GAC7B,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,QAAQ,CAAC,OAAO,GAAG,KAAK,GAAG;GACvE,MAAMC,OAAsB,OAAO,SAAS;GAC5C,MAAM,IAAI,IAAI,YAA0B,KAAK,IAAI,QAAQ,KAAK;AAC9D,KAAE,UAAU,KAAK;AACjB,UAAO;;EAGT,MAAM,WAAW;EACjB,MAAM,QAAQ,KAAK;EAEnB,MAAM,eACJ,MACA,gBACsF;GACtF,MAAM,OAAO,eAAe,EAAE;GAC9B,IAAIC,OAAuB;AAC3B,QAAK,MAAM,OAAO,MAAM;IACtB,MAAM,MAAM,MAAM,IAAI,IAAI;AAC1B,QAAI,CAAC,KAAM,OAAM,QAAQ,QAAQ,KAAK,MAAM,KAAK;QAC5C,OAAM,QAAQ,MAAM,KAAK,QAAQ,KAAK;AAC3C,WAAO;;AAET,OAAI,CAAC,KAAM,QAAO;IAAE,KAAK;IAAQ,WAAW;IAAM,eAAe;IAAM;AACvE,UAAO;IAAE,KAAK;IAAM,WAAW;IAAQ,eAAe;IAAM;;EAG9D,MAAM,IAAI,YAAY,QAAQ,SAAS,KAAK;EAC5C,MAAM,IAAI,YAAY,SAAS,SAAS,MAAM;AAC9C,SAAO,IAAI,YAA0B,KAAK,IAAI,CAC5C;GAAE,MAAM,EAAE;GAAK,QAAQ,EAAE;GAAW,eAAe,EAAE;GAAe,EACpE;GAAE,MAAM,EAAE;GAAK,QAAQ,EAAE;GAAW,eAAe,EAAE;GAAe,CACrE,CAAC;;CAGJ,MACE,UAGwB;AACxB,MAAI,KAAK,UAAU,WAAW,EAC5B,OAAM,IAAI,MAAM,yEAAyE;EAE3F,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAMC,gBAAuC,EAAE;AAC/C,OAAK,MAAM,CAAC,MAAM,kBAAkB,OAAO,QAAQ,SAAS,EAAE;AAC5D,OAAI,CAAC,cACH;GAGF,MAAM,cAAc,cADL,IAAI,YAA0B,KAAK,IAAI,CAAC;IAAE,MAAM,OAAO;IAAM,QAAQ;IAAM,eAAe;IAAM,CAAC,CAAC,CACxE;AACzC,OAAI,CAAC,YACH;AAEF,iBAAc,KAAK,GAAG,YAAY,UAAU;;AAE9C,SAAO,IAAI,YAAuB,KAAK,IAAI,cAAc;;CAG3D,QAA4B;AAC1B,SAAO,KAAK,GAAG,OAAO;;CAGxB,AAAQ,6BAAuD;EAC7D,MAAM,QAAQ,KAAK,UAAU,IAAI;AACjC,MAAI,CAAC,MACH;AAEF,SAAO,KAAK,UAAU,OAAO,aAAa,SAAS,kBAAkB,MAAM,GAAG,QAAQ;;;;;;AClI1F,IAAa,kBAAb,MAA6B;CAC3B,AAAiB,QAA0B,EAAE;CAC7C,AAAiB,QAAqC,EAAE;CACxD,AAAQ,MAAM;CAEd,YACE,AAAiBC,MACjB,AAAiBC,SACjB;EAFiB;EACA;;CAGnB,AAAQ,IAAI,QAAiC;EAC3C,MAAM,YAAY,OAAO,OAAO,SAAS,aAAa,OAAO,KAAK,OAAO,OAAO,OAAO,KAAK;EAC5F,MAAM,KAAK,OAAO,MAAM,GAAG,UAAU,GAAG,EAAE,KAAK;AAC/C,OAAK,MAAM,KAAK;GAAE;GAAI,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM;GAAQ,CAAC;AACxF,SAAO;GAAE;GAAI,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM;;CAGrD,AAAQ,QAAQ,MAAe,IAAa,aAA4B,QAAQ,UAAwB,MAAY;AAClH,OAAK,MAAM,KAAK;GAAE,MAAM;IAAE,QAAQ,KAAK;IAAI,QAAQ;IAAY;GAAE,IAAI;IAAE,QAAQ,GAAG;IAAI,OAAO;IAAS;GAAE,CAAC;;CAG3G,QAA8C,QAA8D;EAC1G,MAAM,MAAM,KAAK,IAAI,OAAO;AAC5B,SAAO,IAAI,YAA4C,MAAM,CAAC;GAAE,MAAM;GAAK,QAAQ;GAAQ,CAAC,CAAC;;CAG/F,MAA6C,QAA+D;EAC1G,MAAM,MAAM,KAAK,IAAI,OAAO;AAC5B,SAAO,IAAI,YAA6C,MAAM,CAAC;GAAE,MAAM;GAAK,QAAQ;GAAQ,CAAC,CAAC;;CAGhG,QAA4B;AAC1B,SAAO;GAAE,GAAG,KAAK;GAAM,OAAO,KAAK;GAAO,OAAO,KAAK;GAAO;;;;;;AC7CjE,IAAa,+BAAb,MAA0E;CACxE,YAAY,AAAiBC,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;;;;;;;ACrBN,IAAa,6CAAb,MAA4F;CAC1F,SAAS,aAAkC;AACzC,SAAO"}
@@ -41,56 +41,96 @@ var WhenBuilder = class WhenBuilder {
41
41
  //#endregion
42
42
  //#region src/workflow/dsl/ChainCursorResolver.ts
43
43
  var ChainCursor = class ChainCursor {
44
- constructor(wf, cursor, cursorOutput) {
44
+ constructor(wf, endpoints) {
45
45
  this.wf = wf;
46
- this.cursor = cursor;
47
- this.cursorOutput = cursorOutput;
46
+ this.endpoints = endpoints;
48
47
  }
49
48
  then(config) {
50
49
  const next = this.wf.add(config);
51
- this.wf.connect(this.cursor, next, this.cursorOutput);
52
- return new ChainCursor(this.wf, next, "main");
50
+ const inputPortHint = this.resolveSharedInputPortHint();
51
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output);
52
+ return new ChainCursor(this.wf, [{
53
+ node: next,
54
+ output: "main",
55
+ ...inputPortHint ? { inputPortHint } : {}
56
+ }]);
57
+ }
58
+ thenIntoInputHints(config) {
59
+ const next = this.wf.add(config);
60
+ for (const e of this.endpoints) this.wf.connect(e.node, next, e.output, e.inputPortHint ?? "in");
61
+ return new ChainCursor(this.wf, [{
62
+ node: next,
63
+ output: "main"
64
+ }]);
53
65
  }
54
66
  when = ((arg1, steps, ...more) => {
67
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.when(...) is only supported from a single cursor endpoint");
68
+ const cursor = this.endpoints[0].node;
55
69
  if (typeof arg1 === "boolean") {
56
70
  const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
57
71
  const port = arg1 ? "true" : "false";
58
- const b = new WhenBuilder(this.wf, this.cursor, port);
72
+ const b = new WhenBuilder(this.wf, cursor, port);
59
73
  b.addBranch(list);
60
74
  return b;
61
75
  }
62
76
  const branches = arg1;
63
- const makeMerge = this.wf.options?.makeMergeNode;
64
- if (!makeMerge) throw new Error("WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".");
65
77
  const wfAny = this.wf;
66
78
  const buildBranch = (port, branchSteps) => {
67
79
  const list = branchSteps ?? [];
68
80
  let prev = null;
69
81
  for (const cfg of list) {
70
82
  const ref = wfAny.add(cfg);
71
- if (!prev) wfAny.connect(this.cursor, ref, port, "in");
83
+ if (!prev) wfAny.connect(cursor, ref, port, "in");
72
84
  else wfAny.connect(prev, ref, "main", "in");
73
85
  prev = ref;
74
86
  }
75
87
  if (!prev) return {
76
- end: this.cursor,
77
- endOutput: port
88
+ end: cursor,
89
+ endOutput: port,
90
+ inputPortHint: port
78
91
  };
79
92
  return {
80
93
  end: prev,
81
- endOutput: "main"
94
+ endOutput: "main",
95
+ inputPortHint: port
82
96
  };
83
97
  };
84
98
  const t = buildBranch("true", branches.true);
85
99
  const f = buildBranch("false", branches.false);
86
- const merge = wfAny.add(makeMerge("Merge (auto)"));
87
- wfAny.connect(t.end, merge, t.endOutput, "true");
88
- wfAny.connect(f.end, merge, f.endOutput, "false");
89
- return new ChainCursor(this.wf, merge, "main");
100
+ return new ChainCursor(this.wf, [{
101
+ node: t.end,
102
+ output: t.endOutput,
103
+ inputPortHint: t.inputPortHint
104
+ }, {
105
+ node: f.end,
106
+ output: f.endOutput,
107
+ inputPortHint: f.inputPortHint
108
+ }]);
90
109
  });
110
+ route(branches) {
111
+ if (this.endpoints.length !== 1) throw new Error("ChainCursor.route(...) is only supported from a single cursor endpoint");
112
+ const cursor = this.endpoints[0];
113
+ const nextEndpoints = [];
114
+ for (const [port, branchFactory] of Object.entries(branches)) {
115
+ if (!branchFactory) continue;
116
+ const builtBranch = branchFactory(new ChainCursor(this.wf, [{
117
+ node: cursor.node,
118
+ output: port,
119
+ inputPortHint: port
120
+ }]));
121
+ if (!builtBranch) continue;
122
+ nextEndpoints.push(...builtBranch.endpoints);
123
+ }
124
+ return new ChainCursor(this.wf, nextEndpoints);
125
+ }
91
126
  build() {
92
127
  return this.wf.build();
93
128
  }
129
+ resolveSharedInputPortHint() {
130
+ const first = this.endpoints[0]?.inputPortHint;
131
+ if (!first) return;
132
+ return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : void 0;
133
+ }
94
134
  };
95
135
 
96
136
  //#endregion
@@ -133,11 +173,17 @@ var WorkflowBuilder = class {
133
173
  }
134
174
  trigger(config) {
135
175
  const ref = this.add(config);
136
- return new ChainCursor(this, ref, "main");
176
+ return new ChainCursor(this, [{
177
+ node: ref,
178
+ output: "main"
179
+ }]);
137
180
  }
138
181
  start(config) {
139
182
  const ref = this.add(config);
140
- return new ChainCursor(this, ref, "main");
183
+ return new ChainCursor(this, [{
184
+ node: ref,
185
+ output: "main"
186
+ }]);
141
187
  }
142
188
  build() {
143
189
  return {
@@ -198,4 +244,4 @@ var AllWorkflowsActiveWorkflowActivationPolicy = class {
198
244
 
199
245
  //#endregion
200
246
  export { WhenBuilder as a, ChainCursor as i, InMemoryRunEventBus as n, WorkflowBuilder as r, AllWorkflowsActiveWorkflowActivationPolicy as t };
201
- //# sourceMappingURL=workflowActivationPolicy-B8HzTk3o.js.map
247
+ //# sourceMappingURL=workflowActivationPolicy-Td9HTOuD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflowActivationPolicy-Td9HTOuD.js","names":["wf: WorkflowBuilder","from: NodeRef","branchPort: OutputPortKey","created: NodeRef[]","prev: NodeRef | null","port: OutputPortKey","wf: WorkflowBuilder","endpoints: ReadonlyArray<ChainCursorEndpoint>","port: OutputPortKey","prev: NodeRef | null","nextEndpoints: ChainCursorEndpoint[]","meta: { id: WorkflowId; name: string }","options?: Readonly<Record<string, never>>","onClose: () => void"],"sources":["../src/workflow/dsl/WhenBuilder.ts","../src/workflow/dsl/ChainCursorResolver.ts","../src/workflow/dsl/WorkflowBuilder.ts","../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts","../src/contracts/workflowActivationPolicy.ts"],"sourcesContent":["import type { NodeId, NodeRef, OutputPortKey, UpstreamRefPlaceholder, WorkflowDefinition } from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport type { AnyRunnableNodeConfig, BooleanWhenOverloads, ValidStepSequence } from \"./workflowBuilderTypes\";\n\nexport class WhenBuilder<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly from: NodeRef,\n private readonly branchPort: OutputPortKey,\n ) {}\n\n addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(\n steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>,\n ): this {\n const created: NodeRef[] = [];\n\n let prev: NodeRef | null = null;\n for (const cfg of steps) {\n const ref = (this.wf as any).add(cfg) as NodeRef;\n created.push(ref);\n if (!prev) (this.wf as any).connect(this.from, ref, this.branchPort, \"in\");\n else (this.wf as any).connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n\n for (const cfg of steps) {\n const maybe = cfg as unknown as { upstreamRefs?: Array<{ nodeId: NodeId } | UpstreamRefPlaceholder> };\n if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;\n\n maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {\n if (typeof r !== \"string\") return r;\n const idx = parseInt(r.slice(1), 10);\n const nodeId = created[idx]?.id;\n return nodeId ? { nodeId } : { nodeId: r };\n });\n }\n\n return this;\n }\n\n readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> = (\n branch: boolean,\n steps: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> => {\n const list = Array.isArray(steps) ? steps : [steps, ...more];\n const port: OutputPortKey = branch ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.from, port);\n b.addBranch(list);\n return b;\n };\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n InputPortKey,\n NodeRef,\n OutputPortKey,\n RunnableNodeConfig,\n RunnableNodeOutputJson,\n WorkflowDefinition,\n} from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport { WhenBuilder } from \"./WhenBuilder\";\nimport type {\n AnyRunnableNodeConfig,\n BooleanWhenOverloads,\n BranchOutputGuard,\n BranchStepsArg,\n StepSequenceOutput,\n} from \"./workflowBuilderTypes\";\n\ntype ChainCursorEndpoint = Readonly<{ node: NodeRef; output: OutputPortKey; inputPortHint?: InputPortKey }>;\n\ntype ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {\n <\n TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n >(\n branches: Readonly<{\n true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;\n false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig>\n ? BranchStepsArg<TCurrentJson, TFalseSteps>\n : never;\n }> &\n BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>,\n ): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;\n};\n\nexport class ChainCursor<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly endpoints: ReadonlyArray<ChainCursorEndpoint>,\n ) {}\n\n then<TOutputJson, TConfig extends RunnableNodeConfig<TCurrentJson, TOutputJson>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n const inputPortHint = this.resolveSharedInputPortHint();\n for (const e of this.endpoints) {\n (this.wf as any).connect(e.node, next, e.output);\n }\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, [\n { node: next, output: \"main\", ...(inputPortHint ? { inputPortHint } : {}) },\n ]);\n }\n\n thenIntoInputHints<TOutputJson, TConfig extends RunnableNodeConfig<any, TOutputJson>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n for (const e of this.endpoints) {\n (this.wf as any).connect(e.node, next, e.output, e.inputPortHint ?? \"in\");\n }\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, [{ node: next, output: \"main\" }]);\n }\n\n readonly when: ChainCursorWhenOverloads<TCurrentJson> = ((\n arg1:\n | boolean\n | Readonly<{ true?: ReadonlyArray<AnyRunnableNodeConfig>; false?: ReadonlyArray<AnyRunnableNodeConfig> }>,\n steps?: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> | ChainCursor<TCurrentJson> => {\n if (this.endpoints.length !== 1) {\n throw new Error(\"ChainCursor.when(...) is only supported from a single cursor endpoint\");\n }\n const cursor = this.endpoints[0]!.node;\n\n if (typeof arg1 === \"boolean\") {\n const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;\n const port: OutputPortKey = arg1 ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, cursor, port);\n b.addBranch(list);\n return b;\n }\n\n const branches = arg1;\n const wfAny = this.wf as any;\n\n const buildBranch = (\n port: OutputPortKey,\n branchSteps: ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n ): Readonly<{ end: NodeRef; endOutput: OutputPortKey; inputPortHint: InputPortKey }> => {\n const list = branchSteps ?? [];\n let prev: NodeRef | null = null;\n for (const cfg of list) {\n const ref = wfAny.add(cfg) as NodeRef;\n if (!prev) wfAny.connect(cursor, ref, port, \"in\");\n else wfAny.connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n if (!prev) return { end: cursor, endOutput: port, inputPortHint: port };\n return { end: prev, endOutput: \"main\", inputPortHint: port };\n };\n\n const t = buildBranch(\"true\", branches.true);\n const f = buildBranch(\"false\", branches.false);\n return new ChainCursor<TCurrentJson>(this.wf, [\n { node: t.end, output: t.endOutput, inputPortHint: t.inputPortHint },\n { node: f.end, output: f.endOutput, inputPortHint: f.inputPortHint },\n ]);\n }) as ChainCursorWhenOverloads<TCurrentJson>;\n\n route<TNextJson>(\n branches: Readonly<\n Record<OutputPortKey, (branch: ChainCursor<TCurrentJson>) => ChainCursor<TNextJson> | undefined>\n >,\n ): ChainCursor<TNextJson> {\n if (this.endpoints.length !== 1) {\n throw new Error(\"ChainCursor.route(...) is only supported from a single cursor endpoint\");\n }\n const cursor = this.endpoints[0]!;\n const nextEndpoints: ChainCursorEndpoint[] = [];\n for (const [port, branchFactory] of Object.entries(branches)) {\n if (!branchFactory) {\n continue;\n }\n const branch = new ChainCursor<TCurrentJson>(this.wf, [{ node: cursor.node, output: port, inputPortHint: port }]);\n const builtBranch = branchFactory(branch);\n if (!builtBranch) {\n continue;\n }\n nextEndpoints.push(...builtBranch.endpoints);\n }\n return new ChainCursor<TNextJson>(this.wf, nextEndpoints);\n }\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n\n private resolveSharedInputPortHint(): InputPortKey | undefined {\n const first = this.endpoints[0]?.inputPortHint;\n if (!first) {\n return undefined;\n }\n return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : undefined;\n }\n}\n","import type {\n InputPortKey,\n NodeConfigBase,\n NodeDefinition,\n NodeRef,\n OutputPortKey,\n RunnableNodeOutputJson,\n TriggerNodeOutputJson,\n WorkflowDefinition,\n WorkflowId,\n} from \"../../types\";\n\nimport { ChainCursor } from \"./ChainCursorResolver\";\nimport type { AnyRunnableNodeConfig, AnyTriggerNodeConfig } from \"./workflowBuilderTypes\";\n\nexport class WorkflowBuilder {\n private readonly nodes: NodeDefinition[] = [];\n private readonly edges: WorkflowDefinition[\"edges\"] = [];\n private seq = 0;\n\n constructor(\n private readonly meta: { id: WorkflowId; name: string },\n private readonly options?: Readonly<Record<string, never>>,\n ) {}\n\n private add(config: NodeConfigBase): NodeRef {\n const tokenName = typeof config.type === \"function\" ? config.type.name : String(config.type);\n const id = config.id ?? `${tokenName}:${++this.seq}`;\n this.nodes.push({ id, kind: config.kind, type: config.type, name: config.name, config });\n return { id, kind: config.kind, name: config.name };\n }\n\n private connect(from: NodeRef, to: NodeRef, fromOutput: OutputPortKey = \"main\", toInput: InputPortKey = \"in\"): void {\n this.edges.push({ from: { nodeId: from.id, output: fromOutput }, to: { nodeId: to.id, input: toInput } });\n }\n\n trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<TriggerNodeOutputJson<TConfig>>(this, [{ node: ref, output: \"main\" }]);\n }\n\n start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this, [{ node: ref, output: \"main\" }]);\n }\n\n build(): WorkflowDefinition {\n return { ...this.meta, nodes: this.nodes, edges: this.edges };\n }\n}\n\nexport { ChainCursor } from \"./ChainCursorResolver\";\nexport { WhenBuilder } from \"./WhenBuilder\";\n","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","import type { WorkflowId } from \"./workflowTypes\";\n\n/**\n * Host-controlled policy: when false, trigger {@link TriggerNode} setup is skipped and webhook routes\n * for that workflow are not registered (see engine trigger runtime + webhook matcher).\n */\nexport interface WorkflowActivationPolicy {\n isActive(workflowId: WorkflowId): boolean;\n}\n\n/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */\nexport class AllWorkflowsActiveWorkflowActivationPolicy implements WorkflowActivationPolicy {\n isActive(_workflowId: WorkflowId): boolean {\n return true;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemation/core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -63,6 +63,7 @@
63
63
  "zod": "^4.3.6"
64
64
  },
65
65
  "scripts": {
66
+ "changeset:verify": "pnpm --workspace-root run changeset:verify",
66
67
  "dev": "tsdown --watch",
67
68
  "build": "tsdown",
68
69
  "typecheck": "tsc -p tsconfig.json --noEmit",
@@ -1,4 +1,5 @@
1
1
  import type { NodeConfigBase } from "../types";
2
+ import { isItemValue } from "../contracts/itemValue";
2
3
  import type { AgentNodeConfig } from "./AiHost";
3
4
 
4
5
  export class AgentConfigInspector {
@@ -17,6 +18,9 @@ export class AgentConfigInspector {
17
18
  return messages.length > 0;
18
19
  }
19
20
  if (typeof messages === "object") {
21
+ if (isItemValue(messages)) {
22
+ return true;
23
+ }
20
24
  const o = messages as { prompt?: unknown; buildMessages?: unknown };
21
25
  return (Array.isArray(o.prompt) && o.prompt.length > 0) || typeof o.buildMessages === "function";
22
26
  }
@@ -1,3 +1,5 @@
1
+ import { isItemValue } from "../contracts/itemValue";
2
+
1
3
  import type {
2
4
  AgentMessageBuildArgs,
3
5
  AgentMessageConfig,
@@ -67,6 +69,11 @@ export class AgentMessageConfigNormalizer {
67
69
  config: AgentMessageConfig<TInputJson>,
68
70
  args: AgentMessageBuildArgs<TInputJson>,
69
71
  ): ReadonlyArray<AgentMessageDto> {
72
+ if (isItemValue(config)) {
73
+ throw new Error(
74
+ "AIAgent messages wrapped in itemValue(...) must be resolved by the engine before prompt normalization.",
75
+ );
76
+ }
70
77
  if (Array.isArray(config)) {
71
78
  return config.map((line) => this.lineToDto(line, args));
72
79
  }
@@ -5,7 +5,7 @@ import { NodeBackedToolConfig } from "./NodeBackedToolConfig";
5
5
 
6
6
  class AgentToolFactoryImpl {
7
7
  asTool<
8
- TNodeConfig extends RunnableNodeConfig<any, any, any>,
8
+ TNodeConfig extends RunnableNodeConfig<any, any>,
9
9
  TInputSchema extends ZodSchemaAny,
10
10
  TOutputSchema extends ZodSchemaAny,
11
11
  >(
@@ -20,7 +20,7 @@ class AgentToolFactoryImpl {
20
20
  }
21
21
 
22
22
  private withDefaultAgentInputMapper<
23
- TNodeConfig extends RunnableNodeConfig<any, any, any>,
23
+ TNodeConfig extends RunnableNodeConfig<any, any>,
24
24
  TInputSchema extends ZodSchemaAny,
25
25
  TOutputSchema extends ZodSchemaAny,
26
26
  >(