@vercel/queue 0.0.0-alpha.33 → 0.0.0-alpha.34

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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/nextjs-pages.ts
@@ -27,8 +37,43 @@ module.exports = __toCommonJS(nextjs_pages_exports);
27
37
  // src/client.ts
28
38
  var import_mixpart = require("mixpart");
29
39
 
30
- // src/oidc.ts
31
- var import_oidc = require("@vercel/oidc");
40
+ // src/dev.ts
41
+ var fs = __toESM(require("fs"));
42
+ var path = __toESM(require("path"));
43
+
44
+ // src/transports.ts
45
+ async function streamToBuffer(stream) {
46
+ let totalLength = 0;
47
+ const reader = stream.getReader();
48
+ const chunks = [];
49
+ try {
50
+ while (true) {
51
+ const { done, value } = await reader.read();
52
+ if (done) break;
53
+ chunks.push(value);
54
+ totalLength += value.length;
55
+ }
56
+ } finally {
57
+ reader.releaseLock();
58
+ }
59
+ return Buffer.concat(chunks, totalLength);
60
+ }
61
+ var JsonTransport = class {
62
+ contentType = "application/json";
63
+ replacer;
64
+ reviver;
65
+ constructor(options = {}) {
66
+ this.replacer = options.replacer;
67
+ this.reviver = options.reviver;
68
+ }
69
+ serialize(value) {
70
+ return Buffer.from(JSON.stringify(value, this.replacer), "utf8");
71
+ }
72
+ async deserialize(stream) {
73
+ const buffer = await streamToBuffer(stream);
74
+ return JSON.parse(buffer.toString("utf8"), this.reviver);
75
+ }
76
+ };
32
77
 
33
78
  // src/types.ts
34
79
  var MessageNotFoundError = class extends Error {
@@ -59,15 +104,6 @@ var QueueEmptyError = class extends Error {
59
104
  this.name = "QueueEmptyError";
60
105
  }
61
106
  };
