@vercel/queue 0.0.0-alpha.39 → 0.0.0-alpha.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,158 +1,650 @@
1
- import { M as MessageHandler, C as ConsumerGroupOptions, Q as QueueClient, P as PublishOptions } from './callback-lq_sorrn.js';
2
- export { g as BadRequestError, B as BufferTransport, a as CLOUD_EVENT_TYPE_V1BETA, b as CLOUD_EVENT_TYPE_V2BETA, i as ConsumerDiscoveryError, j as ConsumerRegistryNotConfiguredError, D as DuplicateMessageError, F as ForbiddenError, H as HandleCallbackOptions, I as InternalServerError, k as InvalidLimitError, J as JsonTransport, s as Message, l as MessageAlreadyProcessedError, m as MessageCorruptedError, n as MessageLockedError, t as MessageMetadata, o as MessageNotAvailableError, q as MessageNotFoundError, d as ParsedCallbackRequest, e as ParsedCallbackV1, f as ParsedCallbackV2, u as QueueClientOptions, r as QueueEmptyError, v as SendMessageOptions, w as SendMessageResponse, S as StreamTransport, T as Transport, U as UnauthorizedError, h as handleCallback, p as parseCallback, c as parseRawCallback } from './callback-lq_sorrn.js';
3
-
4
1
  /**
5
- * Options for consuming a specific message by ID.
2
+ * Serializer/Deserializer interface for message payloads.
3
+ *
4
+ * Built-in implementations:
5
+ * - `JsonTransport` - JSON serialization (default, buffers entire payload)
6
+ * - `BufferTransport` - Binary data (buffers entire payload)
7
+ * - `StreamTransport` - Pass-through streaming (no buffering, ideal for large payloads)
6
8
  */
