import type { APIPromise } from '../core/api-promise'; import type { RequestOptions } from '../internal/request-options'; import { Workflows, WorkflowUserApprovalResponse, type WorkflowApproveUserParams, type WorkflowRetrieveParams, type WorkflowRetrieveResponse, type WorkflowRunParams, type WorkflowRunResponse, } from '../resources/workflows'; import { type WithJob, enhanceJob } from './job'; import { type Scope, effectiveScope, withScope } from './scope'; import { validateWorkflowFlow } from './workflow_validator'; // Type-only import to break the circular `scenario.ts` ↔ `workflow.ts` graph at runtime. import type { Scenario } from './scenario'; type DefinitionFlow = WorkflowRetrieveResponse.Workflow.Flow; type NodeType = DefinitionFlow['type']; /** * Enhanced workflow object with helper methods. * Has all original workflow fields plus `findNode()`, `getNodesByType()`, * `validate()`, and `run()`. * * @example * ```ts * const response = await client.workflows.retrieve(workflowId); * response.workflow.findNode('final_image'); * response.workflow.getNodesByType('custom-model'); * const gen = await response.workflow.run({ body: { prompt: '...' } }); * response.workflow.name; // original fields still work * ``` */ export class WorkflowEntity { /** @internal */ declare readonly _client: Scenario; /** @internal scope captured from the retrieve call — replayed when `.run()` is invoked without an explicit query override. */ declare readonly _scope?: Scope; /** Find a node in the workflow definition by ID. */ findNode( this: WorkflowEntity & WorkflowRetrieveResponse.Workflow, nodeId: string, ): DefinitionFlow | undefined { return this.flow.find((node) => node.id === nodeId); } /** Get all nodes of a specific type from the workflow definition. */ getNodesByType(this: WorkflowEntity & WorkflowRetrieveResponse.Workflow, type: NodeType): DefinitionFlow[] { return this.flow.filter((node) => node.type === type); } /** * Validate the structural integrity of a workflow flow. * Throws an `Error` with a human-readable message on the first violation found. */ validate(this: WorkflowEntity & WorkflowRetrieveResponse.Workflow): void { validateWorkflowFlow(this.flow); } /** * Run this workflow. Shortcut for * `client.workflows.run(this.id, params)`. * * Returns an enhanced response where `response.job` has `.wait()`. * If the workflow was fetched with a `projectId` scope (per-call override * or client default), that scope is reused unless overridden by * `options.query`. */ run( this: WorkflowEntity & WorkflowRetrieveResponse.Workflow, params: WorkflowRunParams, options?: RequestOptions, ): APIPromise> { return this._client.workflows.run(this.id, params, withScope(this._scope, options)); } /** @internal Create a WorkflowEntity from raw workflow data, optionally remembering the originating scope. */ static from( client: Scenario, data: WorkflowRetrieveResponse.Workflow, scope?: Scope, ): WorkflowRetrieveResponse.Workflow & WorkflowEntity { const entity = Object.assign(Object.create(WorkflowEntity.prototype), data); Object.defineProperty(entity, '_client', { value: client, enumerable: false }); if (scope) Object.defineProperty(entity, '_scope', { value: scope, enumerable: false }); return entity; } } /** Enhanced retrieve response with workflow entity methods. */ export type EnhancedWorkflowRetrieveResponse = Omit & { workflow: WorkflowRetrieveResponse.Workflow & WorkflowEntity; }; /** * Enhanced Workflows resource. * Extends the generated {@link Workflows} — all original methods are inherited. * Overrides `retrieve()`, `run()`, and `approveUser()` to return enriched response objects. */ export class EnhancedWorkflows extends Workflows { /** * Get workflow by ID. Returns an enhanced response where `workflow` has * `findNode()`, `getNodesByType()`, and `validate()`. */ override retrieve( workflowID: string, query: WorkflowRetrieveParams | null | undefined = {}, options?: RequestOptions, ): APIPromise { const client = this._client as Scenario; const scope = effectiveScope(options, client.projectId); return super.retrieve(workflowID, query, options)._thenUnwrap((data) => ({ ...data, workflow: WorkflowEntity.from(client, data.workflow, scope), })); } /** Run a workflow. Returns an enhanced response where `job` has `.wait()`. */ override run( workflowID: string, params: WorkflowRunParams, options?: RequestOptions, ): APIPromise> { return enhanceJob(this._client, super.run(workflowID, params, options), options); } /** Approve a user approval node. Returns an enhanced response where `job` has `.wait()`. */ override userApproval( workflowID: string, body: WorkflowApproveUserParams, options?: RequestOptions, ): APIPromise> { return enhanceJob(this._client, super.userApproval(workflowID, body, options), options); } }