@cloudamqp/amqp-client
Version:
AMQP 0-9-1 client, both for browsers (WebSocket) and node (TCP Socket)
259 lines • 12.2 kB
TypeScript
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