@vercel/queue 0.0.0-alpha.2 → 0.0.0-alpha.22

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.js CHANGED
@@ -22,154 +22,100 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  BadRequestError: () => BadRequestError,
24
24
  BufferTransport: () => BufferTransport,
25
- ConsumerGroup: () => ConsumerGroup,
26
- FailedDependencyError: () => FailedDependencyError,
27
- FifoOrderingViolationError: () => FifoOrderingViolationError,
28
25
  ForbiddenError: () => ForbiddenError,
29
26
  InternalServerError: () => InternalServerError,
30
- InvalidCallbackError: () => InvalidCallbackError,
31
27
  InvalidLimitError: () => InvalidLimitError,
32
28
  JsonTransport: () => JsonTransport,
33
29
  MessageCorruptedError: () => MessageCorruptedError,
34
30
  MessageLockedError: () => MessageLockedError,
35
31
  MessageNotAvailableError: () => MessageNotAvailableError,
36
32
  MessageNotFoundError: () => MessageNotFoundError,
37
- QueueClient: () => QueueClient,
38
33
  QueueEmptyError: () => QueueEmptyError,
39
34
  StreamTransport: () => StreamTransport,
40
- Topic: () => Topic,
41
35
  UnauthorizedError: () => UnauthorizedError,
42
- createTopic: () => createTopic,
43
- getVercelOidcToken: () => getVercelOidcToken,
44
- parseCallbackRequest: () => parseCallbackRequest
36
+ handleCallback: () => handleCallback,
37
+ parseCallback: () => parseCallback,
38
+ receive: () => receive,
39
+ send: () => send
45
40
  });
46
41
  module.exports = __toCommonJS(index_exports);
47
42
 
