{"version":3,"file":"index.mjs","names":["RpcError"],"sources":["../src/compression.ts","../src/errors.ts","../src/interceptors.ts","../src/client.ts"],"sourcesContent":["import type { CompressionAlgorithm } from \"@amqp-contract/contract\";\nimport { TechnicalError } from \"@amqp-contract/core\";\nimport { fromPromise, type AsyncResult } from \"unthrown\";\nimport { deflate, gzip } from \"node:zlib\";\nimport { promisify } from \"node:util\";\nimport { match } from \"ts-pattern\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\n\n/**\n * Compress a buffer using the specified compression algorithm.\n *\n * @param buffer - The buffer to compress\n * @param algorithm - The compression algorithm to use\n * @returns An AsyncResult resolving to the compressed buffer or a TechnicalError\n *\n * @internal\n */\nexport function compressBuffer(\n  buffer: Buffer,\n  algorithm: CompressionAlgorithm,\n): AsyncResult<Buffer, TechnicalError> {\n  return match(algorithm)\n    .with(\"gzip\", () =>\n      fromPromise(\n        gzipAsync(buffer),\n        (error) => new TechnicalError(\"Failed to compress with gzip\", error),\n      ),\n    )\n    .with(\"deflate\", () =>\n      fromPromise(\n        deflateAsync(buffer),\n        (error) => new TechnicalError(\"Failed to compress with deflate\", error),\n      ),\n    )\n    .exhaustive();\n}\n","import { TaggedError } from \"unthrown\";\n\nexport { isRpcError, MessageValidationError, RpcError } from \"@amqp-contract/core\";\n\n/**\n * Returned from `TypedAmqpClient.call()` when the configured `timeoutMs` elapses\n * before the RPC server publishes a reply with the matching `correlationId`.\n *\n * The pending call is removed from the in-memory correlation map; if a reply\n * arrives after the timeout it is dropped (and a debug log is emitted by the\n * client if a logger is configured). Carries a namespaced `_tag` of\n * `\"@amqp-contract/RpcTimeoutError\"`; the `Error.name` is kept bare\n * (`\"RpcTimeoutError\"`).\n */\nexport class RpcTimeoutError extends TaggedError(\"@amqp-contract/RpcTimeoutError\", {\n  name: \"RpcTimeoutError\",\n})<{\n  rpcName: string;\n  timeoutMs: number;\n}> {\n  constructor(rpcName: string, timeoutMs: number) {\n    super({ rpcName, timeoutMs });\n    this.message = `RPC call to \"${rpcName}\" timed out after ${timeoutMs}ms with no reply received`;\n  }\n}\n\n/**\n * Returned from any in-flight RPC call when the client is closed before the\n * reply is received. The correlation map is cleared on close and every pending\n * caller's promise resolves with `Err(RpcCancelledError)`. Carries a namespaced\n * `_tag` of `\"@amqp-contract/RpcCancelledError\"`; the `Error.name` is kept bare\n * (`\"RpcCancelledError\"`).\n */\nexport class RpcCancelledError extends TaggedError(\"@amqp-contract/RpcCancelledError\", {\n  name: \"RpcCancelledError\",\n})<{\n  rpcName: string;\n}> {\n  constructor(rpcName: string) {\n    super({ rpcName });\n    this.message = `RPC call to \"${rpcName}\" was cancelled because the client was closed`;\n  }\n}\n","import type { MessageValidationError, RpcError, TechnicalError } from \"@amqp-contract/core\";\nimport type { AsyncResult } from \"unthrown\";\nimport type { CallOptions, PublishOptions } from \"./client.js\";\nimport type { RpcCancelledError, RpcTimeoutError } from \"./errors.js\";\n\n/**\n * Error union a publish interceptor chain resolves with — identical to the\n * error channel of `client.publish(...)`.\n */\nexport type PublishError = TechnicalError | MessageValidationError;\n\n/**\n * Error union a call interceptor chain resolves with. The `RpcError` member\n * is the widened (untyped) form; the public `client.call(...)` signature\n * narrows it to the RPC's declared error union.\n */\nexport type CallError =\n  | TechnicalError\n  | MessageValidationError\n  | RpcTimeoutError\n  | RpcCancelledError\n  | RpcError;\n\n/**\n * Arguments a publish interceptor observes. `message` is the pre-validation\n * payload — a patched message goes through schema validation exactly like the\n * caller's original.\n */\nexport type PublishInterceptorArgs = {\n  /** The contract `publishers` key being published. */\n  publisherName: string;\n  /** The (not yet validated) message payload. */\n  message: unknown;\n  /** Per-call publish options (defaults are merged later, inside the client). */\n  options: PublishOptions;\n};\n\n/**\n * Continuation a publish interceptor calls to run the rest of the chain.\n * The optional patch replaces `message` and/or `options` for everything\n * downstream (inner interceptors, validation, and the publish itself).\n */\nexport type PublishInterceptorNext = (patch?: {\n  message?: unknown;\n  options?: PublishOptions;\n}) => AsyncResult<void, PublishError>;\n\n/**\n * Intercepts `client.publish(...)`: runs outside validation and publishing,\n * so it can stamp headers (e.g. trace context), transform the payload, retry\n * by calling `next` again, or short-circuit by returning without calling\n * `next`. The first interceptor in the array is the outermost.\n *\n * @example Stamp a correlation header on every outgoing message\n * ```typescript\n * const stampTenant: PublishInterceptor = (args, next) =>\n *   next({\n *     options: {\n *       ...args.options,\n *       headers: { ...args.options.headers, 'x-tenant-id': currentTenant() },\n *     },\n *   });\n * ```\n */\nexport type PublishInterceptor = (\n  args: PublishInterceptorArgs,\n  next: PublishInterceptorNext,\n) => AsyncResult<void, PublishError>;\n\n/**\n * Arguments a call interceptor observes. `request` is the pre-validation\n * request payload.\n */\nexport type CallInterceptorArgs = {\n  /** The contract `rpcs` key being called. */\n  rpcName: string;\n  /** The (not yet validated) request payload. */\n  request: unknown;\n  /** Per-call options (`timeoutMs`, `publishOptions`). */\n  options: CallOptions;\n};\n\n/**\n * Continuation a call interceptor calls to run the rest of the chain. The\n * resolved value is the RPC response (typed at the public `call()` boundary).\n */\nexport type CallInterceptorNext = (patch?: {\n  request?: unknown;\n  options?: CallOptions;\n}) => AsyncResult<unknown, CallError>;\n\n/**\n * Intercepts `client.call(...)`: wraps the full request/reply round trip, so\n * it can adjust timeouts, stamp request headers, observe replies and typed\n * errors, or retry by calling `next` again. The first interceptor in the\n * array is the outermost.\n *\n * @example Retry timed-out calls once\n * ```typescript\n * const retryOnce: CallInterceptor = (args, next) =>\n *   next().flatMapErr((error) =>\n *     error instanceof RpcTimeoutError ? next() : ErrAsync(error),\n *   );\n * ```\n */\nexport type CallInterceptor = (\n  args: CallInterceptorArgs,\n  next: CallInterceptorNext,\n) => AsyncResult<unknown, CallError>;\n\n/**\n * Run an interceptor chain: interceptors execute left-to-right (first =\n * outermost), each receiving the args as patched by everything outside it;\n * `terminal` receives the final args and performs the real operation.\n *\n * @internal Shared by `publish()` and `call()`; not part of the public API.\n */\nexport function chainInterceptors<\n  TArgs extends object,\n  TPatch extends Partial<TArgs>,\n  TValue,\n  TError,\n>(\n  interceptors: readonly ((\n    args: TArgs,\n    next: (patch?: TPatch) => AsyncResult<TValue, TError>,\n  ) => AsyncResult<TValue, TError>)[],\n  args: TArgs,\n  terminal: (args: TArgs) => AsyncResult<TValue, TError>,\n): AsyncResult<TValue, TError> {\n  const run = (index: number, current: TArgs): AsyncResult<TValue, TError> =>\n    index >= interceptors.length\n      ? terminal(current)\n      : interceptors[index]!(current, (patch) => run(index + 1, { ...current, ...patch }));\n  return run(0, args);\n}\n","import {\n  extractQueue,\n  type CompressionAlgorithm,\n  type ContractDefinition,\n  type InferPublisherNames,\n  type InferRpcNames,\n  type RpcDefinition,\n  type RpcErrorMap,\n} from \"@amqp-contract/contract\";\nimport {\n  AmqpClient,\n  PublishOptions as AmqpClientPublishOptions,\n  type Logger,\n  MessagingSemanticConventions,\n  RPC_ERROR_CODE_HEADER,\n  RpcError,\n  TechnicalError,\n  type TelemetryProvider,\n  defaultTelemetryProvider,\n  endSpanError,\n  endSpanSuccess,\n  recordLateRpcReply,\n  recordPublishMetric,\n  safeJsonParse,\n  startPublishSpan,\n} from \"@amqp-contract/core\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\nimport {\n  Err,\n  ErrAsync,\n  fromPromise,\n  fromSafePromise,\n  Ok,\n  OkAsync,\n  type AsyncResult,\n  type Result,\n} from \"unthrown\";\nimport { randomUUID } from \"node:crypto\";\nimport { compressBuffer } from \"./compression.js\";\nimport { MessageValidationError, RpcCancelledError, RpcTimeoutError } from \"./errors.js\";\nimport { chainInterceptors } from \"./interceptors.js\";\nimport type {\n  CallError as InterceptorCallError,\n  CallInterceptor,\n  CallInterceptorArgs,\n  PublishError,\n  PublishInterceptor,\n  PublishInterceptorArgs,\n} from \"./interceptors.js\";\nimport type {\n  ClientInferPublisherInput,\n  ClientInferRpcErrors,\n  ClientInferRpcRequestInput,\n  ClientInferRpcResponseOutput,\n} from \"./types.js\";\n\n/**\n * The RabbitMQ direct-reply-to pseudo-queue. Publishing with `replyTo` set to\n * this value tells the server to deliver the response back to the consumer\n * subscribed on this queue on the same channel — no real queue is created and\n * no setup is required beyond consuming from it once with `noAck: true`.\n *\n * @see https://www.rabbitmq.com/docs/direct-reply-to\n */\nconst DIRECT_REPLY_TO = \"amq.rabbitmq.reply-to\";\n\n/**\n * In-flight RPC call tracked by `TypedAmqpClient`. The reply consumer\n * looks up entries by `correlationId` when responses arrive.\n */\ntype PendingCall = {\n  rpcName: string;\n  responseSchema: StandardSchemaV1;\n  /**\n   * The RPC's declared `errors` map (code → message definition), used to\n   * validate the `data` of a typed error reply. Undefined when the RPC\n   * declares no errors — any error reply then resolves to a TechnicalError.\n   */\n  rpcErrorSchemas?: RpcErrorMap | undefined;\n  resolve: (\n    result: Result<\n      unknown,\n      TechnicalError | MessageValidationError | RpcTimeoutError | RpcCancelledError | RpcError\n    >,\n  ) => void;\n  timer: ReturnType<typeof setTimeout>;\n};\n\n/**\n * Publish options that extend amqp-client's PublishOptions with optional compression support.\n */\nexport type PublishOptions = AmqpClientPublishOptions & {\n  /**\n   * Optional compression algorithm to use for the message payload.\n   * When specified, the message will be compressed using the chosen algorithm\n   * and the contentEncoding header will be set automatically.\n   */\n  compression?: CompressionAlgorithm | undefined;\n};\n\n/**\n * Options for creating a client\n */\nexport type CreateClientOptions<TContract extends ContractDefinition> = {\n  contract: TContract;\n  urls: ConnectionUrl[];\n  connectionOptions?: AmqpConnectionManagerOptions | undefined;\n  logger?: Logger | undefined;\n  /**\n   * Optional telemetry provider for tracing and metrics.\n   * If not provided, uses the default provider which attempts to load OpenTelemetry.\n   * OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed.\n   */\n  telemetry?: TelemetryProvider | undefined;\n  /**\n   * Default publish options that will be applied to all publish operations.\n   * These can be overridden by options passed to the publish method.\n   * By default, persistent is set to true for message durability.\n   */\n  defaultPublishOptions?: PublishOptions | undefined;\n  /**\n   * Maximum time in ms to wait for the AMQP connection to become ready before\n   * `create()` resolves to an `Err(TechnicalError)`. Defaults to 30s\n   * (the {@link AmqpClient}'s `DEFAULT_CONNECT_TIMEOUT_MS`). Pass `null` to\n   * disable the timeout and let amqp-connection-manager retry indefinitely.\n   */\n  connectTimeoutMs?: number | null | undefined;\n  /**\n   * Interceptors wrapping every `publish(...)`: the first entry is the\n   * outermost. Each can patch the message/options, observe the outcome,\n   * retry by calling `next` again, or short-circuit. A patched message is\n   * validated exactly like the caller's original.\n   */\n  publishInterceptors?: readonly PublishInterceptor[] | undefined;\n  /**\n   * Interceptors wrapping every `call(...)` round trip (request validation,\n   * publish, reply await): the first entry is the outermost.\n   */\n  callInterceptors?: readonly CallInterceptor[] | undefined;\n};\n\n/**\n * Per-call options for `client.call()`.\n */\nexport type CallOptions = {\n  /**\n   * Maximum time in ms to wait for an RPC reply. If exceeded, the call resolves\n   * to `Err(RpcTimeoutError)` and the in-memory correlation entry is cleared.\n   * A late reply arriving after the timeout is silently dropped.\n   *\n   * Required: RPC without a timeout is a footgun.\n   */\n  timeoutMs: number;\n\n  /**\n   * Optional AMQP message properties to merge into the request. `replyTo` and\n   * `correlationId` are managed by the client and cannot be overridden.\n   */\n  publishOptions?: Omit<AmqpClientPublishOptions, \"replyTo\" | \"correlationId\">;\n};\n\n/**\n * Type-safe AMQP client for publishing messages\n */\nexport class TypedAmqpClient<TContract extends ContractDefinition> {\n  /**\n   * In-flight RPC calls keyed by `correlationId`. Cleared when a reply is\n   * received, when the call times out, or when the client is closed.\n   */\n  private readonly pendingCalls = new Map<string, PendingCall>();\n\n  /**\n   * Consumer tag of the reply consumer subscribed on `amq.rabbitmq.reply-to`.\n   * Set when the contract has at least one entry in `rpcs`; undefined otherwise.\n   */\n  private replyConsumerTag?: string;\n\n  private constructor(\n    private readonly contract: TContract,\n    private readonly amqpClient: AmqpClient,\n    private readonly defaultPublishOptions: PublishOptions,\n    private readonly logger?: Logger,\n    private readonly telemetry: TelemetryProvider = defaultTelemetryProvider,\n    private readonly publishInterceptors: readonly PublishInterceptor[] = [],\n    private readonly callInterceptors: readonly CallInterceptor[] = [],\n  ) {}\n\n  /**\n   * Create a type-safe AMQP client from a contract.\n   *\n   * Connection management (including automatic reconnection) is handled internally\n   * by amqp-connection-manager via the {@link AmqpClient}. The client establishes\n   * infrastructure asynchronously in the background once the connection is ready.\n   *\n   * Connections are automatically shared across clients with the same URLs and\n   * connection options, following RabbitMQ best practices.\n   */\n  static create<TContract extends ContractDefinition>({\n    contract,\n    urls,\n    connectionOptions,\n    defaultPublishOptions,\n    logger,\n    telemetry,\n    connectTimeoutMs,\n    publishInterceptors,\n    callInterceptors,\n  }: CreateClientOptions<TContract>): AsyncResult<TypedAmqpClient<TContract>, TechnicalError> {\n    const client = new TypedAmqpClient(\n      contract,\n      new AmqpClient(contract, { urls, connectionOptions, connectTimeoutMs }),\n      { persistent: true, ...defaultPublishOptions },\n      logger,\n      telemetry ?? defaultTelemetryProvider,\n      publishInterceptors ?? [],\n      callInterceptors ?? [],\n    );\n\n    const setup = client\n      .waitForConnectionReady()\n      .flatMap(() => client.setupReplyConsumerIfNeeded());\n\n    const inner = (async (): Promise<Result<TypedAmqpClient<TContract>, TechnicalError>> => {\n      const setupResult = await setup;\n      if (!setupResult.isOk()) {\n        const closeResult = await client.close();\n        if (closeResult.isErr()) {\n          logger?.warn(\"Failed to close client after connection failure\", {\n            error: closeResult.error,\n          });\n        }\n      }\n      // `map` runs only on Ok; an Err/Defect passes through with its value type\n      // re-shaped to the client, so the failure surfaces unchanged.\n      return setupResult.map(() => client);\n    })();\n\n    return fromSafePromise(inner).flatMap((result) => result);\n  }\n\n  /**\n   * If the contract has any RPC entry, subscribe to `amq.rabbitmq.reply-to`\n   * once. Replies for every in-flight call arrive on this single consumer and\n   * are demultiplexed by `correlationId`.\n   */\n  private setupReplyConsumerIfNeeded(): AsyncResult<void, TechnicalError> {\n    const rpcs = this.contract.rpcs ?? {};\n    if (Object.keys(rpcs).length === 0) {\n      return OkAsync(undefined);\n    }\n\n    return this.amqpClient\n      .consume(DIRECT_REPLY_TO, (msg) => this.handleRpcReply(msg), { noAck: true })\n      .tap((tag) => {\n        this.replyConsumerTag = tag;\n      })\n      .map(() => undefined);\n  }\n\n  /**\n   * Demultiplex an RPC reply by `correlationId`, validate the body against the\n   * call's response schema, and resolve the awaiting caller. Replies with no\n   * matching pending call (the call already timed out, was cancelled, or the\n   * correlationId is unknown) are logged at warn — a non-zero rate of these\n   * usually indicates a tuning problem (handler latency exceeds caller\n   * timeout). The `messaging.rpc.late_reply` counter lets dashboards alert on\n   * sustained drift without parsing logs.\n   */\n  private handleRpcReply(msg: Parameters<Parameters<AmqpClient[\"consume\"]>[1]>[0]): void {\n    if (!msg) return;\n    const correlationId = msg.properties.correlationId;\n    if (typeof correlationId !== \"string\") {\n      this.logger?.warn(\"Received RPC reply without correlationId; dropping\", {\n        deliveryTag: msg.fields.deliveryTag,\n      });\n      recordLateRpcReply(this.telemetry, \"missing-correlation-id\");\n      return;\n    }\n    const pending = this.pendingCalls.get(correlationId);\n    if (!pending) {\n      this.logger?.warn(\n        \"Received RPC reply for unknown correlationId (caller already timed out or cancelled)\",\n        { correlationId },\n      );\n      recordLateRpcReply(this.telemetry, \"unknown-correlation-id\");\n      return;\n    }\n    this.pendingCalls.delete(correlationId);\n    clearTimeout(pending.timer);\n\n    const parseResult = safeJsonParse(\n      msg.content,\n      (error) =>\n        new TechnicalError(`Failed to parse RPC reply JSON for \"${pending.rpcName}\"`, error),\n    );\n    if (!parseResult.isOk()) {\n      pending.resolve(\n        Err(\n          parseResult.isErr()\n            ? parseResult.error\n            : new TechnicalError(\n                `Failed to parse RPC reply JSON for \"${pending.rpcName}\"`,\n                parseResult.cause,\n              ),\n        ),\n      );\n      return;\n    }\n    const parsed = parseResult.value;\n\n    // A reply carrying the error-code header is a typed error reply: its body\n    // is `{ message, data }` rather than the response payload. Resolve it\n    // through the RPC's declared error schemas instead of the response schema.\n    const errorCode = msg.properties.headers?.[RPC_ERROR_CODE_HEADER];\n    if (typeof errorCode === \"string\") {\n      this.resolveRpcErrorReply(pending, errorCode, parsed);\n      return;\n    }\n\n    // Wrap the validate call itself — a Standard Schema implementation may\n    // throw synchronously, and the throw would otherwise escape the consume\n    // callback and could crash the reply consumer.\n    let rawValidation: ReturnType<StandardSchemaV1[\"~standard\"][\"validate\"]>;\n    try {\n      rawValidation = pending.responseSchema[\"~standard\"].validate(parsed);\n    } catch (error: unknown) {\n      pending.resolve(\n        Err(new TechnicalError(`RPC reply validation threw for \"${pending.rpcName}\"`, error)),\n      );\n      return;\n    }\n    const validationPromise =\n      rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation);\n\n    validationPromise.then(\n      (validation) => {\n        if (validation.issues) {\n          pending.resolve(Err(new MessageValidationError(pending.rpcName, validation.issues)));\n          return;\n        }\n        pending.resolve(Ok(validation.value));\n      },\n      (error: unknown) => {\n        pending.resolve(\n          Err(new TechnicalError(`RPC reply validation threw for \"${pending.rpcName}\"`, error)),\n        );\n      },\n    );\n  }\n\n  /**\n   * Resolve a pending call with a typed error reply: look up the error's\n   * schema in the RPC's declared `errors` map, validate the reply's `data`\n   * against it, and resolve the caller with `Err(RpcError<code, data>)`.\n   *\n   * An error code the contract does not declare resolves to a TechnicalError —\n   * it means the two sides run different contract versions (or the worker\n   * bypassed the type system), and the client has no schema to give the data\n   * a type under.\n   */\n  private resolveRpcErrorReply(pending: PendingCall, errorCode: string, parsed: unknown): void {\n    // `Object.hasOwn` rather than plain indexing so prototype properties\n    // (e.g. \"toString\") are not misclassified as declared error codes.\n    const errorSchema =\n      pending.rpcErrorSchemas && Object.hasOwn(pending.rpcErrorSchemas, errorCode)\n        ? pending.rpcErrorSchemas[errorCode]\n        : undefined;\n    if (!errorSchema) {\n      pending.resolve(\n        Err(\n          new TechnicalError(\n            `RPC \"${pending.rpcName}\" replied with undeclared error code \"${errorCode}\"`,\n          ),\n        ),\n      );\n      return;\n    }\n\n    const body =\n      typeof parsed === \"object\" && parsed !== null\n        ? (parsed as { message?: unknown; data?: unknown })\n        : {};\n    const message = typeof body.message === \"string\" ? body.message : undefined;\n\n    // Wrap the validate call itself — a Standard Schema implementation may\n    // throw synchronously, and the throw would otherwise escape the consume\n    // callback and could crash the reply consumer.\n    let rawValidation: ReturnType<StandardSchemaV1[\"~standard\"][\"validate\"]>;\n    try {\n      rawValidation = errorSchema.payload[\"~standard\"].validate(body.data);\n    } catch (error: unknown) {\n      pending.resolve(\n        Err(new TechnicalError(`RPC error data validation threw for \"${pending.rpcName}\"`, error)),\n      );\n      return;\n    }\n    const validationPromise =\n      rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation);\n\n    validationPromise.then(\n      (validation) => {\n        if (validation.issues) {\n          pending.resolve(Err(new MessageValidationError(pending.rpcName, validation.issues)));\n          return;\n        }\n        pending.resolve(Err(new RpcError(errorCode, validation.value, message)));\n      },\n      (error: unknown) => {\n        pending.resolve(\n          Err(\n            new TechnicalError(`RPC error data validation threw for \"${pending.rpcName}\"`, error),\n          ),\n        );\n      },\n    );\n  }\n\n  /**\n   * Publish a message using a defined publisher.\n   *\n   * @param publisherName - The name of the publisher to use\n   * @param message - The message to publish\n   * @param options - Optional publish options including compression, headers, priority, etc.\n   *\n   * @remarks\n   * If `options.compression` is specified, the message will be compressed before publishing\n   * and the `contentEncoding` property will be set automatically. Any `contentEncoding`\n   * value already in options will be overwritten by the compression algorithm.\n   */\n  publish<TName extends InferPublisherNames<TContract>>(\n    publisherName: TName,\n    message: ClientInferPublisherInput<TContract, TName>,\n    options?: PublishOptions,\n  ): AsyncResult<void, TechnicalError | MessageValidationError> {\n    const startTime = Date.now();\n    // Non-null assertions safe: TypeScript guarantees these exist for valid TName\n    const publisher = this.contract.publishers![publisherName as string]!;\n    const { exchange, routingKey } = publisher;\n\n    // Start telemetry span\n    const span = startPublishSpan(this.telemetry, exchange.name, routingKey, {\n      [MessagingSemanticConventions.AMQP_PUBLISHER_NAME]: String(publisherName),\n    });\n\n    const validateMessage = (\n      rawMessage: unknown,\n    ): AsyncResult<unknown, TechnicalError | MessageValidationError> => {\n      const validationResult = publisher.message.payload[\"~standard\"].validate(rawMessage);\n      const promise =\n        validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult);\n      return fromPromise(\n        promise,\n        (error): TechnicalError | MessageValidationError =>\n          new TechnicalError(\"Validation failed\", error),\n      ).flatMap((validation) => {\n        if (validation.issues) {\n          return Err<TechnicalError | MessageValidationError>(\n            new MessageValidationError(String(publisherName), validation.issues),\n          );\n        }\n        return Ok(validation.value);\n      });\n    };\n\n    const publishMessage = (\n      validatedMessage: unknown,\n      callOptions: PublishOptions,\n    ): AsyncResult<void, TechnicalError> => {\n      // Merge default options with provided options\n      const mergedOptions = { ...this.defaultPublishOptions, ...callOptions };\n\n      // Extract compression from merged options and create publish options without it\n      const { compression, ...restOptions } = mergedOptions;\n      const publishOptions: AmqpClientPublishOptions = { ...restOptions };\n\n      // Prepare payload and options based on compression configuration\n      const preparePayload = (): AsyncResult<Buffer | unknown, TechnicalError> => {\n        if (compression) {\n          // Compress the message payload\n          const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));\n          publishOptions.contentEncoding = compression;\n          return compressBuffer(messageBuffer, compression);\n        }\n\n        // No compression: use the channel's built-in JSON serialization\n        return OkAsync(validatedMessage);\n      };\n\n      return preparePayload().flatMap((payload) =>\n        this.amqpClient\n          .publish(publisher.exchange.name, publisher.routingKey ?? \"\", payload, publishOptions)\n          .flatMap((published) => {\n            if (!published) {\n              return Err<TechnicalError>(\n                new TechnicalError(\n                  `Failed to publish message for publisher \"${String(publisherName)}\": Channel rejected the message (buffer full or other channel issue)`,\n                ),\n              );\n            }\n\n            this.logger?.info(\"Message published successfully\", {\n              publisherName: String(publisherName),\n              exchange: publisher.exchange.name,\n              routingKey: publisher.routingKey,\n              compressed: !!compression,\n            });\n\n            return Ok(undefined);\n          }),\n      );\n    };\n\n    // Interceptors wrap validation + publish; telemetry stays outermost so\n    // the span covers interceptor work too.\n    const terminal = (args: PublishInterceptorArgs): AsyncResult<void, PublishError> =>\n      validateMessage(args.message).flatMap((validatedMessage) =>\n        publishMessage(validatedMessage, args.options),\n      );\n\n    // Explicit type arguments: TArgs must be the wire-level interceptor shape\n    // (message: unknown), not the narrower type inferred from this literal.\n    return chainInterceptors<\n      PublishInterceptorArgs,\n      { message?: unknown; options?: PublishOptions },\n      void,\n      PublishError\n    >(\n      this.publishInterceptors,\n      { publisherName: String(publisherName), message, options: options ?? {} },\n      terminal,\n    )\n      .tap(() => {\n        const durationMs = Date.now() - startTime;\n        endSpanSuccess(span);\n        recordPublishMetric(this.telemetry, exchange.name, routingKey, true, durationMs);\n      })\n      .tapErr((error) => {\n        const durationMs = Date.now() - startTime;\n        endSpanError(span, error);\n        recordPublishMetric(this.telemetry, exchange.name, routingKey, false, durationMs);\n      });\n  }\n\n  /**\n   * Invoke an RPC defined via `defineRpc` and await the typed response.\n   *\n   * The request payload is validated against the RPC's request schema, then\n   * published to the AMQP default exchange with the server's queue name as\n   * routing key, `replyTo` set to `amq.rabbitmq.reply-to`, and a fresh UUID\n   * `correlationId`. The returned AsyncResult resolves once a matching reply\n   * arrives and validates against the response schema, or once `timeoutMs`\n   * elapses (whichever comes first).\n   *\n   * @example\n   * ```typescript\n   * const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 });\n   * result.match({\n   *   ok: (value) => console.log(value.sum), // 3\n   *   err: (error) => console.error(error),\n   *   defect: (cause) => console.error(cause),\n   * });\n   * ```\n   */\n  call<TName extends InferRpcNames<TContract>>(\n    rpcName: TName,\n    request: ClientInferRpcRequestInput<TContract, TName>,\n    options: CallOptions,\n  ): AsyncResult<\n    ClientInferRpcResponseOutput<TContract, TName>,\n    | TechnicalError\n    | MessageValidationError\n    | RpcTimeoutError\n    | RpcCancelledError\n    | ClientInferRpcErrors<TContract, TName>\n  > {\n    type ResponseType = ClientInferRpcResponseOutput<TContract, TName>;\n    type CallError =\n      | TechnicalError\n      | MessageValidationError\n      | RpcTimeoutError\n      | RpcCancelledError\n      | ClientInferRpcErrors<TContract, TName>;\n\n    const startTime = Date.now();\n    // Non-null assertion safe: TName is constrained to RPC names in the contract.\n    const rpc = this.contract.rpcs![rpcName as string]!;\n    const queueName = extractQueue(rpc.queue).name;\n\n    // RPC publishes to the default exchange with the queue name as routing key.\n    const span = startPublishSpan(this.telemetry, \"\", queueName, {\n      [MessagingSemanticConventions.AMQP_PUBLISHER_NAME]: String(rpcName),\n    });\n\n    // Interceptors wrap the full round trip (request validation, publish,\n    // reply await) so they can adjust timeouts, stamp headers, or retry by\n    // calling `next` again; telemetry stays outermost. Error/value types are\n    // erased through the chain and restored at this public boundary; TArgs is\n    // pinned to the wire-level interceptor shape (request: unknown).\n    const chained = chainInterceptors<\n      CallInterceptorArgs,\n      { request?: unknown; options?: CallOptions },\n      unknown,\n      InterceptorCallError\n    >(this.callInterceptors, { rpcName: String(rpcName), request, options }, (args) =>\n      this.executeCall(String(rpcName), rpc, args.request, args.options),\n    );\n\n    const instrumented = chained\n      .tap(() => {\n        const durationMs = Date.now() - startTime;\n        endSpanSuccess(span);\n        recordPublishMetric(this.telemetry, \"\", queueName, true, durationMs);\n      })\n      .tapErr((error) => {\n        const durationMs = Date.now() - startTime;\n        endSpanError(span, error);\n        recordPublishMetric(this.telemetry, \"\", queueName, false, durationMs);\n      });\n\n    // Safe: executeCall resolves with the schema-validated response, and its\n    // wire-level error union is the widened form of CallError.\n    return instrumented as AsyncResult<ResponseType, CallError>;\n  }\n\n  /**\n   * The uninstrumented RPC round trip: timeout validation, correlation\n   * bookkeeping, request validation, publish, and reply await. Runs as the\n   * terminal of the call-interceptor chain — `call()` owns telemetry and the\n   * typed public signature.\n   */\n  private executeCall(\n    rpcName: string,\n    rpc: RpcDefinition,\n    request: unknown,\n    options: CallOptions,\n  ): AsyncResult<unknown, InterceptorCallError> {\n    type CallResult = Result<unknown, InterceptorCallError>;\n\n    // setTimeout truncates fractional ms and clamps anything outside the\n    // 32-bit signed integer range (~24.8 days) to 1ms, so reject those up\n    // front as user errors rather than producing surprising behavior.\n    const TIMEOUT_MAX_MS = 2_147_483_647;\n    if (\n      typeof options.timeoutMs !== \"number\" ||\n      !Number.isFinite(options.timeoutMs) ||\n      options.timeoutMs <= 0 ||\n      options.timeoutMs > TIMEOUT_MAX_MS\n    ) {\n      return ErrAsync<InterceptorCallError>(\n        new TechnicalError(\n          `Invalid timeoutMs for RPC call to \"${rpcName}\": expected a finite positive number ≤ ${TIMEOUT_MAX_MS}, got ${String(options.timeoutMs)}`,\n        ),\n      );\n    }\n\n    const requestSchema = rpc.request.payload;\n    const responseSchema = rpc.response.payload;\n    const queueName = extractQueue(rpc.queue).name;\n\n    const correlationId = randomUUID();\n\n    // Set up the reply future + pending entry up front so a reply that arrives\n    // racing the publish round-trip can find a slot. Cleanup on preflight\n    // failure happens in the `.flatMapErr` below.\n    let resolveCall!: (result: CallResult) => void;\n    const callPromise = new Promise<CallResult>((res) => {\n      resolveCall = res;\n    });\n    // `callPromise` resolves to a `Result` (never rejects), so lift it with\n    // `fromSafePromise` and collapse the nested `Result` back into the channel.\n    const callResultAsync: AsyncResult<unknown, InterceptorCallError> = fromSafePromise(\n      callPromise,\n    ).flatMap((result) => result);\n\n    const timer = setTimeout(() => {\n      if (!this.pendingCalls.has(correlationId)) return;\n      this.pendingCalls.delete(correlationId);\n      resolveCall(Err(new RpcTimeoutError(rpcName, options.timeoutMs)));\n    }, options.timeoutMs);\n\n    this.pendingCalls.set(correlationId, {\n      rpcName,\n      responseSchema,\n      rpcErrorSchemas: rpc.errors,\n      resolve: resolveCall as PendingCall[\"resolve\"],\n      timer,\n    });\n\n    const validateRequest = (): AsyncResult<unknown, TechnicalError | MessageValidationError> => {\n      // Wrap the validate call — a Standard Schema implementation may throw\n      // synchronously, and that throw would otherwise escape the chain and\n      // leave the pending-call entry/timer dangling until timeout.\n      let rawValidation: ReturnType<StandardSchemaV1[\"~standard\"][\"validate\"]>;\n      try {\n        rawValidation = requestSchema[\"~standard\"].validate(request);\n      } catch (error: unknown) {\n        return ErrAsync<TechnicalError | MessageValidationError>(\n          new TechnicalError(\"RPC request validation threw\", error),\n        );\n      }\n      const validationPromise =\n        rawValidation instanceof Promise ? rawValidation : Promise.resolve(rawValidation);\n      return fromPromise(\n        validationPromise,\n        (error): TechnicalError | MessageValidationError =>\n          new TechnicalError(\"RPC request validation threw\", error),\n      ).flatMap((validation) =>\n        validation.issues\n          ? Err<TechnicalError | MessageValidationError>(\n              new MessageValidationError(rpcName, validation.issues),\n            )\n          : Ok(validation.value),\n      );\n    };\n\n    const publishRequest = (validatedRequest: unknown): AsyncResult<void, TechnicalError> => {\n      // Merge `defaultPublishOptions` (persistent, priority, headers, …) with\n      // the per-call options, then layer the RPC-managed fields on top so they\n      // cannot be overridden. `compression` is intentionally dropped: RPC v1\n      // does not implement reply-side decompression, so request-side\n      // compression would break the round-trip.\n      const { compression: _ignoredCompression, ...defaultsWithoutCompression } =\n        this.defaultPublishOptions;\n      const publishOptions: AmqpClientPublishOptions = {\n        ...defaultsWithoutCompression,\n        ...options.publishOptions,\n        replyTo: DIRECT_REPLY_TO,\n        correlationId,\n        contentType: \"application/json\",\n      };\n      return this.amqpClient\n        .publish(\"\", queueName, validatedRequest, publishOptions)\n        .flatMap((published) =>\n          published\n            ? Ok(undefined)\n            : Err<TechnicalError>(\n                new TechnicalError(\n                  `Failed to publish RPC request for \"${rpcName}\": channel buffer full`,\n                ),\n              ),\n        );\n    };\n\n    return validateRequest()\n      .flatMap((validated) => publishRequest(validated))\n      .flatMap(() => callResultAsync)\n      .flatMapErr((error: InterceptorCallError) => {\n        // If preflight failed (validate or publish), the pending entry still\n        // exists and the timer is alive. Clean both up so the call doesn't\n        // leak. Timer-fired errors and reply-resolved errors have already\n        // cleaned the entry, so the .has() check guards against double cleanup.\n        if (this.pendingCalls.has(correlationId)) {\n          clearTimeout(timer);\n          this.pendingCalls.delete(correlationId);\n        }\n        return ErrAsync(error);\n      });\n  }\n\n  /**\n   * Close the channel and connection. Cancels the reply consumer (if any) and\n   * rejects every in-flight RPC call with `RpcCancelledError`.\n   */\n  close(): AsyncResult<void, TechnicalError> {\n    // Reject pending calls first — once close() runs, no reply will arrive.\n    for (const [, pending] of this.pendingCalls) {\n      clearTimeout(pending.timer);\n      pending.resolve(Err(new RpcCancelledError(pending.rpcName)));\n    }\n    this.pendingCalls.clear();\n\n    const cancelReply: AsyncResult<void, TechnicalError> = this.replyConsumerTag\n      ? this.amqpClient.cancel(this.replyConsumerTag).flatMapErr((error) => {\n          this.logger?.warn(\"Failed to cancel RPC reply consumer during close\", { error });\n          return Ok(undefined);\n        })\n      : OkAsync(undefined);\n\n    return cancelReply.flatMap(() => this.amqpClient.close());\n  }\n\n  private waitForConnectionReady(): AsyncResult<void, TechnicalError> {\n    return this.amqpClient.waitForConnect();\n  }\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,YAAY,UAAU,IAAI;AAChC,MAAM,eAAe,UAAU,OAAO;;;;;;;;;;AAWtC,SAAgB,eACd,QACA,WACqC;CACrC,OAAO,MAAM,SAAS,CAAC,CACpB,KAAK,cACJ,YACE,UAAU,MAAM,IACf,UAAU,IAAI,eAAe,gCAAgC,KAAK,CACrE,CACF,CAAC,CACA,KAAK,iBACJ,YACE,aAAa,MAAM,IAClB,UAAU,IAAI,eAAe,mCAAmC,KAAK,CACxE,CACF,CAAC,CACA,WAAW;AAChB;;;;;;;;;;;;;ACvBA,IAAa,kBAAb,cAAqC,YAAY,kCAAkC,EACjF,MAAM,kBACR,CAAC,CAAC,CAGC;CACD,YAAY,SAAiB,WAAmB;EAC9C,MAAM;GAAE;GAAS;EAAU,CAAC;EAC5B,KAAK,UAAU,gBAAgB,QAAQ,oBAAoB,UAAU;CACvE;AACF;;;;;;;;AASA,IAAa,oBAAb,cAAuC,YAAY,oCAAoC,EACrF,MAAM,oBACR,CAAC,CAAC,CAEC;CACD,YAAY,SAAiB;EAC3B,MAAM,EAAE,QAAQ,CAAC;EACjB,KAAK,UAAU,gBAAgB,QAAQ;CACzC;AACF;;;;;;;;;;AC2EA,SAAgB,kBAMd,cAIA,MACA,UAC6B;CAC7B,MAAM,OAAO,OAAe,YAC1B,SAAS,aAAa,SAClB,SAAS,OAAO,IAChB,aAAa,MAAM,CAAE,UAAU,UAAU,IAAI,QAAQ,GAAG;EAAE,GAAG;EAAS,GAAG;CAAM,CAAC,CAAC;CACvF,OAAO,IAAI,GAAG,IAAI;AACpB;;;;;;;;;;;ACtEA,MAAM,kBAAkB;;;;AAoGxB,IAAa,kBAAb,MAAa,gBAAsD;CAc9C;CACA;CACA;CACA;CACA;CACA;CACA;;;;;CAfnB,+BAAgC,IAAI,IAAyB;;;;;CAM7D;CAEA,YACE,UACA,YACA,uBACA,QACA,YAAgD,0BAChD,sBAAsE,CAAC,GACvE,mBAAgE,CAAC,GACjE;EAPiB,KAAA,WAAA;EACA,KAAA,aAAA;EACA,KAAA,wBAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,sBAAA;EACA,KAAA,mBAAA;CAChB;;;;;;;;;;;CAYH,OAAO,OAA6C,EAClD,UACA,MACA,mBACA,uBACA,QACA,WACA,kBACA,qBACA,oBAC0F;EAC1F,MAAM,SAAS,IAAI,gBACjB,UACA,IAAI,WAAW,UAAU;GAAE;GAAM;GAAmB;EAAiB,CAAC,GACtE;GAAE,YAAY;GAAM,GAAG;EAAsB,GAC7C,QACA,aAAa,0BACb,uBAAuB,CAAC,GACxB,oBAAoB,CAAC,CACvB;EAEA,MAAM,QAAQ,OACX,uBAAuB,CAAC,CACxB,cAAc,OAAO,2BAA2B,CAAC;EAiBpD,OAAO,iBAfQ,YAAyE;GACtF,MAAM,cAAc,MAAM;GAC1B,IAAI,CAAC,YAAY,KAAK,GAAG;IACvB,MAAM,cAAc,MAAM,OAAO,MAAM;IACvC,IAAI,YAAY,MAAM,GACpB,QAAQ,KAAK,mDAAmD,EAC9D,OAAO,YAAY,MACrB,CAAC;GAEL;GAGA,OAAO,YAAY,UAAU,MAAM;EACrC,EAAA,CAE2B,CAAC,CAAC,CAAC,SAAS,WAAW,MAAM;CAC1D;;;;;;CAOA,6BAAwE;EACtE,MAAM,OAAO,KAAK,SAAS,QAAQ,CAAC;EACpC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,GAC/B,OAAO,QAAQ,KAAA,CAAS;EAG1B,OAAO,KAAK,WACT,QAAQ,kBAAkB,QAAQ,KAAK,eAAe,GAAG,GAAG,EAAE,OAAO,KAAK,CAAC,CAAC,CAC5E,KAAK,QAAQ;GACZ,KAAK,mBAAmB;EAC1B,CAAC,CAAC,CACD,UAAU,KAAA,CAAS;CACxB;;;;;;;;;;CAWA,eAAuB,KAAgE;EACrF,IAAI,CAAC,KAAK;EACV,MAAM,gBAAgB,IAAI,WAAW;EACrC,IAAI,OAAO,kBAAkB,UAAU;GACrC,KAAK,QAAQ,KAAK,sDAAsD,EACtE,aAAa,IAAI,OAAO,YAC1B,CAAC;GACD,mBAAmB,KAAK,WAAW,wBAAwB;GAC3D;EACF;EACA,MAAM,UAAU,KAAK,aAAa,IAAI,aAAa;EACnD,IAAI,CAAC,SAAS;GACZ,KAAK,QAAQ,KACX,wFACA,EAAE,cAAc,CAClB;GACA,mBAAmB,KAAK,WAAW,wBAAwB;GAC3D;EACF;EACA,KAAK,aAAa,OAAO,aAAa;EACtC,aAAa,QAAQ,KAAK;EAE1B,MAAM,cAAc,cAClB,IAAI,UACH,UACC,IAAI,eAAe,uCAAuC,QAAQ,QAAQ,IAAI,KAAK,CACvF;EACA,IAAI,CAAC,YAAY,KAAK,GAAG;GACvB,QAAQ,QACN,IACE,YAAY,MAAM,IACd,YAAY,QACZ,IAAI,eACF,uCAAuC,QAAQ,QAAQ,IACvD,YAAY,KACd,CACN,CACF;GACA;EACF;EACA,MAAM,SAAS,YAAY;EAK3B,MAAM,YAAY,IAAI,WAAW,UAAU;EAC3C,IAAI,OAAO,cAAc,UAAU;GACjC,KAAK,qBAAqB,SAAS,WAAW,MAAM;GACpD;EACF;EAKA,IAAI;EACJ,IAAI;GACF,gBAAgB,QAAQ,eAAe,YAAY,CAAC,SAAS,MAAM;EACrE,SAAS,OAAgB;GACvB,QAAQ,QACN,IAAI,IAAI,eAAe,mCAAmC,QAAQ,QAAQ,IAAI,KAAK,CAAC,CACtF;GACA;EACF;EAIA,CAFE,yBAAyB,UAAU,gBAAgB,QAAQ,QAAQ,aAAa,EAAA,CAEhE,MACf,eAAe;GACd,IAAI,WAAW,QAAQ;IACrB,QAAQ,QAAQ,IAAI,IAAI,uBAAuB,QAAQ,SAAS,WAAW,MAAM,CAAC,CAAC;IACnF;GACF;GACA,QAAQ,QAAQ,GAAG,WAAW,KAAK,CAAC;EACtC,IACC,UAAmB;GAClB,QAAQ,QACN,IAAI,IAAI,eAAe,mCAAmC,QAAQ,QAAQ,IAAI,KAAK,CAAC,CACtF;EACF,CACF;CACF;;;;;;;;;;;CAYA,qBAA6B,SAAsB,WAAmB,QAAuB;EAG3F,MAAM,cACJ,QAAQ,mBAAmB,OAAO,OAAO,QAAQ,iBAAiB,SAAS,IACvE,QAAQ,gBAAgB,aACxB,KAAA;EACN,IAAI,CAAC,aAAa;GAChB,QAAQ,QACN,IACE,IAAI,eACF,QAAQ,QAAQ,QAAQ,wCAAwC,UAAU,EAC5E,CACF,CACF;GACA;EACF;EAEA,MAAM,OACJ,OAAO,WAAW,YAAY,WAAW,OACpC,SACD,CAAC;EACP,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,KAAA;EAKlE,IAAI;EACJ,IAAI;GACF,gBAAgB,YAAY,QAAQ,YAAY,CAAC,SAAS,KAAK,IAAI;EACrE,SAAS,OAAgB;GACvB,QAAQ,QACN,IAAI,IAAI,eAAe,wCAAwC,QAAQ,QAAQ,IAAI,KAAK,CAAC,CAC3F;GACA;EACF;EAIA,CAFE,yBAAyB,UAAU,gBAAgB,QAAQ,QAAQ,aAAa,EAAA,CAEhE,MACf,eAAe;GACd,IAAI,WAAW,QAAQ;IACrB,QAAQ,QAAQ,IAAI,IAAI,uBAAuB,QAAQ,SAAS,WAAW,MAAM,CAAC,CAAC;IACnF;GACF;GACA,QAAQ,QAAQ,IAAI,IAAIA,WAAS,WAAW,WAAW,OAAO,OAAO,CAAC,CAAC;EACzE,IACC,UAAmB;GAClB,QAAQ,QACN,IACE,IAAI,eAAe,wCAAwC,QAAQ,QAAQ,IAAI,KAAK,CACtF,CACF;EACF,CACF;CACF;;;;;;;;;;;;;CAcA,QACE,eACA,SACA,SAC4D;EAC5D,MAAM,YAAY,KAAK,IAAI;EAE3B,MAAM,YAAY,KAAK,SAAS,WAAY;EAC5C,MAAM,EAAE,UAAU,eAAe;EAGjC,MAAM,OAAO,iBAAiB,KAAK,WAAW,SAAS,MAAM,YAAY,GACtE,6BAA6B,sBAAsB,OAAO,aAAa,EAC1E,CAAC;EAED,MAAM,mBACJ,eACkE;GAClE,MAAM,mBAAmB,UAAU,QAAQ,QAAQ,YAAY,CAAC,SAAS,UAAU;GAGnF,OAAO,YADL,4BAA4B,UAAU,mBAAmB,QAAQ,QAAQ,gBAAgB,IAGxF,UACC,IAAI,eAAe,qBAAqB,KAAK,CACjD,CAAC,CAAC,SAAS,eAAe;IACxB,IAAI,WAAW,QACb,OAAO,IACL,IAAI,uBAAuB,OAAO,aAAa,GAAG,WAAW,MAAM,CACrE;IAEF,OAAO,GAAG,WAAW,KAAK;GAC5B,CAAC;EACH;EAEA,MAAM,kBACJ,kBACA,gBACsC;GAKtC,MAAM,EAAE,aAAa,GAAG,gBAAgB;IAHhB,GAAG,KAAK;IAAuB,GAAG;GAGN;GACpD,MAAM,iBAA2C,EAAE,GAAG,YAAY;GAGlE,MAAM,uBAAsE;IAC1E,IAAI,aAAa;KAEf,MAAM,gBAAgB,OAAO,KAAK,KAAK,UAAU,gBAAgB,CAAC;KAClE,eAAe,kBAAkB;KACjC,OAAO,eAAe,eAAe,WAAW;IAClD;IAGA,OAAO,QAAQ,gBAAgB;GACjC;GAEA,OAAO,eAAe,CAAC,CAAC,SAAS,YAC/B,KAAK,WACF,QAAQ,UAAU,SAAS,MAAM,UAAU,cAAc,IAAI,SAAS,cAAc,CAAC,CACrF,SAAS,cAAc;IACtB,IAAI,CAAC,WACH,OAAO,IACL,IAAI,eACF,4CAA4C,OAAO,aAAa,EAAE,qEACpE,CACF;IAGF,KAAK,QAAQ,KAAK,kCAAkC;KAClD,eAAe,OAAO,aAAa;KACnC,UAAU,UAAU,SAAS;KAC7B,YAAY,UAAU;KACtB,YAAY,CAAC,CAAC;IAChB,CAAC;IAED,OAAO,GAAG,KAAA,CAAS;GACrB,CAAC,CACL;EACF;EAIA,MAAM,YAAY,SAChB,gBAAgB,KAAK,OAAO,CAAC,CAAC,SAAS,qBACrC,eAAe,kBAAkB,KAAK,OAAO,CAC/C;EAIF,OAAO,kBAML,KAAK,qBACL;GAAE,eAAe,OAAO,aAAa;GAAG;GAAS,SAAS,WAAW,CAAC;EAAE,GACxE,QACF,CAAC,CACE,UAAU;GACT,MAAM,aAAa,KAAK,IAAI,IAAI;GAChC,eAAe,IAAI;GACnB,oBAAoB,KAAK,WAAW,SAAS,MAAM,YAAY,MAAM,UAAU;EACjF,CAAC,CAAC,CACD,QAAQ,UAAU;GACjB,MAAM,aAAa,KAAK,IAAI,IAAI;GAChC,aAAa,MAAM,KAAK;GACxB,oBAAoB,KAAK,WAAW,SAAS,MAAM,YAAY,OAAO,UAAU;EAClF,CAAC;CACL;;;;;;;;;;;;;;;;;;;;;CAsBA,KACE,SACA,SACA,SAQA;EASA,MAAM,YAAY,KAAK,IAAI;EAE3B,MAAM,MAAM,KAAK,SAAS,KAAM;EAChC,MAAM,YAAY,aAAa,IAAI,KAAK,CAAC,CAAC;EAG1C,MAAM,OAAO,iBAAiB,KAAK,WAAW,IAAI,WAAW,GAC1D,6BAA6B,sBAAsB,OAAO,OAAO,EACpE,CAAC;EA8BD,OAvBgB,kBAKd,KAAK,kBAAkB;GAAE,SAAS,OAAO,OAAO;GAAG;GAAS;EAAQ,IAAI,SACxE,KAAK,YAAY,OAAO,OAAO,GAAG,KAAK,KAAK,SAAS,KAAK,OAAO,CAGxC,CAAC,CACzB,UAAU;GACT,MAAM,aAAa,KAAK,IAAI,IAAI;GAChC,eAAe,IAAI;GACnB,oBAAoB,KAAK,WAAW,IAAI,WAAW,MAAM,UAAU;EACrE,CAAC,CAAC,CACD,QAAQ,UAAU;GACjB,MAAM,aAAa,KAAK,IAAI,IAAI;GAChC,aAAa,MAAM,KAAK;GACxB,oBAAoB,KAAK,WAAW,IAAI,WAAW,OAAO,UAAU;EACtE,CAIgB;CACpB;;;;;;;CAQA,YACE,SACA,KACA,SACA,SAC4C;EAM5C,MAAM,iBAAiB;EACvB,IACE,OAAO,QAAQ,cAAc,YAC7B,CAAC,OAAO,SAAS,QAAQ,SAAS,KAClC,QAAQ,aAAa,KACrB,QAAQ,YAAY,gBAEpB,OAAO,SACL,IAAI,eACF,sCAAsC,QAAQ,yCAAyC,eAAe,QAAQ,OAAO,QAAQ,SAAS,GACxI,CACF;EAGF,MAAM,gBAAgB,IAAI,QAAQ;EAClC,MAAM,iBAAiB,IAAI,SAAS;EACpC,MAAM,YAAY,aAAa,IAAI,KAAK,CAAC,CAAC;EAE1C,MAAM,gBAAgB,WAAW;EAKjC,IAAI;EAMJ,MAAM,kBAA8D,gBAClE,IANsB,SAAqB,QAAQ;GACnD,cAAc;EAChB,CAIY,CACZ,CAAC,CAAC,SAAS,WAAW,MAAM;EAE5B,MAAM,QAAQ,iBAAiB;GAC7B,IAAI,CAAC,KAAK,aAAa,IAAI,aAAa,GAAG;GAC3C,KAAK,aAAa,OAAO,aAAa;GACtC,YAAY,IAAI,IAAI,gBAAgB,SAAS,QAAQ,SAAS,CAAC,CAAC;EAClE,GAAG,QAAQ,SAAS;EAEpB,KAAK,aAAa,IAAI,eAAe;GACnC;GACA;GACA,iBAAiB,IAAI;GACrB,SAAS;GACT;EACF,CAAC;EAED,MAAM,wBAAuF;GAI3F,IAAI;GACJ,IAAI;IACF,gBAAgB,cAAc,YAAY,CAAC,SAAS,OAAO;GAC7D,SAAS,OAAgB;IACvB,OAAO,SACL,IAAI,eAAe,gCAAgC,KAAK,CAC1D;GACF;GAGA,OAAO,YADL,yBAAyB,UAAU,gBAAgB,QAAQ,QAAQ,aAAa,IAG/E,UACC,IAAI,eAAe,gCAAgC,KAAK,CAC5D,CAAC,CAAC,SAAS,eACT,WAAW,SACP,IACE,IAAI,uBAAuB,SAAS,WAAW,MAAM,CACvD,IACA,GAAG,WAAW,KAAK,CACzB;EACF;EAEA,MAAM,kBAAkB,qBAAiE;GAMvF,MAAM,EAAE,aAAa,qBAAqB,GAAG,+BAC3C,KAAK;GACP,MAAM,iBAA2C;IAC/C,GAAG;IACH,GAAG,QAAQ;IACX,SAAS;IACT;IACA,aAAa;GACf;GACA,OAAO,KAAK,WACT,QAAQ,IAAI,WAAW,kBAAkB,cAAc,CAAC,CACxD,SAAS,cACR,YACI,GAAG,KAAA,CAAS,IACZ,IACE,IAAI,eACF,sCAAsC,QAAQ,uBAChD,CACF,CACN;EACJ;EAEA,OAAO,gBAAgB,CAAC,CACrB,SAAS,cAAc,eAAe,SAAS,CAAC,CAAC,CACjD,cAAc,eAAe,CAAC,CAC9B,YAAY,UAAgC;GAK3C,IAAI,KAAK,aAAa,IAAI,aAAa,GAAG;IACxC,aAAa,KAAK;IAClB,KAAK,aAAa,OAAO,aAAa;GACxC;GACA,OAAO,SAAS,KAAK;EACvB,CAAC;CACL;;;;;CAMA,QAA2C;EAEzC,KAAK,MAAM,GAAG,YAAY,KAAK,cAAc;GAC3C,aAAa,QAAQ,KAAK;GAC1B,QAAQ,QAAQ,IAAI,IAAI,kBAAkB,QAAQ,OAAO,CAAC,CAAC;EAC7D;EACA,KAAK,aAAa,MAAM;EASxB,QAPuD,KAAK,mBACxD,KAAK,WAAW,OAAO,KAAK,gBAAgB,CAAC,CAAC,YAAY,UAAU;GAClE,KAAK,QAAQ,KAAK,oDAAoD,EAAE,MAAM,CAAC;GAC/E,OAAO,GAAG,KAAA,CAAS;EACrB,CAAC,IACD,QAAQ,KAAA,CAAS,EAAA,CAEF,cAAc,KAAK,WAAW,MAAM,CAAC;CAC1D;CAEA,yBAAoE;EAClE,OAAO,KAAK,WAAW,eAAe;CACxC;AACF"}