{"version":3,"file":"execa_executor.mjs","names":[],"sources":["../../../../src/batteries/media/engines/execa_executor.ts"],"sourcesContent":["/**\n * A {@link @nhtio/adk/batteries/media/contracts!BinaryExecutor} implementation that runs\n * invocations as local child processes via execa.\n *\n * @module @nhtio/adk/batteries/media/engines/execa_executor\n *\n * @remarks\n * The bundled local-process executor. `execa` is an optional peer dependency acquired through\n * an async resolver (default: a lazy dynamic import) — importing this module pulls nothing;\n * constructing the executor is what resolves the peer, and only on first `exec`.\n *\n * Process execution is a movable seam: anything implementing the `BinaryExecutor` contract —\n * a remote runner, a sandbox, a container shim — composes into binary engines exactly like\n * this one. The paired `ScratchWorkspace` must produce paths this executor can open; for the\n * local-process case, the bundled `fs_workspace` is the natural pair.\n */\n\nimport { isError, isObject } from '@nhtio/adk/guards'\nimport { E_INVALID_MEDIA_PIPELINE_CONFIG } from '../exceptions'\nimport type { BinaryExecutor, BinaryInvocation, BinaryExecResult } from '../contracts'\n\n/** The slice of execa this executor uses (kept minimal for BYO substitution in tests). */\nexport interface ExecaLike {\n  (\n    cmd: string,\n    args: readonly string[],\n    options: {\n      timeout?: number\n      cancelSignal?: AbortSignal\n      reject: false\n      stripFinalNewline?: boolean\n    }\n  ): Promise<{\n    exitCode?: number\n    stdout?: unknown\n    stderr?: unknown\n    failed: boolean\n  }>\n}\n\n/** Resolver forms accepted for the execa module. */\nexport type ExecaResolver =\n  | ExecaLike\n  | (() => ExecaLike | { execa: ExecaLike } | Promise<ExecaLike | { execa: ExecaLike }>)\n\n/** Options for {@link execaExecutor}. */\nexport interface ExecaExecutorOptions {\n  /**\n   * The execa function or an async resolver for it. Defaults to a lazy dynamic import of the\n   * `execa` package (optional peer).\n   */\n  execa?: ExecaResolver\n  /** Default timeout applied when an invocation does not specify one. */\n  defaultTimeoutMs?: number\n}\n\nconst resolveExeca = async (supplied: ExecaResolver | undefined): Promise<ExecaLike> => {\n  let value: unknown = supplied ?? ((): Promise<{ execa: ExecaLike }> => import('execa'))\n  if (typeof value === 'function' && !('exec' in (value as object))) {\n    try {\n      value = await (value as () => unknown)()\n    } catch (err) {\n      const detail = isError(err) ? err.message : String(err)\n      throw new E_INVALID_MEDIA_PIPELINE_CONFIG([\n        `execa resolver failed: ${detail} — install the optional peer dependency \"execa\" or supply your own`,\n      ])\n    }\n  }\n  if (isObject(value) && 'execa' in value) {\n    value = (value as { execa: unknown }).execa\n  }\n  if (typeof value !== 'function') {\n    throw new E_INVALID_MEDIA_PIPELINE_CONFIG(['execa resolver did not resolve to a function'])\n  }\n  return value as ExecaLike\n}\n\n/**\n * Construct the bundled local-process {@link BinaryExecutor}.\n *\n * @param options - The execa resolver and defaults.\n * @returns A `BinaryExecutor` running invocations as local child processes.\n */\nexport const execaExecutor = (options: ExecaExecutorOptions = {}): BinaryExecutor => {\n  let execaPromise: Promise<ExecaLike> | undefined\n  const getExeca = (): Promise<ExecaLike> => {\n    execaPromise ??= resolveExeca(options.execa)\n    return execaPromise\n  }\n  return {\n    async exec(invocation: BinaryInvocation): Promise<BinaryExecResult> {\n      const execa = await getExeca()\n      const result = await execa(invocation.cmd, invocation.args, {\n        timeout: invocation.timeoutMs ?? options.defaultTimeoutMs ?? 120_000,\n        cancelSignal: invocation.signal,\n        reject: false,\n        stripFinalNewline: true,\n      })\n      return {\n        exitCode: result.exitCode ?? -1,\n        stdout: typeof result.stdout === 'string' ? result.stdout : '',\n        stderr: typeof result.stderr === 'string' ? result.stderr : '',\n        failed: result.failed,\n      }\n    },\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwDA,IAAM,eAAe,OAAO,aAA4D;CACtF,IAAI,QAAiB,mBAAkD,OAAO;CAC9E,IAAI,OAAO,UAAU,cAAc,EAAE,UAAW,QAC9C,IAAI;EACF,QAAQ,MAAO,MAAwB;CACzC,SAAS,KAAK;EAEZ,MAAM,IAAI,gCAAgC,CACxC,0BAFa,QAAQ,GAAG,IAAI,IAAI,UAAU,OAAO,GAAG,EAEnB,mEACnC,CAAC;CACH;CAEF,IAAI,SAAS,KAAK,KAAK,WAAW,OAChC,QAAS,MAA6B;CAExC,IAAI,OAAO,UAAU,YACnB,MAAM,IAAI,gCAAgC,CAAC,8CAA8C,CAAC;CAE5F,OAAO;AACT;;;;;;;AAQA,IAAa,iBAAiB,UAAgC,CAAC,MAAsB;CACnF,IAAI;CACJ,MAAM,iBAAqC;EACzC,iBAAiB,aAAa,QAAQ,KAAK;EAC3C,OAAO;CACT;CACA,OAAO,EACL,MAAM,KAAK,YAAyD;EAElE,MAAM,SAAS,OAAM,MADD,SAAS,GACF,WAAW,KAAK,WAAW,MAAM;GAC1D,SAAS,WAAW,aAAa,QAAQ,oBAAoB;GAC7D,cAAc,WAAW;GACzB,QAAQ;GACR,mBAAmB;EACrB,CAAC;EACD,OAAO;GACL,UAAU,OAAO,YAAY;GAC7B,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;GAC5D,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;GAC5D,QAAQ,OAAO;EACjB;CACF,EACF;AACF"}