@vercel/queue 0.0.1 → 0.1.0
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/README.md +91 -61
- package/dist/index.d.mts +148 -42
- package/dist/index.d.ts +148 -42
- package/dist/index.js +130 -81
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +129 -81
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -37,12 +37,11 @@ interface Transport<T = unknown> {
|
|
|
37
37
|
* @example
|
|
38
38
|
* ```typescript
|
|
39
39
|
* // Default (JsonTransport is used automatically)
|
|
40
|
-
* const queue = new QueueClient(
|
|
40
|
+
* const queue = new QueueClient();
|
|
41
41
|
* await queue.send("topic", { data: "example" });
|
|
42
42
|
*
|
|
43
43
|
* // With custom serialization
|
|
44
44
|
* const queue = new QueueClient({
|
|
45
|
-
* region: process.env.QUEUE_REGION!,
|
|
46
45
|
* transport: new JsonTransport({
|
|
47
46
|
* replacer: (key, value) => key === "password" ? undefined : value,
|
|
48
47
|
* reviver: (key, value) => key === "date" ? new Date(value) : value,
|
|
@@ -75,7 +74,7 @@ declare class JsonTransport<T = unknown> implements Transport<T> {
|
|
|
75
74
|
*
|
|
76
75
|
* @example
|
|
77
76
|
* ```typescript
|
|
78
|
-
* const queue = new QueueClient({
|
|
77
|
+
* const queue = new QueueClient({ transport: new BufferTransport() });
|
|
79
78
|
* await queue.send("binary-topic", myBuffer);
|
|
80
79
|
* ```
|
|
81
80
|
*/
|
|
@@ -95,13 +94,13 @@ declare class BufferTransport implements Transport<Buffer> {
|
|
|
95
94
|
*
|
|
96
95
|
* @example
|
|
97
96
|
* ```typescript
|
|
98
|
-
* const queue = new QueueClient({ region: "iad1", transport: new StreamTransport() });
|
|
99
|
-
*
|
|
100
97
|
* // Sending a stream
|
|
98
|
+
* const queue = new QueueClient({ transport: new StreamTransport() });
|
|
101
99
|
* await queue.send("large-file", myReadableStream);
|
|
102
100
|
*
|
|
103
101
|
* // Receiving - cleanup handled automatically
|
|
104
|
-
*
|
|
102
|
+
* const poller = new PollingQueueClient({ region: "iad1", transport: new StreamTransport() });
|
|
103
|
+
* await poller.receive("large-file", "processor", async (stream, meta) => {
|
|
105
104
|
* const reader = stream.getReader();
|
|
106
105
|
* // Process chunks...
|
|
107
106
|
* });
|
|
@@ -130,11 +129,24 @@ declare class StreamTransport implements Transport<ReadableStream<Uint8Array>> {
|
|
|
130
129
|
*/
|
|
131
130
|
type VercelRegion = "arn1" | "bom1" | "cdg1" | "cle1" | "cpt1" | "dub1" | "dxb1" | "fra1" | "gru1" | "hkg1" | "hnd1" | "iad1" | "icn1" | "kix1" | "lhr1" | "pdx1" | "sfo1" | "sin1" | "syd1" | "yul1" | (string & {});
|
|
132
131
|
/**
|
|
133
|
-
* Resolves a region code to a base URL for the Vercel Queue Service API.
|
|
132
|
+
* Resolves a region code to a base {@link URL} for the Vercel Queue Service API.
|
|
133
|
+
*
|
|
134
|
+
* The SDK appends its own API path (`/api/v3/…`) to the returned URL.
|
|
135
|
+
* To add a prefix (e.g. when routing through a reverse proxy), include it
|
|
136
|
+
* in the pathname of the returned URL:
|
|
134
137
|
*
|
|
135
|
-
*
|
|
138
|
+
* ```ts
|
|
139
|
+
* // Default — domain only, no prefix:
|
|
140
|
+
* (region) => new URL(`https://${region}.vercel-queue.com`)
|
|
141
|
+
*
|
|
142
|
+
* // Custom domain with a base path:
|
|
143
|
+
* (region) => new URL(`https://my-proxy.example/custom-prefix`)
|
|
144
|
+
* // → requests go to https://my-proxy.example/custom-prefix/api/v3/…
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* Default: `` (region) => new URL(`https://${region}.vercel-queue.com`) ``
|
|
136
148
|
*/
|
|
137
|
-
type BaseUrlResolver = (region: string) =>
|
|
149
|
+
type BaseUrlResolver = (region: string) => URL;
|
|
138
150
|
interface QueueClientOptions {
|
|
139
151
|
/**
|
|
140
152
|
* Vercel region code for API routing.
|
|
@@ -142,18 +154,28 @@ interface QueueClientOptions {
|
|
|
142
154
|
* Requests are sent to the regional endpoint resolved by
|
|
143
155
|
* {@link BaseUrlResolver} (default: `https://${region}.vercel-queue.com`).
|
|
144
156
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
157
|
+
* When omitted, the region is auto-detected from the `VERCEL_REGION`
|
|
158
|
+
* environment variable (set automatically on Vercel). If not available,
|
|
159
|
+
* defaults to `"iad1"` with a console warning.
|
|
147
160
|
*
|
|
148
161
|
* @example
|
|
149
162
|
* ```ts
|
|
150
|
-
* new QueueClient(
|
|
163
|
+
* new QueueClient() // auto-detect, falls back to "iad1"
|
|
164
|
+
* new QueueClient({ region: "iad1" }) // explicit
|
|
151
165
|
* ```
|
|
152
166
|
*/
|
|
153
|
-
region
|
|
167
|
+
region?: VercelRegion;
|
|
154
168
|
/**
|
|
155
|
-
* Custom resolver that maps a region code to a base URL.
|
|
156
|
-
*
|
|
169
|
+
* Custom resolver that maps a region code to a base {@link URL}.
|
|
170
|
+
*
|
|
171
|
+
* The SDK always appends its own API path (`/api/v3/…`) to the returned URL.
|
|
172
|
+
* Include a pathname to add a prefix (e.g. for reverse-proxy routing):
|
|
173
|
+
*
|
|
174
|
+
* ```ts
|
|
175
|
+
* resolveBaseUrl: (region) => new URL(`https://my-proxy.example/prefix`)
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* @default (region) => new URL(`https://${region}.vercel-queue.com`)
|
|
157
179
|
*/
|
|
158
180
|
resolveBaseUrl?: BaseUrlResolver;
|
|
159
181
|
/**
|
|
@@ -184,6 +206,28 @@ interface QueueClientOptions {
|
|
|
184
206
|
*/
|
|
185
207
|
transport?: Transport;
|
|
186
208
|
}
|
|
209
|
+
/**
|
|
210
|
+
* Options for creating a {@link PollingQueueClient}.
|
|
211
|
+
*
|
|
212
|
+
* Identical to {@link QueueClientOptions} except `region` is **required**
|
|
213
|
+
* because messages can only be received from the region they were sent to.
|
|
214
|
+
* Using a fixed region (e.g. `"iad1"`) ensures that `send` and `receive`
|
|
215
|
+
* target the same endpoint.
|
|
216
|
+
*/
|
|
217
|
+
interface PollingQueueClientOptions extends QueueClientOptions {
|
|
218
|
+
/**
|
|
219
|
+
* Vercel region code for API routing — **required** for polling.
|
|
220
|
+
*
|
|
221
|
+
* Messages can only be received from the region they were sent to.
|
|
222
|
+
* Use a fixed region (e.g. `"iad1"`) for both sending and receiving.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* new PollingQueueClient({ region: "iad1" })
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
region: VercelRegion;
|
|
230
|
+
}
|
|
187
231
|
/**
|
|
188
232
|
* Options for sending messages.
|
|
189
233
|
*/
|
|
@@ -475,14 +519,37 @@ declare class ConsumerRegistryNotConfiguredError extends Error {
|
|
|
475
519
|
constructor(message?: string);
|
|
476
520
|
}
|
|
477
521
|
|
|
522
|
+
/**
|
|
523
|
+
* Queue client for push-based (callback) workflows.
|
|
524
|
+
*
|
|
525
|
+
* Use this client when Vercel delivers messages to your route handlers.
|
|
526
|
+
* Provides {@link send}, {@link handleCallback}, and {@link handleNodeCallback}.
|
|
527
|
+
*
|
|
528
|
+
* Region is resolved automatically:
|
|
529
|
+
* 1. Explicit `region` option (highest priority)
|
|
530
|
+
* 2. `VERCEL_REGION` environment variable (set automatically on Vercel)
|
|
531
|
+
* 3. Falls back to `"iad1"` with a console warning
|
|
532
|
+
*
|
|
533
|
+
* The constructor never throws — `new QueueClient()` always works.
|
|
534
|
+
*
|
|
535
|
+
* For manual polling workflows, use {@link PollingQueueClient} instead.
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* ```typescript
|
|
539
|
+
* import { QueueClient } from "@vercel/queue";
|
|
540
|
+
*
|
|
541
|
+
* const queue = new QueueClient();
|
|
542
|
+
* export const { send, handleCallback, handleNodeCallback } = queue;
|
|
543
|
+
* ```
|
|
544
|
+
*/
|
|
478
545
|
declare class QueueClient {
|
|
479
|
-
constructor(options
|
|
546
|
+
constructor(options?: QueueClientOptions);
|
|
480
547
|
/**
|
|
481
548
|
* Send a message to a topic.
|
|
482
549
|
*
|
|
483
550
|
* This is an arrow function property so it can be destructured:
|
|
484
551
|
* ```typescript
|
|
485
|
-
* const { send } = new QueueClient(
|
|
552
|
+
* const { send } = new QueueClient();
|
|
486
553
|
* await send("my-topic", payload);
|
|
487
554
|
* ```
|
|
488
555
|
*
|
|
@@ -493,28 +560,6 @@ declare class QueueClient {
|
|
|
493
560
|
* the message for deferred processing (no ID available yet)
|
|
494
561
|
*/
|
|
495
562
|
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
563
|
/**
|
|
519
564
|
* Create a Web API route handler for processing queue callback messages.
|
|
520
565
|
*
|
|
@@ -523,7 +568,7 @@ declare class QueueClient {
|
|
|
523
568
|
*
|
|
524
569
|
* This is an arrow function property so it can be destructured:
|
|
525
570
|
* ```typescript
|
|
526
|
-
* const { handleCallback } = new QueueClient(
|
|
571
|
+
* const { handleCallback } = new QueueClient();
|
|
527
572
|
* export const POST = handleCallback(handler);
|
|
528
573
|
* ```
|
|
529
574
|
*
|
|
@@ -547,7 +592,7 @@ declare class QueueClient {
|
|
|
547
592
|
*
|
|
548
593
|
* This is an arrow function property so it can be destructured:
|
|
549
594
|
* ```typescript
|
|
550
|
-
* const { handleNodeCallback } = new QueueClient(
|
|
595
|
+
* const { handleNodeCallback } = new QueueClient();
|
|
551
596
|
* app.post("/api/queue", handleNodeCallback(handler));
|
|
552
597
|
* ```
|
|
553
598
|
*
|
|
@@ -573,6 +618,67 @@ declare class QueueClient {
|
|
|
573
618
|
end(): void;
|
|
574
619
|
}) => Promise<void>);
|
|
575
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Queue client for poll-based (manual receive) workflows.
|
|
623
|
+
*
|
|
624
|
+
* Use this client when you manually poll for messages with {@link receive}.
|
|
625
|
+
* Also provides {@link send} for publishing messages.
|
|
626
|
+
*
|
|
627
|
+
* Region is **required** because messages can only be received from the
|
|
628
|
+
* region they were sent to. Use a fixed region (e.g. `"iad1"`) for both
|
|
629
|
+
* sending and receiving.
|
|
630
|
+
*
|
|
631
|
+
* For push-based (callback) workflows on Vercel, use {@link QueueClient} instead.
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```typescript
|
|
635
|
+
* import { PollingQueueClient } from "@vercel/queue";
|
|
636
|
+
*
|
|
637
|
+
* const queue = new PollingQueueClient({ region: "iad1" });
|
|
638
|
+
* export const { send, receive } = queue;
|
|
639
|
+
* ```
|
|
640
|
+
*/
|
|
641
|
+
declare class PollingQueueClient {
|
|
642
|
+
constructor(options: PollingQueueClientOptions);
|
|
643
|
+
/**
|
|
644
|
+
* Send a message to a topic.
|
|
645
|
+
*
|
|
646
|
+
* This is an arrow function property so it can be destructured:
|
|
647
|
+
* ```typescript
|
|
648
|
+
* const { send } = new PollingQueueClient({ region: "iad1" });
|
|
649
|
+
* await send("my-topic", payload);
|
|
650
|
+
* ```
|
|
651
|
+
*
|
|
652
|
+
* @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
|
|
653
|
+
* @param payload - The data to send (serialized via the configured transport)
|
|
654
|
+
* @param options - Optional send options (idempotencyKey, retentionSeconds, delaySeconds, headers)
|
|
655
|
+
* @returns `{ messageId }` — `messageId` is `null` when the server accepted
|
|
656
|
+
* the message for deferred processing (no ID available yet)
|
|
657
|
+
*/
|
|
658
|
+
send: <T = unknown>(topicName: string, payload: T, options?: SendOptions) => Promise<SendResult>;
|
|
659
|
+
/**
|
|
660
|
+
* Receive and process messages from a topic.
|
|
661
|
+
*
|
|
662
|
+
* Each message is automatically locked, kept alive via periodic visibility
|
|
663
|
+
* extensions during processing, and acknowledged upon successful handler completion.
|
|
664
|
+
* The handler is not called when the queue is empty — check `result.ok` instead.
|
|
665
|
+
*
|
|
666
|
+
* This is an arrow function property so it can be destructured:
|
|
667
|
+
* ```typescript
|
|
668
|
+
* const { receive } = new PollingQueueClient({ region: "iad1" });
|
|
669
|
+
* const result = await receive("my-topic", "my-group", handler);
|
|
670
|
+
* if (!result.ok) console.log(result.reason);
|
|
671
|
+
* ```
|
|
672
|
+
*
|
|
673
|
+
* @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
|
|
674
|
+
* @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
|
|
675
|
+
* @param handler - Function to process each message payload and metadata.
|
|
676
|
+
* Not called when the queue is empty.
|
|
677
|
+
* @param options - Optional receive options (visibilityTimeoutSeconds, limit, or messageId)
|
|
678
|
+
* @returns Discriminated result: `{ ok: true }` on success, `{ ok: false, reason }` otherwise
|
|
679
|
+
*/
|
|
680
|
+
receive: <T = unknown>(topicName: string, consumerGroup: string, handler: MessageHandler<T>, options?: ReceiveOptions) => Promise<ReceiveResult>;
|
|
681
|
+
}
|
|
576
682
|
|
|
577
683
|
/**
|
|
578
684
|
* Core queue callback utilities for handling incoming webhook payloads
|
|
@@ -647,4 +753,4 @@ declare function parseRawCallback(body: unknown, headers: Record<string, string
|
|
|
647
753
|
*/
|
|
648
754
|
declare function parseCallback(request: Request): Promise<ParsedCallbackRequest>;
|
|
649
755
|
|
|
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 };
|
|
756
|
+
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, PollingQueueClient, type PollingQueueClientOptions, 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 };
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
MessageLockedError: () => MessageLockedError,
|
|
47
47
|
MessageNotAvailableError: () => MessageNotAvailableError,
|
|
48
48
|
MessageNotFoundError: () => MessageNotFoundError,
|
|
49
|
+
PollingQueueClient: () => PollingQueueClient,
|
|
49
50
|
QueueClient: () => QueueClient,
|
|
50
51
|
QueueEmptyError: () => QueueEmptyError,
|
|
51
52
|
StreamTransport: () => StreamTransport,
|
|
@@ -1021,7 +1022,7 @@ function parseQueueHeaders(headers) {
|
|
|
1021
1022
|
receiptHandle
|
|
1022
1023
|
};
|
|
1023
1024
|
}
|
|
1024
|
-
var DEFAULT_BASE_URL_RESOLVER = (region) => `https://${region}.vercel-queue.com
|
|
1025
|
+
var DEFAULT_BASE_URL_RESOLVER = (region) => new URL(`https://${region}.vercel-queue.com`);
|
|
1025
1026
|
function resolveBaseUrl(region, resolver) {
|
|
1026
1027
|
return (resolver ?? DEFAULT_BASE_URL_RESOLVER)(region);
|
|
1027
1028
|
}
|
|
@@ -1079,7 +1080,7 @@ var ApiClient = class _ApiClient {
|
|
|
1079
1080
|
return;
|
|
1080
1081
|
}
|
|
1081
1082
|
throw new Error(
|
|
1082
|
-
'No deployment ID available. VERCEL_DEPLOYMENT_ID is not set.\n\nThis usually means the code is running outside a Vercel deployment (e.g. during build or in a non-Vercel environment).\n\nTo fix this, create a
|
|
1083
|
+
'No deployment ID available. VERCEL_DEPLOYMENT_ID is not set.\n\nThis usually means the code is running outside a Vercel deployment (e.g. during build or in a non-Vercel environment).\n\nTo fix this, create a client with an explicit deploymentId:\n new QueueClient({ deploymentId: "dpl_xxx" })\nOr explicitly opt out of deployment pinning:\n new QueueClient({ deploymentId: null })'
|
|
1083
1084
|
);
|
|
1084
1085
|
}
|
|
1085
1086
|
getSendDeploymentId() {
|
|
@@ -1112,7 +1113,8 @@ var ApiClient = class _ApiClient {
|
|
|
1112
1113
|
const encodedQueue = encodeURIComponent(queueName);
|
|
1113
1114
|
const segments = pathSegments.map((s) => encodeURIComponent(s));
|
|
1114
1115
|
const path2 = segments.length > 0 ? "/" + segments.join("/") : "";
|
|
1115
|
-
|
|
1116
|
+
const basePath = this.baseUrl.pathname.replace(/\/+$/, "");
|
|
1117
|
+
return `${this.baseUrl.origin}${basePath}${BASE_PATH}/${encodedQueue}${path2}`;
|
|
1116
1118
|
}
|
|
1117
1119
|
async fetch(url, init) {
|
|
1118
1120
|
const method = init.method || "GET";
|
|
@@ -1136,7 +1138,7 @@ var ApiClient = class _ApiClient {
|
|
|
1136
1138
|
}
|
|
1137
1139
|
console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
|
|
1138
1140
|
}
|
|
1139
|
-
init.headers.set("User-Agent", `@vercel/queue/${"0.0
|
|
1141
|
+
init.headers.set("User-Agent", `@vercel/queue/${"0.1.0"}`);
|
|
1140
1142
|
init.headers.set("Vqs-Client-Ts", (/* @__PURE__ */ new Date()).toISOString());
|
|
1141
1143
|
const response = await fetch(url, init);
|
|
1142
1144
|
if (isDebugEnabled()) {
|
|
@@ -1472,23 +1474,37 @@ var ApiClient = class _ApiClient {
|
|
|
1472
1474
|
|
|
1473
1475
|
// src/client.ts
|
|
1474
1476
|
var apiClients = /* @__PURE__ */ new WeakMap();
|
|
1475
|
-
function
|
|
1477
|
+
function getApi(client) {
|
|
1476
1478
|
const api = apiClients.get(client);
|
|
1477
1479
|
if (!api) {
|
|
1478
|
-
throw new Error("
|
|
1480
|
+
throw new Error("Client not initialized");
|
|
1479
1481
|
}
|
|
1480
1482
|
return api;
|
|
1481
1483
|
}
|
|
1484
|
+
function getApiClient(client) {
|
|
1485
|
+
return getApi(client);
|
|
1486
|
+
}
|
|
1487
|
+
var DEFAULT_REGION = "iad1";
|
|
1488
|
+
function resolveRegion(region) {
|
|
1489
|
+
if (region) return region;
|
|
1490
|
+
const fromEnv = process.env.VERCEL_REGION;
|
|
1491
|
+
if (fromEnv) return fromEnv;
|
|
1492
|
+
console.warn(
|
|
1493
|
+
`[QueueClient] Region not detected \u2014 defaulting to "${DEFAULT_REGION}". On Vercel this is set automatically via VERCEL_REGION. To silence this warning, pass region explicitly: new QueueClient({ region: "iad1" })`
|
|
1494
|
+
);
|
|
1495
|
+
return DEFAULT_REGION;
|
|
1496
|
+
}
|
|
1482
1497
|
var QueueClient = class {
|
|
1483
|
-
constructor(options) {
|
|
1484
|
-
|
|
1498
|
+
constructor(options = {}) {
|
|
1499
|
+
const region = resolveRegion(options.region);
|
|
1500
|
+
apiClients.set(this, new ApiClient({ ...options, region }));
|
|
1485
1501
|
}
|
|
1486
1502
|
/**
|
|
1487
1503
|
* Send a message to a topic.
|
|
1488
1504
|
*
|
|
1489
1505
|
* This is an arrow function property so it can be destructured:
|
|
1490
1506
|
* ```typescript
|
|
1491
|
-
* const { send } = new QueueClient(
|
|
1507
|
+
* const { send } = new QueueClient();
|
|
1492
1508
|
* await send("my-topic", payload);
|
|
1493
1509
|
* ```
|
|
1494
1510
|
*
|
|
@@ -1499,7 +1515,7 @@ var QueueClient = class {
|
|
|
1499
1515
|
* the message for deferred processing (no ID available yet)
|
|
1500
1516
|
*/
|
|
1501
1517
|
send = async (topicName, payload, options) => {
|
|
1502
|
-
const api =
|
|
1518
|
+
const api = getApi(this);
|
|
1503
1519
|
const result = await api.sendMessage({
|
|
1504
1520
|
queueName: topicName,
|
|
1505
1521
|
payload,
|
|
@@ -1518,75 +1534,6 @@ var QueueClient = class {
|
|
|
1518
1534
|
}
|
|
1519
1535
|
return { messageId: result.messageId };
|
|
1520
1536
|
};
|
|
1521
|
-
/**
|
|
1522
|
-
* Receive and process messages from a topic.
|
|
1523
|
-
*
|
|
1524
|
-
* Each message is automatically locked, kept alive via periodic visibility
|
|
1525
|
-
* extensions during processing, and acknowledged upon successful handler completion.
|
|
1526
|
-
* The handler is not called when the queue is empty — check `result.ok` instead.
|
|
1527
|
-
*
|
|
1528
|
-
* This is an arrow function property so it can be destructured:
|
|
1529
|
-
* ```typescript
|
|
1530
|
-
* const { receive } = new QueueClient({ region: process.env.QUEUE_REGION! });
|
|
1531
|
-
* const result = await receive("my-topic", "my-group", handler);
|
|
1532
|
-
* if (!result.ok) console.log(result.reason);
|
|
1533
|
-
* ```
|
|
1534
|
-
*
|
|
1535
|
-
* @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
|
|
1536
|
-
* @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
|
|
1537
|
-
* @param handler - Function to process each message payload and metadata.
|
|
1538
|
-
* Not called when the queue is empty.
|
|
1539
|
-
* @param options - Optional receive options (visibilityTimeoutSeconds, limit, or messageId)
|
|
1540
|
-
* @returns Discriminated result: `{ ok: true }` on success, `{ ok: false, reason }` otherwise
|
|
1541
|
-
*/
|
|
1542
|
-
receive = async (topicName, consumerGroup, handler, options) => {
|
|
1543
|
-
const api = getApiClient(this);
|
|
1544
|
-
const topic = new Topic(api, topicName);
|
|
1545
|
-
const visibilityTimeoutSeconds = options && "visibilityTimeoutSeconds" in options ? options.visibilityTimeoutSeconds : void 0;
|
|
1546
|
-
const consumer = topic.consumerGroup(
|
|
1547
|
-
consumerGroup,
|
|
1548
|
-
visibilityTimeoutSeconds !== void 0 ? { visibilityTimeoutSeconds } : {}
|
|
1549
|
-
);
|
|
1550
|
-
try {
|
|
1551
|
-
let count;
|
|
1552
|
-
const retry = options?.retry;
|
|
1553
|
-
if (options && "messageId" in options) {
|
|
1554
|
-
count = await consumer.consume(handler, {
|
|
1555
|
-
messageId: options.messageId,
|
|
1556
|
-
retry
|
|
1557
|
-
});
|
|
1558
|
-
} else {
|
|
1559
|
-
const limit = options && "limit" in options ? options.limit : void 0;
|
|
1560
|
-
count = await consumer.consume(handler, {
|
|
1561
|
-
...limit !== void 0 ? { limit } : {},
|
|
1562
|
-
retry
|
|
1563
|
-
});
|
|
1564
|
-
}
|
|
1565
|
-
if (count === 0) {
|
|
1566
|
-
return { ok: false, reason: "empty" };
|
|
1567
|
-
}
|
|
1568
|
-
return { ok: true };
|
|
1569
|
-
} catch (error) {
|
|
1570
|
-
if (options && "messageId" in options && error instanceof MessageNotFoundError) {
|
|
1571
|
-
return { ok: false, reason: "not_found", messageId: options.messageId };
|
|
1572
|
-
}
|
|
1573
|
-
if (options && "messageId" in options && error instanceof MessageNotAvailableError) {
|
|
1574
|
-
return {
|
|
1575
|
-
ok: false,
|
|
1576
|
-
reason: "not_available",
|
|
1577
|
-
messageId: options.messageId
|
|
1578
|
-
};
|
|
1579
|
-
}
|
|
1580
|
-
if (options && "messageId" in options && error instanceof MessageAlreadyProcessedError) {
|
|
1581
|
-
return {
|
|
1582
|
-
ok: false,
|
|
1583
|
-
reason: "already_processed",
|
|
1584
|
-
messageId: options.messageId
|
|
1585
|
-
};
|
|
1586
|
-
}
|
|
1587
|
-
throw error;
|
|
1588
|
-
}
|
|
1589
|
-
};
|
|
1590
1537
|
/**
|
|
1591
1538
|
* Create a Web API route handler for processing queue callback messages.
|
|
1592
1539
|
*
|
|
@@ -1595,7 +1542,7 @@ var QueueClient = class {
|
|
|
1595
1542
|
*
|
|
1596
1543
|
* This is an arrow function property so it can be destructured:
|
|
1597
1544
|
* ```typescript
|
|
1598
|
-
* const { handleCallback } = new QueueClient(
|
|
1545
|
+
* const { handleCallback } = new QueueClient();
|
|
1599
1546
|
* export const POST = handleCallback(handler);
|
|
1600
1547
|
* ```
|
|
1601
1548
|
*
|
|
@@ -1637,7 +1584,7 @@ var QueueClient = class {
|
|
|
1637
1584
|
*
|
|
1638
1585
|
* This is an arrow function property so it can be destructured:
|
|
1639
1586
|
* ```typescript
|
|
1640
|
-
* const { handleNodeCallback } = new QueueClient(
|
|
1587
|
+
* const { handleNodeCallback } = new QueueClient();
|
|
1641
1588
|
* app.post("/api/queue", handleNodeCallback(handler));
|
|
1642
1589
|
* ```
|
|
1643
1590
|
*
|
|
@@ -1673,6 +1620,107 @@ var QueueClient = class {
|
|
|
1673
1620
|
};
|
|
1674
1621
|
};
|
|
1675
1622
|
};
|
|
1623
|
+
var PollingQueueClient = class {
|
|
1624
|
+
constructor(options) {
|
|
1625
|
+
apiClients.set(this, new ApiClient(options));
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Send a message to a topic.
|
|
1629
|
+
*
|
|
1630
|
+
* This is an arrow function property so it can be destructured:
|
|
1631
|
+
* ```typescript
|
|
1632
|
+
* const { send } = new PollingQueueClient({ region: "iad1" });
|
|
1633
|
+
* await send("my-topic", payload);
|
|
1634
|
+
* ```
|
|
1635
|
+
*
|
|
1636
|
+
* @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
|
|
1637
|
+
* @param payload - The data to send (serialized via the configured transport)
|
|
1638
|
+
* @param options - Optional send options (idempotencyKey, retentionSeconds, delaySeconds, headers)
|
|
1639
|
+
* @returns `{ messageId }` — `messageId` is `null` when the server accepted
|
|
1640
|
+
* the message for deferred processing (no ID available yet)
|
|
1641
|
+
*/
|
|
1642
|
+
send = async (topicName, payload, options) => {
|
|
1643
|
+
const api = getApi(this);
|
|
1644
|
+
const result = await api.sendMessage({
|
|
1645
|
+
queueName: topicName,
|
|
1646
|
+
payload,
|
|
1647
|
+
idempotencyKey: options?.idempotencyKey,
|
|
1648
|
+
retentionSeconds: options?.retentionSeconds,
|
|
1649
|
+
delaySeconds: options?.delaySeconds,
|
|
1650
|
+
headers: options?.headers
|
|
1651
|
+
});
|
|
1652
|
+
return { messageId: result.messageId };
|
|
1653
|
+
};
|
|
1654
|
+
/**
|
|
1655
|
+
* Receive and process messages from a topic.
|
|
1656
|
+
*
|
|
1657
|
+
* Each message is automatically locked, kept alive via periodic visibility
|
|
1658
|
+
* extensions during processing, and acknowledged upon successful handler completion.
|
|
1659
|
+
* The handler is not called when the queue is empty — check `result.ok` instead.
|
|
1660
|
+
*
|
|
1661
|
+
* This is an arrow function property so it can be destructured:
|
|
1662
|
+
* ```typescript
|
|
1663
|
+
* const { receive } = new PollingQueueClient({ region: "iad1" });
|
|
1664
|
+
* const result = await receive("my-topic", "my-group", handler);
|
|
1665
|
+
* if (!result.ok) console.log(result.reason);
|
|
1666
|
+
* ```
|
|
1667
|
+
*
|
|
1668
|
+
* @param topicName - Name of the topic (pattern: `[A-Za-z0-9_-]+`)
|
|
1669
|
+
* @param consumerGroup - Name of the consumer group (pattern: `[A-Za-z0-9_-]+`)
|
|
1670
|
+
* @param handler - Function to process each message payload and metadata.
|
|
1671
|
+
* Not called when the queue is empty.
|
|
1672
|
+
* @param options - Optional receive options (visibilityTimeoutSeconds, limit, or messageId)
|
|
1673
|
+
* @returns Discriminated result: `{ ok: true }` on success, `{ ok: false, reason }` otherwise
|
|
1674
|
+
*/
|
|
1675
|
+
receive = async (topicName, consumerGroup, handler, options) => {
|
|
1676
|
+
const api = getApi(this);
|
|
1677
|
+
const topic = new Topic(api, topicName);
|
|
1678
|
+
const visibilityTimeoutSeconds = options && "visibilityTimeoutSeconds" in options ? options.visibilityTimeoutSeconds : void 0;
|
|
1679
|
+
const consumer = topic.consumerGroup(
|
|
1680
|
+
consumerGroup,
|
|
1681
|
+
visibilityTimeoutSeconds !== void 0 ? { visibilityTimeoutSeconds } : {}
|
|
1682
|
+
);
|
|
1683
|
+
try {
|
|
1684
|
+
let count;
|
|
1685
|
+
const retry = options?.retry;
|
|
1686
|
+
if (options && "messageId" in options) {
|
|
1687
|
+
count = await consumer.consume(handler, {
|
|
1688
|
+
messageId: options.messageId,
|
|
1689
|
+
retry
|
|
1690
|
+
});
|
|
1691
|
+
} else {
|
|
1692
|
+
const limit = options && "limit" in options ? options.limit : void 0;
|
|
1693
|
+
count = await consumer.consume(handler, {
|
|
1694
|
+
...limit !== void 0 ? { limit } : {},
|
|
1695
|
+
retry
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
if (count === 0) {
|
|
1699
|
+
return { ok: false, reason: "empty" };
|
|
1700
|
+
}
|
|
1701
|
+
return { ok: true };
|
|
1702
|
+
} catch (error) {
|
|
1703
|
+
if (options && "messageId" in options && error instanceof MessageNotFoundError) {
|
|
1704
|
+
return { ok: false, reason: "not_found", messageId: options.messageId };
|
|
1705
|
+
}
|
|
1706
|
+
if (options && "messageId" in options && error instanceof MessageNotAvailableError) {
|
|
1707
|
+
return {
|
|
1708
|
+
ok: false,
|
|
1709
|
+
reason: "not_available",
|
|
1710
|
+
messageId: options.messageId
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
if (options && "messageId" in options && error instanceof MessageAlreadyProcessedError) {
|
|
1714
|
+
return {
|
|
1715
|
+
ok: false,
|
|
1716
|
+
reason: "already_processed",
|
|
1717
|
+
messageId: options.messageId
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1720
|
+
throw error;
|
|
1721
|
+
}
|
|
1722
|
+
};
|
|
1723
|
+
};
|
|
1676
1724
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1677
1725
|
0 && (module.exports = {
|
|
1678
1726
|
BadRequestError,
|
|
@@ -1691,6 +1739,7 @@ var QueueClient = class {
|
|
|
1691
1739
|
MessageLockedError,
|
|
1692
1740
|
MessageNotAvailableError,
|
|
1693
1741
|
MessageNotFoundError,
|
|
1742
|
+
PollingQueueClient,
|
|
1694
1743
|
QueueClient,
|
|
1695
1744
|
QueueEmptyError,
|
|
1696
1745
|
StreamTransport,
|