@@ -0,0 +1,72 @@
|
||||
import type { ExecutionPlan, ExecutionPlanNode, PlanEdge, BoundaryNode } from '../../src/generated/common.js';
|
||||
|
||||
/**
|
||||
* Small fluent builder for ExecutionPlans, so scenario journeys read like the
|
||||
* DAGs they model rather than walls of object literals.
|
||||
*
|
||||
* plan('offer_flow')
|
||||
* .node('wait1', 'wait', { duration: 1, unit: 'minutes' })
|
||||
* .node('offer', 'store', { storeSlug: 'starter', offerId: 'pack_1' })
|
||||
* .edge('wait1', 'onComplete', 'offer')
|
||||
* .build();
|
||||
*
|
||||
* The first node added becomes the start node unless `.start(id)` is called.
|
||||
*/
|
||||
export class PlanBuilder {
|
||||
private readonly nodes: ExecutionPlanNode[] = [];
|
||||
private readonly edges: PlanEdge[] = [];
|
||||
private readonly boundaryNodes: BoundaryNode[] = [];
|
||||
private startNodeId?: string;
|
||||
private runIdValue?: string;
|
||||
|
||||
constructor(
|
||||
private readonly scenarioId: string,
|
||||
private readonly opts: { planId?: string; userId?: string } = {},
|
||||
) {}
|
||||
|
||||
/** Sets a specific run ID (default: auto-derived from scenarioId). */
|
||||
runId(id: string): this {
|
||||
this.runIdValue = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
node(id: string, type: string, data?: Record<string, unknown>): this {
|
||||
this.nodes.push({ id, type, data: data as ExecutionPlanNode['data'] });
|
||||
if (!this.startNodeId) this.startNodeId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
edge(source: string, sourceHandle: string, target: string): this {
|
||||
this.edges.push({ id: `e-${source}-${sourceHandle}-${target}`, source, sourceHandle, target });
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Registers a server-side boundary node (handle that calls back to the gateway). */
|
||||
boundary(sourceNodeId: string, sourceHandle: string, nodeId = `b-${sourceNodeId}-${sourceHandle}`): this {
|
||||
this.boundaryNodes.push({ sourceNodeId, sourceHandle, nodeId });
|
||||
return this;
|
||||
}
|
||||
|
||||
start(id: string): this {
|
||||
this.startNodeId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): ExecutionPlan {
|
||||
return {
|
||||
planId: this.opts.planId ?? `${this.scenarioId}-plan`,
|
||||
scenarioId: this.scenarioId,
|
||||
userId: this.opts.userId ?? 'player-1',
|
||||
startNodeId: this.startNodeId,
|
||||
runId: this.runIdValue ?? `${this.scenarioId}-run`,
|
||||
nodes: this.nodes,
|
||||
edges: this.edges,
|
||||
boundaryNodes: this.boundaryNodes,
|
||||
context: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function plan(scenarioId: string, opts?: { planId?: string; userId?: string }): PlanBuilder {
|
||||
return new PlanBuilder(scenarioId, opts);
|
||||
}
|
||||
Reference in New Issue
Block a user