import { CompressionAlgorithm, ContractDefinition, InferPublisherNames, InferRpcNames, MessageDefinition, PublisherEntry, QueueEntry, RpcDefinition, RpcErrorMap } from "@amqp-contract/contract"; import { Logger, MessageValidationError, MessageValidationError as MessageValidationError$1, PublishOptions as PublishOptions$1, RpcError, RpcError as RpcError$1, TechnicalError, TelemetryProvider, isRpcError } from "@amqp-contract/core"; import { AsyncResult } from "unthrown"; import { ConnectionOptions } from "tls"; import { TcpSocketConnectOpts } from "net"; import { StandardSchemaV1 } from "@standard-schema/spec"; //#region ../../node_modules/.pnpm/amqplib@2.0.1/node_modules/amqplib/lib/properties.d.ts declare namespace Options { interface Connect { protocol?: string; hostname?: string; port?: number; username?: string; password?: string; locale?: string; frameMax?: number; heartbeat?: number; vhost?: string; channelMax?: number; credentials?: { mechanism: string; response(): Buffer; username?: string; password?: string; }; } interface AssertQueue { exclusive?: boolean; durable?: boolean; autoDelete?: boolean; arguments?: any; messageTtl?: number; expires?: number; deadLetterExchange?: string; deadLetterRoutingKey?: string; maxLength?: number; maxPriority?: number; overflow?: string; queueMode?: string; } interface DeleteQueue { ifUnused?: boolean; ifEmpty?: boolean; } interface AssertExchange { durable?: boolean; internal?: boolean; autoDelete?: boolean; alternateExchange?: string; arguments?: any; } interface DeleteExchange { ifUnused?: boolean; } interface Publish { expiration?: string | number; userId?: string; CC?: string | string[]; mandatory?: boolean; persistent?: boolean; deliveryMode?: boolean | number; BCC?: string | string[]; contentType?: string; contentEncoding?: string; headers?: any; priority?: number; correlationId?: string; replyTo?: string; messageId?: string; timestamp?: number; type?: string; appId?: string; } interface Consume { consumerTag?: string; noLocal?: boolean; noAck?: boolean; exclusive?: boolean; priority?: number; arguments?: any; } interface Get { noAck?: boolean; } } //#endregion //#region ../../node_modules/.pnpm/amqp-connection-manager@5.0.0_amqplib@2.0.1/node_modules/amqp-connection-manager/dist/types/AmqpConnectionManager.d.ts type ConnectionUrl = string | Options.Connect | { url: string; connectionOptions?: AmqpConnectionOptions; }; type AmqpConnectionOptions = (ConnectionOptions | TcpSocketConnectOpts) & { noDelay?: boolean; timeout?: number; keepAlive?: boolean; keepAliveDelay?: number; clientProperties?: any; credentials?: { mechanism: string; username: string; password: string; response: () => Buffer; } | { mechanism: string; response: () => Buffer; } | undefined; }; interface AmqpConnectionManagerOptions { /** Interval to send heartbeats to broker. Defaults to 5 seconds. */ heartbeatIntervalInSeconds?: number; /** * The time to wait before trying to reconnect. If not specified, defaults * to `heartbeatIntervalInSeconds`. */ reconnectTimeInSeconds?: number | undefined; /** * `findServers` is a function that which returns one or more servers to * connect to. This should return either a single URL or an array of URLs. * This is handy when you're using a service discovery mechanism such as * Consul or etcd. Instead of taking a callback, this can also return a * Promise. Note that if this is supplied, then `urls` is ignored. */ findServers?: ((callback: (urls: ConnectionUrl | ConnectionUrl[]) => void) => void) | (() => Promise) | undefined; /** Connection options, passed as options to the amqplib.connect() method. */ connectionOptions?: AmqpConnectionOptions; } //#endregion //#region src/errors.d.ts declare const RpcTimeoutError_base: import("unthrown").TaggedErrorConstructor<"@amqp-contract/RpcTimeoutError">; /** * Returned from `TypedAmqpClient.call()` when the configured `timeoutMs` elapses * before the RPC server publishes a reply with the matching `correlationId`. * * The pending call is removed from the in-memory correlation map; if a reply * arrives after the timeout it is dropped (and a debug log is emitted by the * client if a logger is configured). Carries a namespaced `_tag` of * `"@amqp-contract/RpcTimeoutError"`; the `Error.name` is kept bare * (`"RpcTimeoutError"`). */ declare class RpcTimeoutError extends RpcTimeoutError_base<{ rpcName: string; timeoutMs: number; }> { constructor(rpcName: string, timeoutMs: number); } declare const RpcCancelledError_base: import("unthrown").TaggedErrorConstructor<"@amqp-contract/RpcCancelledError">; /** * Returned from any in-flight RPC call when the client is closed before the * reply is received. The correlation map is cleared on close and every pending * caller's promise resolves with `Err(RpcCancelledError)`. Carries a namespaced * `_tag` of `"@amqp-contract/RpcCancelledError"`; the `Error.name` is kept bare * (`"RpcCancelledError"`). */ declare class RpcCancelledError extends RpcCancelledError_base<{ rpcName: string; }> { constructor(rpcName: string); } //#endregion //#region src/interceptors.d.ts /** * Error union a publish interceptor chain resolves with — identical to the * error channel of `client.publish(...)`. */ type PublishError = TechnicalError | MessageValidationError$1; /** * Error union a call interceptor chain resolves with. The `RpcError` member * is the widened (untyped) form; the public `client.call(...)` signature * narrows it to the RPC's declared error union. */ type CallError = TechnicalError | MessageValidationError$1 | RpcTimeoutError | RpcCancelledError | RpcError$1; /** * Arguments a publish interceptor observes. `message` is the pre-validation * payload — a patched message goes through schema validation exactly like the * caller's original. */ type PublishInterceptorArgs = { /** The contract `publishers` key being published. */publisherName: string; /** The (not yet validated) message payload. */ message: unknown; /** Per-call publish options (defaults are merged later, inside the client). */ options: PublishOptions; }; /** * Continuation a publish interceptor calls to run the rest of the chain. * The optional patch replaces `message` and/or `options` for everything * downstream (inner interceptors, validation, and the publish itself). */ type PublishInterceptorNext = (patch?: { message?: unknown; options?: PublishOptions; }) => AsyncResult; /** * Intercepts `client.publish(...)`: runs outside validation and publishing, * so it can stamp headers (e.g. trace context), transform the payload, retry * by calling `next` again, or short-circuit by returning without calling * `next`. The first interceptor in the array is the outermost. * * @example Stamp a correlation header on every outgoing message * ```typescript * const stampTenant: PublishInterceptor = (args, next) => * next({ * options: { * ...args.options, * headers: { ...args.options.headers, 'x-tenant-id': currentTenant() }, * }, * }); * ``` */ type PublishInterceptor = (args: PublishInterceptorArgs, next: PublishInterceptorNext) => AsyncResult; /** * Arguments a call interceptor observes. `request` is the pre-validation * request payload. */ type CallInterceptorArgs = { /** The contract `rpcs` key being called. */rpcName: string; /** The (not yet validated) request payload. */ request: unknown; /** Per-call options (`timeoutMs`, `publishOptions`). */ options: CallOptions; }; /** * Continuation a call interceptor calls to run the rest of the chain. The * resolved value is the RPC response (typed at the public `call()` boundary). */ type CallInterceptorNext = (patch?: { request?: unknown; options?: CallOptions; }) => AsyncResult; /** * Intercepts `client.call(...)`: wraps the full request/reply round trip, so * it can adjust timeouts, stamp request headers, observe replies and typed * errors, or retry by calling `next` again. The first interceptor in the * array is the outermost. * * @example Retry timed-out calls once * ```typescript * const retryOnce: CallInterceptor = (args, next) => * next().flatMapErr((error) => * error instanceof RpcTimeoutError ? next() : ErrAsync(error), * ); * ``` */ type CallInterceptor = (args: CallInterceptorArgs, next: CallInterceptorNext) => AsyncResult; //#endregion //#region src/types.d.ts /** * Infer the TypeScript type from a schema (input side, used for publish payloads). */ type InferSchemaInput = TSchema extends StandardSchemaV1 ? TInput : never; /** * Infer the TypeScript type from a schema (output side, used for validated responses). */ type InferSchemaOutput = TSchema extends StandardSchemaV1 ? TOutput : never; /** * Infer publisher message input type. * Works with both PublisherDefinition and EventPublisherConfig since both have * a `message` property with a `payload` schema. */ type PublisherInferInput = TPublisher extends { message: { payload: StandardSchemaV1; }; } ? InferSchemaInput : never; type InferPublishers = NonNullable; type InferPublisher> = InferPublishers[TName]; /** * Input type accepted by `client.publish(name, ...)` for a specific publisher. */ type ClientInferPublisherInput> = PublisherInferInput>; type InferRpcs = NonNullable; type InferRpc> = InferRpcs[TName]; /** * Input type accepted by `client.call(name, request, ...)`. */ type ClientInferRpcRequestInput> = InferRpc extends RpcDefinition ? TRequest extends MessageDefinition ? InferSchemaInput : never : never; /** * Output (validated) response type returned by `client.call(name, ...)`. */ type ClientInferRpcResponseOutput> = InferRpc extends RpcDefinition ? TResponse extends MessageDefinition ? InferSchemaOutput : never : never; /** * Typed error union for `client.call(name, ...)` — one `RpcError` * member per entry in the RPC's declared `errors` map, with `data` typed as * the declared schema's *output* (the client re-validates error data when the * reply arrives). Resolves to `never` when the RPC declares no errors, so the * call's error union stays purely transport-level. */ type ClientInferRpcErrors> = InferRpc extends RpcDefinition ? TErrors extends RpcErrorMap ? { [K in keyof TErrors & string]: RpcError$1> }[keyof TErrors & string] : never : never; //#endregion //#region src/client.d.ts /** * Publish options that extend amqp-client's PublishOptions with optional compression support. */ type PublishOptions = PublishOptions$1 & { /** * Optional compression algorithm to use for the message payload. * When specified, the message will be compressed using the chosen algorithm * and the contentEncoding header will be set automatically. */ compression?: CompressionAlgorithm | undefined; }; /** * Options for creating a client */ type CreateClientOptions = { contract: TContract; urls: ConnectionUrl[]; connectionOptions?: AmqpConnectionManagerOptions | undefined; logger?: Logger | undefined; /** * Optional telemetry provider for tracing and metrics. * If not provided, uses the default provider which attempts to load OpenTelemetry. * OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed. */ telemetry?: TelemetryProvider | undefined; /** * Default publish options that will be applied to all publish operations. * These can be overridden by options passed to the publish method. * By default, persistent is set to true for message durability. */ defaultPublishOptions?: PublishOptions | undefined; /** * Maximum time in ms to wait for the AMQP connection to become ready before * `create()` resolves to an `Err(TechnicalError)`. Defaults to 30s * (the {@link AmqpClient}'s `DEFAULT_CONNECT_TIMEOUT_MS`). Pass `null` to * disable the timeout and let amqp-connection-manager retry indefinitely. */ connectTimeoutMs?: number | null | undefined; /** * Interceptors wrapping every `publish(...)`: the first entry is the * outermost. Each can patch the message/options, observe the outcome, * retry by calling `next` again, or short-circuit. A patched message is * validated exactly like the caller's original. */ publishInterceptors?: readonly PublishInterceptor[] | undefined; /** * Interceptors wrapping every `call(...)` round trip (request validation, * publish, reply await): the first entry is the outermost. */ callInterceptors?: readonly CallInterceptor[] | undefined; }; /** * Per-call options for `client.call()`. */ type CallOptions = { /** * Maximum time in ms to wait for an RPC reply. If exceeded, the call resolves * to `Err(RpcTimeoutError)` and the in-memory correlation entry is cleared. * A late reply arriving after the timeout is silently dropped. * * Required: RPC without a timeout is a footgun. */ timeoutMs: number; /** * Optional AMQP message properties to merge into the request. `replyTo` and * `correlationId` are managed by the client and cannot be overridden. */ publishOptions?: Omit; }; /** * Type-safe AMQP client for publishing messages */ declare class TypedAmqpClient { private readonly contract; private readonly amqpClient; private readonly defaultPublishOptions; private readonly logger?; private readonly telemetry; private readonly publishInterceptors; private readonly callInterceptors; /** * In-flight RPC calls keyed by `correlationId`. Cleared when a reply is * received, when the call times out, or when the client is closed. */ private readonly pendingCalls; /** * Consumer tag of the reply consumer subscribed on `amq.rabbitmq.reply-to`. * Set when the contract has at least one entry in `rpcs`; undefined otherwise. */ private replyConsumerTag?; private constructor(); /** * Create a type-safe AMQP client from a contract. * * Connection management (including automatic reconnection) is handled internally * by amqp-connection-manager via the {@link AmqpClient}. The client establishes * infrastructure asynchronously in the background once the connection is ready. * * Connections are automatically shared across clients with the same URLs and * connection options, following RabbitMQ best practices. */ static create({ contract, urls, connectionOptions, defaultPublishOptions, logger, telemetry, connectTimeoutMs, publishInterceptors, callInterceptors }: CreateClientOptions): AsyncResult, TechnicalError>; /** * If the contract has any RPC entry, subscribe to `amq.rabbitmq.reply-to` * once. Replies for every in-flight call arrive on this single consumer and * are demultiplexed by `correlationId`. */ private setupReplyConsumerIfNeeded; /** * Demultiplex an RPC reply by `correlationId`, validate the body against the * call's response schema, and resolve the awaiting caller. Replies with no * matching pending call (the call already timed out, was cancelled, or the * correlationId is unknown) are logged at warn — a non-zero rate of these * usually indicates a tuning problem (handler latency exceeds caller * timeout). The `messaging.rpc.late_reply` counter lets dashboards alert on * sustained drift without parsing logs. */ private handleRpcReply; /** * Resolve a pending call with a typed error reply: look up the error's * schema in the RPC's declared `errors` map, validate the reply's `data` * against it, and resolve the caller with `Err(RpcError)`. * * An error code the contract does not declare resolves to a TechnicalError — * it means the two sides run different contract versions (or the worker * bypassed the type system), and the client has no schema to give the data * a type under. */ private resolveRpcErrorReply; /** * Publish a message using a defined publisher. * * @param publisherName - The name of the publisher to use * @param message - The message to publish * @param options - Optional publish options including compression, headers, priority, etc. * * @remarks * If `options.compression` is specified, the message will be compressed before publishing * and the `contentEncoding` property will be set automatically. Any `contentEncoding` * value already in options will be overwritten by the compression algorithm. */ publish>(publisherName: TName, message: ClientInferPublisherInput, options?: PublishOptions): AsyncResult; /** * Invoke an RPC defined via `defineRpc` and await the typed response. * * The request payload is validated against the RPC's request schema, then * published to the AMQP default exchange with the server's queue name as * routing key, `replyTo` set to `amq.rabbitmq.reply-to`, and a fresh UUID * `correlationId`. The returned AsyncResult resolves once a matching reply * arrives and validates against the response schema, or once `timeoutMs` * elapses (whichever comes first). * * @example * ```typescript * const result = await client.call('calculate', { a: 1, b: 2 }, { timeoutMs: 5_000 }); * result.match({ * ok: (value) => console.log(value.sum), // 3 * err: (error) => console.error(error), * defect: (cause) => console.error(cause), * }); * ``` */ call>(rpcName: TName, request: ClientInferRpcRequestInput, options: CallOptions): AsyncResult, TechnicalError | MessageValidationError | RpcTimeoutError | RpcCancelledError | ClientInferRpcErrors>; /** * The uninstrumented RPC round trip: timeout validation, correlation * bookkeeping, request validation, publish, and reply await. Runs as the * terminal of the call-interceptor chain — `call()` owns telemetry and the * typed public signature. */ private executeCall; /** * Close the channel and connection. Cancels the reply consumer (if any) and * rejects every in-flight RPC call with `RpcCancelledError`. */ close(): AsyncResult; private waitForConnectionReady; } //#endregion export { type CallInterceptor, type CallInterceptorArgs, type CallInterceptorNext, type CallOptions, type ClientInferPublisherInput, type ClientInferRpcErrors, type ClientInferRpcRequestInput, type ClientInferRpcResponseOutput, type CreateClientOptions, MessageValidationError, type PublishInterceptor, type PublishInterceptorArgs, type PublishInterceptorNext, type PublishOptions, RpcCancelledError, RpcError, RpcTimeoutError, TypedAmqpClient, isRpcError }; //# sourceMappingURL=index.d.mts.map