UNPKG

@cloudamqp/amqp-client

Version:

AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)

259 lines 12.2 kB
import type { ExchangeParams, ExchangeType, QueueParams } from "./amqp-channel.js"; /** * Options for {@link AMQPSession#queue}. Combines queue declaration * parameters (`passive`, `durable`, `autoDelete`, `exclusive`) with the * queue arguments table (`x-message-ttl`, `x-delivery-limit`, ...) so * callers don't have to pass `undefined` placeholders to reach the * arguments table. */ export type QueueOptions = QueueParams & { /** Queue arguments table (e.g. `{ "x-delivery-limit": 3 }`). */ arguments?: Record<string, unknown>; }; /** * Options for {@link AMQPSession#exchange} and the typed-exchange * shortcuts. Combines exchange declaration parameters (`passive`, * `durable`, `autoDelete`, `internal`) with the exchange arguments table * (`x-delayed-type`, `alternate-exchange`, ...). */ export type ExchangeOptions = ExchangeParams & { /** Exchange arguments table (e.g. `{ "x-delayed-type": "direct" }`). */ arguments?: Record<string, unknown>; }; import type { ParserMap, CoderMap, ParserRegistry, CoderRegistry } from "./amqp-codec-registry.js"; import type { AMQPProperties } from "./amqp-properties.js"; import type { ResolveBody } from "./amqp-publisher.js"; import { AMQPQueue } from "./amqp-queue.js"; import type { AMQPTlsOptions } from "./amqp-tls-options.js"; import type { Logger } from "./types.js"; import { AMQPExchange } from "./amqp-exchange.js"; import { AMQPRPCClient } from "./amqp-rpc-client.js"; import { AMQPRPCServer } from "./amqp-rpc-server.js"; import type { RPCHandler } from "./amqp-rpc-server.js"; import type { AMQPMessage } from "./amqp-message.js"; /** * Options for {@link AMQPSession.connect}. */ export interface AMQPSessionOptions<P extends ParserMap = {}, C extends CoderMap = {}, KP extends keyof P & string = never, KC extends keyof C & string = never> { /** Initial delay in milliseconds before reconnecting (default: 1000) */ reconnectInterval?: number; /** Maximum delay in milliseconds between reconnection attempts (default: 30000) */ maxReconnectInterval?: number; /** Multiplier for exponential backoff (default: 2) */ backoffMultiplier?: number; /** Maximum number of reconnection attempts — 0 means infinite (default: 0) */ maxRetries?: number; /** TLS options — only used when connecting via amqp/amqps */ tlsOptions?: AMQPTlsOptions; /** Logger instance. Pass `null` to disable logging explicitly. */ logger?: Logger | null; /** Parser registry for automatic message serialization/deserialization. */ parsers?: ParserRegistry<P>; /** Coder registry for automatic message encoding/decoding. */ coders?: CoderRegistry<C>; /** Default content-type applied to published messages when not set explicitly. */ defaultContentType?: KP; /** Default content-encoding applied to published messages when not set explicitly. */ defaultContentEncoding?: KC; /** * AMQP virtual host. For WebSocket URLs the URL path is the relay endpoint, * not the vhost — use this option to specify the vhost explicitly. * Defaults to `"/"` for WebSocket connections and to the URL path for TCP connections. */ vhost?: string; /** * Connection name, shown in the RabbitMQ management UI. Overrides any * `?name=` in the URL. */ name?: string; /** * Heartbeat interval in seconds (0 disables). Overrides any `?heartbeat=` in * the URL. */ heartbeat?: number; /** * Max AMQP frame size in bytes (minimum 8192). Overrides any `?frameMax=` in * the URL. */ frameMax?: number; /** * Max channels the session may open on this connection (0 = unlimited). * Overrides any `?channelMax=` in the URL. */ channelMax?: number; /** * Fires after a successful (re)connection — both the initial connect and * every reconnect after consumer recovery completes. Registering here * rather than after `connect()` resolves means a single handler covers * both code paths. * * The session is passed in because on the initial connect this fires * before the `connect()` call returns, so closures over the outer * `session` variable would still see `undefined`. Use the argument — * it's the same instance either way. * * Fire-and-forget. If your handler does async setup that the rest of * your code depends on, drive it yourself (e.g. `await setup(session)` * after `connect()` resolves) and use `onconnect` to re-run it on * reconnects. */ onconnect?(session: AMQPSession<P, C, KP, KC>): void; /** * Fires when the underlying connection drops, before the reconnect loop * starts. Useful for visibility into the gap between disconnect and * reconnect. */ ondisconnect?: (error?: Error) => void; /** Fires when max reconnect retries are exhausted. */ onfailed?: (error?: Error) => void; /** * Fires when the broker blocks the connection from publishing — usually * triggered by a resource alarm (memory or disk) on the server. Subsequent * publishes reject with `Connection blocked by server` until the broker * unblocks. Use this to apply backpressure upstream. */ onblocked?: (reason: string) => void; /** Fires when the broker lifts a previous block on the connection. */ onunblocked?: () => void; /** * Fires when a `mandatory: true` publish is returned by the broker because * it had no route to a queue. The session wires this onto every channel it * opens for publishing, so a single handler covers all session publishes. */ onreturn?: (msg: AMQPMessage<P>) => void; } /** * High-level session with automatic reconnection and consumer recovery. * * The generic parameters thread parser/coder type information through all * session-owned handles (queues, exchanges, RPC clients/servers). * * Users never write the generics explicitly — they're inferred from the `connect()` call. * * Create via `AMQPSession.connect(url, options)`. */ export declare class AMQPSession<P extends ParserMap = {}, C extends CoderMap = {}, KP extends keyof P & string = never, KC extends keyof C & string = never> { private readonly onconnect?; private readonly ondisconnect?; private readonly onfailed?; private readonly onreturn?; private readonly client; /** `true` when the underlying connection is closed. */ get closed(): boolean; private readonly options; private readonly queues; private readonly rpcClients; private reconnectAttempts; private reconnectTimer; private reconnectResolve; private reconnecting; private stopped; private opsChannel; private confirmChannel; private opsChannelPromise; private confirmChannelPromise; private constructor(); private logTag; /** * Connect to an AMQP broker and return a session with automatic reconnection. * * The transport is chosen from the URL scheme: * - `amqp://` / `amqps://` → TCP socket (`AMQPClient`) * - `ws://` / `wss://` → WebSocket (`AMQPWebSocketClient`) */ static connect<P extends ParserMap = {}, C extends CoderMap = {}, KP extends keyof P & string = never, KC extends keyof C & string = never>(url: string, options?: AMQPSessionOptions<P, C, KP, KC>): Promise<AMQPSession<P, C, KP, KC>>; private wireReturnHandler; private wireManagedChannelErrorHandler; private opsLock; /** * Declare a queue and return a session-bound {@link AMQPQueue} handle. * The returned queue's `subscribe` uses auto-recovery and `publish` waits for * a broker confirm. * * Subsequent calls with the same (non-empty) name return the cached handle * without redeclaring, and `options` on those calls are ignored. * * Server-named queues (declared with `""`) are not cached or tracked for * auto-recovery: every call declares a fresh queue, and the broker assigns a * new name on every connection, so the old name is dead after a reconnect and * can't be recovered. Neither the queue nor its consumers are auto-recovered — * `AMQPQueue.subscribe()` recovery does not apply here. Re-declare such a queue * in an {@link AMQPSessionOptions.onconnect} handler — it runs again after every * reconnect — and bind/subscribe there. * @param name - queue name (use "" to let the broker generate a name) * @param [options] - queue declaration parameters and queue arguments */ queue(name: string, options?: QueueOptions): Promise<AMQPQueue<P, C, KP, KC>>; /** * Declare an exchange and return a session-bound {@link AMQPExchange} handle. * @param name - exchange name * @param type - exchange type: `"direct"`, `"fanout"`, `"topic"`, `"headers"`, or a custom type * @param [options] - exchange declaration parameters and exchange arguments */ exchange(name: string, type: ExchangeType, options?: ExchangeOptions): Promise<AMQPExchange<P, C, KP, KC>>; /** * Declare a direct exchange and return a session-bound {@link AMQPExchange} handle. * @param [name="amq.direct"] - exchange name */ directExchange(name?: string, options?: ExchangeOptions): Promise<AMQPExchange<P, C, KP, KC>>; /** * Declare a fanout exchange and return a session-bound {@link AMQPExchange} handle. * @param [name="amq.fanout"] - exchange name */ fanoutExchange(name?: string, options?: ExchangeOptions): Promise<AMQPExchange<P, C, KP, KC>>; /** * Declare a topic exchange and return a session-bound {@link AMQPExchange} handle. * @param [name="amq.topic"] - exchange name */ topicExchange(name?: string, options?: ExchangeOptions): Promise<AMQPExchange<P, C, KP, KC>>; /** * Declare a headers exchange and return a session-bound {@link AMQPExchange} handle. * @param [name="amq.headers"] - exchange name */ headersExchange(name?: string, options?: ExchangeOptions): Promise<AMQPExchange<P, C, KP, KC>>; /** * Perform an RPC call: publish a message and wait for the response. * Creates a temporary client per call — simple and sufficient for most use cases. * * For high-throughput scenarios where the per-call channel overhead matters, * use {@link rpcClient} to create a reusable client instead. * * @param queue - The routing key / queue name of the RPC server * @param body - The request body * @param options - Optional AMQP properties and timeout * @param options.timeout - Timeout in milliseconds * @returns The reply {@link AMQPMessage} */ rpcCall(queue: string, body: ResolveBody<P, KP>, options?: AMQPProperties & { timeout?: number; }): Promise<AMQPMessage<P>>; /** * Create and start a reusable RPC client that keeps its channel open * across multiple calls. Prefer {@link rpcCall} for simplicity; use this * when you need to avoid the per-call channel overhead. * * @returns A started {@link AMQPRPCClient} ready for {@link AMQPRPCClient.call} invocations. */ rpcClient(): Promise<AMQPRPCClient<P, C, KP, KC>>; /** * Create and start an RPC server that consumes from the given queue. * Each incoming message is passed to `handler`; the returned value is * published back to the caller's `replyTo` address. * * @param queue - Queue name to consume from * @param handler - Callback that receives the decoded message, returns the response body * @param prefetch - Channel prefetch count (default: 1) * @returns A started {@link AMQPRPCServer} */ rpcServer(queue: string, handler: RPCHandler<P, KP>, prefetch?: number): Promise<AMQPRPCServer<P, C, KP, KC>>; /** * Stop the session: cancel reconnection, clear consumer tracking, * and close the underlying connection. */ stop(reason?: string): Promise<void>; private reconnectLoop; private waitBeforeRetry; private cancelWait; private recoverQueues; } //# sourceMappingURL=amqp-session.d.ts.map