{"version":3,"file":"child_process.cjs","names":[],"sources":["../../../src/batteries/isolation/child_process/transport.ts"],"sourcesContent":["/**\n * Node `child_process`-backed {@link @nhtio/adk/batteries/isolation!IsolationTransport} — forks (or\n * BYO-spawns) a guest process and wraps its IPC channel in the `PortLike` duck the wire protocol is\n * built over.\n *\n * @remarks\n * This module is NODE-ONLY: it imports `node:child_process` directly (unlike `serve.ts`'s guest-side\n * duck detection, which never imports `node:*` so it stays loadable in a Worker/browser bundle). See\n * this subpath's `index.ts` for why a real process — rather than a `worker_threads` `Worker` — is the\n * right host-side primitive for the Node transport.\n *\n * Two ways to obtain the child:\n *\n * - `{ modulePath, forkOptions? }` — the common case. Calls node's own `child_process.fork(modulePath,\n *   forkOptions)`. Unless the caller's `forkOptions` explicitly sets `serialization`, this pins\n *   `serialization: 'advanced'` (V8's structured-clone algorithm over the IPC channel) rather than\n *   node's default `'json'`. This matters because `codec.ts` treats `TypedArray`/`ArrayBuffer`/\n *   `DataView`/`Date`/`RegExp`/`Map`/`Set` as OPAQUE traversal leaves that ship **raw**, trusting the\n *   transport to carry them faithfully — under default JSON serialization a `Float32Array` argument\n *   would silently degrade to a plain `{0: ..., 1: ...}` object on arrival (empirically confirmed: a\n *   `fork()` with no `serialization` override loses `instanceof Float32Array` across the wire). If a\n *   caller forces `forkOptions: { serialization: 'json' }` anyway, tier-0 (`raw`) round-trips are\n *   restricted to JSON-safe values for THOSE exotic containers; the codec's auto-escalation to tier-1/2\n *   still carries functions/Errors/custom-encodables correctly (just paying the `@nhtio/encoder`\n *   encode/decode cost) — only raw-tier TypedArray/Map/Set/Date/RegExp fidelity is at risk, and only\n *   when the caller opted out of the default explicitly.\n * - `{ spawn }` — a {@link ChildResolver} BYO-spawner seam for callers who need their own process\n *   manager (pooling, custom stdio wiring, sandboxing) or who spawn via a wrapper library instead of\n *   `fork()` directly. The resolver must return (or resolve to) an {@link IsolatedChildLike} — see that\n *   type's doc for the exact surface this module was empirically verified against, including execa≥9.\n *\n * These two forms are mutually exclusive and validated eagerly (this subpath's own local joi schema —\n * the shared `validation.ts` is not touched).\n *\n * `terminate()` sends `SIGTERM` (or the caller's configured signal) and does NOT itself wait for exit\n * or run any grace period of its own — `host.ts`'s `dispose()` already sends a `shutdown` envelope and\n * waits `disposeGraceMs` for the guest to exit voluntarily before calling `transport.terminate()`\n * unconditionally; duplicating a grace window here would just double it. An `'exit'` that fires while\n * `terminate()`/`recycle()` is in progress is expected and never reported as a crash; any other exit\n * (including a non-zero code, e.g. `process.exit(7)` in the guest) or an `'error'` event on the child\n * fires {@link @nhtio/adk/batteries/isolation!IsolationTransport.onCrash}. `recycle()` (driven by\n * `host.ts`, not implemented in this module) re-enters this same transport's `connect()`, which forks\n * (or re-invokes the resolver) a brand-new child every time — there is no child reuse across recycles.\n */\n\nimport { fork } from 'node:child_process'\nimport { isError, isInstanceOf } from '@nhtio/adk/guards'\nimport { validator, ValidationError } from '@nhtio/validation'\nimport {\n  createIsolatedService,\n  E_INVALID_ISOLATION_OPTIONS,\n  E_ISOLATION_UNSUPPORTED_ENV,\n} from '@nhtio/adk/batteries/isolation'\nimport type { ForkOptions } from 'node:child_process'\nimport type {\n  CrashInfo,\n  IsolatedService,\n  IsolatedServiceOptions,\n  IsolatedServiceSpec,\n  IsolationTransport,\n  PortLike,\n} from '@nhtio/adk/batteries/isolation'\n\n/**\n * The minimal Node `ChildProcess`-shaped duck this transport drives. Structurally satisfied by BOTH:\n *\n * - the object returned by `node:child_process`'s own `fork()`, and\n * - an `execa`≥9 subprocess spawned with `{ ipc: true }` — empirically verified: execa's\n *   `Subprocess<OptionsType>` type is `Omit<ChildProcess, keyof ExecaCustomSubprocess<OptionsType>> &\n *   ExecaCustomSubprocess<OptionsType>`, i.e. it keeps the classic Node `ChildProcess` EventEmitter\n *   surface (`.send()`, `.on('message'|'exit'|'error', ...)`, `.kill()`, `.connected`) alongside\n *   execa's own promise-based `sendMessage()`/`getEachMessage()` API. This transport only ever uses the\n *   classic EventEmitter surface, so an execa `{ ipc: true }` subprocess satisfies this duck WITHOUT\n *   any adapter.\n *\n * execa's channel, like node's own `fork()`, defaults to JSON-style serialization unless the\n * subprocess is spawned with `serialization: 'advanced'` (execa forwards that option straight to the\n * underlying `child_process.fork()` it uses internally for `ipc: true`) — the same \"pin `advanced` for\n * exotic-value fidelity\" requirement documented on {@link ForkIsolatedOptions} applies whether the\n * child came from this module's own `fork()` call or from a caller-supplied {@link ChildResolver}.\n *\n * @remarks\n * A {@link ChildResolver} must NOT itself attach a `'message'` listener to the child it returns before\n * handing it back to this transport (e.g. for logging). Node buffers a child's `message`/`ipc` events\n * until the FIRST listener is attached, then flushes the whole buffer to that one listener exactly\n * once — a resolver-side listener attached first (even just to log) permanently steals the buffered\n * `ready` envelope from `connect()`'s own listener, which then waits out `readyTimeoutMs` for a `ready`\n * that already came and went. execa's `Subprocess` additionally proxies raw child events through its\n * own internal debounced `message` re-emitter (see execa's `lib/ipc/forward.js`), so this applies to\n * execa subprocesses too — empirically confirmed by instrumenting a resolver with a diagnostic\n * `subprocess.on('message', ...)` and observing the resulting connection hang.\n *\n * A {@link ChildResolver} that returns an execa `{ ipc: true }` subprocess should attach its own\n * no-op `.catch(() => {})` to it before returning. execa's subprocess is ITSELF a promise (via\n * `mergePromise`) that settles REJECTED on a non-zero exit or termination signal — including the\n * ordinary `SIGTERM` this transport's `terminate()` sends on every `dispose()`/`recycle()`. Since this\n * transport only ever drives the classic EventEmitter surface (never awaits/`.then()`s the child\n * itself — see this module's `spawnChild` remarks for why an unguarded `await`/`return` of a thenable\n * child is unsafe in the first place), nothing else ever attaches a rejection handler; without one, a\n * routine `terminate()` reports as an unhandled promise rejection.\n */\nexport interface IsolatedChildLike {\n  /** Send a message across the IPC channel. Returns `false` (or void, depending on the implementation)\n   *  when the channel is closed/backed-up; this transport does not currently act on that return value. */\n  send?(msg: unknown): boolean | void\n  /** Subscribe to a child lifecycle/IPC event (`'message'`, `'exit'`, `'error'`). Listener param typed\n   *  `any[]` to structurally match node's own `ChildProcess#on` overload set (whose listener signatures\n   *  are themselves `(...args: any[]) => void`). */\n  on(event: string, fn: (...args: any[]) => void): unknown\n  /** Unsubscribe, mirroring `.on`. Optional — some resolvers may return a duck without it; this\n   *  transport degrades to leaking the listener rather than throwing (the process is short-lived and\n   *  torn down on `terminate()`/`recycle()` regardless). */\n  off?(event: string, fn: (...args: any[]) => void): unknown\n  /** Alias some ducks expose instead of/alongside `off`. */\n  removeListener?(event: string, fn: (...args: any[]) => void): unknown\n  /** Send a termination signal to the child. */\n  kill(signal?: NodeJS.Signals | number): boolean | void\n  /** Whether the IPC channel is currently open. Read once at connect time for a `send`-before-`connect`\n   *  sanity check; not polled thereafter. */\n  connected?: boolean\n}\n\n/**\n * A BYO-spawner resolver — the seam for callers who need their own process manager (a pool, custom\n * stdio, a sandboxing wrapper, or a library like `execa`) instead of this module's own default\n * `fork()`. Invoked once per `connect()` (including every `recycle()`), i.e. once per guest spawn.\n *\n * @remarks\n * The resolver receives the fully-resolved {@link\n * @nhtio/adk/batteries/isolation!IsolatedServiceSpec} so it can name/label the spawned process (e.g. for\n * logging), but is otherwise free to spawn however it likes — this transport only requires the\n * returned value to satisfy {@link IsolatedChildLike}.\n *\n * A returned execa `{ ipc: true }` subprocess is itself thenable (execa mixes `.then`/`.catch`/\n * `.finally` onto it so it can double as \"the child\" and \"a promise for its exit result\"). This\n * transport's own `spawnChild` internals guard against that value being mistaken for a real `Promise`\n * and adopted (which would silently defer \"spawned\" until the child EXITS) — a resolver author does not\n * need to do anything special here, this is called out purely so the mechanism is documented in one\n * place close to where a resolver returns its child.\n */\nexport type ChildResolver = (ctx: {\n  spec: IsolatedServiceSpec\n}) => IsolatedChildLike | Promise<IsolatedChildLike>\n\n/** The `{ modulePath, forkOptions? }` variant of {@link ForkIsolatedOptions} — spawns via this\n *  module's own `node:child_process.fork()` call. */\nexport interface ForkIsolatedModuleOptions {\n  /** Path to the guest's entry module — passed straight through to `child_process.fork()`. Must be a\n   *  runnable module (already bundled/transpiled if it isn't plain CommonJS/ESM node can load\n   *  directly — `fork()` cannot load a `.ts` file itself). */\n  modulePath: string | URL\n  /** Forwarded to `child_process.fork()`. Unless this sets `serialization` explicitly, this transport\n   *  pins `serialization: 'advanced'` — see this module's top-level remarks. */\n  forkOptions?: ForkOptions\n  /** Absent in this variant — mutually exclusive with `modulePath`/`forkOptions`. See {@link\n   *  ForkIsolatedResolverOptions} for the BYO-spawner variant. */\n  spawn?: never\n}\n\n/** The `{ spawn }` variant of {@link ForkIsolatedOptions} — spawns via a caller-supplied {@link\n *  ChildResolver} instead of this module's own `fork()`. */\nexport interface ForkIsolatedResolverOptions {\n  /** Absent in this variant — mutually exclusive with `spawn`. See {@link ForkIsolatedModuleOptions}. */\n  modulePath?: never\n  /** Absent in this variant — mutually exclusive with `spawn`. See {@link ForkIsolatedModuleOptions}. */\n  forkOptions?: never\n  /** BYO-spawner resolver, invoked once per `connect()`/`recycle()`. See {@link ChildResolver}. */\n  spawn: ChildResolver\n}\n\n/**\n * Options accepted by {@link forkIsolated}/{@link createChildProcessTransport} — extends `host.ts`'s\n * {@link @nhtio/adk/batteries/isolation!IsolatedServiceOptions} with exactly one of the two mutually\n * exclusive spawn shapes: {@link ForkIsolatedModuleOptions} (the common `fork()`-a-module case) or\n * {@link ForkIsolatedResolverOptions} (BYO spawner). Supplying both `modulePath`/`forkOptions` AND\n * `spawn` (or neither) fails eager validation with {@link\n * @nhtio/adk/batteries/isolation!E_INVALID_ISOLATION_OPTIONS}.\n */\nexport type ForkIsolatedOptions = IsolatedServiceOptions &\n  (ForkIsolatedModuleOptions | ForkIsolatedResolverOptions)\n\nconst isValidationError = (value: unknown): value is ValidationError =>\n  isError(value) && Array.isArray((value as ValidationError).details)\n\nconst formatValidationDetails = (err: ValidationError): string =>\n  err.details.map((d) => d.message).join(' and ')\n\n/** Local (this-subpath-only) validator for the spawn-shape half of {@link ForkIsolatedOptions} — the\n *  shared `validation.ts` is not modified; this schema only covers the fields this module adds. */\nconst forkIsolatedSpawnShapeSchema = validator\n  .object<{ modulePath?: string | URL; forkOptions?: object; spawn?: unknown }>({\n    modulePath: validator\n      .alternatives(\n        validator.string().min(1),\n        validator.custom((v, h) => (isInstanceOf(v, 'URL', URL) ? v : h.error('any.invalid')))\n      )\n      .optional(),\n    forkOptions: validator.object().unknown(true).optional(),\n    spawn: validator.function().optional(),\n  })\n  .unknown(true)\n  .xor('modulePath', 'spawn')\n  .with('forkOptions', 'modulePath')\n\n/**\n * Validate the spawn-shape half of a {@link ForkIsolatedOptions} bag: exactly one of `modulePath` /\n * `spawn` must be present, and `forkOptions` may only accompany `modulePath`.\n *\n * @throws {@link @nhtio/adk/batteries/isolation!E_INVALID_ISOLATION_OPTIONS} on failure.\n */\nconst validateForkIsolatedOptions = (input: object): void => {\n  const { error } = forkIsolatedSpawnShapeSchema.validate(input, {\n    abortEarly: false,\n    convert: false,\n  })\n  if (error && isValidationError(error)) {\n    throw new E_INVALID_ISOLATION_OPTIONS([formatValidationDetails(error)])\n  }\n}\n\n/** Structural check for whether the current process can host a `child_process`-backed transport at\n *  all (i.e. we are actually running under node, not e.g. a browser polyfill of parts of this module's\n *  imports). Mirrors `serve.ts`'s guest-side duck check, but on the HOST side: node's own `process`\n *  global always exposes `.pid`, which a browser/worker `globalThis.process` shim would not. */\nconst isNodeHost = (): boolean =>\n  typeof globalThis.process?.pid === 'number' && typeof fork === 'function'\n\n/** Reason string threaded into `onCrash` when the child's `'exit'` fires unexpectedly (i.e. not during\n *  `terminate()`/`recycle()`). */\nconst exitReason = (code: number | null, signal: NodeJS.Signals | null): string =>\n  signal\n    ? `child process exited via signal ${signal}`\n    : `child process exited with code ${code ?? 'null'}`\n\n/**\n * Build a real {@link @nhtio/adk/batteries/isolation!IsolationTransport} over a node `child_process`\n * (or BYO-resolved) child. `connect()` spawns a fresh child every call (including every `recycle()` —\n * there is no child reuse); `terminate()` sends `SIGTERM` (or `forkOptions.killSignal`/the resolver's\n * own convention) without waiting for exit or imposing any grace period of its own (`host.ts` already\n * owns that via `disposeGraceMs`).\n *\n * @throws {@link @nhtio/adk/batteries/isolation!E_ISOLATION_UNSUPPORTED_ENV} when called outside node\n *   (no `process.pid` / no `child_process.fork`).\n * @throws {@link @nhtio/adk/batteries/isolation!E_INVALID_ISOLATION_OPTIONS} when `options` fails the\n *   mutual-exclusivity check documented on {@link ForkIsolatedOptions}.\n */\nexport const createChildProcessTransport = <S extends IsolatedServiceSpec>(\n  spec: S,\n  options: ForkIsolatedOptions\n): IsolationTransport => {\n  if (!isNodeHost()) {\n    throw new E_ISOLATION_UNSUPPORTED_ENV([\n      'createChildProcessTransport requires a node host (process.pid / child_process.fork unavailable) — this transport cannot run in a browser/worker environment',\n    ])\n  }\n  validateForkIsolatedOptions(options)\n\n  let child: IsolatedChildLike | undefined\n  let terminating = false\n  const crashListeners = new Set<(info: CrashInfo) => void>()\n  let messageListener: ((msg: unknown) => void) | undefined\n  let exitListener: ((code: number | null, signal: NodeJS.Signals | null) => void) | undefined\n  let errorListener: ((err: Error) => void) | undefined\n\n  const detachChildListeners = (): void => {\n    if (!child) return\n    const off = (event: string, fn: ((...a: never[]) => void) | undefined): void => {\n      if (!fn) return\n      if (child!.off) child!.off(event, fn as never)\n      else if (child!.removeListener) child!.removeListener(event, fn as never)\n    }\n    off('message', messageListener as never)\n    off('exit', exitListener as never)\n    off('error', errorListener as never)\n    messageListener = undefined\n    exitListener = undefined\n    errorListener = undefined\n  }\n\n  // Deliberately NOT an `async function`, and deliberately returns a BOXED `{ child }` wrapper rather\n  // than the child itself. A resolver-supplied child (e.g. an execa `{ ipc: true }` subprocess) is\n  // ITSELF thenable — execa's `mergePromise` mixes `.then`/`.catch`/`.finally` onto the subprocess\n  // object so `execa(...)`'s return value can be both \"the child\" and \"awaited for its exit result\".\n  // `return`ing (or `await`ing) that value directly from inside an `async function` triggers the\n  // language's thenable-ADOPTION rule: the engine treats the returned/awaited thenable as a real\n  // Promise and defers settling until IT resolves — which for an execa subprocess is when the CHILD\n  // PROCESS EXITS, not when it spawns. That silently turns \"spawn a child\" into \"wait for the child to\n  // exit\", hanging every caller of `connect()` for the child's entire lifetime. Empirically confirmed:\n  // an `async spawnChild` doing `return options.spawn({ spec })` hangs even when the resolver itself is\n  // a plain (non-async) function — the adoption happens at `spawnChild`'s own `return`, not the\n  // resolver's. Boxing the child inside a fresh plain object (which has no `.then` of its own) before\n  // it ever crosses a `return`/`await` boundary avoids triggering adoption anywhere in the chain.\n  const spawnChild = (): Promise<{ child: IsolatedChildLike }> => {\n    if ('spawn' in options && options.spawn) {\n      const maybe = options.spawn({ spec })\n      // A genuine `Promise` (the resolver itself is async/needs to await setup) must still be awaited;\n      // a resolver-returned execa subprocess is thenable-DUCK (see this function's remarks) but is not\n      // actually `instanceof Promise`, so this check correctly tells the two apart without adopting the\n      // duck.\n      return isInstanceOf(maybe, 'Promise', Promise)\n        ? maybe.then((resolvedChild) => ({ child: resolvedChild }))\n        : Promise.resolve({ child: maybe })\n    }\n    const forkOptions = options.forkOptions ?? {}\n    const resolvedForkOptions: ForkOptions =\n      forkOptions.serialization !== undefined\n        ? forkOptions\n        : { ...forkOptions, serialization: 'advanced' }\n    return Promise.resolve({ child: fork(options.modulePath!, resolvedForkOptions) })\n  }\n\n  const connect = async (): Promise<PortLike> => {\n    terminating = false\n    const { child: spawned } = await spawnChild()\n    child = spawned\n\n    const port: PortLike = {\n      post: (msg) => {\n        spawned.send?.(msg)\n      },\n      onMessage: (fn) => {\n        const listener = (msg: unknown): void => fn(msg)\n        messageListener = listener\n        spawned.on('message', listener as never)\n        return () => {\n          if (spawned.off) spawned.off('message', listener as never)\n          else if (spawned.removeListener) spawned.removeListener('message', listener as never)\n        }\n      },\n    }\n\n    exitListener = (code, signal) => {\n      if (terminating) return\n      const info: CrashInfo = { reason: exitReason(code, signal), code: code ?? null, signal }\n      for (const fn of crashListeners) fn(info)\n    }\n    errorListener = (err) => {\n      if (terminating) return\n      const info: CrashInfo = { reason: err.message, code: null, signal: null }\n      for (const fn of crashListeners) fn(info)\n    }\n    spawned.on('exit', exitListener as never)\n    spawned.on('error', errorListener as never)\n\n    return port\n  }\n\n  const terminate = (): void => {\n    terminating = true\n    detachChildListeners()\n    if (child) {\n      const signal = ('forkOptions' in options && options.forkOptions?.killSignal) || 'SIGTERM'\n      child.kill(signal as NodeJS.Signals)\n    }\n    child = undefined\n  }\n\n  return {\n    connect,\n    terminate,\n    onCrash: (fn) => {\n      crashListeners.add(fn)\n      return () => crashListeners.delete(fn)\n    },\n  }\n}\n\n/**\n * Sugar over {@link createChildProcessTransport} + {@link\n * @nhtio/adk/batteries/isolation!createIsolatedService} — the one-call entry point most callers want:\n * fork a guest module (or BYO-spawn one) and get back a ready-to-use {@link\n * @nhtio/adk/batteries/isolation!IsolatedService}.\n *\n * @throws {@link @nhtio/adk/batteries/isolation!E_ISOLATION_UNSUPPORTED_ENV} when called outside node.\n * @throws {@link @nhtio/adk/batteries/isolation!E_INVALID_ISOLATION_OPTIONS} when `options` fails the\n *   mutual-exclusivity check documented on {@link ForkIsolatedOptions}, or when `createIsolatedService`'s\n *   own option validation fails.\n */\nexport const forkIsolated = <S extends IsolatedServiceSpec>(\n  spec: S,\n  options: ForkIsolatedOptions\n): IsolatedService<S> => {\n  const transport = createChildProcessTransport(spec, options)\n  // `options` also carries this subpath's own spawn-shape fields (`modulePath`/`forkOptions`/`spawn`),\n  // which `createIsolatedService` must never see — `host.ts` validates its options bag against the shared\n  // `isolatedServiceOptionsSchema` with `.unknown(false)`, so passing the raw bag through would fail\n  // eager validation on fields that schema (correctly) doesn't know about. Strip them here rather than\n  // loosen the shared schema.\n  const spawnShapeKeys = new Set(['modulePath', 'forkOptions', 'spawn'])\n  const hostOptions = Object.fromEntries(\n    Object.entries(options).filter(([key]) => !spawnShapeKeys.has(key))\n  ) as IsolatedServiceOptions\n  return createIsolatedService(spec, transport, hostOptions)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqLA,IAAM,qBAAqB,UACzB,eAAA,QAAQ,KAAK,KAAK,MAAM,QAAS,MAA0B,OAAO;AAEpE,IAAM,2BAA2B,QAC/B,IAAI,QAAQ,KAAK,MAAM,EAAE,OAAO,EAAE,KAAK,OAAO;;;AAIhD,IAAM,+BAA+B,kBAAA,UAClC,OAA6E;CAC5E,YAAY,kBAAA,UACT,aACC,kBAAA,UAAU,OAAO,EAAE,IAAI,CAAC,GACxB,kBAAA,UAAU,QAAQ,GAAG,MAAO,eAAA,aAAa,GAAG,OAAO,GAAG,IAAI,IAAI,EAAE,MAAM,aAAa,CAAE,CACvF,EACC,SAAS;CACZ,aAAa,kBAAA,UAAU,OAAO,EAAE,QAAQ,IAAI,EAAE,SAAS;CACvD,OAAO,kBAAA,UAAU,SAAS,EAAE,SAAS;AACvC,CAAC,EACA,QAAQ,IAAI,EACZ,IAAI,cAAc,OAAO,EACzB,KAAK,eAAe,YAAY;;;;;;;AAQnC,IAAM,+BAA+B,UAAwB;CAC3D,MAAM,EAAE,UAAU,6BAA6B,SAAS,OAAO;EAC7D,YAAY;EACZ,SAAS;CACX,CAAC;CACD,IAAI,SAAS,kBAAkB,KAAK,GAClC,MAAM,IAAI,kBAAA,4BAA4B,CAAC,wBAAwB,KAAK,CAAC,CAAC;AAE1E;;;;;AAMA,IAAM,mBACJ,OAAO,WAAW,SAAS,QAAQ,YAAY,OAAO,mBAAA,SAAS;;;AAIjE,IAAM,cAAc,MAAqB,WACvC,SACI,mCAAmC,WACnC,kCAAkC,QAAQ;;;;;;;;;;;;;AAchD,IAAa,+BACX,MACA,YACuB;CACvB,IAAI,CAAC,WAAW,GACd,MAAM,IAAI,kBAAA,4BAA4B,CACpC,6JACF,CAAC;CAEH,4BAA4B,OAAO;CAEnC,IAAI;CACJ,IAAI,cAAc;CAClB,MAAM,iCAAiB,IAAI,IAA+B;CAC1D,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,MAAM,6BAAmC;EACvC,IAAI,CAAC,OAAO;EACZ,MAAM,OAAO,OAAe,OAAoD;GAC9E,IAAI,CAAC,IAAI;GACT,IAAI,MAAO,KAAK,MAAO,IAAI,OAAO,EAAW;QACxC,IAAI,MAAO,gBAAgB,MAAO,eAAe,OAAO,EAAW;EAC1E;EACA,IAAI,WAAW,eAAwB;EACvC,IAAI,QAAQ,YAAqB;EACjC,IAAI,SAAS,aAAsB;EACnC,kBAAkB,KAAA;EAClB,eAAe,KAAA;EACf,gBAAgB,KAAA;CAClB;CAeA,MAAM,mBAA0D;EAC9D,IAAI,WAAW,WAAW,QAAQ,OAAO;GACvC,MAAM,QAAQ,QAAQ,MAAM,EAAE,KAAK,CAAC;GAKpC,OAAO,eAAA,aAAa,OAAO,WAAW,OAAO,IACzC,MAAM,MAAM,mBAAmB,EAAE,OAAO,cAAc,EAAE,IACxD,QAAQ,QAAQ,EAAE,OAAO,MAAM,CAAC;EACtC;EACA,MAAM,cAAc,QAAQ,eAAe,CAAC;EAC5C,MAAM,sBACJ,YAAY,kBAAkB,KAAA,IAC1B,cACA;GAAE,GAAG;GAAa,eAAe;EAAW;EAClD,OAAO,QAAQ,QAAQ,EAAE,QAAA,GAAA,mBAAA,MAAY,QAAQ,YAAa,mBAAmB,EAAE,CAAC;CAClF;CAEA,MAAM,UAAU,YAA+B;EAC7C,cAAc;EACd,MAAM,EAAE,OAAO,YAAY,MAAM,WAAW;EAC5C,QAAQ;EAER,MAAM,OAAiB;GACrB,OAAO,QAAQ;IACb,QAAQ,OAAO,GAAG;GACpB;GACA,YAAY,OAAO;IACjB,MAAM,YAAY,QAAuB,GAAG,GAAG;IAC/C,kBAAkB;IAClB,QAAQ,GAAG,WAAW,QAAiB;IACvC,aAAa;KACX,IAAI,QAAQ,KAAK,QAAQ,IAAI,WAAW,QAAiB;UACpD,IAAI,QAAQ,gBAAgB,QAAQ,eAAe,WAAW,QAAiB;IACtF;GACF;EACF;EAEA,gBAAgB,MAAM,WAAW;GAC/B,IAAI,aAAa;GACjB,MAAM,OAAkB;IAAE,QAAQ,WAAW,MAAM,MAAM;IAAG,MAAM,QAAQ;IAAM;GAAO;GACvF,KAAK,MAAM,MAAM,gBAAgB,GAAG,IAAI;EAC1C;EACA,iBAAiB,QAAQ;GACvB,IAAI,aAAa;GACjB,MAAM,OAAkB;IAAE,QAAQ,IAAI;IAAS,MAAM;IAAM,QAAQ;GAAK;GACxE,KAAK,MAAM,MAAM,gBAAgB,GAAG,IAAI;EAC1C;EACA,QAAQ,GAAG,QAAQ,YAAqB;EACxC,QAAQ,GAAG,SAAS,aAAsB;EAE1C,OAAO;CACT;CAEA,MAAM,kBAAwB;EAC5B,cAAc;EACd,qBAAqB;EACrB,IAAI,OAAO;GACT,MAAM,SAAU,iBAAiB,WAAW,QAAQ,aAAa,cAAe;GAChF,MAAM,KAAK,MAAwB;EACrC;EACA,QAAQ,KAAA;CACV;CAEA,OAAO;EACL;EACA;EACA,UAAU,OAAO;GACf,eAAe,IAAI,EAAE;GACrB,aAAa,eAAe,OAAO,EAAE;EACvC;CACF;AACF;;;;;;;;;;;;AAaA,IAAa,gBACX,MACA,YACuB;CACvB,MAAM,YAAY,4BAA4B,MAAM,OAAO;CAM3D,MAAM,iBAAiB,IAAI,IAAI;EAAC;EAAc;EAAe;CAAO,CAAC;CAIrE,OAAO,kBAAA,sBAAsB,MAAM,WAHf,OAAO,YACzB,OAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,eAAe,IAAI,GAAG,CAAC,CAEtB,CAAW;AAC3D"}