{"version":3,"sources":["../../src/authoring/FlowBuilderCore.ts"],"sourcesContent":["import type {\n  AppliedGuard,\n  Call,\n  Flow,\n  FlowInput,\n  Ref,\n  Resource,\n  SolType,\n} from '@lifi/compose-spec';\n\nimport type {\n  InputDecl,\n  InputSchema,\n  OutputKind,\n  TypedGuard,\n  TypedRef,\n} from '../types.js';\n\nimport type {\n  InputHandle,\n  OutputHandle,\n  ResourceInputHandle,\n} from './handles.js';\nimport { handleToRef } from './handles.js';\nimport { ref } from './raw.js';\n\n/**\n * Arguments for calling an operation node in a flow.\n */\nexport interface CallArgs {\n  /** Maps parameter names to input/output handles or raw `$ref` pointers. */\n  readonly bind: Record<string, AnyBindable>;\n  /** Optional operation-specific configuration. */\n  readonly config?: object;\n  /** Optional guards (e.g. slippage checks) applied to this operation's outputs. */\n  readonly guards?: readonly TypedGuard[];\n}\n\n/**\n * Any value that can be bound to an operation parameter: an input handle,\n * an output handle from a previous operation, or a typed `$ref` pointer.\n *\n * Use `raw.ref<T>()` to create a typed ref from a raw path string.\n */\nexport type AnyBindable = InputHandle | OutputHandle | TypedRef;\n\nconst toRef = (bindable: AnyBindable): Ref => {\n  if ('_tag' in bindable) return handleToRef(bindable);\n  return bindable;\n};\n\n/**\n * Provides references to runtime context values available inside a flow.\n * Access via `builder.context`.\n */\nexport interface ContextAccessor {\n  /** A `$ref` pointing to the transaction sender (signer) address. */\n  readonly sender: TypedRef<'address'>;\n  /** A `$ref` pointing to the on-chain execution (proxy) address. */\n  readonly executionAddress: TypedRef<'address'>;\n}\n\ntype InputHandleOf<D extends InputDecl> = D extends Resource\n  ? ResourceInputHandle\n  : D extends SolType\n    ? InputHandle<D>\n    : InputHandle;\n\n/**\n * A mapped type that converts an input schema into typed handles.\n * Resource inputs produce {@link ResourceInputHandle}; scalar inputs produce {@link InputHandle}.\n *\n * @typeParam T - The flow's input schema.\n */\nexport type InputHandles<T extends InputSchema> = {\n  readonly [K in keyof T]: InputHandleOf<T[K]>;\n};\n\n/**\n * Options for creating a new flow builder.\n *\n * @typeParam T - The flow's input schema.\n */\nexport interface FlowOptions<T extends InputSchema> {\n  /** Optional human-readable name for the flow. Defaults to a random UUID. */\n  readonly name?: string;\n  /** Input declarations mapping names to resource or scalar types. */\n  readonly inputs: T;\n}\n\n/**\n * A Flow document branded with its input schema for type-safe request building.\n *\n * The `__inputs` field is a phantom type — it exists only at compile time for\n * TypeScript inference and is never present at runtime.\n */\nexport type TypedFlow<T extends InputSchema = InputSchema> = Flow & {\n  readonly __inputs?: T;\n};\n\n/**\n * Core flow builder interface providing low-level access to flow construction.\n *\n * For most use cases, prefer the {@link FlowBuilder} type returned by `sdk.flow()`\n * which adds generated operation methods and a `compile` method.\n *\n * @typeParam T - The flow's input schema.\n */\nexport interface FlowBuilderCore<T extends InputSchema = InputSchema> {\n  /** Runtime context references (sender address, execution address). */\n  readonly context: ContextAccessor;\n  /** Typed handles for each declared flow input, used to bind inputs to operations. */\n  readonly inputs: InputHandles<T>;\n  /**\n   * Appends an untyped operation node to the flow. This is an escape hatch\n   * for operations not yet covered by the generated methods.\n   *\n   * Use `raw.ref<T>()` to reference this node's outputs in subsequent typed\n   * operations.\n   *\n   * @param id - Unique node identifier within the flow.\n   * @param op - The operation name (e.g. `\"custom.vaultQuery\"`).\n   * @param args - Bind map, config, and optional guards for the node.\n   * @throws Error if a node with the same `id` already exists in the flow.\n   */\n  readonly untypedOp: (\n    id: string,\n    op: string,\n    args: {\n      readonly bind: Record<string, Ref>;\n      readonly config: Record<string, unknown>;\n      readonly guards?: readonly AppliedGuard[];\n    },\n  ) => void;\n  /** Serialises the builder state into a {@link TypedFlow} document. */\n  readonly build: () => TypedFlow<T>;\n}\n\n/** Maps output port names to their output kind for compile-time and runtime validation. */\nexport type OutputSpec = Record<string, OutputKind>;\n\n/** Internal interface exposed to bindGeneratedOps — not part of the public API. */\nexport interface FlowBuilderInternal<\n  T extends InputSchema = InputSchema,\n> extends FlowBuilderCore<T> {\n  readonly call: <O extends OutputSpec>(\n    nodeId: string,\n    op: string,\n    args: CallArgs,\n    outputs: O,\n  ) => { readonly [K in keyof O & string]: OutputHandle<O[K]> };\n}\n\nconst isResource = (decl: InputDecl): decl is Resource =>\n  typeof decl === 'object' && decl !== null && 'kind' in decl;\n\n/**\n * Creates a new flow builder targeting the given chain.\n *\n * @param chainId - The EVM chain ID (e.g. `1` for Ethereum mainnet).\n * @param options - Flow configuration including input declarations.\n * @returns A {@link FlowBuilderInternal} instance.\n * @internal\n */\nexport const createFlowBuilderCore = <T extends InputSchema>(\n  chainId: number,\n  options: FlowOptions<T>,\n): FlowBuilderInternal<T> => {\n  const id = options.name ?? crypto.randomUUID();\n  const flowInputs: FlowInput[] = [];\n  const nodes: Call[] = [];\n  const nodeIds = new Set<string>();\n\n  const inputHandles = {} as Record<string, InputHandle | ResourceInputHandle>;\n  for (const [name, decl] of Object.entries(options.inputs)) {\n    if (isResource(decl)) {\n      if (decl.chainId !== chainId) {\n        throw new Error(\n          `Input \"${name}\" has chainId ${decl.chainId} but flow targets chain ${chainId}`,\n        );\n      }\n      flowInputs.push({ name, resource: decl });\n      inputHandles[name] = { _tag: 'input', inputName: name, resource: decl };\n    } else {\n      flowInputs.push({ name, type: decl });\n      inputHandles[name] = { _tag: 'input', inputName: name };\n    }\n  }\n\n  const call = <O extends OutputSpec>(\n    nodeId: string,\n    op: string,\n    args: CallArgs,\n    outputs: O,\n  ): { readonly [K in keyof O & string]: OutputHandle<O[K]> } => {\n    if (nodeIds.has(nodeId)) throw new Error(`Duplicate node id: \"${nodeId}\"`);\n    nodeIds.add(nodeId);\n\n    const bind: Record<string, Ref> = {};\n    for (const [key, val] of Object.entries(args.bind)) {\n      bind[key] = toRef(val);\n    }\n\n    const node: Call = {\n      id: nodeId,\n      op,\n      bind,\n      config: (args.config ?? {}) as Record<string, unknown>,\n      ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n    };\n    nodes.push(node);\n\n    type Result = { readonly [K in keyof O & string]: OutputHandle<O[K]> };\n    return new Proxy({} as Result, {\n      get: (_target, prop): OutputHandle | undefined => {\n        if (typeof prop !== 'string' || prop === 'then') return undefined;\n        if (!(prop in outputs)) {\n          throw new Error(\n            `Op \"${op}\" has no output port \"${prop}\". Valid ports: ${Object.keys(\n              outputs,\n            ).join(', ')}`,\n          );\n        }\n        return { _tag: 'output', nodeId, portName: prop };\n      },\n    });\n  };\n\n  const untypedOp = (\n    nodeId: string,\n    op: string,\n    args: {\n      readonly bind: Record<string, Ref>;\n      readonly config: Record<string, unknown>;\n      readonly guards?: readonly AppliedGuard[];\n    },\n  ): void => {\n    if (nodeIds.has(nodeId)) throw new Error(`Duplicate node id: \"${nodeId}\"`);\n    nodeIds.add(nodeId);\n    const node: Call = {\n      id: nodeId,\n      op,\n      bind: args.bind,\n      config: args.config,\n      ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n    };\n    nodes.push(node);\n  };\n\n  const build = (): TypedFlow<T> => ({\n    version: 1,\n    id,\n    chainId,\n    inputs: [...flowInputs],\n    nodes: [...nodes],\n  });\n\n  const context: ContextAccessor = {\n    sender: ref<'address'>('context.sender'),\n    executionAddress: ref<'address'>('context.executionAddress'),\n  };\n\n  return {\n    context,\n    inputs: inputHandles as InputHandles<T>,\n    call,\n    untypedOp,\n    build,\n  };\n};\n"],"mappings":"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","names":[]}