62
- var MessageLockedError = class extends Error {
63
- retryAfter;
64
- constructor(messageId, retryAfter) {
65
- const retryMessage = retryAfter ? ` Retry after ${retryAfter} seconds.` : " Try again later.";
66
- super(`Message ${messageId} is temporarily locked.${retryMessage}`);
67
- this.name = "MessageLockedError";
68
- this.retryAfter = retryAfter;
69
- }
70
- };
71
107
  var UnauthorizedError = class extends Error {
72
108
  constructor(message = "Missing or invalid authentication token") {
73
109
  super(message);
@@ -98,6 +134,263 @@ var InvalidLimitError = class extends Error {
98
134
  this.name = "InvalidLimitError";
99
135
  }
100
136
  };
137
+ var MessageAlreadyProcessedError = class extends Error {
138
+ constructor(messageId) {
139
+ super(`Message ${messageId} has already been processed`);
140
+ this.name = "MessageAlreadyProcessedError";
141
+ }
142
+ };
143
+ var ConcurrencyLimitError = class extends Error {
144
+ currentInflight;
145
+ maxConcurrency;
146
+ constructor(message = "Concurrency limit exceeded", currentInflight, maxConcurrency) {
147
+ super(message);
148
+ this.name = "ConcurrencyLimitError";
149
+ this.currentInflight = currentInflight;
150
+ this.maxConcurrency = maxConcurrency;
151
+ }
152
+ };
153
+ var DuplicateMessageError = class extends Error {
154
+ idempotencyKey;
155
+ constructor(message, idempotencyKey) {
156
+ super(message);
157
+ this.name = "DuplicateMessageError";
158
+ this.idempotencyKey = idempotencyKey;
159
+ }
160
+ };
161
+ var ConsumerDiscoveryError = class extends Error {
162
+ deploymentId;
163
+ constructor(message, deploymentId) {
164
+ super(message);
165
+ this.name = "ConsumerDiscoveryError";
166
+ this.deploymentId = deploymentId;
167
+ }
168
+ };
169
+ var ConsumerRegistryNotConfiguredError = class extends Error {
170
+ constructor(message = "Consumer registry not configured") {
171
+ super(message);
172
+ this.name = "ConsumerRegistryNotConfiguredError";
173
+ }
174
+ };
175
+
176
+ // src/dev.ts
177
+ var ROUTE_MAPPINGS_KEY = Symbol.for("@vercel/queue.devRouteMappings");
178
+ function filePathToUrlPath(filePath) {
179
+ let urlPath = filePath.replace(/^app\//, "/").replace(/^pages\//, "/").replace(/\/route\.(ts|js|tsx|jsx)$/, "").replace(/\.(ts|js|tsx|jsx)$/, "");
180
+ if (!urlPath.startsWith("/")) {
181
+ urlPath = "/" + urlPath;
182
+ }
183
+ return urlPath;
184
+ }
185
+ function getDevRouteMappings() {
186
+ const g = globalThis;
187
+ if (ROUTE_MAPPINGS_KEY in g) {
188
+ return g[ROUTE_MAPPINGS_KEY] ?? null;
189
+ }
190
+ try {
191
+ const vercelJsonPath = path.join(process.cwd(), "vercel.json");
192
+ if (!fs.existsSync(vercelJsonPath)) {
193
+ g[ROUTE_MAPPINGS_KEY] = null;
194
+ return null;
195
+ }
196
+ const vercelJson = JSON.parse(fs.readFileSync(vercelJsonPath, "utf-8"));
197
+ if (!vercelJson.functions) {
198
+ g[ROUTE_MAPPINGS_KEY] = null;
199
+ return null;
200
+ }
201
+ const mappings = [];
202
+ for (const [filePath, config] of Object.entries(vercelJson.functions)) {
203
+ if (!config.experimentalTriggers) continue;
204
+ for (const trigger of config.experimentalTriggers) {
205
+ if (trigger.type?.startsWith("queue/") && trigger.topic && trigger.consumer) {
206
+ mappings.push({
207
+ urlPath: filePathToUrlPath(filePath),
208
+ topic: trigger.topic,
209
+ consumer: trigger.consumer
210
+ });
211
+ }
212
+ }
213
+ }
214
+ g[ROUTE_MAPPINGS_KEY] = mappings.length > 0 ? mappings : null;
215
+ return g[ROUTE_MAPPINGS_KEY];
216
+ } catch (error) {
217
+ console.warn("[Dev Mode] Failed to read vercel.json:", error);
218
+ g[ROUTE_MAPPINGS_KEY] = null;
219
+ return null;
220
+ }
221
+ }
222
+ function findMatchingRoutes(topicName) {
223
+ const mappings = getDevRouteMappings();
224
+ if (!mappings) {
225
+ return [];
226
+ }
227
+ return mappings.filter((mapping) => {
228
+ if (mapping.topic.includes("*")) {
229
+ return matchesWildcardPattern(topicName, mapping.topic);
230
+ }
231
+ return mapping.topic === topicName;
232
+ });
233
+ }
234
+ function isDevMode() {
235
+ return process.env.NODE_ENV === "development";
236
+ }
237
+ var DEV_VISIBILITY_POLL_INTERVAL = 50;
238
+ var DEV_VISIBILITY_MAX_WAIT = 5e3;
239
+ var DEV_VISIBILITY_BACKOFF_MULTIPLIER = 2;
240
+ async function waitForMessageVisibility(topicName, consumerGroup, messageId) {
241
+ const client = new QueueClient();
242
+ const transport = new JsonTransport();
243
+ let elapsed = 0;
244
+ let interval = DEV_VISIBILITY_POLL_INTERVAL;
245
+ while (elapsed < DEV_VISIBILITY_MAX_WAIT) {
246
+ try {
247
+ await client.receiveMessageById(
248
+ {
249
+ queueName: topicName,
250
+ consumerGroup,
251
+ messageId,
252
+ visibilityTimeoutSeconds: 0
253
+ },
254
+ transport
255
+ );
256
+ return true;
257
+ } catch (error) {
258
+ if (error instanceof MessageNotFoundError) {
259
+ await new Promise((resolve) => setTimeout(resolve, interval));
260
+ elapsed += interval;
261
+ interval = Math.min(
262
+ interval * DEV_VISIBILITY_BACKOFF_MULTIPLIER,
263
+ DEV_VISIBILITY_MAX_WAIT - elapsed
264
+ );
265
+ continue;
266
+ }
267
+ if (error instanceof MessageAlreadyProcessedError) {
268
+ console.log(
269
+ `[Dev Mode] Message already processed: topic="${topicName}" messageId="${messageId}"`
270
+ );
271
+ return false;
272
+ }
273
+ console.error(
274
+ `[Dev Mode] Error polling for message visibility: topic="${topicName}" messageId="${messageId}"`,
275
+ error
276
+ );
277
+ return false;
278
+ }
279
+ }
280
+ console.warn(
281
+ `[Dev Mode] Message visibility timeout after ${DEV_VISIBILITY_MAX_WAIT}ms: topic="${topicName}" messageId="${messageId}"`
282
+ );
283
+ return false;
284
+ }
285
+ function triggerDevCallbacks(topicName, messageId, delaySeconds) {
286
+ if (delaySeconds && delaySeconds > 0) {
287
+ console.log(
288
+ `[Dev Mode] Message sent with delay: topic="${topicName}" messageId="${messageId}" delay=${delaySeconds}s`
289
+ );
290
+ setTimeout(() => {
291
+ triggerDevCallbacks(topicName, messageId);
292
+ }, delaySeconds * 1e3);
293
+ return;
294
+ }
295
+ console.log(
296
+ `[Dev Mode] Message sent: topic="${topicName}" messageId="${messageId}"`
297
+ );
298
+ const matchingRoutes = findMatchingRoutes(topicName);
299
+ if (matchingRoutes.length === 0) {
300
+ console.log(
301
+ `[Dev Mode] No matching routes in vercel.json for topic "${topicName}"`
302
+ );
303
+ return;
304
+ }
305
+ const consumerGroups = matchingRoutes.map((r) => r.consumer);
306
+ console.log(
307
+ `[Dev Mode] Scheduling callbacks for topic="${topicName}" messageId="${messageId}" \u2192 consumers: [${consumerGroups.join(", ")}]`
308
+ );
309
+ (async () => {
310
+ const firstRoute = matchingRoutes[0];
311
+ const isVisible = await waitForMessageVisibility(
312
+ topicName,
313
+ firstRoute.consumer,
314
+ messageId
315
+ );
316
+ if (!isVisible) {
317
+ console.warn(
318
+ `[Dev Mode] Skipping callbacks - message not visible: topic="${topicName}" messageId="${messageId}"`
319
+ );
320
+ return;
321
+ }
322
+ const port = process.env.PORT || 3e3;
323
+ const baseUrl = `http://localhost:${port}`;
324
+ for (const route of matchingRoutes) {
325
+ const url = `${baseUrl}${route.urlPath}`;
326
+ console.log(
327
+ `[Dev Mode] Invoking handler: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url}"`
328
+ );
329
+ const cloudEvent = {
330
+ type: "com.vercel.queue.v1beta",
331
+ source: `/topic/${topicName}/consumer/${route.consumer}`,
332
+ id: messageId,
333
+ datacontenttype: "application/json",
334
+ data: {
335
+ messageId,
336
+ queueName: topicName,
337
+ consumerGroup: route.consumer
338
+ },
339
+ time: (/* @__PURE__ */ new Date()).toISOString(),
340
+ specversion: "1.0"
341
+ };
342
+ try {
343
+ const response = await fetch(url, {
344
+ method: "POST",
345
+ headers: {
346
+ "Content-Type": "application/cloudevents+json"
347
+ },
348
+ body: JSON.stringify(cloudEvent)
349
+ });
350
+ if (response.ok) {
351
+ try {
352
+ const responseData = await response.json();
353
+ if (responseData.status === "success") {
354
+ console.log(
355
+ `[Dev Mode] \u2713 Message processed successfully: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}"`
356
+ );
357
+ }
358
+ } catch {
359
+ console.warn(
360
+ `[Dev Mode] Handler returned OK but response was not JSON: topic="${topicName}" consumer="${route.consumer}"`
361
+ );
362
+ }
363
+ } else {
364
+ try {
365
+ const errorData = await response.json();
366
+ console.error(
367
+ `[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" error="${errorData.error || response.statusText}"`
368
+ );
369
+ } catch {
370
+ console.error(
371
+ `[Dev Mode] \u2717 Handler failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" status=${response.status}`
372
+ );
373
+ }
374
+ }
375
+ } catch (error) {
376
+ console.error(
377
+ `[Dev Mode] \u2717 HTTP request failed: topic="${topicName}" consumer="${route.consumer}" messageId="${messageId}" url="${url}"`,
378
+ error
379
+ );
380
+ }
381
+ }
382
+ })();
383
+ }
384
+ function clearDevRouteMappings() {
385
+ const g = globalThis;
386
+ delete g[ROUTE_MAPPINGS_KEY];
387
+ }
388
+ if (process.env.NODE_ENV === "test" || process.env.VITEST) {
389
+ globalThis.__clearDevRouteMappings = clearDevRouteMappings;
390
+ }
391
+
392
+ // src/oidc.ts
393
+ var import_oidc = require("@vercel/oidc");
101
394
 
102
395
  // src/client.ts
103
396
  function isDebugEnabled() {
@@ -114,14 +407,6 @@ async function consumeStream(stream) {
114
407
  reader.releaseLock();
115
408
  }
116
409
  }
117
- function parseRetryAfter(headers) {
118
- const retryAfterHeader = headers.get("Retry-After");
119
- if (retryAfterHeader) {
120
- const parsed = parseInt(retryAfterHeader, 10);
121
- return Number.isNaN(parsed) ? void 0 : parsed;
122
- }
123
- return void 0;
124
- }
125
410
  function throwCommonHttpError(status, statusText, errorText, operation, badRequestDefault = "Invalid parameters") {
126
411
  if (status === 400) {
127
412
  throw new BadRequestError(errorText || badRequestDefault);
@@ -144,8 +429,8 @@ function parseQueueHeaders(headers) {
144
429
  const deliveryCountStr = headers.get("Vqs-Delivery-Count") || "0";
145
430
  const timestamp = headers.get("Vqs-Timestamp");
146
431
  const contentType = headers.get("Content-Type") || "application/octet-stream";
147
- const ticket = headers.get("Vqs-Ticket");
148
- if (!messageId || !timestamp || !ticket) {
432
+ const receiptHandle = headers.get("Vqs-Receipt-Handle");
433
+ if (!messageId || !timestamp || !receiptHandle) {
149
434
  return null;
150
435
  }
151
436
  const deliveryCount = parseInt(deliveryCountStr, 10);
@@ -157,7 +442,7 @@ function parseQueueHeaders(headers) {
157
442
  deliveryCount,
158
443
  createdAt: new Date(timestamp),
159
444
  contentType,
160
- ticket
445
+ receiptHandle
161
446
  };
162
447
  }
163
448
  var QueueClient = class {
@@ -165,15 +450,30 @@ var QueueClient = class {
165
450
  basePath;
166
451
  customHeaders;
167
452
  providedToken;
168
- /**
169
- * Create a new Vercel Queue Service client
170
- * @param options QueueClient configuration options
171
- */
453
+ defaultDeploymentId;
454
+ pinToDeployment;
172
455
  constructor(options = {}) {
173
456
  this.baseUrl = options.baseUrl || process.env.VERCEL_QUEUE_BASE_URL || "https://vercel-queue.com";
174
- this.basePath = options.basePath || process.env.VERCEL_QUEUE_BASE_PATH || "/api/v2/messages";
457
+ this.basePath = options.basePath || process.env.VERCEL_QUEUE_BASE_PATH || "/api/v3/topic";
175
458
  this.customHeaders = options.headers || {};
176
459
  this.providedToken = options.token;
460
+ this.defaultDeploymentId = options.deploymentId || process.env.VERCEL_DEPLOYMENT_ID;
461
+ this.pinToDeployment = options.pinToDeployment ?? true;
462
+ }
463
+ getSendDeploymentId() {
464
+ if (isDevMode()) {
465
+ return void 0;
466
+ }
467
+ if (this.pinToDeployment) {
468
+ return this.defaultDeploymentId;
469
+ }
470
+ return void 0;
471
+ }
472
+ getConsumeDeploymentId() {
473
+ if (isDevMode()) {
474
+ return void 0;
475
+ }
476
+ return this.defaultDeploymentId;
177
477
  }
178
478
  async getToken() {
179
479
  if (this.providedToken) {
@@ -187,10 +487,12 @@ var QueueClient = class {
187
487
  }
188
488
  return token;
189
489
  }
190
- /**
191
- * Internal fetch wrapper that automatically handles debug logging
192
- * when VERCEL_QUEUE_DEBUG is enabled
193
- */
490
+ buildUrl(queueName, ...pathSegments) {
491
+ const encodedQueue = encodeURIComponent(queueName);
492
+ const segments = pathSegments.map((s) => encodeURIComponent(s));
493
+ const path2 = segments.length > 0 ? "/" + segments.join("/") : "";
494
+ return `${this.baseUrl}${this.basePath}/${encodedQueue}${path2}`;
495
+ }
194
496
  async fetch(url, init) {
195
497
  const method = init.method || "GET";
196
498
  if (isDebugEnabled()) {
@@ -226,25 +528,20 @@ var QueueClient = class {
226
528
  }
227
529
  return response;
228
530
  }
229
- /**
230
- * Send a message to a queue
231
- * @param options Send message options
232
- * @param transport Serializer/deserializer for the payload
233
- * @returns Promise with the message ID
234
- * @throws {BadRequestError} When request parameters are invalid
235
- * @throws {UnauthorizedError} When authentication fails
236
- * @throws {ForbiddenError} When access is denied (environment mismatch)
237
- * @throws {InternalServerError} When server encounters an error
238
- */
239
531
  async sendMessage(options, transport) {
240
- const { queueName, payload, idempotencyKey, retentionSeconds } = options;
532
+ const {
533
+ queueName,
534
+ payload,
535
+ idempotencyKey,
536
+ retentionSeconds,
537
+ delaySeconds
538
+ } = options;
241
539
  const headers = new Headers({
242
540
  Authorization: `Bearer ${await this.getToken()}`,
243
- "Vqs-Queue-Name": queueName,
244
541
  "Content-Type": transport.contentType,
245
542
  ...this.customHeaders
246
543
  });
247
- const deploymentId = options.deploymentId || process.env.VERCEL_DEPLOYMENT_ID;
544
+ const deploymentId = this.getSendDeploymentId();
248
545
  if (deploymentId) {
249
546
  headers.set("Vqs-Deployment-Id", deploymentId);
250
547
  }
@@ -254,8 +551,12 @@ var QueueClient = class {
254
551
  if (retentionSeconds !== void 0) {
255
552
  headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
256
553
  }
257
- const body = transport.serialize(payload);
258
- const response = await this.fetch(`${this.baseUrl}${this.basePath}`, {
554
+ if (delaySeconds !== void 0) {
555
+ headers.set("Vqs-Delay-Seconds", delaySeconds.toString());
556
+ }
557
+ const serialized = transport.serialize(payload);
558
+ const body = Buffer.isBuffer(serialized) ? new Uint8Array(serialized) : serialized;
559
+ const response = await this.fetch(this.buildUrl(queueName), {
259
560
  method: "POST",
260
561
  body,
261
562
  headers
@@ -263,7 +564,21 @@ var QueueClient = class {
263
564
  if (!response.ok) {
264
565
  const errorText = await response.text();
265
566
  if (response.status === 409) {
266
- throw new Error("Duplicate idempotency key detected");
567
+ throw new DuplicateMessageError(
568
+ errorText || "Duplicate idempotency key detected",
569
+ idempotencyKey
570
+ );
571
+ }
572
+ if (response.status === 502) {
573
+ throw new ConsumerDiscoveryError(
574
+ errorText || "Consumer discovery failed",
575
+ deploymentId
576
+ );
577
+ }
578
+ if (response.status === 503) {
579
+ throw new ConsumerRegistryNotConfiguredError(
580
+ errorText || "Consumer registry not configured"
581
+ );
267
582
  }
268
583
  throwCommonHttpError(
269
584
  response.status,
@@ -275,53 +590,60 @@ var QueueClient = class {
275
590
  const responseData = await response.json();
276
591
  return responseData;
277
592
  }
278
- /**
279
- * Receive messages from a queue
280
- * @param options Receive messages options
281
- * @param transport Serializer/deserializer for the payload
282
- * @returns AsyncGenerator that yields messages as they arrive
283
- * @throws {InvalidLimitError} When limit parameter is not between 1 and 10
284
- * @throws {QueueEmptyError} When no messages are available (204)
285
- * @throws {MessageLockedError} When messages are temporarily locked (423)
286
- * @throws {BadRequestError} When request parameters are invalid
287
- * @throws {UnauthorizedError} When authentication fails
288
- * @throws {ForbiddenError} When access is denied (environment mismatch)
289
- * @throws {InternalServerError} When server encounters an error
290
- */
291
593
  async *receiveMessages(options, transport) {
292
- const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } = options;
594
+ const {
595
+ queueName,
596
+ consumerGroup,
597
+ visibilityTimeoutSeconds,
598
+ limit,
599
+ maxConcurrency
600
+ } = options;
293
601
  if (limit !== void 0 && (limit < 1 || limit > 10)) {
294
602
  throw new InvalidLimitError(limit);
295
603
  }
296
604
  const headers = new Headers({
297
605
  Authorization: `Bearer ${await this.getToken()}`,
298
- "Vqs-Queue-Name": queueName,
299
- "Vqs-Consumer-Group": consumerGroup,
300
606
  Accept: "multipart/mixed",
301
607
  ...this.customHeaders
302
608
  });
303
609
  if (visibilityTimeoutSeconds !== void 0) {
304
610
  headers.set(
305
- "Vqs-Visibility-Timeout",
611
+ "Vqs-Visibility-Timeout-Seconds",
306
612
  visibilityTimeoutSeconds.toString()
307
613
  );
308
614
  }
309
615
  if (limit !== void 0) {
310
- headers.set("Vqs-Limit", limit.toString());
616
+ headers.set("Vqs-Max-Messages", limit.toString());
311
617
  }
312
- const response = await this.fetch(`${this.baseUrl}${this.basePath}`, {
313
- method: "GET",
314
- headers
315
- });
618
+ if (maxConcurrency !== void 0) {
619
+ headers.set("Vqs-Max-Concurrency", maxConcurrency.toString());
620
+ }
621
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
622
+ if (effectiveDeploymentId) {
623
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
624
+ }
625
+ const response = await this.fetch(
626
+ this.buildUrl(queueName, "consumer", consumerGroup),
627
+ {
628
+ method: "POST",
629
+ headers
630
+ }
631
+ );
316
632
  if (response.status === 204) {
317
633
  throw new QueueEmptyError(queueName, consumerGroup);
318
634
  }
319
635
  if (!response.ok) {
320
636
  const errorText = await response.text();
321
- if (response.status === 423) {
322
- throw new MessageLockedError(
323
- "next message",
324
- parseRetryAfter(response.headers)
637
+ if (response.status === 429) {
638
+ let errorData = {};
639
+ try {
640
+ errorData = JSON.parse(errorText);
641
+ } catch {
642
+ }
643
+ throw new ConcurrencyLimitError(
644
+ errorData.error || "Concurrency limit exceeded or throttled",
645
+ errorData.currentInflight,
646
+ errorData.maxConcurrency
325
647
  );
326
648
  }
327
649
  throwCommonHttpError(
@@ -359,28 +681,30 @@ var QueueClient = class {
359
681
  consumerGroup,
360
682
  messageId,
361
683
  visibilityTimeoutSeconds,
362
- skipPayload
684
+ maxConcurrency
363
685
  } = options;
364
686
  const headers = new Headers({
365
687
  Authorization: `Bearer ${await this.getToken()}`,
366
- "Vqs-Queue-Name": queueName,
367
- "Vqs-Consumer-Group": consumerGroup,
368
688
  Accept: "multipart/mixed",
369
689
  ...this.customHeaders
370
690
  });
371
691
  if (visibilityTimeoutSeconds !== void 0) {
372
692
  headers.set(
373
- "Vqs-Visibility-Timeout",
693
+ "Vqs-Visibility-Timeout-Seconds",
374
694
  visibilityTimeoutSeconds.toString()
375
695
  );
376
696
  }
377
- if (skipPayload) {
378
- headers.set("Vqs-Skip-Payload", "1");
697
+ if (maxConcurrency !== void 0) {
698
+ headers.set("Vqs-Max-Concurrency", maxConcurrency.toString());
699
+ }
700
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
701
+ if (effectiveDeploymentId) {
702
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
379
703
  }
380
704
  const response = await this.fetch(
381
- `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
705
+ this.buildUrl(queueName, "consumer", consumerGroup, "id", messageId),
382
706
  {
383
- method: "GET",
707
+ method: "POST",
384
708
  headers
385
709
  }
386
710
  );
@@ -390,12 +714,32 @@ var QueueClient = class {
390
714
  throw new MessageNotFoundError(messageId);
391
715
  }
392
716
  if (response.status === 409) {
717
+ let errorData = {};
718
+ try {
719
+ errorData = JSON.parse(errorText);
720
+ } catch {
721
+ }
722
+ if (errorData.originalMessageId) {
723
+ throw new MessageNotAvailableError(
724
+ messageId,
725
+ `This message was a duplicate - use originalMessageId: ${errorData.originalMessageId}`
726
+ );
727
+ }
393
728
  throw new MessageNotAvailableError(messageId);
394
729
  }
395
- if (response.status === 423) {
396
- throw new MessageLockedError(
397
- messageId,
398
- parseRetryAfter(response.headers)
730
+ if (response.status === 410) {
731
+ throw new MessageAlreadyProcessedError(messageId);
732
+ }
733
+ if (response.status === 429) {
734
+ let errorData = {};
735
+ try {
736
+ errorData = JSON.parse(errorText);
737
+ } catch {
738
+ }
739
+ throw new ConcurrencyLimitError(
740
+ errorData.error || "Concurrency limit exceeded or throttled",
741
+ errorData.currentInflight,
742
+ errorData.maxConcurrency
399
743
  );
400
744
  }
401
745
  throwCommonHttpError(
@@ -405,95 +749,58 @@ var QueueClient = class {
405
749
  "receive message by ID"
406
750
  );
407
751
  }
408
- if (skipPayload && response.status === 204) {
409
- const parsedHeaders = parseQueueHeaders(response.headers);
752
+ for await (const multipartMessage of (0, import_mixpart.parseMultipartStream)(response)) {
753
+ const parsedHeaders = parseQueueHeaders(multipartMessage.headers);
410
754
  if (!parsedHeaders) {
755
+ await consumeStream(multipartMessage.payload);
411
756
  throw new MessageCorruptedError(
412
757
  messageId,
413
- "Missing required queue headers in 204 response"
758
+ "Missing required queue headers in response"
414
759
  );
415
760
  }
761
+ const deserializedPayload = await transport.deserialize(
762
+ multipartMessage.payload
763
+ );
416
764
  const message = {
417
765
  ...parsedHeaders,
418
- payload: void 0
766
+ payload: deserializedPayload
419
767
  };
420
768
  return { message };
421
769
  }
422
- if (!transport) {
423
- throw new Error("Transport is required when skipPayload is not true");
424
- }
425
- try {
426
- for await (const multipartMessage of (0, import_mixpart.parseMultipartStream)(response)) {
427
- try {
428
- const parsedHeaders = parseQueueHeaders(multipartMessage.headers);
429
- if (!parsedHeaders) {
430
- console.warn("Missing required queue headers in multipart part");
431
- await consumeStream(multipartMessage.payload);
432
- continue;
433
- }
434
- const deserializedPayload = await transport.deserialize(
435
- multipartMessage.payload
436
- );
437
- const message = {
438
- ...parsedHeaders,
439
- payload: deserializedPayload
440
- };
441
- return { message };
442
- } catch (error) {
443
- console.warn("Failed to deserialize message by ID:", error);
444
- await consumeStream(multipartMessage.payload);
445
- throw new MessageCorruptedError(
446
- messageId,
447
- `Failed to deserialize payload: ${error}`
448
- );
449
- }
450
- }
451
- } catch (error) {
452
- if (error instanceof MessageCorruptedError) {
453
- throw error;
454
- }
455
- throw new MessageCorruptedError(
456
- messageId,
457
- `Failed to parse multipart response: ${error}`
458
- );
459
- }
460
770
  throw new MessageNotFoundError(messageId);
461
771
  }
462
- /**
463
- * Delete a message (acknowledge processing)
464
- * @param options Delete message options
465
- * @returns Promise with delete status
466
- * @throws {MessageNotFoundError} When the message doesn't exist (404)
467
- * @throws {MessageNotAvailableError} When message can't be deleted (409)
468
- * @throws {BadRequestError} When ticket is missing or invalid (400)
469
- * @throws {UnauthorizedError} When authentication fails
470
- * @throws {ForbiddenError} When access is denied (environment mismatch)
471
- * @throws {InternalServerError} When server encounters an error
472
- */
473
772
  async deleteMessage(options) {
474
- const { queueName, consumerGroup, messageId, ticket } = options;
773
+ const { queueName, consumerGroup, receiptHandle } = options;
774
+ const headers = new Headers({
775
+ Authorization: `Bearer ${await this.getToken()}`,
776
+ ...this.customHeaders
777
+ });
778
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
779
+ if (effectiveDeploymentId) {
780
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
781
+ }
475
782
  const response = await this.fetch(
476
- `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
783
+ this.buildUrl(
784
+ queueName,
785
+ "consumer",
786
+ consumerGroup,
787
+ "lease",
788
+ receiptHandle
789
+ ),
477
790
  {
478
791
  method: "DELETE",
479
- headers: new Headers({
480
- Authorization: `Bearer ${await this.getToken()}`,
481
- "Vqs-Queue-Name": queueName,
482
- "Vqs-Consumer-Group": consumerGroup,
483
- "Vqs-Ticket": ticket,
484
- ...this.customHeaders
485
- })
792
+ headers
486
793
  }
487
794
  );
488
795
  if (!response.ok) {
489
796
  const errorText = await response.text();
490
797
  if (response.status === 404) {
491
- throw new MessageNotFoundError(messageId);
798
+ throw new MessageNotFoundError(receiptHandle);
492
799
  }
493
800
  if (response.status === 409) {
494
801
  throw new MessageNotAvailableError(
495
- messageId,
496
- errorText || "Invalid ticket, message not in correct state, or already processed"
802
+ receiptHandle,
803
+ errorText || "Invalid receipt handle, message not in correct state, or already processed"
497
804
  );
498
805
  }
499
806
  throwCommonHttpError(
@@ -501,53 +808,50 @@ var QueueClient = class {
501
808
  response.statusText,
502
809
  errorText,
503
810
  "delete message",
504
- "Missing or invalid ticket"
811
+ "Missing or invalid receipt handle"
505
812
  );
506
813
  }
507
814
  return { deleted: true };
508
815
  }
509
- /**
510
- * Change the visibility timeout of a message
511
- * @param options Change visibility options
512
- * @returns Promise with update status
513
- * @throws {MessageNotFoundError} When the message doesn't exist (404)
514
- * @throws {MessageNotAvailableError} When message can't be updated (409)
515
- * @throws {BadRequestError} When ticket is missing or visibility timeout invalid (400)
516
- * @throws {UnauthorizedError} When authentication fails
517
- * @throws {ForbiddenError} When access is denied (environment mismatch)
518
- * @throws {InternalServerError} When server encounters an error
519
- */
520
816
  async changeVisibility(options) {
521
817
  const {
522
818
  queueName,
523
819
  consumerGroup,
524
- messageId,
525
- ticket,
820
+ receiptHandle,
526
821
  visibilityTimeoutSeconds
527
822
  } = options;
823
+ const headers = new Headers({
824
+ Authorization: `Bearer ${await this.getToken()}`,
825
+ "Content-Type": "application/json",
826
+ ...this.customHeaders
827
+ });
828
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
829
+ if (effectiveDeploymentId) {
830
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
831
+ }
528
832
  const response = await this.fetch(
529
- `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
833
+ this.buildUrl(
834
+ queueName,
835
+ "consumer",
836
+ consumerGroup,
837
+ "lease",
838
+ receiptHandle
839
+ ),
530
840
  {
531
841
  method: "PATCH",
532
- headers: new Headers({
533
- Authorization: `Bearer ${await this.getToken()}`,
534
- "Vqs-Queue-Name": queueName,
535
- "Vqs-Consumer-Group": consumerGroup,
536
- "Vqs-Ticket": ticket,
537
- "Vqs-Visibility-Timeout": visibilityTimeoutSeconds.toString(),
538
- ...this.customHeaders
539
- })
842
+ headers,
843
+ body: JSON.stringify({ visibilityTimeoutSeconds })
540
844
  }
541
845
  );
542
846
  if (!response.ok) {
543
847
  const errorText = await response.text();
544
848
  if (response.status === 404) {
545
- throw new MessageNotFoundError(messageId);
849
+ throw new MessageNotFoundError(receiptHandle);
546
850
  }
547
851
  if (response.status === 409) {
548
852
  throw new MessageNotAvailableError(
549
- messageId,
550
- errorText || "Invalid ticket, message not in correct state, or already processed"
853
+ receiptHandle,
854
+ errorText || "Invalid receipt handle, message not in correct state, or already processed"
551
855
  );
552
856
  }
553
857
  throwCommonHttpError(
@@ -555,228 +859,72 @@ var QueueClient = class {
555
859
  response.statusText,
556
860
  errorText,
557
861
  "change visibility",
558
- "Missing ticket or invalid visibility timeout"
862
+ "Missing receipt handle or invalid visibility timeout"
559
863
  );
560
864
  }
561
- return { updated: true };
865
+ return { success: true };
562
866
  }
563
- };
564
-
565
- // src/transports.ts
566
- async function streamToBuffer(stream) {
567
- let totalLength = 0;
568
- const reader = stream.getReader();
569
- const chunks = [];
570
- try {
571
- while (true) {
572
- const { done, value } = await reader.read();
573
- if (done) break;
574
- chunks.push(value);
575
- totalLength += value.length;
867
+ /**
868
+ * Alternative endpoint for changing message visibility timeout.
869
+ * Uses the /visibility path suffix and expects visibilityTimeoutSeconds in the body.
870
+ * Functionally equivalent to changeVisibility but follows an alternative API pattern.
871
+ *
872
+ * @param options - Options for changing visibility
873
+ * @returns Promise resolving to change visibility response
874
+ */
875
+ async changeVisibilityAlt(options) {
876
+ const {
877
+ queueName,
878
+ consumerGroup,
879
+ receiptHandle,
880
+ visibilityTimeoutSeconds
881
+ } = options;
882
+ const headers = new Headers({
883
+ Authorization: `Bearer ${await this.getToken()}`,
884
+ "Content-Type": "application/json",
885
+ ...this.customHeaders
886
+ });
887
+ const effectiveDeploymentId = this.getConsumeDeploymentId();
888
+ if (effectiveDeploymentId) {
889
+ headers.set("Vqs-Deployment-Id", effectiveDeploymentId);
576
890
  }
577
- } finally {
578
- reader.releaseLock();
579
- }
580
- return Buffer.concat(chunks, totalLength);
581
- }
582
- var JsonTransport = class {
583
- contentType = "application/json";
584
- replacer;
585
- reviver;
586
- constructor(options = {}) {
587
- this.replacer = options.replacer;
588
- this.reviver = options.reviver;
589
- }
590
- serialize(value) {
591
- return Buffer.from(JSON.stringify(value, this.replacer), "utf8");
592
- }
593
- async deserialize(stream) {
594
- const buffer = await streamToBuffer(stream);
595
- return JSON.parse(buffer.toString("utf8"), this.reviver);
596
- }
597
- };
598
-
599
- // src/dev.ts
600
- var GLOBAL_KEY = Symbol.for("@vercel/queue.devHandlers");
601
- function getDevHandlerState() {
602
- const g = globalThis;
603
- if (!g[GLOBAL_KEY]) {
604
- g[GLOBAL_KEY] = {
605
- devRouteHandlers: /* @__PURE__ */ new Map(),
606
- wildcardRouteHandlers: /* @__PURE__ */ new Map()
607
- };
608
- }
609
- return g[GLOBAL_KEY];
610
- }
611
- var { devRouteHandlers, wildcardRouteHandlers } = getDevHandlerState();
612
- function cleanupDeadRefs(key, refs) {
613
- const aliveRefs = refs.filter((ref) => ref.deref() !== void 0);
614
- if (aliveRefs.length === 0) {
615
- wildcardRouteHandlers.delete(key);
616
- } else if (aliveRefs.length < refs.length) {
617
- wildcardRouteHandlers.set(key, aliveRefs);
618
- }
619
- }
620
- function isDevMode() {
621
- return process.env.NODE_ENV === "development";
622
- }
623
- function registerDevRouteHandler(routeHandler, handlers) {
624
- for (const topicName in handlers) {
625
- for (const consumerGroup in handlers[topicName]) {
626
- const key = `${topicName}:${consumerGroup}`;
627
- if (topicName.includes("*")) {
628
- const existing = wildcardRouteHandlers.get(key) || [];
629
- cleanupDeadRefs(key, existing);
630
- const cleanedRefs = wildcardRouteHandlers.get(key) || [];
631
- const weakRef = new WeakRef(routeHandler);
632
- cleanedRefs.push(weakRef);
633
- wildcardRouteHandlers.set(key, cleanedRefs);
634
- } else {
635
- devRouteHandlers.set(key, {
636
- routeHandler,
637
- topicPattern: topicName
638
- });
891
+ const response = await this.fetch(
892
+ this.buildUrl(
893
+ queueName,
894
+ "consumer",
895
+ consumerGroup,
896
+ "lease",
897
+ receiptHandle,
898
+ "visibility"
899
+ ),
900
+ {
901
+ method: "PATCH",
902
+ headers,
903
+ body: JSON.stringify({ visibilityTimeoutSeconds })
639
904
  }
640
- }
641
- }
642
- }
643
- function findRouteHandlersForTopic(topicName) {
644
- const handlersMap = /* @__PURE__ */ new Map();
645
- for (const [
646
- key,
647
- { routeHandler, topicPattern }
648
- ] of devRouteHandlers.entries()) {
649
- const [_, consumerGroup] = key.split(":");
650
- if (topicPattern === topicName) {
651
- if (!handlersMap.has(routeHandler)) {
652
- handlersMap.set(routeHandler, /* @__PURE__ */ new Set());
905
+ );
906
+ if (!response.ok) {
907
+ const errorText = await response.text();
908
+ if (response.status === 404) {
909
+ throw new MessageNotFoundError(receiptHandle);
653
910
  }
654
- handlersMap.get(routeHandler).add(consumerGroup);
655
- }
656
- }
657
- for (const [key, refs] of wildcardRouteHandlers.entries()) {
658
- const [pattern, consumerGroup] = key.split(":");
659
- if (matchesWildcardPattern(topicName, pattern)) {
660
- cleanupDeadRefs(key, refs);
661
- const cleanedRefs = wildcardRouteHandlers.get(key) || [];
662
- for (const ref of cleanedRefs) {
663
- const routeHandler = ref.deref();
664
- if (routeHandler) {
665
- if (!handlersMap.has(routeHandler)) {
666
- handlersMap.set(routeHandler, /* @__PURE__ */ new Set());
667
- }
668
- handlersMap.get(routeHandler).add(consumerGroup);
669
- }
911
+ if (response.status === 409) {
912
+ throw new MessageNotAvailableError(
913
+ receiptHandle,
914
+ errorText || "Invalid receipt handle, message not in correct state, or already processed"
915
+ );
670
916
  }
671
- }
672
- }
673
- return handlersMap;
674
- }
675
- function createMockCloudEventRequest(topicName, consumerGroup, messageId) {
676
- const cloudEvent = {
677
- type: "com.vercel.queue.v1beta",
678
- source: `/topic/${topicName}/consumer/${consumerGroup}`,
679
- id: messageId,
680
- datacontenttype: "application/json",
681
- data: {
682
- messageId,
683
- queueName: topicName,
684
- consumerGroup
685
- },
686
- time: (/* @__PURE__ */ new Date()).toISOString(),
687
- specversion: "1.0"
688
- };
689
- return new Request("https://localhost/api/queue/callback", {
690
- method: "POST",
691
- headers: {
692
- "Content-Type": "application/cloudevents+json"
693
- },
694
- body: JSON.stringify(cloudEvent)
695
- });
696
- }
697
- var DEV_CALLBACK_DELAY = 1e3;
698
- function scheduleDevTimeout(topicName, messageId, timeoutSeconds) {
699
- console.log(
700
- `[Dev Mode] Message ${messageId} timed out for ${timeoutSeconds}s, will re-trigger`
701
- );
702
- setTimeout(
703
- () => {
704
- console.log(
705
- `[Dev Mode] Re-triggering callback for timed-out message ${messageId}`
917
+ throwCommonHttpError(
918
+ response.status,
919
+ response.statusText,
920
+ errorText,
921
+ "change visibility (alt)",
922
+ "Missing receipt handle or invalid visibility timeout"
706
923
  );
707
- triggerDevCallbacks(topicName, messageId);
708
- },
709
- timeoutSeconds * 1e3 + DEV_CALLBACK_DELAY
710
- );
711
- }
712
- function triggerDevCallbacks(topicName, messageId) {
713
- const handlersMap = findRouteHandlersForTopic(topicName);
714
- if (handlersMap.size === 0) {
715
- return;
716
- }
717
- const consumerGroups = Array.from(
718
- new Set(
719
- Array.from(handlersMap.values()).flatMap((groups) => Array.from(groups))
720
- )
721
- );
722
- console.log(
723
- `[Dev Mode] Triggering local callbacks for topic "${topicName}" \u2192 consumers: ${consumerGroups.join(", ")}`
724
- );
725
- setTimeout(async () => {
726
- for (const [routeHandler, consumerGroups2] of handlersMap.entries()) {
727
- for (const consumerGroup of consumerGroups2) {
728
- try {
729
- const request = createMockCloudEventRequest(
730
- topicName,
731
- consumerGroup,
732
- messageId
733
- );
734
- const response = await routeHandler(request);
735
- if (response.ok) {
736
- try {
737
- const responseData = await response.json();
738
- if (responseData.status === "success") {
739
- console.log(
740
- `[Dev Mode] Message processed for ${topicName}/${consumerGroup}`
741
- );
742
- }
743
- } catch (jsonError) {
744
- console.error(
745
- `[Dev Mode] Failed to parse success response for ${topicName}/${consumerGroup}:`,
746
- jsonError
747
- );
748
- }
749
- } else {
750
- try {
751
- const errorData = await response.json();
752
- console.error(
753
- `[Dev Mode] Failed to process message for ${topicName}/${consumerGroup}:`,
754
- errorData.error || response.statusText
755
- );
756
- } catch (jsonError) {
757
- console.error(
758
- `[Dev Mode] Failed to process message for ${topicName}/${consumerGroup}:`,
759
- response.statusText
760
- );
761
- }
762
- }
763
- } catch (error) {
764
- console.error(
765
- `[Dev Mode] Error triggering callback for ${topicName}/${consumerGroup}:`,
766
- error
767
- );
768
- }
769
- }
770
924
  }
771
- }, DEV_CALLBACK_DELAY);
772
- }
773
- function clearDevHandlers() {
774
- devRouteHandlers.clear();
775
- wildcardRouteHandlers.clear();
776
- }
777
- if (process.env.NODE_ENV === "test" || process.env.VITEST) {
778
- globalThis.__clearDevHandlers = clearDevHandlers;
779
- }
925
+ return { success: true };
926
+ }
927
+ };
780
928
 
781
929
  // src/consumer-group.ts
782
930
  var ConsumerGroup = class {
@@ -808,8 +956,7 @@ var ConsumerGroup = class {
808
956
  * The extension loop runs every `refreshInterval` seconds and updates the message's
809
957
  * visibility timeout to `visibilityTimeout` seconds from the current time.
810
958
  *
811
- * @param messageId - The unique identifier of the message to extend visibility for
812
- * @param ticket - The receipt ticket that proves ownership of the message
959
+ * @param receiptHandle - The receipt handle that proves ownership of the message
813
960
  * @returns A function that when called will stop the extension loop
814
961
  *
815
962
  * @remarks
@@ -819,37 +966,43 @@ var ConsumerGroup = class {
819
966
  * - By default, the stop function returns immediately without waiting for in-flight
820
967
  * - Pass `true` to the stop function to wait for any in-flight extension to complete
821
968
  */
822
- startVisibilityExtension(messageId, ticket) {
969
+ startVisibilityExtension(receiptHandle) {
823
970
  let isRunning = true;
971
+ let isResolved = false;
824
972
  let resolveLifecycle;
825
973
  let timeoutId = null;
826
974
  const lifecyclePromise = new Promise((resolve) => {
827
975
  resolveLifecycle = resolve;
828
976
  });
977
+ const safeResolve = () => {
978
+ if (!isResolved) {
979
+ isResolved = true;
980
+ resolveLifecycle();
981
+ }
982
+ };
829
983
  const extend = async () => {
830
984
  if (!isRunning) {
831
- resolveLifecycle();
985
+ safeResolve();
832
986
  return;
833
987
  }
834
988
  try {
835
989
  await this.client.changeVisibility({
836
990
  queueName: this.topicName,
837
991
  consumerGroup: this.consumerGroupName,
838
- messageId,
839
- ticket,
992
+ receiptHandle,
840
993
  visibilityTimeoutSeconds: this.visibilityTimeout
841
994
  });
842
995
  if (isRunning) {
843
996
  timeoutId = setTimeout(() => extend(), this.refreshInterval * 1e3);
844
997
  } else {
845
- resolveLifecycle();
998
+ safeResolve();
846
999
  }
847
1000
  } catch (error) {
848
1001
  console.error(
849
- `Failed to extend visibility for message ${messageId}:`,
1002
+ `Failed to extend visibility for receipt handle ${receiptHandle}:`,
850
1003
  error
851
1004
  );
852
- resolveLifecycle();
1005
+ safeResolve();
853
1006
  }
854
1007
  };
855
1008
  timeoutId = setTimeout(() => extend(), this.refreshInterval * 1e3);
@@ -862,22 +1015,14 @@ var ConsumerGroup = class {
862
1015
  if (waitForCompletion) {
863
1016
  await lifecyclePromise;
864
1017
  } else {
865
- resolveLifecycle();
1018
+ safeResolve();
866
1019
  }
867
1020
  };
868
1021
  }
869
- /**
870
- * Process a single message with the given handler
871
- * @param message The message to process
872
- * @param handler Function to process the message
873
- */
874
1022
  async processMessage(message, handler) {
875
- const stopExtension = this.startVisibilityExtension(
876
- message.messageId,
877
- message.ticket
878
- );
1023
+ const stopExtension = this.startVisibilityExtension(message.receiptHandle);
879
1024
  try {
880
- const result = await handler(message.payload, {
1025
+ await handler(message.payload, {
881
1026
  messageId: message.messageId,
882
1027
  deliveryCount: message.deliveryCount,
883
1028
  createdAt: message.createdAt,
@@ -885,29 +1030,11 @@ var ConsumerGroup = class {
885
1030
  consumerGroup: this.consumerGroupName
886
1031
  });
887
1032
  await stopExtension();
888
- if (result && "timeoutSeconds" in result) {
889
- await this.client.changeVisibility({
890
- queueName: this.topicName,
891
- consumerGroup: this.consumerGroupName,
892
- messageId: message.messageId,
893
- ticket: message.ticket,
894
- visibilityTimeoutSeconds: result.timeoutSeconds
895
- });
896
- if (isDevMode()) {
897
- scheduleDevTimeout(
898
- this.topicName,
899
- message.messageId,
900
- result.timeoutSeconds
901
- );
902
- }
903
- } else {
904
- await this.client.deleteMessage({
905
- queueName: this.topicName,
906
- consumerGroup: this.consumerGroupName,
907
- messageId: message.messageId,
908
- ticket: message.ticket
909
- });
910
- }
1033
+ await this.client.deleteMessage({
1034
+ queueName: this.topicName,
1035
+ consumerGroup: this.consumerGroupName,
1036
+ receiptHandle: message.receiptHandle
1037
+ });
911
1038
  } catch (error) {
912
1039
  await stopExtension();
913
1040
  if (this.transport.finalize && message.payload !== void 0 && message.payload !== null) {
@@ -922,36 +1049,16 @@ var ConsumerGroup = class {
922
1049
  }
923
1050
  async consume(handler, options) {
924
1051
  if (options?.messageId) {
925
- if (options.skipPayload) {
926
- const response = await this.client.receiveMessageById(
927
- {
928
- queueName: this.topicName,
929
- consumerGroup: this.consumerGroupName,
930
- messageId: options.messageId,
931
- visibilityTimeoutSeconds: this.visibilityTimeout,
932
- skipPayload: true
933
- },
934
- this.transport
935
- );
936
- await this.processMessage(
937
- response.message,
938
- handler
939
- );
940
- } else {
941
- const response = await this.client.receiveMessageById(
942
- {
943
- queueName: this.topicName,
944
- consumerGroup: this.consumerGroupName,
945
- messageId: options.messageId,
946
- visibilityTimeoutSeconds: this.visibilityTimeout
947
- },
948
- this.transport
949
- );
950
- await this.processMessage(
951
- response.message,
952
- handler
953
- );
954
- }
1052
+ const response = await this.client.receiveMessageById(
1053
+ {
1054
+ queueName: this.topicName,
1055
+ consumerGroup: this.consumerGroupName,
1056
+ messageId: options.messageId,
1057
+ visibilityTimeoutSeconds: this.visibilityTimeout
1058
+ },
1059
+ this.transport
1060
+ );
1061
+ await this.processMessage(response.message, handler);
955
1062
  } else {
956
1063
  let messageFound = false;
957
1064
  for await (const message of this.client.receiveMessages(
@@ -1019,7 +1126,7 @@ var Topic = class {
1019
1126
  payload,
1020
1127
  idempotencyKey: options?.idempotencyKey,
1021
1128
  retentionSeconds: options?.retentionSeconds,
1022
- deploymentId: options?.deploymentId
1129
+ delaySeconds: options?.delaySeconds
1023
1130
  },
1024
1131
  this.transport
1025
1132
  );
@@ -1179,9 +1286,6 @@ function createCallbackHandler(handlers, client) {
1179
1286
  );
1180
1287
  }
1181
1288
  };
1182
- if (isDevMode()) {
1183
- registerDevRouteHandler(routeHandler, handlers);
1184
- }
1185
1289
  return routeHandler;
1186
1290
  }
1187
1291
  function handleCallback(handlers, client) {