7
- interface ConsumeByIdOptions {
8
- /** The specific message ID to consume */
9
- messageId: string;
9
+ interface Transport<T = unknown> {
10
+ /**
11
+ * Serialize a value to a buffer or stream for transmission.
12
+ * The result is sent as the request body with the `contentType` header.
13
+ */
14
+ serialize(value: T): Buffer | ReadableStream<Uint8Array>;
15
+ /**
16
+ * Deserialize a readable stream back to the original value.
17
+ * Called when receiving messages from the queue.
18
+ */
19
+ deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;
20
+ /**
21
+ * Optional cleanup method for deserialized payloads that may contain resources.
22
+ * Called automatically by ConsumerGroup on error; manual cleanup required for direct client usage.
23
+ * @param payload The deserialized payload to clean up
24
+ */
25
+ finalize?(payload: T): Promise<void>;
26
+ /**
27
+ * MIME type for this serialization format.
28
+ * Sent as the Content-Type header when publishing messages.
29
+ */
30
+ contentType: string;
10
31
  }
11
32
  /**
12
- * Options for consuming messages from the queue.
33
+ * JSON serializer/deserializer (default transport).
34
+ *
35
+ * Ideal for structured data. Buffers the entire payload in memory for parsing.
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * // Default (JsonTransport is used automatically)
40
+ * const queue = new QueueClient({ region: process.env.QUEUE_REGION! });
41
+ * await queue.send("topic", { data: "example" });
42
+ *
43
+ * // With custom serialization
44
+ * const queue = new QueueClient({
45
+ * region: process.env.QUEUE_REGION!,
46
+ * transport: new JsonTransport({
47
+ * replacer: (key, value) => key === "password" ? undefined : value,
48
+ * reviver: (key, value) => key === "date" ? new Date(value) : value,
49
+ * }),
50
+ * });
51
+ * await queue.send("topic", { data: "example" });
52
+ * ```
13
53
  */
14
- interface ConsumeBatchOptions {
54
+ declare class JsonTransport<T = unknown> implements Transport<T> {
55
+ readonly contentType = "application/json";
56
+ readonly replacer?: Parameters<typeof JSON.stringify>[1];
57
+ readonly reviver?: Parameters<typeof JSON.parse>[1];
15
58
  /**
16
- * Maximum number of messages to retrieve in a single request.
17
- * @default 1
18
- * @minimum 1
19
- * @maximum 10
59
+ * Create a new JsonTransport.
60
+ * @param options - Optional JSON serialization options
61
+ * @param options.replacer - Custom replacer for JSON.stringify
62
+ * @param options.reviver - Custom reviver for JSON.parse
20
63
  */
21
- limit?: number;
64
+ constructor(options?: {
65
+ replacer?: Parameters<typeof JSON.stringify>[1];
66
+ reviver?: Parameters<typeof JSON.parse>[1];
67
+ });
68
+ serialize(value: T): Buffer;
69
+ deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;
22
70
  }
23
-
24
71
  /**
25
- * Options for the send function.
72
+ * Binary data serializer/deserializer.
73
+ *
74
+ * Ideal for binary data that fits in memory. Buffers the entire payload.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const queue = new QueueClient({ region: "iad1", transport: new BufferTransport() });
79
+ * await queue.send("binary-topic", myBuffer);
80
+ * ```
26
81
  */
27
- interface SendOptions extends PublishOptions {
28
- /**
29
- * QueueClient instance to use for sending the message.
30
- * Configure transport on the client if you need custom serialization.
31
- * If not provided, a default client is created with OIDC authentication and JsonTransport.
32
- */
33
- client?: QueueClient;
82
+ declare class BufferTransport implements Transport<Buffer> {
83
+ readonly contentType = "application/octet-stream";
84
+ serialize(value: Buffer): Buffer;
85
+ deserialize(stream: ReadableStream<Uint8Array>): Promise<Buffer>;
34
86
  }
35
87
  /**
36
- * Send a message to a topic.
88
+ * Pass-through stream serializer/deserializer.
37
89
  *
38
- * Uses the default QueueClient with automatic OIDC token detection, or a provided client.
90
+ * Ideal for large files and real-time streams. Does not buffer data in memory.
39
91
  *
40
- * @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
41
- * @param payload - The data to send
42
- * @param options - Optional send options
43
- * @param options.idempotencyKey - Deduplication key (dedup window: min(retention, 24h))
44
- * @param options.retentionSeconds - Message TTL (default: 86400, min: 60, max: 86400)
45
- * @param options.delaySeconds - Delivery delay (default: 0, max: retentionSeconds)
46
- * @param options.client - Custom QueueClient instance (configure transport on the client)
47
- * @returns Promise with the generated messageId
48
- * @throws {DuplicateMessageError} When idempotency key was already used
49
- * @throws {BadRequestError} When parameters are invalid
50
- * @throws {UnauthorizedError} When authentication fails
51
- * @throws {ForbiddenError} When access is denied
52
- * @throws {InternalServerError} When server encounters an error
92
+ * **Important:** When using StreamTransport, you must call `finalize(payload)` when done
93
+ * processing to prevent resource leaks. ConsumerGroup handles this automatically;
94
+ * direct client usage requires manual cleanup.
53
95
  *
54
96
  * @example
55
97
  * ```typescript
56
- * // Basic usage (OIDC auth, JSON serialization)
57
- * await send("my-topic", { hello: "world" });
58
- *
59
- * // With options
60
- * await send("my-topic", payload, {
61
- * idempotencyKey: "unique-key",
62
- * retentionSeconds: 3600, // 1 hour TTL
63
- * delaySeconds: 60, // Delay 1 minute
64
- * });
98
+ * const queue = new QueueClient({ region: "iad1", transport: new StreamTransport() });
99
+ *
100
+ * // Sending a stream
101
+ * await queue.send("large-file", myReadableStream);
65
102
  *
66
- * // Using custom client with custom transport
67
- * const client = new QueueClient({
68
- * token: "my-token",
69
- * transport: new BufferTransport(),
103
+ * // Receiving - cleanup handled automatically
104
+ * await queue.receive("large-file", "processor", async (stream, meta) => {
105
+ * const reader = stream.getReader();
106
+ * // Process chunks...
70
107
  * });
71
- * await send("my-topic", myBuffer, { client });
72
108
  * ```
73
109
  */
74
- declare function send<T = unknown>(topicName: string, payload: T, options?: SendOptions): Promise<{
75
- messageId: string;
76
- }>;
110
+ declare class StreamTransport implements Transport<ReadableStream<Uint8Array>> {
111
+ readonly contentType = "application/octet-stream";
112
+ serialize(value: ReadableStream<Uint8Array>): ReadableStream<Uint8Array>;
113
+ deserialize(stream: ReadableStream<Uint8Array>): Promise<ReadableStream<Uint8Array>>;
114
+ /**
115
+ * Consume any remaining stream data to prevent resource leaks.
116
+ * Called automatically by ConsumerGroup; manual call required for direct client usage.
117
+ */
118
+ finalize(payload: ReadableStream<Uint8Array>): Promise<void>;
119
+ }
120
+
121
+ /**
122
+ * Vercel Queue Service client types
123
+ */
124
+
125
+ /**
126
+ * Vercel region code. The 20 known codes match
127
+ * {@link https://dcs.vercel-infra.com/ | dcs.vercel-infra.com}.
128
+ * Arbitrary strings are also accepted for forward compatibility
129
+ * with regions added after this SDK version.
130
+ */
131
+ type VercelRegion = "arn1" | "bom1" | "cdg1" | "cle1" | "cpt1" | "dub1" | "dxb1" | "fra1" | "gru1" | "hkg1" | "hnd1" | "iad1" | "icn1" | "kix1" | "lhr1" | "pdx1" | "sfo1" | "sin1" | "syd1" | "yul1" | (string & {});
132
+ /**
133
+ * Resolves a region code to a base URL for the Vercel Queue Service API.
134
+ *
135
+ * Default: `` (region) => `https://${region}.vercel-queue.com` ``
136
+ */
137
+ type BaseUrlResolver = (region: string) => string;
138
+ interface QueueClientOptions {
139
+ /**
140
+ * Vercel region code for API routing.
141
+ *
142
+ * Requests are sent to the regional endpoint resolved by
143
+ * {@link BaseUrlResolver} (default: `https://${region}.vercel-queue.com`).
144
+ *
145
+ * Use a `QUEUE_REGION` env var set to `${VERCEL_REGION}` in production
146
+ * and a fixed region (e.g. `"iad1"`) in development.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * new QueueClient({ region: process.env.QUEUE_REGION! })
151
+ * ```
152
+ */
153
+ region: VercelRegion;
154
+ /**
155
+ * Custom resolver that maps a region code to a base URL.
156
+ * @default (region) => `https://${region}.vercel-queue.com`
157
+ */
158
+ resolveBaseUrl?: BaseUrlResolver;
159
+ /**
160
+ * Authentication token for the Vercel Queue Service API.
161
+ * If not provided, the client will attempt to get a token via OIDC
162
+ * when running in a Vercel Function environment.
163
+ */
164
+ token?: string;
165
+ /**
166
+ * Custom headers to include in all requests.
167
+ */
168
+ headers?: Record<string, string>;
169
+ /**
170
+ * Deployment ID for message routing and lease validation.
171
+ *
172
+ * - `undefined` (default): auto-detect from `VERCEL_DEPLOYMENT_ID` env var;
173
+ * sent messages are pinned to this deployment.
174
+ * - `null`: explicitly unpinned — no deployment ID is sent on any request.
175
+ * - `"dpl_xxx"`: explicit value used for both send pinning and consume identification.
176
+ *
177
+ * Ignored in development mode (deployment ID is never sent locally).
178
+ */
179
+ deploymentId?: string | null;
180
+ /**
181
+ * Serializer/deserializer for message payloads.
182
+ * Used for all send and receive operations.
183
+ * @default JsonTransport
184
+ */
185
+ transport?: Transport;
186
+ }
77
187
  /**
78
- * Base options shared by all receive variants.
188
+ * Options for sending messages.
79
189
  */
80
- interface ReceiveBaseOptions extends ConsumerGroupOptions {
190
+ interface SendOptions {
191
+ /**
192
+ * Unique key to prevent duplicate message submissions.
193
+ * Deduplication window: `min(message retention, 24 hours)`.
194
+ */
195
+ idempotencyKey?: string;
81
196
  /**
82
- * QueueClient instance to use for receiving the message.
83
- * Configure transport on the client if you need custom deserialization.
84
- * If not provided, a default client is created with OIDC authentication and JsonTransport.
197
+ * Message retention time in seconds. After this period, the message expires.
198
+ * @default 86400 (24 hours)
199
+ * @minimum 60 (1 minute)
200
+ * @maximum 86400 (24 hours)
85
201
  */
86
- client?: QueueClient;
202
+ retentionSeconds?: number;
203
+ /**
204
+ * Delay delivery of the message by this many seconds.
205
+ * The message will not be visible to consumers until the delay has passed.
206
+ * @default 0
207
+ * @minimum 0
208
+ * @maximum Value of retentionSeconds (delay cannot exceed retention)
209
+ */
210
+ delaySeconds?: number;
211
+ /**
212
+ * Custom headers to include with this message.
213
+ * These headers are passed through to the VQS server.
214
+ */
215
+ headers?: Record<string, string>;
216
+ }
217
+ /**
218
+ * Result returned by `send()`.
219
+ *
220
+ * `messageId` is `null` when the server accepted the message for deferred
221
+ * processing (e.g. during a server-side outage) and no ID is available yet.
222
+ */
223
+ interface SendResult {
224
+ messageId: string | null;
87
225
  }
226
+ interface Message<T = unknown> {
227
+ /**
228
+ * Unique message identifier. Used for receive-by-ID operations.
229
+ */
230
+ messageId: string;
231
+ /**
232
+ * The deserialized message payload.
233
+ * Note: If using StreamTransport, ensure proper cleanup by calling
234
+ * `transport.finalize(payload)` when done processing, especially in error cases.
235
+ */
236
+ payload: T;
237
+ /**
238
+ * Number of times this message has been delivered.
239
+ * Starts at 1 for the first delivery, increments on each retry.
240
+ */
241
+ deliveryCount: number;
242
+ /**
243
+ * Timestamp when the message was created/published.
244
+ */
245
+ createdAt: Date;
246
+ /**
247
+ * Timestamp when the message expires.
248
+ * Only present for messages delivered via the v2beta binary callback path.
249
+ */
250
+ expiresAt?: Date;
251
+ /**
252
+ * MIME type of the message content.
253
+ * Set by the transport's `contentType` property during publish.
254
+ */
255
+ contentType: string;
256
+ /**
257
+ * Receipt handle (lease token) for this message delivery.
258
+ * Required for acknowledge and visibility extension operations.
259
+ * Valid only until the visibility timeout expires.
260
+ */
261
+ receiptHandle: string;
262
+ }
263
+ /**
264
+ * Message metadata provided to handlers
265
+ */
266
+ interface MessageMetadata {
267
+ messageId: string;
268
+ deliveryCount: number;
269
+ createdAt: Date;
270
+ expiresAt?: Date;
271
+ topicName: string;
272
+ consumerGroup: string;
273
+ /** Vercel region the client is targeting. */
274
+ region: string;
275
+ }
276
+ /**
277
+ * Instruction returned by a {@link RetryHandler} to control what happens
278
+ * to a message when the handler throws.
279
+ *
280
+ * - `{ afterSeconds: N }` — reschedule the message for redelivery after N seconds
281
+ * - `{ acknowledge: true }` — acknowledge the message so it is never retried
282
+ */
283
+ type RetryDirective = {
284
+ afterSeconds: number;
285
+ } | {
286
+ acknowledge: true;
287
+ };
288
+ /**
289
+ * Called when the message handler throws an error.
290
+ * Return a {@link RetryDirective} to reschedule or acknowledge the message,
291
+ * or return `undefined` to let the error propagate normally.
292
+ */
293
+ type RetryHandler = (error: unknown, metadata: MessageMetadata) => RetryDirective | void | undefined;
294
+ /**
295
+ * Message handler function type.
296
+ *
297
+ * Called once per message with the deserialized payload and metadata.
298
+ * Not called when the queue is empty — check the return value of `receive()` instead.
299
+ */
300
+ type MessageHandler<T = unknown> = (message: T, metadata: MessageMetadata) => Promise<void> | void;
301
+ /**
302
+ * Result returned by `receive()`. Use `ok` to check if messages were processed.
303
+ *
304
+ * @example
305
+ * ```typescript
306
+ * const result = await receive("topic", "group", handler);
307
+ * if (result.ok) {
308
+ * // Messages were processed successfully
309
+ * } else if (result.reason === "empty") {
310
+ * // Queue had no messages available
311
+ * }
312
+ * ```
313
+ */
314
+ type ReceiveResult = {
315
+ ok: true;
316
+ } | {
317
+ ok: false;
318
+ reason: "empty";
319
+ } | {
320
+ ok: false;
321
+ reason: "not_found";
322
+ messageId: string;
323
+ } | {
324
+ ok: false;
325
+ reason: "not_available";
326
+ messageId: string;
327
+ } | {
328
+ ok: false;
329
+ reason: "already_processed";
330
+ messageId: string;
331
+ };
88
332
  /**
89
333
  * Options for receiving a specific message by ID.
90
334
  */
91
- type ReceiveByIdOptions = ReceiveBaseOptions & ConsumeByIdOptions;
335
+ interface ReceiveByIdOptions {
336
+ /** The specific message ID to consume */
337
+ messageId: string;
338
+ /**
339
+ * Message lock duration in seconds.
340
+ * @default 300 (5 minutes)
341
+ * @minimum 30
342
+ * @maximum 3600 (1 hour)
343
+ */
344
+ visibilityTimeoutSeconds?: number;
345
+ /**
346
+ * Called when the handler throws. Return `{ afterSeconds: N }` to reschedule
347
+ * the message for redelivery after N seconds, or return `undefined`
348
+ * to let the error propagate normally.
349
+ */
350
+ retry?: RetryHandler;
351
+ }
92
352
  /**
93
353
  * Options for receiving messages from the queue with an optional batch limit.
94
354
  */
95
- type ReceiveBatchOptions = ReceiveBaseOptions & ConsumeBatchOptions;
355
+ interface ReceiveBatchOptions {
356
+ /**
357
+ * Maximum number of messages to retrieve in a single request.
358
+ * @default 1
359
+ * @minimum 1
360
+ * @maximum 10
361
+ */
362
+ limit?: number;
363
+ /**
364
+ * Message lock duration in seconds.
365
+ * @default 300 (5 minutes)
366
+ * @minimum 30
367
+ * @maximum 3600 (1 hour)
368
+ */
369
+ visibilityTimeoutSeconds?: number;
370
+ /**
371
+ * Called when the handler throws. Return `{ afterSeconds: N }` to reschedule
372
+ * the message for redelivery after N seconds, or return `undefined`
373
+ * to let the error propagate normally.
374
+ */
375
+ retry?: RetryHandler;
376
+ }
96
377
  /**
97
- * Options for the receive function. Either receive by message ID or receive
378
+ * Options for the receive method. Either receive by message ID or receive
98
379
  * from the queue with an optional limit. These options are mutually exclusive.
99
380
  */
100
381
  type ReceiveOptions = ReceiveByIdOptions | ReceiveBatchOptions;
101
382
  /**
102
- * Receive messages from a topic.
103
- *
104
- * Shorthand for creating a topic and consumer group. Each message is automatically:
105
- * - Locked with the configured visibility timeout
106
- * - Kept alive via periodic visibility extensions during processing
107
- * - Deleted upon successful handler completion
108
- *
109
- * When the queue is empty, the handler is called with `null` for both
110
- * message and metadata, allowing graceful handling without exceptions.
383
+ * Error thrown when a message does not exist or has expired.
384
+ */
385
+ declare class MessageNotFoundError extends Error {
386
+ constructor(messageId: string);
387
+ }
388
+ /**
389
+ * Error thrown when a message exists but cannot be processed.
390
+ * This can happen when the message is in the wrong state or already claimed by another consumer.
391
+ */
392
+ declare class MessageNotAvailableError extends Error {
393
+ constructor(messageId: string, reason?: string);
394
+ }
395
+ /**
396
+ * Error thrown when message data is corrupted or can't be parsed
397
+ */
398
+ declare class MessageCorruptedError extends Error {
399
+ constructor(messageId: string, reason: string);
400
+ }
401
+ /**
402
+ * Error thrown when there are no messages available in the queue.
403
+ */
404
+ declare class QueueEmptyError extends Error {
405
+ constructor(queueName: string, consumerGroup: string);
406
+ }
407
+ /**
408
+ * Error thrown when a message is temporarily locked by another consumer.
409
+ * The message is currently being processed and cannot be claimed.
410
+ */
411
+ declare class MessageLockedError extends Error {
412
+ /** Suggested retry delay in seconds, if provided by the server. */
413
+ readonly retryAfter?: number;
414
+ constructor(messageId: string, retryAfter?: number);
415
+ }
416
+ /**
417
+ * Error thrown when authentication fails.
418
+ * This typically means the token is missing, invalid, or expired.
419
+ */
420
+ declare class UnauthorizedError extends Error {
421
+ constructor(message?: string);
422
+ }
423
+ /**
424
+ * Error thrown when access is forbidden.
425
+ * This typically means the queue belongs to a different environment or project.
426
+ */
427
+ declare class ForbiddenError extends Error {
428
+ constructor(message?: string);
429
+ }
430
+ /**
431
+ * Error thrown when request parameters are invalid.
432
+ */
433
+ declare class BadRequestError extends Error {
434
+ constructor(message: string);
435
+ }
436
+ /**
437
+ * Error thrown when the server encounters an unexpected error.
438
+ */
439
+ declare class InternalServerError extends Error {
440
+ constructor(message?: string);
441
+ }
442
+ /**
443
+ * Error thrown when the batch limit parameter is outside the valid range.
444
+ * The limit must be between 1 and 10 (inclusive).
445
+ */
446
+ declare class InvalidLimitError extends Error {
447
+ constructor(limit: number, min?: number, max?: number);
448
+ }
449
+ /**
450
+ * Error thrown when attempting to process a message that has already been successfully processed.
451
+ */
452
+ declare class MessageAlreadyProcessedError extends Error {
453
+ constructor(messageId: string);
454
+ }
455
+ /**
456
+ * Error thrown when a duplicate idempotency key is detected.
457
+ * The message was already sent within the deduplication window.
458
+ */
459
+ declare class DuplicateMessageError extends Error {
460
+ readonly idempotencyKey?: string;
461
+ constructor(message: string, idempotencyKey?: string);
462
+ }
463
+ /**
464
+ * Error thrown when consumer discovery fails.
465
+ * This typically means the deployment could not be reached or is not configured correctly.
466
+ */
467
+ declare class ConsumerDiscoveryError extends Error {
468
+ readonly deploymentId?: string;
469
+ constructor(message: string, deploymentId?: string);
470
+ }
471
+ /**
472
+ * Error thrown when the consumer registry is not configured for the project.
473
+ */
474
+ declare class ConsumerRegistryNotConfiguredError extends Error {
475
+ constructor(message?: string);
476
+ }
477
+
478
+ declare class QueueClient {
479
+ constructor(options: QueueClientOptions);
480
+ /**
481
+ * Send a message to a topic.
482
+ *
483
+ * This is an arrow function property so it can be destructured:
484
+ * ```typescript
485
+ * const { send } = new QueueClient({ region: process.env.QUEUE_REGION! });
486
+ * await send("my-topic", payload);
487
+ * ```
488
+ *
489
+ * @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
490
+ * @param payload - The data to send (serialized via the configured transport)
491
+ * @param options - Optional send options (idempotencyKey, retentionSeconds, delaySeconds, headers)
492
+ * @returns `{ messageId }` — `messageId` is `null` when the server accepted
493
+ * the message for deferred processing (no ID available yet)
494
+ */
495
+ send: <T = unknown>(topicName: string, payload: T, options?: SendOptions) => Promise<SendResult>;
496
+ /**
497
+ * Receive and process messages from a topic.
498
+ *
499
+ * Each message is automatically locked, kept alive via periodic visibility
500
+ * extensions during processing, and acknowledged upon successful handler completion.
501
+ * The handler is not called when the queue is empty — check `result.ok` instead.
502
+ *
503
+ * This is an arrow function property so it can be destructured:
504
+ * ```typescript
505
+ * const { receive } = new QueueClient({ region: process.env.QUEUE_REGION! });
506
+ * const result = await receive("my-topic", "my-group", handler);
507
+ * if (!result.ok) console.log(result.reason);
508
+ * ```
509
+ *
510
+ * @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
511
+ * @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
512
+ * @param handler - Function to process each message payload and metadata.
513
+ * Not called when the queue is empty.
514
+ * @param options - Optional receive options (visibilityTimeoutSeconds, limit, or messageId)
515
+ * @returns Discriminated result: `{ ok: true }` on success, `{ ok: false, reason }` otherwise
516
+ */
517
+ receive: <T = unknown>(topicName: string, consumerGroup: string, handler: MessageHandler<T>, options?: ReceiveOptions) => Promise<ReceiveResult>;
518
+ /**
519
+ * Create a Web API route handler for processing queue callback messages.
520
+ *
521
+ * Parses incoming `Request` as a CloudEvent and invokes the handler.
522
+ * For use on Vercel — Vercel invokes this route when messages are available.
523
+ *
524
+ * This is an arrow function property so it can be destructured:
525
+ * ```typescript
526
+ * const { handleCallback } = new QueueClient({ region: process.env.QUEUE_REGION! });
527
+ * export const POST = handleCallback(handler);
528
+ * ```
529
+ *
530
+ * @param handler - Function to process the message payload and metadata
531
+ * @param options - Optional configuration
532
+ * @param options.visibilityTimeoutSeconds - Message lock duration (default: 300, max: 3600)
533
+ * @param options.retry - Called when the handler throws. Return `{ afterSeconds: N }` to
534
+ * reschedule the message for redelivery after N seconds.
535
+ * @returns A `(request: Request) => Promise<Response>` route handler
536
+ */
537
+ handleCallback: <T = unknown>(handler: MessageHandler<T>, options?: {
538
+ visibilityTimeoutSeconds?: number;
539
+ retry?: RetryHandler;
540
+ }) => ((request: Request) => Promise<Response>);
541
+ /**
542
+ * Create a Connect-style route handler for processing queue callback messages.
543
+ * For use on Vercel — Vercel invokes this route when messages are available.
544
+ *
545
+ * For frameworks using the `(req, res)` middleware pattern where `req.body`
546
+ * is pre-parsed (Next.js Pages Router, etc.).
547
+ *
548
+ * This is an arrow function property so it can be destructured:
549
+ * ```typescript
550
+ * const { handleNodeCallback } = new QueueClient({ region: process.env.QUEUE_REGION! });
551
+ * app.post("/api/queue", handleNodeCallback(handler));
552
+ * ```
553
+ *
554
+ * @param handler - Function to process the message payload and metadata
555
+ * @param options - Optional configuration
556
+ * @param options.visibilityTimeoutSeconds - Message lock duration (default: 300, max: 3600)
557
+ * @param options.retry - Called when the handler throws. Return `{ afterSeconds: N }` to
558
+ * reschedule the message for redelivery after N seconds.
559
+ * @returns A `(req, res) => Promise<void>` route handler
560
+ */
561
+ handleNodeCallback: <T = unknown>(handler: MessageHandler<T>, options?: {
562
+ visibilityTimeoutSeconds?: number;
563
+ retry?: RetryHandler;
564
+ }) => ((req: {
565
+ method?: string;
566
+ headers: Record<string, string | string[] | undefined>;
567
+ body?: unknown;
568
+ }, res: {
569
+ status(code: number): {
570
+ json(data: unknown): void;
571
+ end(): void;
572
+ };
573
+ end(): void;
574
+ }) => Promise<void>);
575
+ }
576
+
577
+ /**
578
+ * Core queue callback utilities for handling incoming webhook payloads
579
+ * from Vercel triggers using the CloudEvent specification.
111
580
  *
112
- * @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
113
- * @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
114
- * @param handler - Function to process each message payload and metadata.
115
- * Receives (null, null) when queue is empty.
116
- * @param options - Optional receive options
117
- * @param options.visibilityTimeoutSeconds - Message lock duration (default: 300, max: 3600)
118
- * @param options.limit - Maximum messages to retrieve (default: 1, min: 1, max: 10)
119
- * @param options.client - Custom QueueClient instance (configure transport on the client)
120
- * @returns Promise that resolves when all messages are processed and deleted,
121
- * or when the handler returns after receiving null (empty queue)
581
+ * This module provides the framework-agnostic core. For framework-specific
582
+ * wrappers, see `@vercel/queue/web` and `@vercel/queue/nextjs/pages`.
583
+ */
584
+
585
+ declare const CLOUD_EVENT_TYPE_V1BETA = "com.vercel.queue.v1beta";
586
+ declare const CLOUD_EVENT_TYPE_V2BETA = "com.vercel.queue.v2beta";
587
+ /**
588
+ * Routing-only callback: the SDK must fetch the message by ID.
589
+ * Produced by v1beta structured mode and v2beta large-body mode.
590
+ */
591
+ type ParsedCallbackV1 = {
592
+ queueName: string;
593
+ consumerGroup: string;
594
+ messageId: string;
595
+ region?: string;
596
+ };
597
+ /**
598
+ * Full-message callback: payload and receipt handle are inlined,
599
+ * so the SDK can process directly without an extra fetch.
600
+ * Produced by v2beta small-body mode.
601
+ */
602
+ type ParsedCallbackV2 = {
603
+ queueName: string;
604
+ consumerGroup: string;
605
+ messageId: string;
606
+ region?: string;
607
+ receiptHandle: string;
608
+ deliveryCount?: number;
609
+ createdAt?: string;
610
+ expiresAt?: string;
611
+ contentType?: string;
612
+ visibilityDeadline?: string;
613
+ rawBody?: ReadableStream<Uint8Array>;
614
+ parsedPayload?: unknown;
615
+ };
616
+ type ParsedCallbackRequest = ParsedCallbackV1 | ParsedCallbackV2;
617
+ /**
618
+ * Parse a callback from a pre-parsed body and headers.
122
619
  *
123
- * @example
124
- * ```typescript
125
- * // Basic usage (OIDC auth, JSON deserialization)
126
- * await receive("my-topic", "my-group", async (payload, metadata) => {
127
- * console.log("Received:", payload);
128
- * });
620
+ * For frameworks like Next.js Pages Router where the body has already been
621
+ * parsed, use this instead of {@link parseCallback}.
129
622
  *
130
- * // Batch processing - fetch up to 10 messages in one request
131
- * await receive("my-topic", "my-group", handler, { limit: 10 });
623
+ * Detects the CloudEvent version from the `ce-type` header:
624
+ * - `com.vercel.queue.v2beta`: binary content mode (metadata in headers,
625
+ * payload in body). For small messages, the body is attached as `parsedPayload`.
626
+ * - Otherwise: structured content mode (v1beta, entire CloudEvent in JSON body)
132
627
  *
133
- * // Using custom client with custom transport
134
- * const client = new QueueClient({
135
- * transport: new BufferTransport(),
136
- * });
137
- * await receive("my-topic", "my-group", handler, { client });
138
- * ```
628
+ * @param body - The framework-parsed request body. Type depends on Content-Type
629
+ * and framework configuration:
630
+ * - v1beta: parsed CloudEvent JSON object
631
+ * - v2beta: the message payload as parsed by the framework (object, Buffer, or string)
632
+ * @param headers - HTTP headers
633
+ * @returns Parsed callback request with routing metadata and optional payload
139
634
  */
140
- declare function receive<T = unknown>(topicName: string, consumerGroup: string, handler: MessageHandler<T>, options?: ReceiveBatchOptions): Promise<void>;
635
+ declare function parseRawCallback(body: unknown, headers: Record<string, string | string[] | undefined>): ParsedCallbackRequest;
141
636
  /**
142
- * Receive a specific message by its ID.
637
+ * Parse and validate a CloudEvent callback from a Web API `Request` object.
143
638
  *
144
- * Used for targeted message processing, typically from webhook callbacks.
639
+ * Detects the CloudEvent version from the `ce-type` header:
640
+ * - `com.vercel.queue.v2beta`: binary content mode (metadata in headers,
641
+ * payload in body). For v2beta, the body is attached as `rawBody` (a
642
+ * ReadableStream) rather than being parsed.
643
+ * - Otherwise: structured content mode (v1beta, entire CloudEvent in JSON body)
145
644
  *
146
- * @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
147
- * @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
148
- * @param handler - Function to process the message payload and metadata
149
- * @param options - Receive options with messageId
150
- * @param options.messageId - Specific message ID to consume
151
- * @returns Promise that resolves when the message is processed and deleted
152
- * @throws {MessageNotFoundError} When message doesn't exist
153
- * @throws {MessageNotAvailableError} When message in wrong state
154
- * @throws {MessageAlreadyProcessedError} When already processed
645
+ * For frameworks that pre-parse the body (e.g. Next.js Pages Router),
646
+ * use {@link parseRawCallback} instead.
155
647
  */
156
- declare function receive<T = unknown>(topicName: string, consumerGroup: string, handler: MessageHandler<T>, options: ReceiveByIdOptions): Promise<void>;
648
+ declare function parseCallback(request: Request): Promise<ParsedCallbackRequest>;
157
649
 
158
- export { MessageHandler, PublishOptions, QueueClient, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type SendOptions, receive, send };
650
+ export { BadRequestError, type BaseUrlResolver, BufferTransport, CLOUD_EVENT_TYPE_V1BETA, CLOUD_EVENT_TYPE_V2BETA, ConsumerDiscoveryError, ConsumerRegistryNotConfiguredError, DuplicateMessageError, ForbiddenError, InternalServerError, InvalidLimitError, JsonTransport, type Message, MessageAlreadyProcessedError, MessageCorruptedError, type MessageHandler, MessageLockedError, type MessageMetadata, MessageNotAvailableError, MessageNotFoundError, type ParsedCallbackRequest, type ParsedCallbackV1, type ParsedCallbackV2, QueueClient, type QueueClientOptions, QueueEmptyError, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type ReceiveResult, type RetryDirective, type RetryHandler, type SendOptions, type SendResult, StreamTransport, type Transport, UnauthorizedError, type VercelRegion, parseCallback, parseRawCallback };