48
- // src/oidc.ts
49
- async function getVercelOidcToken() {
50
- const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
51
- const fromSymbol = globalThis;
52
- const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
53
- const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
54
- if (!token) {
55
- throw new Error(
56
- `The 'x-vercel-oidc-token' header is missing from the request. Do you have the OIDC option enabled in the Vercel project settings?`
57
- );
58
- }
59
- return token;
60
- }
61
-
62
- // src/client.ts
63
- var import_mixpart = require("mixpart");
64
-
65
- // src/local.ts
66
- var import_node_child_process = require("child_process");
67
- function isLocalhostWithPort(url) {
43
+ // src/transports.ts
44
+ async function streamToBuffer(stream) {
45
+ let totalLength = 0;
46
+ const reader = stream.getReader();
47
+ const chunks = [];
68
48
  try {
69
- const parsedUrl = new URL(url);
70
- const isLocalhost = parsedUrl.hostname === "localhost";
71
- const port = parsedUrl.port ? parseInt(parsedUrl.port, 10) : 0;
72
- return { isLocalhost, port };
73
- } catch {
74
- return { isLocalhost: false };
49
+ while (true) {
50
+ const { done, value } = await reader.read();
51
+ if (done) break;
52
+ chunks.push(value);
53
+ totalLength += value.length;
54
+ }
55
+ } finally {
56
+ reader.releaseLock();
75
57
  }
58
+ return Buffer.concat(chunks, totalLength);
76
59
  }
77
- function isSupportedPlatform() {
78
- const platform = process.platform;
79
- return platform === "darwin" || platform === "linux";
80
- }
81
- function processDevelopmentCallbacks(callbacks) {
82
- const isDevelopment = process.env.NODE_ENV === "development";
83
- if (!isDevelopment) {
84
- return [];
60
+ var JsonTransport = class {
61
+ contentType = "application/json";
62
+ replacer;
63
+ reviver;
64
+ constructor(options = {}) {
65
+ this.replacer = options.replacer;
66
+ this.reviver = options.reviver;
85
67
  }
86
- if (!isSupportedPlatform()) {
87
- const hasLocalhostCallbacks = Object.values(callbacks).some((config) => {
88
- const { isLocalhost } = isLocalhostWithPort(config.url);
89
- return isLocalhost;
90
- });
91
- if (hasLocalhostCallbacks) {
92
- console.warn(
93
- `Queue Development Mode: Localhost callbacks are not supported on ${process.platform}. Localhost callback handling requires bash, nc, and curl which are available on macOS and Linux only. Consider using a production callback URL or developing on a supported platform.`
94
- );
95
- }
96
- return [];
68
+ serialize(value) {
69
+ return Buffer.from(JSON.stringify(value, this.replacer), "utf8");
97
70
  }
98
- const localhostCallbacks = [];
99
- Object.entries(callbacks).forEach(([group, config]) => {
100
- const { isLocalhost, port } = isLocalhostWithPort(config.url);
101
- if (isLocalhost && port && port > 0) {
102
- localhostCallbacks.push({ group, config, port });
103
- } else {
104
- console.warn(
105
- `Queue Development Mode: Skipping non-localhost callback for group "${group}": ${config.url}. Only localhost callbacks with explicit ports are supported in development.`
106
- );
107
- }
108
- });
109
- return localhostCallbacks;
110
- }
111
- function fireLocalhostCallbacks(localhostCallbacks, queueName, responseData) {
112
- localhostCallbacks.forEach(({ group, config, port }) => {
113
- const callbackHeaders = new Headers();
114
- callbackHeaders.set("Vqs-Message-Id", responseData.messageId);
115
- callbackHeaders.set("Vqs-Queue-Name", queueName);
116
- callbackHeaders.set("Vqs-Consumer-Group", group);
117
- fireAndForgetWaitForHttpReady(
118
- config.url,
119
- port,
120
- config.delay || 0,
121
- 3,
122
- // Default retry frequency
123
- callbackHeaders
124
- );
125
- });
126
- }
127
- function fireAndForgetWaitForHttpReady(url, port, initialDelaySeconds = 0, retryFrequencySeconds = 3, headers) {
128
- if (!isSupportedPlatform()) {
129
- console.warn(
130
- `Queue: fireAndForgetWaitForHttpReady is not supported on ${process.platform}. This function requires bash, nc, and curl which are available on macOS and Linux only.`
131
- );
132
- return;
71
+ async deserialize(stream) {
72
+ const buffer = await streamToBuffer(stream);
73
+ return JSON.parse(buffer.toString("utf8"), this.reviver);
133
74
  }
134
- let headerArgs = "";
135
- if (headers) {
136
- const headerArray = [];
137
- headers.forEach((value, key) => {
138
- headerArray.push(`-H '${key}: ${value}'`);
139
- });
140
- headerArgs = headerArray.join(" ");
75
+ };
76
+ var BufferTransport = class {
77
+ contentType = "application/octet-stream";
78
+ serialize(value) {
79
+ return value;
80
+ }
81
+ async deserialize(stream) {
82
+ return await streamToBuffer(stream);
83
+ }
84
+ };
85
+ var StreamTransport = class {
86
+ contentType = "application/octet-stream";
87
+ serialize(value) {
88
+ return value;
89
+ }
90
+ async deserialize(stream) {
91
+ return stream;
141
92
  }
142
- const bashScript = `
143
- # Wait for any initial boot time
144
- sleep ${initialDelaySeconds}
93
+ async finalize(payload) {
94
+ const reader = payload.getReader();
95
+ try {
96
+ while (true) {
97
+ const { done } = await reader.read();
98
+ if (done) break;
99
+ }
100
+ } finally {
101
+ reader.releaseLock();
102
+ }
103
+ }
104
+ };
145
105
 
146
- missed=0
147
- while true; do
148
- # 1) Check if TCP port is listening
149
- if nc -z localhost ${port} 2>/dev/null; then
150
- missed=0
151
- # 2) If port is open, try HTTP POST check
152
- if curl -sSL --fail -o /dev/null -X POST ${headerArgs} "${url}"; then
153
- # Success: port is up AND HTTP returned 2xx (following redirects)
154
- exit 0
155
- fi
156
- else
157
- # Port was closed\u2014increment miss counter
158
- ((missed+=1))
159
- # If closed twice in a row, give up immediately
160
- if [ "$missed" -ge 2 ]; then
161
- exit 1
162
- fi
163
- fi
164
- # Wait before next cycle
165
- sleep ${retryFrequencySeconds}
166
- done
167
- `;
168
- const childProcess = (0, import_node_child_process.spawn)("bash", ["-c", bashScript], {
169
- stdio: "ignore",
170
- detached: true
171
- });
172
- childProcess.unref();
106
+ // src/client.ts
107
+ var import_mixpart = require("mixpart");
108
+
109
+ // src/oidc.ts
110
+ function getVercelOidcToken() {
111
+ const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
112
+ const fromSymbol = globalThis;
113
+ const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
114
+ const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
115
+ if (!token) {
116
+ return null;
117
+ }
118
+ return token;
173
119
  }
174
120
 
175
121
  // src/types.ts
@@ -187,16 +133,6 @@ var MessageNotAvailableError = class extends Error {
187
133
  this.name = "MessageNotAvailableError";
188
134
  }
189
135
  };
190
- var FifoOrderingViolationError = class extends Error {
191
- nextMessageId;
192
- constructor(messageId, nextMessageId, reason) {
193
- super(
194
- `FIFO ordering violation for message ${messageId}: ${reason}. Process message ${nextMessageId} first.`
195
- );
196
- this.name = "FifoOrderingViolationError";
197
- this.nextMessageId = nextMessageId;
198
- }
199
- };
200
136
  var MessageCorruptedError = class extends Error {
201
137
  constructor(messageId, reason) {
202
138
  super(`Message ${messageId} is corrupted: ${reason}`);
@@ -238,16 +174,6 @@ var BadRequestError = class extends Error {
238
174
  this.name = "BadRequestError";
239
175
  }
240
176
  };
241
- var FailedDependencyError = class extends Error {
242
- nextMessageId;
243
- constructor(messageId, nextMessageId) {
244
- super(
245
- `Failed dependency: FIFO ordering violation for message ${messageId}. Must process message ${nextMessageId} first.`
246
- );
247
- this.name = "FailedDependencyError";
248
- this.nextMessageId = nextMessageId;
249
- }
250
- };
251
177
  var InternalServerError = class extends Error {
252
178
  constructor(message = "Unexpected server error") {
253
179
  super(message);
@@ -260,12 +186,6 @@ var InvalidLimitError = class extends Error {
260
186
  this.name = "InvalidLimitError";
261
187
  }
262
188
  };
263
- var InvalidCallbackError = class extends Error {
264
- constructor(message) {
265
- super(message);
266
- this.name = "InvalidCallbackError";
267
- }
268
- };
269
189
 
270
190
  // src/client.ts
271
191
  async function consumeStream(stream) {
@@ -295,40 +215,33 @@ function parseQueueHeaders(headers) {
295
215
  return {
296
216
  messageId,
297
217
  deliveryCount,
298
- timestamp,
218
+ createdAt: new Date(timestamp),
299
219
  contentType,
300
220
  ticket
301
221
  };
302
222
  }
303
- var QueueClient = class _QueueClient {
223
+ var QueueClient = class {
304
224
  baseUrl;
225
+ basePath;
305
226
  token;
306
227
  /**
307
228
  * Create a new Vercel Queue Service client
308
- * @param options Client configuration options
229
+ * @param options Client configuration options (optional - will auto-detect Vercel Function environment)
309
230
  */
310
- constructor(options) {
311
- this.baseUrl = options.baseUrl || "https://vqs.vercel.sh";
312
- this.token = options.token;
313
- }
314
- /**
315
- * Create a QueueClient automatically configured for Vercel Functions
316
- * This method automatically retrieves the OIDC token from the Vercel Function environment
317
- * Always creates a fresh instance since OIDC tokens expire after 15 minutes
318
- * @param baseUrl Optional base URL override
319
- * @returns Promise resolving to a new QueueClient instance
320
- */
321
- static async fromVercelFunction(baseUrl) {
322
- const token = await getVercelOidcToken();
323
- if (!token) {
324
- throw new Error(
325
- "Failed to get OIDC token from Vercel Functions. Make sure you are running in a Vercel Function environment."
326
- );
231
+ constructor(options = {}) {
232
+ this.baseUrl = options.baseUrl || "https://vercel-queue.com";
233
+ this.basePath = options.basePath || "/api/v2/messages";
234
+ if (options.token) {
235
+ this.token = options.token;
236
+ } else {
237
+ const token = getVercelOidcToken();
238
+ if (!token) {
239
+ throw new Error(
240
+ "Failed to get OIDC token from Vercel Functions. Make sure you are running in a Vercel Function environment, or provide a token explicitly.\n\nTo set up your environment:\n1. Link your project: 'vercel link'\n2. Pull environment variables: 'vercel env pull'\n3. Run with environment: 'dotenv -e .env.local -- your-command'"
241
+ );
242
+ }
243
+ this.token = token;
327
244
  }
328
- return new _QueueClient({
329
- token,
330
- baseUrl
331
- });
332
245
  }
333
246
  /**
334
247
  * Send a message to a queue
@@ -341,40 +254,23 @@ var QueueClient = class _QueueClient {
341
254
  * @throws {InternalServerError} When server encounters an error
342
255
  */
343
256
  async sendMessage(options, transport) {
344
- const { queueName, payload, idempotencyKey, retentionSeconds, callbacks } = options;
257
+ const { queueName, payload, idempotencyKey, retentionSeconds } = options;
345
258
  const headers = new Headers({
346
259
  Authorization: `Bearer ${this.token}`,
347
260
  "Vqs-Queue-Name": queueName,
348
261
  "Content-Type": transport.contentType
349
262
  });
263
+ if (process.env.VERCEL_DEPLOYMENT_ID) {
264
+ headers.set("Vqs-Deployment-Id", process.env.VERCEL_DEPLOYMENT_ID);
265
+ }
350
266
  if (idempotencyKey) {
351
267
  headers.set("Vqs-Idempotency-Key", idempotencyKey);
352
268
  }
353
269
  if (retentionSeconds !== void 0) {
354
270
  headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
355
271
  }
356
- let localhostCallbacks = [];
357
- if (callbacks) {
358
- const isDevelopment = process.env.NODE_ENV === "development";
359
- if (isDevelopment) {
360
- localhostCallbacks = processDevelopmentCallbacks(callbacks);
361
- } else {
362
- const endpoints = Object.entries(callbacks).map(
363
- ([group, config]) => `${group}=${Buffer.from(config.url).toString("base64")}`
364
- ).join(",");
365
- headers.set("Vqs-Callback-Url", endpoints);
366
- const delays = Object.entries(callbacks).filter(([, config]) => config.delay !== void 0).map(([group, config]) => `${group}=${config.delay}`).join(",");
367
- if (delays) {
368
- headers.set("Vqs-Callback-Delay", delays);
369
- }
370
- const frequencies = Object.entries(callbacks).filter(([, config]) => config.frequency !== void 0).map(([group, config]) => `${group}=${config.frequency}`).join(",");
371
- if (frequencies) {
372
- headers.set("Vqs-Callback-Frequency", frequencies);
373
- }
374
- }
375
- }
376
272
  const body = transport.serialize(payload);
377
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
273
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
378
274
  method: "POST",
379
275
  headers,
380
276
  body
@@ -403,9 +299,6 @@ var QueueClient = class _QueueClient {
403
299
  );
404
300
  }
405
301
  const responseData = await response.json();
406
- if (localhostCallbacks.length > 0) {
407
- fireLocalhostCallbacks(localhostCallbacks, queueName, responseData);
408
- }
409
302
  return responseData;
410
303
  }
411
304
  /**
@@ -415,7 +308,7 @@ var QueueClient = class _QueueClient {
415
308
  * @returns AsyncGenerator that yields messages as they arrive
416
309
  * @throws {InvalidLimitError} When limit parameter is not between 1 and 10
417
310
  * @throws {QueueEmptyError} When no messages are available (204)
418
- * @throws {MessageLockedError} When FIFO queue has locked messages (423)
311
+ * @throws {MessageLockedError} When messages are temporarily locked (423)
419
312
  * @throws {BadRequestError} When request parameters are invalid
420
313
  * @throws {UnauthorizedError} When authentication fails
421
314
  * @throws {ForbiddenError} When access is denied (environment mismatch)
@@ -441,7 +334,7 @@ var QueueClient = class _QueueClient {
441
334
  if (limit !== void 0) {
442
335
  headers.set("Vqs-Limit", limit.toString());
443
336
  }
444
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
337
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
445
338
  method: "GET",
446
339
  headers
447
340
  });
@@ -466,7 +359,7 @@ var QueueClient = class _QueueClient {
466
359
  const parsed = parseInt(retryAfterHeader, 10);
467
360
  retryAfter = isNaN(parsed) ? void 0 : parsed;
468
361
  }
469
- throw new MessageLockedError("next message in FIFO queue", retryAfter);
362
+ throw new MessageLockedError("next message", retryAfter);
470
363
  }
471
364
  if (response.status >= 500) {
472
365
  throw new InternalServerError(
@@ -523,7 +416,7 @@ var QueueClient = class _QueueClient {
523
416
  headers.set("Vqs-Skip-Payload", "1");
524
417
  }
525
418
  const response = await fetch(
526
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
419
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
527
420
  {
528
421
  method: "GET",
529
422
  headers
@@ -552,37 +445,7 @@ var QueueClient = class _QueueClient {
552
445
  }
553
446
  throw new MessageLockedError(messageId, retryAfter);
554
447
  }
555
- if (response.status === 424) {
556
- try {
557
- const errorData = await response.json();
558
- if (errorData.meta?.nextMessageId) {
559
- throw new FailedDependencyError(
560
- messageId,
561
- errorData.meta.nextMessageId
562
- );
563
- }
564
- } catch (parseError) {
565
- if (parseError instanceof FailedDependencyError) {
566
- throw parseError;
567
- }
568
- }
569
- throw new MessageNotAvailableError(
570
- messageId,
571
- "FIFO ordering violation"
572
- );
573
- }
574
448
  if (response.status === 409) {
575
- try {
576
- const errorData = await response.json();
577
- if (errorData.nextMessageId) {
578
- throw new FifoOrderingViolationError(
579
- messageId,
580
- errorData.nextMessageId,
581
- errorData.error
582
- );
583
- }
584
- } catch (parseError) {
585
- }
586
449
  throw new MessageNotAvailableError(messageId);
587
450
  }
588
451
  if (response.status >= 500) {
@@ -662,7 +525,7 @@ var QueueClient = class _QueueClient {
662
525
  async deleteMessage(options) {
663
526
  const { queueName, consumerGroup, messageId, ticket } = options;
664
527
  const response = await fetch(
665
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
528
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
666
529
  {
667
530
  method: "DELETE",
668
531
  headers: new Headers({
@@ -723,7 +586,7 @@ var QueueClient = class _QueueClient {
723
586
  visibilityTimeoutSeconds
724
587
  } = options;
725
588
  const response = await fetch(
726
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
589
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
727
590
  {
728
591
  method: "PATCH",
729
592
  headers: new Headers({
@@ -769,81 +632,336 @@ var QueueClient = class _QueueClient {
769
632
  }
770
633
  };
771
634
 
772
- // src/transports.ts
773
- var JsonTransport = class {
774
- contentType = "application/json";
775
- serialize(value) {
776
- return Buffer.from(JSON.stringify(value), "utf8");
635
+ // src/callback.ts
636
+ function validateWildcardPattern(pattern) {
637
+ const firstIndex = pattern.indexOf("*");
638
+ const lastIndex = pattern.lastIndexOf("*");
639
+ if (firstIndex !== lastIndex) {
640
+ return false;
777
641
  }
778
- async deserialize(stream) {
779
- const reader = stream.getReader();
780
- const chunks = [];
781
- try {
782
- while (true) {
783
- const { done, value } = await reader.read();
784
- if (done) break;
785
- chunks.push(value);
642
+ if (firstIndex === -1) {
643
+ return false;
644
+ }
645
+ if (firstIndex !== pattern.length - 1) {
646
+ return false;
647
+ }
648
+ return true;
649
+ }
650
+ function matchesWildcardPattern(topicName, pattern) {
651
+ const prefix = pattern.slice(0, -1);
652
+ return topicName.startsWith(prefix);
653
+ }
654
+ function findTopicHandler(queueName, handlers) {
655
+ const exactHandler = handlers[queueName];
656
+ if (exactHandler) {
657
+ return exactHandler;
658
+ }
659
+ for (const pattern in handlers) {
660
+ if (pattern.includes("*") && matchesWildcardPattern(queueName, pattern)) {
661
+ return handlers[pattern];
662
+ }
663
+ }
664
+ return null;
665
+ }
666
+ async function parseCallback(request) {
667
+ const contentType = request.headers.get("content-type");
668
+ if (!contentType || !contentType.includes("application/cloudevents+json")) {
669
+ throw new Error(
670
+ "Invalid content type: expected 'application/cloudevents+json'"
671
+ );
672
+ }
673
+ let cloudEvent;
674
+ try {
675
+ cloudEvent = await request.json();
676
+ } catch (error) {
677
+ throw new Error("Failed to parse CloudEvent from request body");
678
+ }
679
+ if (!cloudEvent.type || !cloudEvent.source || !cloudEvent.id || typeof cloudEvent.data !== "object" || cloudEvent.data == null) {
680
+ throw new Error("Invalid CloudEvent: missing required fields");
681
+ }
682
+ if (cloudEvent.type !== "com.vercel.queue.v1beta") {
683
+ throw new Error(
684
+ `Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`
685
+ );
686
+ }
687
+ const missingFields = [];
688
+ if (!("queueName" in cloudEvent.data)) missingFields.push("queueName");
689
+ if (!("consumerGroup" in cloudEvent.data))
690
+ missingFields.push("consumerGroup");
691
+ if (!("messageId" in cloudEvent.data)) missingFields.push("messageId");
692
+ if (missingFields.length > 0) {
693
+ throw new Error(
694
+ `Missing required CloudEvent data fields: ${missingFields.join(", ")}`
695
+ );
696
+ }
697
+ const { messageId, queueName, consumerGroup } = cloudEvent.data;
698
+ return {
699
+ queueName,
700
+ consumerGroup,
701
+ messageId
702
+ };
703
+ }
704
+ function handleCallback(handlers) {
705
+ for (const topicPattern in handlers) {
706
+ if (topicPattern.includes("*")) {
707
+ if (!validateWildcardPattern(topicPattern)) {
708
+ throw new Error(
709
+ `Invalid wildcard pattern "${topicPattern}": * may only appear once and must be at the end of the topic name`
710
+ );
786
711
  }
787
- } finally {
788
- reader.releaseLock();
789
712
  }
790
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
791
- const buffer = new Uint8Array(totalLength);
792
- let offset = 0;
793
- for (const chunk of chunks) {
794
- buffer.set(chunk, offset);
795
- offset += chunk.length;
713
+ }
714
+ const routeHandler = async (request) => {
715
+ try {
716
+ const { queueName, consumerGroup, messageId } = await parseCallback(request);
717
+ const topicHandler = findTopicHandler(queueName, handlers);
718
+ if (!topicHandler) {
719
+ const availableTopics = Object.keys(handlers).join(", ");
720
+ return Response.json(
721
+ {
722
+ error: `No handler found for topic: ${queueName}`,
723
+ availableTopics
724
+ },
725
+ { status: 404 }
726
+ );
727
+ }
728
+ const consumerGroupHandler = topicHandler[consumerGroup];
729
+ if (!consumerGroupHandler) {
730
+ const availableGroups = Object.keys(topicHandler).join(", ");
731
+ return Response.json(
732
+ {
733
+ error: `No handler found for consumer group "${consumerGroup}" in topic "${queueName}".`,
734
+ availableGroups
735
+ },
736
+ { status: 404 }
737
+ );
738
+ }
739
+ const client = new QueueClient();
740
+ const topic = new Topic(client, queueName);
741
+ const cg = topic.consumerGroup(consumerGroup);
742
+ await cg.consume(consumerGroupHandler, { messageId });
743
+ return Response.json({ status: "success" });
744
+ } catch (error) {
745
+ console.error("Queue callback error:", error);
746
+ if (error instanceof Error && (error.message.includes("Missing required CloudEvent data fields") || error.message.includes("Invalid CloudEvent") || error.message.includes("Invalid CloudEvent type") || error.message.includes("Invalid content type") || error.message.includes("Failed to parse CloudEvent"))) {
747
+ return Response.json({ error: error.message }, { status: 400 });
748
+ }
749
+ return Response.json(
750
+ { error: "Failed to process queue message" },
751
+ { status: 500 }
752
+ );
796
753
  }
797
- return JSON.parse(Buffer.from(buffer).toString("utf8"));
754
+ };
755
+ if (isDevMode()) {
756
+ registerDevRouteHandler(routeHandler, handlers);
798
757
  }
799
- };
800
- var BufferTransport = class {
801
- contentType = "application/octet-stream";
802
- serialize(value) {
803
- return value;
758
+ return routeHandler;
759
+ }
760
+
761
+ // src/dev.ts
762
+ var devRouteHandlers = /* @__PURE__ */ new Map();
763
+ var wildcardRouteHandlers = /* @__PURE__ */ new Map();
764
+ var routeHandlerKeys = /* @__PURE__ */ new WeakMap();
765
+ function cleanupDeadRefs(key, refs) {
766
+ const aliveRefs = refs.filter((ref) => ref.deref() !== void 0);
767
+ if (aliveRefs.length === 0) {
768
+ wildcardRouteHandlers.delete(key);
769
+ } else if (aliveRefs.length < refs.length) {
770
+ wildcardRouteHandlers.set(key, aliveRefs);
804
771
  }
805
- async deserialize(stream) {
806
- const reader = stream.getReader();
807
- const chunks = [];
808
- try {
809
- while (true) {
810
- const { done, value } = await reader.read();
811
- if (done) break;
812
- chunks.push(value);
772
+ }
773
+ function isDevMode() {
774
+ return process.env.NODE_ENV === "development";
775
+ }
776
+ function registerDevRouteHandler(routeHandler, handlers) {
777
+ const existingKeys = routeHandlerKeys.get(routeHandler);
778
+ if (existingKeys) {
779
+ const newKeys = /* @__PURE__ */ new Set();
780
+ for (const topicName in handlers) {
781
+ for (const consumerGroup in handlers[topicName]) {
782
+ newKeys.add(`${topicName}:${consumerGroup}`);
813
783
  }
814
- } finally {
815
- reader.releaseLock();
816
784
  }
817
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
818
- const buffer = new Uint8Array(totalLength);
819
- let offset = 0;
820
- for (const chunk of chunks) {
821
- buffer.set(chunk, offset);
822
- offset += chunk.length;
785
+ for (const key of existingKeys) {
786
+ if (!newKeys.has(key)) {
787
+ const [topicPattern] = key.split(":");
788
+ if (topicPattern.includes("*")) {
789
+ const refs = wildcardRouteHandlers.get(key);
790
+ if (refs) {
791
+ const filteredRefs = refs.filter(
792
+ (ref) => ref.deref() !== routeHandler
793
+ );
794
+ if (filteredRefs.length === 0) {
795
+ wildcardRouteHandlers.delete(key);
796
+ } else {
797
+ wildcardRouteHandlers.set(key, filteredRefs);
798
+ }
799
+ }
800
+ } else {
801
+ devRouteHandlers.delete(key);
802
+ }
803
+ }
823
804
  }
824
- return Buffer.from(buffer);
825
805
  }
826
- };
827
- var StreamTransport = class {
828
- contentType = "application/octet-stream";
829
- serialize(value) {
830
- return value;
806
+ const keys = /* @__PURE__ */ new Set();
807
+ for (const topicName in handlers) {
808
+ for (const consumerGroup in handlers[topicName]) {
809
+ const key = `${topicName}:${consumerGroup}`;
810
+ keys.add(key);
811
+ if (topicName.includes("*")) {
812
+ const weakRef = new WeakRef(routeHandler);
813
+ const existing = wildcardRouteHandlers.get(key) || [];
814
+ cleanupDeadRefs(key, existing);
815
+ const cleanedRefs = wildcardRouteHandlers.get(key) || [];
816
+ cleanedRefs.push(weakRef);
817
+ wildcardRouteHandlers.set(key, cleanedRefs);
818
+ } else {
819
+ devRouteHandlers.set(key, {
820
+ routeHandler,
821
+ topicPattern: topicName
822
+ });
823
+ }
824
+ }
831
825
  }
832
- async deserialize(stream) {
833
- return stream;
826
+ routeHandlerKeys.set(routeHandler, keys);
827
+ }
828
+ function findRouteHandlersForTopic(topicName) {
829
+ const handlersMap = /* @__PURE__ */ new Map();
830
+ for (const [
831
+ key,
832
+ { routeHandler, topicPattern }
833
+ ] of devRouteHandlers.entries()) {
834
+ const [_, consumerGroup] = key.split(":");
835
+ if (topicPattern === topicName) {
836
+ if (!handlersMap.has(routeHandler)) {
837
+ handlersMap.set(routeHandler, /* @__PURE__ */ new Set());
838
+ }
839
+ handlersMap.get(routeHandler).add(consumerGroup);
840
+ }
834
841
  }
835
- async finalize(payload) {
836
- const reader = payload.getReader();
837
- try {
838
- while (true) {
839
- const { done } = await reader.read();
840
- if (done) break;
842
+ for (const [key, refs] of wildcardRouteHandlers.entries()) {
843
+ const [pattern, consumerGroup] = key.split(":");
844
+ if (matchesWildcardPattern(topicName, pattern)) {
845
+ cleanupDeadRefs(key, refs);
846
+ const cleanedRefs = wildcardRouteHandlers.get(key) || [];
847
+ for (const ref of cleanedRefs) {
848
+ const routeHandler = ref.deref();
849
+ if (routeHandler) {
850
+ if (!handlersMap.has(routeHandler)) {
851
+ handlersMap.set(routeHandler, /* @__PURE__ */ new Set());
852
+ }
853
+ handlersMap.get(routeHandler).add(consumerGroup);
854
+ }
841
855
  }
842
- } finally {
843
- reader.releaseLock();
844
856
  }
845
857
  }
846
- };
858
+ return handlersMap;
859
+ }
860
+ function createMockCloudEventRequest(topicName, consumerGroup, messageId) {
861
+ const cloudEvent = {
862
+ type: "com.vercel.queue.v1beta",
863
+ source: `/topic/${topicName}/consumer/${consumerGroup}`,
864
+ id: messageId,
865
+ datacontenttype: "application/json",
866
+ data: {
867
+ messageId,
868
+ queueName: topicName,
869
+ consumerGroup
870
+ },
871
+ time: (/* @__PURE__ */ new Date()).toISOString(),
872
+ specversion: "1.0"
873
+ };
874
+ return new Request("https://localhost/api/queue/callback", {
875
+ method: "POST",
876
+ headers: {
877
+ "Content-Type": "application/cloudevents+json"
878
+ },
879
+ body: JSON.stringify(cloudEvent)
880
+ });
881
+ }
882
+ var DEV_CALLBACK_DELAY = 1e3;
883
+ function scheduleDevTimeout(topicName, messageId, timeoutSeconds) {
884
+ console.log(
885
+ `[Dev Mode] Message ${messageId} timed out for ${timeoutSeconds}s, will re-trigger`
886
+ );
887
+ setTimeout(
888
+ () => {
889
+ console.log(
890
+ `[Dev Mode] Re-triggering callback for timed-out message ${messageId}`
891
+ );
892
+ triggerDevCallbacks(topicName, messageId);
893
+ },
894
+ timeoutSeconds * 1e3 + DEV_CALLBACK_DELAY
895
+ );
896
+ }
897
+ function triggerDevCallbacks(topicName, messageId) {
898
+ const handlersMap = findRouteHandlersForTopic(topicName);
899
+ if (handlersMap.size === 0) {
900
+ return;
901
+ }
902
+ const consumerGroups = Array.from(
903
+ new Set(
904
+ Array.from(handlersMap.values()).flatMap((groups) => Array.from(groups))
905
+ )
906
+ );
907
+ console.log(
908
+ `[Dev Mode] Triggering local callbacks for topic "${topicName}" \u2192 consumers: ${consumerGroups.join(", ")}`
909
+ );
910
+ setTimeout(async () => {
911
+ for (const [routeHandler, consumerGroups2] of handlersMap.entries()) {
912
+ for (const consumerGroup of consumerGroups2) {
913
+ try {
914
+ const request = createMockCloudEventRequest(
915
+ topicName,
916
+ consumerGroup,
917
+ messageId
918
+ );
919
+ const response = await routeHandler(request);
920
+ if (response.ok) {
921
+ try {
922
+ const responseData = await response.json();
923
+ if (responseData.status === "success") {
924
+ console.log(
925
+ `[Dev Mode] Message processed for ${topicName}/${consumerGroup}`
926
+ );
927
+ }
928
+ } catch (jsonError) {
929
+ console.error(
930
+ `[Dev Mode] Failed to parse success response for ${topicName}/${consumerGroup}:`,
931
+ jsonError
932
+ );
933
+ }
934
+ } else {
935
+ try {
936
+ const errorData = await response.json();
937
+ console.error(
938
+ `[Dev Mode] Failed to process message for ${topicName}/${consumerGroup}:`,
939
+ errorData.error || response.statusText
940
+ );
941
+ } catch (jsonError) {
942
+ console.error(
943
+ `[Dev Mode] Failed to process message for ${topicName}/${consumerGroup}:`,
944
+ response.statusText
945
+ );
946
+ }
947
+ }
948
+ } catch (error) {
949
+ console.error(
950
+ `[Dev Mode] Error triggering callback for ${topicName}/${consumerGroup}:`,
951
+ error
952
+ );
953
+ }
954
+ }
955
+ }
956
+ }, DEV_CALLBACK_DELAY);
957
+ }
958
+ function clearDevHandlers() {
959
+ devRouteHandlers.clear();
960
+ wildcardRouteHandlers.clear();
961
+ }
962
+ if (process.env.NODE_ENV === "test" || process.env.VITEST) {
963
+ globalThis.__clearDevHandlers = clearDevHandlers;
964
+ }
847
965
 
848
966
  // src/consumer-group.ts
849
967
  var ConsumerGroup = class {
@@ -944,7 +1062,13 @@ var ConsumerGroup = class {
944
1062
  message.ticket
945
1063
  );
946
1064
  try {
947
- const result = await handler(message);
1065
+ const result = await handler(message.payload, {
1066
+ messageId: message.messageId,
1067
+ deliveryCount: message.deliveryCount,
1068
+ createdAt: message.createdAt,
1069
+ topicName: this.topicName,
1070
+ consumerGroup: this.consumerGroupName
1071
+ });
948
1072
  await stopExtension();
949
1073
  if (result && "timeoutSeconds" in result) {
950
1074
  await this.client.changeVisibility({
@@ -954,6 +1078,13 @@ var ConsumerGroup = class {
954
1078
  ticket: message.ticket,
955
1079
  visibilityTimeoutSeconds: result.timeoutSeconds
956
1080
  });
1081
+ if (isDevMode()) {
1082
+ scheduleDevTimeout(
1083
+ this.topicName,
1084
+ message.messageId,
1085
+ result.timeoutSeconds
1086
+ );
1087
+ }
957
1088
  } else {
958
1089
  await this.client.deleteMessage({
959
1090
  queueName: this.topicName,
@@ -974,219 +1105,58 @@ var ConsumerGroup = class {
974
1105
  throw error;
975
1106
  }
976
1107
  }
977
- /**
978
- * Start continuous processing of messages from the topic
979
- * @param signal AbortSignal to control when to stop processing
980
- * @param handler Function to process each message
981
- * @param options Processing options
982
- * @returns Promise that resolves when processing stops (due to signal or error)
983
- */
984
- async subscribe(signal, handler, options = {}) {
985
- const pollingInterval = options.pollingInterval || 1e3;
986
- while (!signal.aborted) {
987
- try {
988
- for await (const message of this.client.receiveMessages(
1108
+ async consume(handler, options) {
1109
+ if (options?.messageId) {
1110
+ if (options.skipPayload) {
1111
+ const response = await this.client.receiveMessageById(
989
1112
  {
990
1113
  queueName: this.topicName,
991
1114
  consumerGroup: this.consumerGroupName,
1115
+ messageId: options.messageId,
992
1116
  visibilityTimeoutSeconds: this.visibilityTimeout,
993
- limit: 1
994
- // Always process one message at a time
1117
+ skipPayload: true
995
1118
  },
996
1119
  this.transport
997
- )) {
998
- if (signal.aborted) {
999
- break;
1000
- }
1001
- try {
1002
- await this.processMessage(message, handler);
1003
- } catch (error) {
1004
- console.error("Error processing message:", error);
1005
- }
1006
- }
1007
- if (!signal.aborted) {
1008
- await new Promise((resolve) => {
1009
- const timeoutId = setTimeout(resolve, pollingInterval);
1010
- signal.addEventListener(
1011
- "abort",
1012
- () => {
1013
- clearTimeout(timeoutId);
1014
- resolve();
1015
- },
1016
- { once: true }
1017
- );
1018
- });
1019
- }
1020
- } catch (error) {
1021
- if (error instanceof QueueEmptyError) {
1022
- if (!signal.aborted) {
1023
- await new Promise((resolve) => {
1024
- const timeoutId = setTimeout(resolve, pollingInterval);
1025
- signal.addEventListener(
1026
- "abort",
1027
- () => {
1028
- clearTimeout(timeoutId);
1029
- resolve();
1030
- },
1031
- { once: true }
1032
- );
1033
- });
1034
- }
1035
- continue;
1036
- }
1037
- if (error instanceof MessageLockedError) {
1038
- const waitTime = error.retryAfter ? error.retryAfter * 1e3 : pollingInterval;
1039
- if (!signal.aborted) {
1040
- await new Promise((resolve) => {
1041
- const timeoutId = setTimeout(resolve, waitTime);
1042
- signal.addEventListener(
1043
- "abort",
1044
- () => {
1045
- clearTimeout(timeoutId);
1046
- resolve();
1047
- },
1048
- { once: true }
1049
- );
1050
- });
1051
- }
1052
- continue;
1053
- }
1054
- console.error("Error polling topic:", error);
1055
- throw error;
1120
+ );
1121
+ await this.processMessage(
1122
+ response.message,
1123
+ handler
1124
+ );
1125
+ } else {
1126
+ const response = await this.client.receiveMessageById(
1127
+ {
1128
+ queueName: this.topicName,
1129
+ consumerGroup: this.consumerGroupName,
1130
+ messageId: options.messageId,
1131
+ visibilityTimeoutSeconds: this.visibilityTimeout
1132
+ },
1133
+ this.transport
1134
+ );
1135
+ await this.processMessage(
1136
+ response.message,
1137
+ handler
1138
+ );
1139
+ }
1140
+ } else {
1141
+ let messageFound = false;
1142
+ for await (const message of this.client.receiveMessages(
1143
+ {
1144
+ queueName: this.topicName,
1145
+ consumerGroup: this.consumerGroupName,
1146
+ visibilityTimeoutSeconds: this.visibilityTimeout,
1147
+ limit: 1
1148
+ },
1149
+ this.transport
1150
+ )) {
1151
+ messageFound = true;
1152
+ await this.processMessage(message, handler);
1153
+ break;
1154
+ }
1155
+ if (!messageFound) {
1156
+ throw new Error("No messages available");
1056
1157
  }
1057
1158
  }
1058
1159
  }
1059
- /**
1060
- * Receive and process a specific message by its ID with full payload
1061
- * @param messageId The ID of the message to receive and process
1062
- * @param handler Function to process the message with full payload
1063
- * @returns Promise that resolves when the message is processed or rejects with specific errors
1064
- * @throws {MessageNotFoundError} When the message doesn't exist (404)
1065
- * @throws {MessageNotAvailableError} When the message exists but isn't available for processing (409)
1066
- * @throws {MessageLockedError} When the message is temporarily locked (423)
1067
- * @throws {FifoOrderingViolationError} When there's a FIFO ordering violation (409 with nextMessageId)
1068
- * @throws {FailedDependencyError} When FIFO ordering is violated (424)
1069
- * @throws {MessageCorruptedError} When the message data is corrupted
1070
- * @throws {BadRequestError} When request parameters are invalid
1071
- * @throws {UnauthorizedError} When authentication fails
1072
- * @throws {ForbiddenError} When access is denied
1073
- * @throws {InternalServerError} When server encounters an error
1074
- */
1075
- async receiveMessage(messageId, handler) {
1076
- const response = await this.client.receiveMessageById(
1077
- {
1078
- queueName: this.topicName,
1079
- consumerGroup: this.consumerGroupName,
1080
- messageId,
1081
- visibilityTimeoutSeconds: this.visibilityTimeout
1082
- },
1083
- this.transport
1084
- );
1085
- await this.processMessage(response.message, handler);
1086
- }
1087
- /**
1088
- * Receive and process the next available message from the queue
1089
- * @param handler Function to process the message
1090
- * @returns Promise that resolves when the message is processed or rejects with specific errors
1091
- * @throws {QueueEmptyError} When no messages are available in the queue (204)
1092
- * @throws {MessageLockedError} When the next message in a FIFO queue is locked (423)
1093
- * @throws {BadRequestError} When request parameters are invalid
1094
- * @throws {UnauthorizedError} When authentication fails
1095
- * @throws {ForbiddenError} When access is denied
1096
- * @throws {InternalServerError} When server encounters an error
1097
- */
1098
- async receiveNextMessage(handler) {
1099
- let messageFound = false;
1100
- for await (const message of this.client.receiveMessages(
1101
- {
1102
- queueName: this.topicName,
1103
- consumerGroup: this.consumerGroupName,
1104
- visibilityTimeoutSeconds: this.visibilityTimeout,
1105
- limit: 1
1106
- },
1107
- this.transport
1108
- )) {
1109
- messageFound = true;
1110
- await this.processMessage(message, handler);
1111
- break;
1112
- }
1113
- if (!messageFound) {
1114
- throw new Error("No messages available");
1115
- }
1116
- }
1117
- /**
1118
- * Receive and process multiple next available messages from the queue
1119
- * @param limit Number of messages to process (1-10)
1120
- * @param handler Function to process each message
1121
- * @returns Promise that resolves to an array of PromiseSettledResult (same as Promise.allSettled)
1122
- * @throws {InvalidLimitError} When limit parameter is not between 1 and 10
1123
- * @throws {QueueEmptyError} When no messages are available in the queue (204)
1124
- * @throws {MessageLockedError} When the next message in a FIFO queue is locked (423)
1125
- * @throws {BadRequestError} When request parameters are invalid
1126
- * @throws {UnauthorizedError} When authentication fails
1127
- * @throws {ForbiddenError} When access is denied
1128
- * @throws {InternalServerError} When server encounters an error
1129
- */
1130
- async receiveNextMessages(limit, handler) {
1131
- if (limit < 1 || limit > 10) {
1132
- throw new InvalidLimitError(limit);
1133
- }
1134
- const processingPromises = [];
1135
- let messageCount = 0;
1136
- for await (const message of this.client.receiveMessages(
1137
- {
1138
- queueName: this.topicName,
1139
- consumerGroup: this.consumerGroupName,
1140
- visibilityTimeoutSeconds: this.visibilityTimeout,
1141
- limit
1142
- },
1143
- this.transport
1144
- )) {
1145
- messageCount++;
1146
- const wrappedPromise = this.processMessage(message, handler).then(
1147
- (value) => ({
1148
- status: "fulfilled",
1149
- value
1150
- }),
1151
- (reason) => ({ status: "rejected", reason })
1152
- );
1153
- processingPromises.push(wrappedPromise);
1154
- }
1155
- if (messageCount === 0) {
1156
- throw new Error("No messages available");
1157
- }
1158
- const results = await Promise.all(processingPromises);
1159
- return results;
1160
- }
1161
- /**
1162
- * Handle a specific message by its ID without downloading the payload (metadata only)
1163
- * @param messageId The ID of the message to handle
1164
- * @param handler Function to process the message metadata (payload will be void)
1165
- * @returns Promise that resolves when the message is handled or rejects with specific errors
1166
- * @throws {MessageNotFoundError} When the message doesn't exist (404)
1167
- * @throws {MessageNotAvailableError} When the message exists but isn't available for processing (409)
1168
- * @throws {MessageLockedError} When the message is temporarily locked (423)
1169
- * @throws {FifoOrderingViolationError} When there's a FIFO ordering violation (409 with nextMessageId)
1170
- * @throws {FailedDependencyError} When FIFO ordering is violated (424)
1171
- * @throws {MessageCorruptedError} When the message data is corrupted
1172
- * @throws {BadRequestError} When request parameters are invalid
1173
- * @throws {UnauthorizedError} When authentication fails
1174
- * @throws {ForbiddenError} When access is denied
1175
- * @throws {InternalServerError} When server encounters an error
1176
- */
1177
- async handleMessage(messageId, handler) {
1178
- const response = await this.client.receiveMessageById(
1179
- {
1180
- queueName: this.topicName,
1181
- consumerGroup: this.consumerGroupName,
1182
- messageId,
1183
- visibilityTimeoutSeconds: this.visibilityTimeout,
1184
- skipPayload: true
1185
- },
1186
- this.transport
1187
- );
1188
- await this.processMessage(response.message, handler);
1189
- }
1190
1160
  /**
1191
1161
  * Get the consumer group name
1192
1162
  */
@@ -1233,11 +1203,13 @@ var Topic = class {
1233
1203
  queueName: this.topicName,
1234
1204
  payload,
1235
1205
  idempotencyKey: options?.idempotencyKey,
1236
- retentionSeconds: options?.retentionSeconds,
1237
- callbacks: options?.callbacks
1206
+ retentionSeconds: options?.retentionSeconds
1238
1207
  },
1239
1208
  this.transport
1240
1209
  );
1210
+ if (isDevMode()) {
1211
+ triggerDevCallbacks(this.topicName, result.messageId);
1212
+ }
1241
1213
  return { messageId: result.messageId };
1242
1214
  }
1243
1215
  /**
@@ -1273,54 +1245,60 @@ var Topic = class {
1273
1245
  };
1274
1246
 
1275
1247
  // src/factory.ts
1276
- function createTopic(client, topicName, transport) {
1277
- return new Topic(client, topicName, transport);
1248
+ async function send(topicName, payload, options) {
1249
+ const transport = options?.transport || new JsonTransport();
1250
+ const client = new QueueClient();
1251
+ const result = await client.sendMessage(
1252
+ {
1253
+ queueName: topicName,
1254
+ payload,
1255
+ idempotencyKey: options?.idempotencyKey,
1256
+ retentionSeconds: options?.retentionSeconds
1257
+ },
1258
+ transport
1259
+ );
1260
+ if (isDevMode()) {
1261
+ triggerDevCallbacks(topicName, result.messageId);
1262
+ }
1263
+ return { messageId: result.messageId };
1278
1264
  }
1279
-
1280
- // src/callback.ts
1281
- function parseCallbackRequest(request) {
1282
- const headers = request.headers;
1283
- const messageId = headers.get("Vqs-Message-Id");
1284
- const queueName = headers.get("Vqs-Queue-Name");
1285
- const consumerGroup = headers.get("Vqs-Consumer-Group");
1286
- const missingHeaders = [];
1287
- if (!messageId) missingHeaders.push("Vqs-Message-Id");
1288
- if (!queueName) missingHeaders.push("Vqs-Queue-Name");
1289
- if (!consumerGroup) missingHeaders.push("Vqs-Consumer-Group");
1290
- if (missingHeaders.length > 0) {
1291
- throw new InvalidCallbackError(
1292
- `Missing required queue callback headers: ${missingHeaders.join(", ")}`
1293
- );
1265
+ async function receive(topicName, consumerGroup, handler, options) {
1266
+ const transport = options?.transport || new JsonTransport();
1267
+ const client = new QueueClient();
1268
+ const topic = new Topic(client, topicName, transport);
1269
+ const { messageId, skipPayload, ...consumerGroupOptions } = options || {};
1270
+ const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);
1271
+ if (messageId) {
1272
+ if (skipPayload) {
1273
+ return consumer.consume(handler, {
1274
+ messageId,
1275
+ skipPayload: true
1276
+ });
1277
+ } else {
1278
+ return consumer.consume(handler, { messageId });
1279
+ }
1280
+ } else {
1281
+ return consumer.consume(handler);
1294
1282
  }
1295
- return {
1296
- messageId,
1297
- queueName,
1298
- consumerGroup
1299
- };
1300
1283
  }
1301
1284
  // Annotate the CommonJS export names for ESM import in node:
1302
1285
  0 && (module.exports = {
1303
1286
  BadRequestError,
1304
1287
  BufferTransport,
1305
- ConsumerGroup,
1306
- FailedDependencyError,
1307
- FifoOrderingViolationError,
1308
1288
  ForbiddenError,
1309
1289
  InternalServerError,
1310
- InvalidCallbackError,
1311
1290
  InvalidLimitError,
1312
1291
  JsonTransport,
1313
1292
  MessageCorruptedError,
1314
1293
  MessageLockedError,
1315
1294
  MessageNotAvailableError,
1316
1295
  MessageNotFoundError,
1317
- QueueClient,
1318
1296
  QueueEmptyError,
1319
1297
  StreamTransport,
1320
- Topic,
1321
1298
  UnauthorizedError,
1322
- createTopic,
1323
- getVercelOidcToken,
1324
- parseCallbackRequest
1299
+ handleCallback,
1300
+ parseCallback,
1301
+ receive,
1302
+ send
1325
1303
  });
1326
1304
  //# sourceMappingURL=index.js.map