@vercel/queue 0.0.0-alpha.7 → 0.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -328,7 +328,7 @@ type CallbackHandlers = {
328
328
  /**
329
329
  * Simplified queue callback handler for Next.js route handlers
330
330
  *
331
- * Automatically extracts queue information from Vercel-provided headers
331
+ * Automatically extracts queue information from CloudEvent format
332
332
  * and routes to the appropriate handler based on topic and consumer group.
333
333
  *
334
334
  * @param handlers Object with topic-specific handlers organized by consumer groups
package/dist/index.d.ts CHANGED
@@ -328,7 +328,7 @@ type CallbackHandlers = {
328
328
  /**
329
329
  * Simplified queue callback handler for Next.js route handlers
330
330
  *
331
- * Automatically extracts queue information from Vercel-provided headers
331
+ * Automatically extracts queue information from CloudEvent format
332
332
  * and routes to the appropriate handler based on topic and consumer group.
333
333
  *
334
334
  * @param handlers Object with topic-specific handlers organized by consumer groups
package/dist/index.js CHANGED
@@ -114,6 +114,18 @@ var StreamTransport = class {
114
114
  // src/client.ts
115
115
  var import_mixpart = require("mixpart");
116
116
 
117
+ // src/oidc.ts
118
+ function getVercelOidcToken() {
119
+ const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
120
+ const fromSymbol = globalThis;
121
+ const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
122
+ const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
123
+ if (!token) {
124
+ return null;
125
+ }
126
+ return token;
127
+ }
128
+
117
129
  // src/types.ts
118
130
  var MessageNotFoundError = class extends Error {
119
131
  constructor(messageId) {
@@ -216,24 +228,21 @@ function parseQueueHeaders(headers) {
216
228
  ticket
217
229
  };
218
230
  }
219
- var QueueClient = class _QueueClient {
231
+ var QueueClient = class {
220
232
  baseUrl;
233
+ basePath;
221
234
  token;
222
- /**
223
- * Internal default instance for use by convenience functions
224
- * @internal
225
- */
226
- static _defaultInstance = null;
227
235
  /**
228
236
  * Create a new Vercel Queue Service client
229
237
  * @param options Client configuration options (optional - will auto-detect Vercel Function environment)
230
238
  */
231
239
  constructor(options = {}) {
232
- this.baseUrl = options.baseUrl || "https://vqs.vercel.sh";
240
+ this.baseUrl = options.baseUrl || "https://api.vercel.com";
241
+ this.basePath = options.basePath || "/v1/queue/messages";
233
242
  if (options.token) {
234
243
  this.token = options.token;
235
244
  } else {
236
- const token = this.getVercelOidcTokenSync();
245
+ const token = getVercelOidcToken();
237
246
  if (!token) {
238
247
  throw new Error(
239
248
  "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'"
@@ -242,31 +251,6 @@ var QueueClient = class _QueueClient {
242
251
  this.token = token;
243
252
  }
244
253
  }
245
- /**
246
- * Get the default client instance for internal use by convenience functions
247
- * @internal
248
- */
249
- static _getDefaultInstance() {
250
- if (!this._defaultInstance) {
251
- this._defaultInstance = new _QueueClient();
252
- }
253
- return this._defaultInstance;
254
- }
255
- /**
256
- * Synchronously get OIDC token from environment
257
- * Used internally by constructor - mirrors the logic from getVercelOidcToken but synchronously
258
- */
259
- getVercelOidcTokenSync() {
260
- try {
261
- const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
262
- const fromSymbol = globalThis;
263
- const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
264
- const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
265
- return token || null;
266
- } catch {
267
- return null;
268
- }
269
- }
270
254
  /**
271
255
  * Send a message to a queue
272
256
  * @param options Send message options
@@ -294,7 +278,7 @@ var QueueClient = class _QueueClient {
294
278
  headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
295
279
  }
296
280
  const body = transport.serialize(payload);
297
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
281
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
298
282
  method: "POST",
299
283
  headers,
300
284
  body
@@ -358,7 +342,7 @@ var QueueClient = class _QueueClient {
358
342
  if (limit !== void 0) {
359
343
  headers.set("Vqs-Limit", limit.toString());
360
344
  }
361
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
345
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
362
346
  method: "GET",
363
347
  headers
364
348
  });
@@ -440,7 +424,7 @@ var QueueClient = class _QueueClient {
440
424
  headers.set("Vqs-Skip-Payload", "1");
441
425
  }
442
426
  const response = await fetch(
443
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
427
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
444
428
  {
445
429
  method: "GET",
446
430
  headers
@@ -549,7 +533,7 @@ var QueueClient = class _QueueClient {
549
533
  async deleteMessage(options) {
550
534
  const { queueName, consumerGroup, messageId, ticket } = options;
551
535
  const response = await fetch(
552
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
536
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
553
537
  {
554
538
  method: "DELETE",
555
539
  headers: new Headers({
@@ -610,7 +594,7 @@ var QueueClient = class _QueueClient {
610
594
  visibilityTimeoutSeconds
611
595
  } = options;
612
596
  const response = await fetch(
613
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
597
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
614
598
  {
615
599
  method: "PATCH",
616
600
  headers: new Headers({
@@ -928,7 +912,7 @@ var Topic = class {
928
912
  // src/factory.ts
929
913
  async function send(topicName, payload, options) {
930
914
  const transport = options?.transport || new JsonTransport();
931
- const client = QueueClient._getDefaultInstance();
915
+ const client = new QueueClient();
932
916
  const result = await client.sendMessage(
933
917
  {
934
918
  queueName: topicName,
@@ -942,7 +926,7 @@ async function send(topicName, payload, options) {
942
926
  }
943
927
  async function receive(topicName, consumerGroup, handler, options) {
944
928
  const transport = options?.transport || new JsonTransport();
945
- const client = QueueClient._getDefaultInstance();
929
+ const client = new QueueClient();
946
930
  const topic = new Topic(client, topicName, transport);
947
931
  const { messageId, skipPayload, ...consumerGroupOptions } = options || {};
948
932
  const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);
@@ -961,19 +945,38 @@ async function receive(topicName, consumerGroup, handler, options) {
961
945
  }
962
946
 
963
947
  // src/callback.ts
964
- function parseCallbackRequest(request) {
965
- const queueName = request.headers.get("Vqs-Queue-Name");
966
- const consumerGroup = request.headers.get("Vqs-Consumer-Group");
967
- const messageId = request.headers.get("Vqs-Message-Id");
968
- if (!queueName || !consumerGroup || !messageId) {
969
- const missingHeaders = [];
970
- if (!queueName) missingHeaders.push("Vqs-Queue-Name");
971
- if (!consumerGroup) missingHeaders.push("Vqs-Consumer-Group");
972
- if (!messageId) missingHeaders.push("Vqs-Message-Id");
948
+ async function parseCallbackRequest(request) {
949
+ const contentType = request.headers.get("content-type");
950
+ if (!contentType || !contentType.includes("application/cloudevents+json")) {
951
+ throw new Error(
952
+ "Invalid content type: expected 'application/cloudevents+json'"
953
+ );
954
+ }
955
+ let cloudEvent;
956
+ try {
957
+ cloudEvent = await request.json();
958
+ } catch (error) {
959
+ throw new Error("Failed to parse CloudEvent from request body");
960
+ }
961
+ if (!cloudEvent.type || !cloudEvent.source || !cloudEvent.id || typeof cloudEvent.data !== "object" || cloudEvent.data == null) {
962
+ throw new Error("Invalid CloudEvent: missing required fields");
963
+ }
964
+ if (cloudEvent.type !== "com.vercel.queue.v1beta") {
965
+ throw new Error(
966
+ `Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`
967
+ );
968
+ }
969
+ const missingFields = [];
970
+ if (!("queueName" in cloudEvent.data)) missingFields.push("queueName");
971
+ if (!("consumerGroup" in cloudEvent.data))
972
+ missingFields.push("consumerGroup");
973
+ if (!("messageId" in cloudEvent.data)) missingFields.push("messageId");
974
+ if (missingFields.length > 0) {
973
975
  throw new Error(
974
- `Missing required queue headers: ${missingHeaders.join(", ")}`
976
+ `Missing required CloudEvent data fields: ${missingFields.join(", ")}`
975
977
  );
976
978
  }
979
+ const { messageId, queueName, consumerGroup } = cloudEvent.data;
977
980
  return {
978
981
  queueName,
979
982
  consumerGroup,
@@ -983,7 +986,7 @@ function parseCallbackRequest(request) {
983
986
  function handleCallback(handlers) {
984
987
  return async (request) => {
985
988
  try {
986
- const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);
989
+ const { queueName, consumerGroup, messageId } = await parseCallbackRequest(request);
987
990
  const topicHandler = handlers[queueName];
988
991
  if (!topicHandler) {
989
992
  const availableTopics = Object.keys(handlers).join(", ");
@@ -1013,7 +1016,7 @@ function handleCallback(handlers) {
1013
1016
  return Response.json({ status: "success" });
1014
1017
  } catch (error) {
1015
1018
  console.error("Queue callback error:", error);
1016
- if (error instanceof Error && error.message.includes("Missing required queue headers")) {
1019
+ 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"))) {
1017
1020
  return Response.json({ error: error.message }, { status: 400 });
1018
1021
  }
1019
1022
  return Response.json(
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/transports.ts","../src/client.ts","../src/types.ts","../src/consumer-group.ts","../src/topic.ts","../src/factory.ts","../src/callback.ts"],"sourcesContent":["// Export transport classes\nexport { BufferTransport, JsonTransport, StreamTransport } from \"./transports\";\n\n// Export factory functions\nexport { receive, send } from \"./factory\";\nexport type { ReceiveOptions, SendOptions } from \"./factory\";\n\n// Export callback utilities\nexport { handleCallback } from \"./callback\";\n\n// Export error classes\nexport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n// Export types used by send/receive functions and message handlers\nexport type {\n Message,\n MessageHandler,\n MessageHandlerResult,\n MessageMetadata,\n MessageTimeoutResult,\n PublishOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\n","/**\n * Serializer/Deserializer interface for message payloads\n */\nexport interface Transport<T = unknown> {\n /**\n * Serialize a value to a buffer or stream for transmission\n */\n serialize(value: T): Buffer | ReadableStream<Uint8Array>;\n\n /**\n * Deserialize a readable stream back to the original value\n */\n deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;\n\n /**\n * Optional cleanup method for deserialized payloads that may contain resources\n * Should be called when the payload is no longer needed, especially in error cases\n * @param payload The deserialized payload to clean up\n */\n finalize?(payload: T): Promise<void>;\n\n /**\n * MIME type for this serialization format\n */\n contentType: string;\n}\n\n/**\n * Built-in JSON serializer/deserializer\n * This implementation reads the entire stream into memory for JSON parsing\n */\nexport class JsonTransport<T = unknown> implements Transport<T> {\n readonly contentType = \"application/json\";\n\n serialize(value: T): Buffer {\n return Buffer.from(JSON.stringify(value), \"utf8\");\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<T> {\n // JSON requires reading the entire payload to parse\n const reader = stream.getReader();\n let totalLength = 0;\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const buffer = Buffer.concat(chunks, totalLength);\n return JSON.parse(buffer.toString(\"utf8\"));\n }\n}\n\n/**\n * Built-in Buffer serializer/deserializer (reads entire stream into a Buffer)\n */\nexport class BufferTransport implements Transport<Buffer> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: Buffer): Buffer {\n return value;\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<Buffer> {\n // Buffer transport reads the entire stream into memory\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.length;\n }\n\n return Buffer.from(buffer);\n }\n}\n\n/**\n * Stream serializer/deserializer (pass-through for streaming binary data)\n * This is ideal for large payloads that don't need to be buffered in memory\n *\n * IMPORTANT: When using StreamTransport, you must call finalize(payload) when done\n * processing the message to prevent resource leaks, especially in error cases.\n * ConsumerGroup handles this automatically, but direct QueueClient usage requires manual cleanup.\n *\n * Example usage:\n * ```typescript\n * const transport = new StreamTransport();\n * try {\n * for await (const message of client.receiveMessages(options, transport)) {\n * // Process the stream...\n * const reader = message.payload.getReader();\n * // ... handle stream data\n * }\n * } catch (error) {\n * // Cleanup is handled automatically by ConsumerGroup\n * // or manually: await transport.finalize(message.payload);\n * }\n */\nexport class StreamTransport implements Transport<ReadableStream<Uint8Array>> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n // Pass through the stream directly without buffering\n return value;\n }\n\n async deserialize(\n stream: ReadableStream<Uint8Array>,\n ): Promise<ReadableStream<Uint8Array>> {\n // Pass through the stream directly without buffering\n return stream;\n }\n\n async finalize(payload: ReadableStream<Uint8Array>): Promise<void> {\n // Consume any remaining stream data to prevent resource leaks\n const reader = payload.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","import { parseMultipartStream } from \"mixpart\";\nimport type {\n ChangeVisibilityOptions,\n ChangeVisibilityResponse,\n DeleteMessageOptions,\n DeleteMessageResponse,\n Message,\n QueueClientOptions,\n ReceiveMessageByIdOptions,\n ReceiveMessageByIdResponse,\n ReceiveMessagesOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\nimport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n/**\n * Helper function to consume a ReadableStream to completion\n * This is necessary when we need to drain a stream to let the multipart parser proceed\n */\nasync function consumeStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<void> {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Helper function to parse queue headers into a partial message object\n * Handles both multipart message headers and HTTP response headers\n */\nfunction parseQueueHeaders(\n headers: Headers,\n): Omit<Message<unknown>, \"payload\"> | null {\n const messageId = headers.get(\"Vqs-Message-Id\");\n const deliveryCountStr = headers.get(\"Vqs-Delivery-Count\") || \"0\";\n const timestamp = headers.get(\"Vqs-Timestamp\");\n const contentType = headers.get(\"Content-Type\") || \"application/octet-stream\";\n const ticket = headers.get(\"Vqs-Ticket\");\n\n if (!messageId || !timestamp || !ticket) {\n return null;\n }\n\n const deliveryCount = parseInt(deliveryCountStr, 10);\n if (isNaN(deliveryCount)) {\n return null;\n }\n\n return {\n messageId,\n deliveryCount,\n timestamp,\n contentType,\n ticket,\n };\n}\n\n/**\n * Client for interacting with the Vercel Queue Service API\n */\nexport class QueueClient {\n private baseUrl: string;\n private token: string;\n\n /**\n * Internal default instance for use by convenience functions\n * @internal\n */\n private static _defaultInstance: QueueClient | null = null;\n\n /**\n * Create a new Vercel Queue Service client\n * @param options Client configuration options (optional - will auto-detect Vercel Function environment)\n */\n constructor(options: QueueClientOptions = {}) {\n this.baseUrl = options.baseUrl || \"https://vqs.vercel.sh\";\n\n if (options.token) {\n this.token = options.token;\n } else {\n // Try to get OIDC token from Vercel Function environment\n const token = this.getVercelOidcTokenSync();\n if (!token) {\n throw new Error(\n \"Failed to get OIDC token from Vercel Functions. \" +\n \"Make sure you are running in a Vercel Function environment, or provide a token explicitly.\\n\\n\" +\n \"To set up your environment:\\n\" +\n \"1. Link your project: 'vercel link'\\n\" +\n \"2. Pull environment variables: 'vercel env pull'\\n\" +\n \"3. Run with environment: 'dotenv -e .env.local -- your-command'\",\n );\n }\n this.token = token;\n }\n }\n\n /**\n * Get the default client instance for internal use by convenience functions\n * @internal\n */\n static _getDefaultInstance(): QueueClient {\n if (!this._defaultInstance) {\n this._defaultInstance = new QueueClient();\n }\n return this._defaultInstance;\n }\n\n /**\n * Synchronously get OIDC token from environment\n * Used internally by constructor - mirrors the logic from getVercelOidcToken but synchronously\n */\n private getVercelOidcTokenSync(): string | null {\n try {\n // Check for OIDC token in request context (same logic as async version)\n const SYMBOL_FOR_REQ_CONTEXT = Symbol.for(\"@vercel/request-context\");\n const fromSymbol = globalThis as any;\n const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};\n\n const token =\n context.headers?.[\"x-vercel-oidc-token\"] ??\n process.env.VERCEL_OIDC_TOKEN;\n\n return token || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Send a message to a queue\n * @param options Send message options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async sendMessage<T = unknown>(\n options: SendMessageOptions<T>,\n transport: Transport<T>,\n ): Promise<SendMessageResponse> {\n const { queueName, payload, idempotencyKey, retentionSeconds } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Content-Type\": transport.contentType,\n });\n\n if (process.env.VERCEL_DEPLOYMENT_ID) {\n headers.set(\"Vqs-Deployment-Id\", process.env.VERCEL_DEPLOYMENT_ID);\n }\n\n if (idempotencyKey) {\n headers.set(\"Vqs-Idempotency-Key\", idempotencyKey);\n }\n\n if (retentionSeconds !== undefined) {\n headers.set(\"Vqs-Retention-Seconds\", retentionSeconds.toString());\n }\n\n // Serialize the payload using the provided transport\n const body = transport.serialize(payload);\n\n const response = await fetch(`${this.baseUrl}/api/v2/messages`, {\n method: \"POST\",\n headers,\n body,\n });\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 409) {\n throw new Error(\"Duplicate idempotency key detected\");\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to send message: ${response.status} ${response.statusText}`,\n );\n }\n\n const responseData = (await response.json()) as SendMessageResponse;\n\n return responseData;\n }\n\n /**\n * Receive messages from a queue\n * @param options Receive messages options\n * @param transport Serializer/deserializer for the payload\n * @returns AsyncGenerator that yields messages as they arrive\n * @throws {InvalidLimitError} When limit parameter is not between 1 and 10\n * @throws {QueueEmptyError} When no messages are available (204)\n * @throws {MessageLockedError} When messages are temporarily locked (423)\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async *receiveMessages<T = unknown>(\n options: ReceiveMessagesOptions<T>,\n transport: Transport<T>,\n ): AsyncGenerator<Message<T>, void, unknown> {\n const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } =\n options;\n\n // Validate limit parameter\n if (limit !== undefined && (limit < 1 || limit > 10)) {\n throw new InvalidLimitError(limit);\n }\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (limit !== undefined) {\n headers.set(\"Vqs-Limit\", limit.toString());\n }\n\n const response = await fetch(`${this.baseUrl}/api/v2/messages`, {\n method: \"GET\",\n headers,\n });\n\n // Check for 204 No Content - queue is empty\n if (response.status === 204) {\n throw new QueueEmptyError(queueName, consumerGroup);\n }\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 423) {\n // Message locked - temporarily unavailable\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(\"next message\", retryAfter);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive messages: ${response.status} ${response.statusText}`,\n );\n }\n\n // Stream messages as they arrive from the multipart parser\n // Each message's payload stream must be consumed immediately for the parser to proceed\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse VQS headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n yield message;\n } catch (error) {\n console.warn(\"Failed to process multipart message:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n }\n }\n }\n\n /**\n * Receive a specific message by its ID from a queue\n * @param options Receive message by ID options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message or null if not found/available\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageLockedError} When the message is temporarily locked (423)\n * @throws {MessageNotAvailableError} When message exists but isn't available (409)\n * @throws {MessageCorruptedError} When message data is corrupted\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload: true },\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, true>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload?: false | undefined },\n transport: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, false>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T>,\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, boolean>> {\n const {\n queueName,\n consumerGroup,\n messageId,\n visibilityTimeoutSeconds,\n skipPayload,\n } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (skipPayload) {\n headers.set(\"Vqs-Skip-Payload\", \"1\");\n }\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"GET\",\n headers,\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n // Message not found\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 423) {\n // Message is temporarily locked\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(messageId, retryAfter);\n }\n\n if (response.status === 409) {\n // Message not available (wrong state or claimed by another consumer)\n throw new MessageNotAvailableError(messageId);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive message by ID: ${response.status} ${response.statusText}`,\n );\n }\n\n // Handle skipPayload case with 204 response\n if (skipPayload && response.status === 204) {\n const parsedHeaders = parseQueueHeaders(response.headers);\n\n if (!parsedHeaders) {\n throw new MessageCorruptedError(\n messageId,\n \"Missing required queue headers in 204 response\",\n );\n }\n\n const message: Message<void> = {\n ...parsedHeaders,\n payload: undefined as void,\n };\n\n return { message } as ReceiveMessageByIdResponse<T, boolean>;\n }\n\n // Handle regular multipart response\n if (!transport) {\n throw new Error(\"Transport is required when skipPayload is not true\");\n }\n\n // Parse multipart/mixed response using streaming parser\n try {\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse queue headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n return { message };\n } catch (error) {\n console.warn(\"Failed to deserialize message by ID:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n throw new MessageCorruptedError(\n messageId,\n `Failed to deserialize payload: ${error}`,\n );\n }\n }\n } catch (error) {\n if (error instanceof MessageCorruptedError) {\n throw error; // Re-throw our own errors\n }\n throw new MessageCorruptedError(\n messageId,\n `Failed to parse multipart response: ${error}`,\n );\n }\n\n // If we get here, no message was found in the multipart response\n throw new MessageNotFoundError(messageId);\n }\n\n /**\n * Delete a message (acknowledge processing)\n * @param options Delete message options\n * @returns Promise with delete status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be deleted (409)\n * @throws {BadRequestError} When ticket is missing or invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async deleteMessage(\n options: DeleteMessageOptions,\n ): Promise<DeleteMessageResponse> {\n const { queueName, consumerGroup, messageId, ticket } = options;\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"DELETE\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\"Missing or invalid ticket\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to delete message: ${response.status} ${response.statusText}`,\n );\n }\n\n return { deleted: true };\n }\n\n /**\n * Change the visibility timeout of a message\n * @param options Change visibility options\n * @returns Promise with update status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be updated (409)\n * @throws {BadRequestError} When ticket is missing or visibility timeout invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async changeVisibility(\n options: ChangeVisibilityOptions,\n ): Promise<ChangeVisibilityResponse> {\n const {\n queueName,\n consumerGroup,\n messageId,\n ticket,\n visibilityTimeoutSeconds,\n } = options;\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"PATCH\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n \"Vqs-Visibility-Timeout\": visibilityTimeoutSeconds.toString(),\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\n \"Missing ticket or invalid visibility timeout\",\n );\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to change visibility: ${response.status} ${response.statusText}`,\n );\n }\n\n return { updated: true };\n }\n}\n","/**\n * Vercel Queue Service client types\n */\nimport type { Transport } from \"./transports\";\n\n// Re-export transport interface for convenience\nexport type { Transport };\n\nexport interface QueueClientOptions {\n /**\n * Base URL for the Vercel Queue Service API\n * @default \"https://vqs.vercel.sh\"\n */\n baseUrl?: string;\n /**\n * Vercel function OIDC token\n * Can be obtained from x-vercel-oidc-token header in Vercel Serverless Functions\n * If not provided, will automatically attempt to retrieve from Vercel Function environment\n */\n token?: string;\n}\n\n/**\n * Shared options for publishing messages\n */\nexport interface PublishOptions {\n /**\n * Unique key to prevent duplicate message submissions\n * @default random UUID\n */\n idempotencyKey?: string;\n /**\n * Message retention time in seconds\n * @default 86400 (24 hours)\n * @min 60\n * @max 86400\n */\n retentionSeconds?: number;\n}\n\nexport interface SendMessageOptions<T = unknown> extends PublishOptions {\n /**\n * The queue name to send the message to\n */\n queueName: string;\n /**\n * The message payload\n */\n payload: T;\n}\n\nexport interface SendMessageResponse {\n /**\n * The generated message ID\n */\n messageId: string;\n}\n\nexport interface Message<T = unknown> {\n /**\n * The message ID\n */\n messageId: string;\n /**\n * The deserialized message payload\n * Note: If using streaming transports, ensure proper cleanup by calling transport.finalize(payload)\n * when done processing, especially in error cases\n */\n payload: T;\n /**\n * Number of times this message has been delivered\n */\n deliveryCount: number;\n /**\n * Timestamp when the message was created\n */\n timestamp: string;\n /**\n * MIME type of the message content\n */\n contentType: string;\n /**\n * Unique ticket for this message delivery (required for delete/patch operations)\n */\n ticket: string;\n}\n\nexport interface ReceiveMessagesOptions<T = unknown> {\n /**\n * The queue name to receive messages from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Maximum number of messages to retrieve\n * @default 10\n * @max 10\n */\n limit?: number;\n}\n\nexport interface DeleteMessageOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to delete\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n}\n\nexport interface DeleteMessageResponse {\n /**\n * Whether the message was successfully deleted\n */\n deleted: boolean;\n}\n\nexport interface ChangeVisibilityOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to update\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n /**\n * New visibility timeout in seconds\n */\n visibilityTimeoutSeconds: number;\n}\n\nexport interface ChangeVisibilityResponse {\n /**\n * Whether the visibility was successfully updated\n */\n updated: boolean;\n}\n\n/**\n * Result indicating the message should be timed out for retry later\n */\nexport interface MessageTimeoutResult {\n /**\n * Time in seconds before the message becomes visible again\n */\n timeoutSeconds: number;\n}\n\n/**\n * Result returned by message handlers\n */\nexport type MessageHandlerResult = void | MessageTimeoutResult;\n\n/**\n * Message metadata provided to handlers\n */\nexport interface MessageMetadata {\n messageId: string;\n deliveryCount: number;\n timestamp: string;\n}\n\n/**\n * Message handler function type\n */\nexport type MessageHandler<T = unknown> = (\n message: T,\n metadata: MessageMetadata,\n) => Promise<MessageHandlerResult> | MessageHandlerResult;\n\n/**\n * Options for creating a ConsumerGroup instance\n */\nexport interface ConsumerGroupOptions<T = unknown> {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 30\n */\n visibilityTimeoutSeconds?: number;\n /**\n * How often to refresh the visibility timeout during processing (in seconds)\n * @default 10\n */\n refreshInterval?: number;\n}\n\nexport interface ReceiveMessageByIdOptions<T = unknown> {\n /**\n * The queue name to receive the message from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to retrieve\n */\n messageId: string;\n /**\n * Time in seconds that the message will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Skip payload content and only return message metadata\n * When true, the server returns a 204 status with headers containing message metadata\n * @default false\n */\n skipPayload?: boolean;\n}\n\n// Response type that always contains a message (errors are thrown for failures)\nexport interface ReceiveMessageByIdResponse<\n T = unknown,\n TSkipPayload extends boolean = false,\n> {\n message: TSkipPayload extends true ? Message<void> : Message<T>;\n}\n\n/**\n * Error thrown when a message is not found (404)\n */\nexport class MessageNotFoundError extends Error {\n constructor(messageId: string) {\n super(`Message ${messageId} not found`);\n this.name = \"MessageNotFoundError\";\n }\n}\n\n/**\n * Error thrown when a message is not available for processing (409)\n * This can happen when the message is in the wrong state, already claimed, etc.\n */\nexport class MessageNotAvailableError extends Error {\n constructor(messageId: string, reason?: string) {\n super(\n `Message ${messageId} not available for processing${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"MessageNotAvailableError\";\n }\n}\n\n/**\n * Error thrown when message data is corrupted or can't be parsed\n */\nexport class MessageCorruptedError extends Error {\n constructor(messageId: string, reason: string) {\n super(`Message ${messageId} is corrupted: ${reason}`);\n this.name = \"MessageCorruptedError\";\n }\n}\n\n/**\n * Error thrown when there are no messages available in the queue (204)\n */\nexport class QueueEmptyError extends Error {\n constructor(queueName: string, consumerGroup: string) {\n super(\n `No messages available in queue \"${queueName}\" for consumer group \"${consumerGroup}\"`,\n );\n this.name = \"QueueEmptyError\";\n }\n}\n\n/**\n * Error thrown when a message is temporarily locked (423)\n */\nexport class MessageLockedError extends Error {\n public readonly retryAfter?: number;\n\n constructor(messageId: string, retryAfter?: number) {\n const retryMessage = retryAfter\n ? ` Retry after ${retryAfter} seconds.`\n : \" Try again later.\";\n super(`Message ${messageId} is temporarily locked.${retryMessage}`);\n this.name = \"MessageLockedError\";\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when authentication fails (401)\n */\nexport class UnauthorizedError extends Error {\n constructor(message: string = \"Missing or invalid authentication token\") {\n super(message);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * Error thrown when access is forbidden (403)\n */\nexport class ForbiddenError extends Error {\n constructor(\n message: string = \"Queue environment doesn't match token environment\",\n ) {\n super(message);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * Error thrown for bad requests (400)\n */\nexport class BadRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * Error thrown for internal server errors (500)\n */\nexport class InternalServerError extends Error {\n constructor(message: string = \"Unexpected server error\") {\n super(message);\n this.name = \"InternalServerError\";\n }\n}\n\n/**\n * Error thrown when batch limit parameter is invalid\n */\nexport class InvalidLimitError extends Error {\n constructor(limit: number, min: number = 1, max: number = 10) {\n super(`Invalid limit: ${limit}. Limit must be between ${min} and ${max}.`);\n this.name = \"InvalidLimitError\";\n }\n}\n","import { QueueClient } from \"./client\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n Message,\n MessageHandler,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the consume method\n */\nexport interface ConsumeOptions {\n /** The specific message ID to consume (if not provided, consumes next available message) */\n messageId?: string;\n /** Whether to skip downloading the payload (only allowed when messageId is provided) */\n skipPayload?: boolean;\n}\n\n/**\n * A ConsumerGroup represents a named group of consumers that process messages from a topic\n */\nexport class ConsumerGroup<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private consumerGroupName: string;\n private visibilityTimeout: number;\n private refreshInterval: number;\n private transport: Transport<T>;\n\n /**\n * Create a new ConsumerGroup instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to consume from\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration\n */\n constructor(\n client: QueueClient,\n topicName: string,\n consumerGroupName: string,\n options: ConsumerGroupOptions<T> = {},\n ) {\n this.client = client;\n this.topicName = topicName;\n this.consumerGroupName = consumerGroupName;\n this.visibilityTimeout = options.visibilityTimeoutSeconds || 30; // 30 seconds default\n this.refreshInterval = options.refreshInterval || 10; // 10 seconds default\n this.transport = options.transport || new JsonTransport<T>();\n }\n\n /**\n * Starts a background loop that periodically extends the visibility timeout for a message.\n * This prevents the message from becoming visible to other consumers while it's being processed.\n *\n * The extension loop runs every `refreshInterval` seconds and updates the message's\n * visibility timeout to `visibilityTimeout` seconds from the current time.\n *\n * @param messageId - The unique identifier of the message to extend visibility for\n * @param ticket - The receipt ticket that proves ownership of the message\n * @returns A function that when called will stop the extension loop\n *\n * @remarks\n * - The first extension attempt occurs after `refreshInterval` seconds, not immediately\n * - If an extension fails, the loop terminates with an error logged to console\n * - The returned stop function is idempotent - calling it multiple times is safe\n * - By default, the stop function returns immediately without waiting for in-flight\n * - Pass `true` to the stop function to wait for any in-flight extension to complete\n */\n private startVisibilityExtension(\n messageId: string,\n ticket: string,\n ): (waitForCompletion?: boolean) => Promise<void> {\n let isRunning = true;\n let resolveLifecycle: () => void;\n let timeoutId: NodeJS.Timeout | null = null;\n\n // Promise that tracks the actual termination of the extension loop\n const lifecyclePromise = new Promise<void>((resolve) => {\n resolveLifecycle = resolve;\n });\n\n const extend = async (): Promise<void> => {\n // Check if we should stop before attempting extension\n if (!isRunning) {\n resolveLifecycle();\n return;\n }\n\n try {\n // Extend the visibility timeout for another period\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId,\n ticket,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n });\n\n // Schedule next extension if still running\n if (isRunning) {\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n } else {\n // Signal that the loop has terminated after successful extension\n resolveLifecycle();\n }\n } catch (error) {\n // Log error and terminate the loop on failure\n console.error(\n `Failed to extend visibility for message ${messageId}:`,\n error,\n );\n resolveLifecycle();\n }\n };\n\n // Schedule the first extension attempt\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n\n // Return a function to stop the extension loop\n return async (waitForCompletion: boolean = false) => {\n // Signal the loop to stop\n isRunning = false;\n\n // Cancel any pending timeout to avoid unnecessary waiting\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n // Only wait for in-flight operations if explicitly requested\n if (waitForCompletion) {\n // Wait for the loop to actually terminate\n // This ensures any in-progress extension completes or fails\n await lifecyclePromise;\n } else {\n // Resolve the lifecycle immediately for any waiting operations\n // This allows immediate return without waiting for in-flight extensions\n resolveLifecycle();\n }\n };\n }\n\n /**\n * Process a single message with the given handler\n * @param message The message to process\n * @param handler Function to process the message\n */\n private async processMessage<TPayload>(\n message: Message<TPayload>,\n handler: MessageHandler<TPayload>,\n ): Promise<void> {\n const stopExtension = this.startVisibilityExtension(\n message.messageId,\n message.ticket,\n );\n\n try {\n const result = await handler(message.payload, {\n messageId: message.messageId,\n deliveryCount: message.deliveryCount,\n timestamp: message.timestamp,\n });\n // Stop extensions immediately - we don't need to wait for in-flight extensions\n // since we're about to delete or update the message visibility anyway\n await stopExtension();\n\n if (result && \"timeoutSeconds\" in result) {\n // Handle timeout request - set new visibility timeout instead of deleting\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n visibilityTimeoutSeconds: result.timeoutSeconds,\n });\n } else {\n // Normal completion - delete the message\n await this.client.deleteMessage({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n });\n }\n } catch (error) {\n // Stop extensions immediately on error - fail fast without waiting\n // for any in-flight extension attempts\n await stopExtension();\n\n // Clean up the message payload if the transport supports it and payload exists\n // Only call finalize for non-void payloads since transport is typed for T, not void\n if (\n this.transport.finalize &&\n message.payload !== undefined &&\n message.payload !== null\n ) {\n try {\n // Safe cast: when processMessage<T> is called, TPayload is T\n // when processMessage<void> is called, payload is undefined so this won't execute\n await this.transport.finalize(message.payload as T);\n } catch (finalizeError) {\n console.warn(\"Failed to finalize message payload:\", finalizeError);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Consume the next available message from the queue\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(handler: MessageHandler<T>): Promise<void>;\n\n /**\n * Consume a specific message by its ID with full payload\n * @param handler Function to process the message\n * @param options Consume options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<T>,\n options: { messageId: string; skipPayload?: false | undefined },\n ): Promise<void>;\n\n /**\n * Consume a specific message by its ID without downloading the payload (metadata only)\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Consume options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<void>,\n options: { messageId: string; skipPayload: true },\n ): Promise<void>;\n\n async consume(\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ConsumeOptions,\n ): Promise<void> {\n if (options?.messageId) {\n // Specific message mode\n if (options.skipPayload) {\n // Skip payload - like old handleMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n skipPayload: true,\n },\n this.transport,\n );\n await this.processMessage<void>(\n response.message,\n handler as MessageHandler<void>,\n );\n } else {\n // With payload - like old receiveMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n },\n this.transport,\n );\n await this.processMessage<T>(\n response.message,\n handler as MessageHandler<T>,\n );\n }\n } else {\n // Next message mode - like old receiveNextMessage\n let messageFound = false;\n\n for await (const message of this.client.receiveMessages<T>(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n limit: 1,\n },\n this.transport,\n )) {\n messageFound = true;\n await this.processMessage<T>(message, handler as MessageHandler<T>);\n break; // Process only one message\n }\n\n // If we get here without finding a message, the async generator\n // should have already thrown QueueEmptyError, but just in case\n if (!messageFound) {\n throw new Error(\"No messages available\");\n }\n }\n }\n\n /**\n * Get the consumer group name\n */\n get name(): string {\n return this.consumerGroupName;\n }\n\n /**\n * Get the topic name this consumer group is subscribed to\n */\n get topic(): string {\n return this.topicName;\n }\n}\n","import { QueueClient } from \"./client\";\nimport { ConsumerGroup } from \"./consumer-group\";\nimport { JsonTransport } from \"./transports\";\nimport type { ConsumerGroupOptions, PublishOptions, Transport } from \"./types\";\n\n/**\n * A Topic represents a named channel for publishing messages in a pub/sub pattern\n */\nexport class Topic<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private transport: Transport<T>;\n\n /**\n * Create a new Topic instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to work with\n * @param transport Optional serializer/deserializer for the payload (defaults to JSON)\n */\n constructor(\n client: QueueClient,\n topicName: string,\n transport?: Transport<T>,\n ) {\n this.client = client;\n this.topicName = topicName;\n this.transport = transport || new JsonTransport<T>();\n }\n\n /**\n * Publish a message to the topic\n * @param payload The data to publish\n * @param options Optional publish options\n * @returns An object containing the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async publish(\n payload: T,\n options?: PublishOptions,\n ): Promise<{ messageId: string }> {\n const result = await this.client.sendMessage<T>(\n {\n queueName: this.topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n this.transport,\n );\n return { messageId: result.messageId };\n }\n\n /**\n * Create a consumer group for this topic\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration for the consumer group\n * @returns A ConsumerGroup instance\n */\n consumerGroup<U = T>(\n consumerGroupName: string,\n options?: ConsumerGroupOptions<U>,\n ): ConsumerGroup<U> {\n // If no transport is provided in options, use the topic's transport if types match\n const consumerOptions: ConsumerGroupOptions<U> = {\n ...options,\n transport:\n options?.transport || (this.transport as unknown as Transport<U>),\n };\n\n return new ConsumerGroup<U>(\n this.client,\n this.topicName,\n consumerGroupName,\n consumerOptions,\n );\n }\n\n /**\n * Get the topic name\n */\n get name(): string {\n return this.topicName;\n }\n\n /**\n * Get the transport used by this topic\n */\n get serializer(): Transport<T> {\n return this.transport;\n }\n}\n","import { QueueClient } from \"./client\";\nimport type { ConsumeOptions } from \"./consumer-group\";\nimport { Topic } from \"./topic\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n MessageHandler,\n PublishOptions,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the send function\n */\nexport interface SendOptions<T = unknown> extends PublishOptions {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n}\n\n/**\n * Send a message to a topic (shorthand for topic creation and publishing)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to send to\n * @param payload The data to send\n * @param options Optional send options including transport and publish settings\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\nexport async function send<T = unknown>(\n topicName: string,\n payload: T,\n options?: SendOptions<T>,\n): Promise<{ messageId: string }> {\n const transport = options?.transport || new JsonTransport<T>();\n const client = QueueClient._getDefaultInstance();\n\n const result = await client.sendMessage<T>(\n {\n queueName: topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n transport,\n );\n\n return { messageId: result.messageId };\n}\n\n/**\n * Options for the receive function\n */\nexport interface ReceiveOptions<T = unknown>\n extends ConsumerGroupOptions<T>,\n ConsumeOptions {}\n\n/**\n * Receive a message from a topic (shorthand for topic and consumer group creation)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options?: ReceiveOptions<T>,\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID with full payload\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @param options Receive options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options: ReceiveOptions<T> & {\n messageId: string;\n skipPayload?: false | undefined;\n },\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID without downloading the payload (metadata only)\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Receive options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<void>,\n options: ReceiveOptions<T> & { messageId: string; skipPayload: true },\n): Promise<void>;\n\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ReceiveOptions<T>,\n): Promise<void> {\n const transport = options?.transport || new JsonTransport<T>();\n\n // Create topic with transport directly\n const client = QueueClient._getDefaultInstance();\n const topic = new Topic<T>(client, topicName, transport);\n\n // Create consumer group with options (excluding consume-specific options)\n const { messageId, skipPayload, ...consumerGroupOptions } = options || {};\n const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);\n\n // Call consume with the appropriate overload based on options\n if (messageId) {\n if (skipPayload) {\n // skipPayload: true case\n return consumer.consume(handler as MessageHandler<void>, {\n messageId,\n skipPayload: true,\n });\n } else {\n // messageId with payload case\n return consumer.consume(handler as MessageHandler<T>, { messageId });\n }\n } else {\n // No options case - next available message\n return consumer.consume(handler as MessageHandler<T>);\n }\n}\n","/**\n * Queue Callback utilities for handling incoming webhook payloads from Vercel triggers\n */\nimport { QueueClient } from \"./client\";\nimport { Topic } from \"./topic\";\nimport type { MessageHandler } from \"./types\";\n\n/**\n * Configuration object with handlers for different topics and consumer groups\n */\ntype CallbackHandlers = {\n [topicName: string]: { [consumerGroup: string]: MessageHandler };\n};\n\n/**\n * Parsed callback request information\n */\nexport type ParsedCallbackRequest = {\n queueName: string;\n consumerGroup: string;\n messageId: string;\n};\n\n/**\n * Parse and validate callback request headers\n *\n * Extracts queue information from Vercel-provided headers and validates\n * that all required headers are present.\n *\n * @param request The incoming webhook request\n * @returns Parsed queue information\n * @throws Error if required headers are missing\n *\n * @example\n * ```typescript\n * // In Next.js API route\n * export async function POST(request: Request) {\n * try {\n * const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);\n *\n * // Use the parsed information...\n * await myWorkflow.handleWebhook(queueName, consumerGroup, messageId);\n *\n * return Response.json({ status: \"success\" });\n * } catch (error) {\n * return Response.json({ error: error.message }, { status: 400 });\n * }\n * }\n * ```\n */\nexport function parseCallbackRequest(request: Request): ParsedCallbackRequest {\n // Extract queue information from Vercel-provided headers\n const queueName = request.headers.get(\"Vqs-Queue-Name\");\n const consumerGroup = request.headers.get(\"Vqs-Consumer-Group\");\n const messageId = request.headers.get(\"Vqs-Message-Id\");\n\n // Validate all required headers are present\n if (!queueName || !consumerGroup || !messageId) {\n const missingHeaders: string[] = [];\n if (!queueName) missingHeaders.push(\"Vqs-Queue-Name\");\n if (!consumerGroup) missingHeaders.push(\"Vqs-Consumer-Group\");\n if (!messageId) missingHeaders.push(\"Vqs-Message-Id\");\n\n throw new Error(\n `Missing required queue headers: ${missingHeaders.join(\", \")}`,\n );\n }\n\n return {\n queueName,\n consumerGroup,\n messageId,\n };\n}\n\n/**\n * Simplified queue callback handler for Next.js route handlers\n *\n * Automatically extracts queue information from Vercel-provided headers\n * and routes to the appropriate handler based on topic and consumer group.\n *\n * @param handlers Object with topic-specific handlers organized by consumer groups\n * @returns A Next.js route handler function\n *\n * @example\n * ```typescript\n * // Single topic with multiple consumer groups\n * export const POST = handleCallback({\n * \"image-processing\": {\n * \"compress\": (message, metadata) => console.log(\"Compressing image\", message),\n * \"resize\": (message, metadata) => console.log(\"Resizing image\", message),\n * }\n * });\n *\n * // Multiple topics with consumer groups\n * export const POST = handleCallback({\n * \"user-events\": {\n * \"welcome\": (user, metadata) => console.log(\"Welcoming user\", user),\n * \"analytics\": (user, metadata) => console.log(\"Tracking user\", user),\n * },\n * \"order-events\": {\n * \"fulfillment\": (order, metadata) => console.log(\"Fulfilling order\", order),\n * \"notifications\": (order, metadata) => console.log(\"Notifying order\", order),\n * }\n * });\n * ```\n */\nexport function handleCallback(\n handlers: CallbackHandlers,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n // Parse the callback request\n const { queueName, consumerGroup, messageId } =\n parseCallbackRequest(request);\n\n // Find the topic handler\n const topicHandler = handlers[queueName];\n\n if (!topicHandler) {\n const availableTopics = Object.keys(handlers).join(\", \");\n return Response.json(\n {\n error: `No handler found for topic: ${queueName}`,\n availableTopics,\n },\n { status: 404 },\n );\n }\n\n // Find the consumer group handler\n const consumerGroupHandler = topicHandler[consumerGroup];\n\n if (!consumerGroupHandler) {\n const availableGroups = Object.keys(topicHandler).join(\", \");\n return Response.json(\n {\n error: `No handler found for consumer group \"${consumerGroup}\" in topic \"${queueName}\".`,\n availableGroups,\n },\n { status: 404 },\n );\n }\n\n // Create client and process the message\n const client = new QueueClient();\n const topic = new Topic(client, queueName);\n const cg = topic.consumerGroup(consumerGroup);\n\n await cg.consume(consumerGroupHandler, { messageId });\n\n return Response.json({ status: \"success\" });\n } catch (error) {\n console.error(\"Queue callback error:\", error);\n\n // Handle parsing errors with appropriate status codes\n if (\n error instanceof Error &&\n error.message.includes(\"Missing required queue headers\")\n ) {\n return Response.json({ error: error.message }, { status: 400 });\n }\n\n return Response.json(\n { error: \"Failed to process queue message\" },\n { status: 500 },\n );\n }\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/transports.ts","../src/client.ts","../src/oidc.ts","../src/types.ts","../src/consumer-group.ts","../src/topic.ts","../src/factory.ts","../src/callback.ts"],"sourcesContent":["// Export transport classes\nexport { BufferTransport, JsonTransport, StreamTransport } from \"./transports\";\n\n// Export factory functions\nexport { receive, send } from \"./factory\";\nexport type { ReceiveOptions, SendOptions } from \"./factory\";\n\n// Export callback utilities\nexport { handleCallback } from \"./callback\";\n\n// Export error classes\nexport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n// Export types used by send/receive functions and message handlers\nexport type {\n Message,\n MessageHandler,\n MessageHandlerResult,\n MessageMetadata,\n MessageTimeoutResult,\n PublishOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\n","/**\n * Serializer/Deserializer interface for message payloads\n */\nexport interface Transport<T = unknown> {\n /**\n * Serialize a value to a buffer or stream for transmission\n */\n serialize(value: T): Buffer | ReadableStream<Uint8Array>;\n\n /**\n * Deserialize a readable stream back to the original value\n */\n deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;\n\n /**\n * Optional cleanup method for deserialized payloads that may contain resources\n * Should be called when the payload is no longer needed, especially in error cases\n * @param payload The deserialized payload to clean up\n */\n finalize?(payload: T): Promise<void>;\n\n /**\n * MIME type for this serialization format\n */\n contentType: string;\n}\n\n/**\n * Built-in JSON serializer/deserializer\n * This implementation reads the entire stream into memory for JSON parsing\n */\nexport class JsonTransport<T = unknown> implements Transport<T> {\n readonly contentType = \"application/json\";\n\n serialize(value: T): Buffer {\n return Buffer.from(JSON.stringify(value), \"utf8\");\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<T> {\n // JSON requires reading the entire payload to parse\n const reader = stream.getReader();\n let totalLength = 0;\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const buffer = Buffer.concat(chunks, totalLength);\n return JSON.parse(buffer.toString(\"utf8\"));\n }\n}\n\n/**\n * Built-in Buffer serializer/deserializer (reads entire stream into a Buffer)\n */\nexport class BufferTransport implements Transport<Buffer> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: Buffer): Buffer {\n return value;\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<Buffer> {\n // Buffer transport reads the entire stream into memory\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.length;\n }\n\n return Buffer.from(buffer);\n }\n}\n\n/**\n * Stream serializer/deserializer (pass-through for streaming binary data)\n * This is ideal for large payloads that don't need to be buffered in memory\n *\n * IMPORTANT: When using StreamTransport, you must call finalize(payload) when done\n * processing the message to prevent resource leaks, especially in error cases.\n * ConsumerGroup handles this automatically, but direct QueueClient usage requires manual cleanup.\n *\n * Example usage:\n * ```typescript\n * const transport = new StreamTransport();\n * try {\n * for await (const message of client.receiveMessages(options, transport)) {\n * // Process the stream...\n * const reader = message.payload.getReader();\n * // ... handle stream data\n * }\n * } catch (error) {\n * // Cleanup is handled automatically by ConsumerGroup\n * // or manually: await transport.finalize(message.payload);\n * }\n */\nexport class StreamTransport implements Transport<ReadableStream<Uint8Array>> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n // Pass through the stream directly without buffering\n return value;\n }\n\n async deserialize(\n stream: ReadableStream<Uint8Array>,\n ): Promise<ReadableStream<Uint8Array>> {\n // Pass through the stream directly without buffering\n return stream;\n }\n\n async finalize(payload: ReadableStream<Uint8Array>): Promise<void> {\n // Consume any remaining stream data to prevent resource leaks\n const reader = payload.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","import { parseMultipartStream } from \"mixpart\";\nimport { getVercelOidcToken } from \"./oidc\";\nimport type {\n ChangeVisibilityOptions,\n ChangeVisibilityResponse,\n DeleteMessageOptions,\n DeleteMessageResponse,\n Message,\n QueueClientOptions,\n ReceiveMessageByIdOptions,\n ReceiveMessageByIdResponse,\n ReceiveMessagesOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\nimport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n/**\n * Helper function to consume a ReadableStream to completion\n * This is necessary when we need to drain a stream to let the multipart parser proceed\n */\nasync function consumeStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<void> {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Helper function to parse queue headers into a partial message object\n * Handles both multipart message headers and HTTP response headers\n */\nfunction parseQueueHeaders(\n headers: Headers,\n): Omit<Message<unknown>, \"payload\"> | null {\n const messageId = headers.get(\"Vqs-Message-Id\");\n const deliveryCountStr = headers.get(\"Vqs-Delivery-Count\") || \"0\";\n const timestamp = headers.get(\"Vqs-Timestamp\");\n const contentType = headers.get(\"Content-Type\") || \"application/octet-stream\";\n const ticket = headers.get(\"Vqs-Ticket\");\n\n if (!messageId || !timestamp || !ticket) {\n return null;\n }\n\n const deliveryCount = parseInt(deliveryCountStr, 10);\n if (isNaN(deliveryCount)) {\n return null;\n }\n\n return {\n messageId,\n deliveryCount,\n timestamp,\n contentType,\n ticket,\n };\n}\n\n/**\n * Client for interacting with the Vercel Queue Service API\n */\nexport class QueueClient {\n private baseUrl: string;\n private basePath: string;\n private token: string;\n\n /**\n * Create a new Vercel Queue Service client\n * @param options Client configuration options (optional - will auto-detect Vercel Function environment)\n */\n constructor(options: QueueClientOptions = {}) {\n this.baseUrl = options.baseUrl || \"https://api.vercel.com\";\n this.basePath = options.basePath || \"/v1/queue/messages\";\n\n if (options.token) {\n this.token = options.token;\n } else {\n // Try to get OIDC token from Vercel Function environment\n const token = getVercelOidcToken();\n if (!token) {\n throw new Error(\n \"Failed to get OIDC token from Vercel Functions. \" +\n \"Make sure you are running in a Vercel Function environment, or provide a token explicitly.\\n\\n\" +\n \"To set up your environment:\\n\" +\n \"1. Link your project: 'vercel link'\\n\" +\n \"2. Pull environment variables: 'vercel env pull'\\n\" +\n \"3. Run with environment: 'dotenv -e .env.local -- your-command'\",\n );\n }\n this.token = token;\n }\n }\n\n /**\n * Send a message to a queue\n * @param options Send message options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async sendMessage<T = unknown>(\n options: SendMessageOptions<T>,\n transport: Transport<T>,\n ): Promise<SendMessageResponse> {\n const { queueName, payload, idempotencyKey, retentionSeconds } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Content-Type\": transport.contentType,\n });\n\n if (process.env.VERCEL_DEPLOYMENT_ID) {\n headers.set(\"Vqs-Deployment-Id\", process.env.VERCEL_DEPLOYMENT_ID);\n }\n\n if (idempotencyKey) {\n headers.set(\"Vqs-Idempotency-Key\", idempotencyKey);\n }\n\n if (retentionSeconds !== undefined) {\n headers.set(\"Vqs-Retention-Seconds\", retentionSeconds.toString());\n }\n\n // Serialize the payload using the provided transport\n const body = transport.serialize(payload);\n\n const response = await fetch(`${this.baseUrl}${this.basePath}`, {\n method: \"POST\",\n headers,\n body,\n });\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 409) {\n throw new Error(\"Duplicate idempotency key detected\");\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to send message: ${response.status} ${response.statusText}`,\n );\n }\n\n const responseData = (await response.json()) as SendMessageResponse;\n\n return responseData;\n }\n\n /**\n * Receive messages from a queue\n * @param options Receive messages options\n * @param transport Serializer/deserializer for the payload\n * @returns AsyncGenerator that yields messages as they arrive\n * @throws {InvalidLimitError} When limit parameter is not between 1 and 10\n * @throws {QueueEmptyError} When no messages are available (204)\n * @throws {MessageLockedError} When messages are temporarily locked (423)\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async *receiveMessages<T = unknown>(\n options: ReceiveMessagesOptions<T>,\n transport: Transport<T>,\n ): AsyncGenerator<Message<T>, void, unknown> {\n const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } =\n options;\n\n // Validate limit parameter\n if (limit !== undefined && (limit < 1 || limit > 10)) {\n throw new InvalidLimitError(limit);\n }\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (limit !== undefined) {\n headers.set(\"Vqs-Limit\", limit.toString());\n }\n\n const response = await fetch(`${this.baseUrl}${this.basePath}`, {\n method: \"GET\",\n headers,\n });\n\n // Check for 204 No Content - queue is empty\n if (response.status === 204) {\n throw new QueueEmptyError(queueName, consumerGroup);\n }\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 423) {\n // Message locked - temporarily unavailable\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(\"next message\", retryAfter);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive messages: ${response.status} ${response.statusText}`,\n );\n }\n\n // Stream messages as they arrive from the multipart parser\n // Each message's payload stream must be consumed immediately for the parser to proceed\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse VQS headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n yield message;\n } catch (error) {\n console.warn(\"Failed to process multipart message:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n }\n }\n }\n\n /**\n * Receive a specific message by its ID from a queue\n * @param options Receive message by ID options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message or null if not found/available\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageLockedError} When the message is temporarily locked (423)\n * @throws {MessageNotAvailableError} When message exists but isn't available (409)\n * @throws {MessageCorruptedError} When message data is corrupted\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload: true },\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, true>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload?: false | undefined },\n transport: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, false>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T>,\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, boolean>> {\n const {\n queueName,\n consumerGroup,\n messageId,\n visibilityTimeoutSeconds,\n skipPayload,\n } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (skipPayload) {\n headers.set(\"Vqs-Skip-Payload\", \"1\");\n }\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"GET\",\n headers,\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n // Message not found\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 423) {\n // Message is temporarily locked\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(messageId, retryAfter);\n }\n\n if (response.status === 409) {\n // Message not available (wrong state or claimed by another consumer)\n throw new MessageNotAvailableError(messageId);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive message by ID: ${response.status} ${response.statusText}`,\n );\n }\n\n // Handle skipPayload case with 204 response\n if (skipPayload && response.status === 204) {\n const parsedHeaders = parseQueueHeaders(response.headers);\n\n if (!parsedHeaders) {\n throw new MessageCorruptedError(\n messageId,\n \"Missing required queue headers in 204 response\",\n );\n }\n\n const message: Message<void> = {\n ...parsedHeaders,\n payload: undefined as void,\n };\n\n return { message } as ReceiveMessageByIdResponse<T, boolean>;\n }\n\n // Handle regular multipart response\n if (!transport) {\n throw new Error(\"Transport is required when skipPayload is not true\");\n }\n\n // Parse multipart/mixed response using streaming parser\n try {\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse queue headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n return { message };\n } catch (error) {\n console.warn(\"Failed to deserialize message by ID:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n throw new MessageCorruptedError(\n messageId,\n `Failed to deserialize payload: ${error}`,\n );\n }\n }\n } catch (error) {\n if (error instanceof MessageCorruptedError) {\n throw error; // Re-throw our own errors\n }\n throw new MessageCorruptedError(\n messageId,\n `Failed to parse multipart response: ${error}`,\n );\n }\n\n // If we get here, no message was found in the multipart response\n throw new MessageNotFoundError(messageId);\n }\n\n /**\n * Delete a message (acknowledge processing)\n * @param options Delete message options\n * @returns Promise with delete status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be deleted (409)\n * @throws {BadRequestError} When ticket is missing or invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async deleteMessage(\n options: DeleteMessageOptions,\n ): Promise<DeleteMessageResponse> {\n const { queueName, consumerGroup, messageId, ticket } = options;\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"DELETE\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\"Missing or invalid ticket\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to delete message: ${response.status} ${response.statusText}`,\n );\n }\n\n return { deleted: true };\n }\n\n /**\n * Change the visibility timeout of a message\n * @param options Change visibility options\n * @returns Promise with update status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be updated (409)\n * @throws {BadRequestError} When ticket is missing or visibility timeout invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async changeVisibility(\n options: ChangeVisibilityOptions,\n ): Promise<ChangeVisibilityResponse> {\n const {\n queueName,\n consumerGroup,\n messageId,\n ticket,\n visibilityTimeoutSeconds,\n } = options;\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"PATCH\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n \"Vqs-Visibility-Timeout\": visibilityTimeoutSeconds.toString(),\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\n \"Missing ticket or invalid visibility timeout\",\n );\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to change visibility: ${response.status} ${response.statusText}`,\n );\n }\n\n return { updated: true };\n }\n}\n","// NOT SAFE TO CACHE\nexport function getVercelOidcToken(): string | null {\n const SYMBOL_FOR_REQ_CONTEXT = Symbol.for(\"@vercel/request-context\");\n const fromSymbol = globalThis as any;\n const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};\n\n const token =\n context.headers?.[\"x-vercel-oidc-token\"] ?? process.env.VERCEL_OIDC_TOKEN;\n\n if (!token) {\n return null;\n }\n\n return token;\n}\n","/**\n * Vercel Queue Service client types\n */\nimport type { Transport } from \"./transports\";\n\n// Re-export transport interface for convenience\nexport type { Transport };\n\nexport interface QueueClientOptions {\n /**\n * Base URL for the Vercel Queue Service API\n * @default \"https://api.vercel.com\"\n */\n baseUrl?: string;\n /**\n * Base path for API endpoints\n * @default \"/api/v2/messages\"\n */\n basePath?: string;\n /**\n * Vercel function OIDC token\n * Can be obtained from x-vercel-oidc-token header in Vercel Serverless Functions\n * If not provided, will automatically attempt to retrieve from Vercel Function environment\n */\n token?: string;\n}\n\n/**\n * Shared options for publishing messages\n */\nexport interface PublishOptions {\n /**\n * Unique key to prevent duplicate message submissions\n * @default random UUID\n */\n idempotencyKey?: string;\n /**\n * Message retention time in seconds\n * @default 86400 (24 hours)\n * @min 60\n * @max 86400\n */\n retentionSeconds?: number;\n}\n\nexport interface SendMessageOptions<T = unknown> extends PublishOptions {\n /**\n * The queue name to send the message to\n */\n queueName: string;\n /**\n * The message payload\n */\n payload: T;\n}\n\nexport interface SendMessageResponse {\n /**\n * The generated message ID\n */\n messageId: string;\n}\n\nexport interface Message<T = unknown> {\n /**\n * The message ID\n */\n messageId: string;\n /**\n * The deserialized message payload\n * Note: If using streaming transports, ensure proper cleanup by calling transport.finalize(payload)\n * when done processing, especially in error cases\n */\n payload: T;\n /**\n * Number of times this message has been delivered\n */\n deliveryCount: number;\n /**\n * Timestamp when the message was created\n */\n timestamp: string;\n /**\n * MIME type of the message content\n */\n contentType: string;\n /**\n * Unique ticket for this message delivery (required for delete/patch operations)\n */\n ticket: string;\n}\n\nexport interface ReceiveMessagesOptions<T = unknown> {\n /**\n * The queue name to receive messages from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Maximum number of messages to retrieve\n * @default 10\n * @max 10\n */\n limit?: number;\n}\n\nexport interface DeleteMessageOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to delete\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n}\n\nexport interface DeleteMessageResponse {\n /**\n * Whether the message was successfully deleted\n */\n deleted: boolean;\n}\n\nexport interface ChangeVisibilityOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to update\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n /**\n * New visibility timeout in seconds\n */\n visibilityTimeoutSeconds: number;\n}\n\nexport interface ChangeVisibilityResponse {\n /**\n * Whether the visibility was successfully updated\n */\n updated: boolean;\n}\n\n/**\n * Result indicating the message should be timed out for retry later\n */\nexport interface MessageTimeoutResult {\n /**\n * Time in seconds before the message becomes visible again\n */\n timeoutSeconds: number;\n}\n\n/**\n * Result returned by message handlers\n */\nexport type MessageHandlerResult = void | MessageTimeoutResult;\n\n/**\n * Message metadata provided to handlers\n */\nexport interface MessageMetadata {\n messageId: string;\n deliveryCount: number;\n timestamp: string;\n}\n\n/**\n * Message handler function type\n */\nexport type MessageHandler<T = unknown> = (\n message: T,\n metadata: MessageMetadata,\n) => Promise<MessageHandlerResult> | MessageHandlerResult;\n\n/**\n * Options for creating a ConsumerGroup instance\n */\nexport interface ConsumerGroupOptions<T = unknown> {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 30\n */\n visibilityTimeoutSeconds?: number;\n /**\n * How often to refresh the visibility timeout during processing (in seconds)\n * @default 10\n */\n refreshInterval?: number;\n}\n\nexport interface ReceiveMessageByIdOptions<T = unknown> {\n /**\n * The queue name to receive the message from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to retrieve\n */\n messageId: string;\n /**\n * Time in seconds that the message will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Skip payload content and only return message metadata\n * When true, the server returns a 204 status with headers containing message metadata\n * @default false\n */\n skipPayload?: boolean;\n}\n\n// Response type that always contains a message (errors are thrown for failures)\nexport interface ReceiveMessageByIdResponse<\n T = unknown,\n TSkipPayload extends boolean = false,\n> {\n message: TSkipPayload extends true ? Message<void> : Message<T>;\n}\n\n/**\n * Error thrown when a message is not found (404)\n */\nexport class MessageNotFoundError extends Error {\n constructor(messageId: string) {\n super(`Message ${messageId} not found`);\n this.name = \"MessageNotFoundError\";\n }\n}\n\n/**\n * Error thrown when a message is not available for processing (409)\n * This can happen when the message is in the wrong state, already claimed, etc.\n */\nexport class MessageNotAvailableError extends Error {\n constructor(messageId: string, reason?: string) {\n super(\n `Message ${messageId} not available for processing${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"MessageNotAvailableError\";\n }\n}\n\n/**\n * Error thrown when message data is corrupted or can't be parsed\n */\nexport class MessageCorruptedError extends Error {\n constructor(messageId: string, reason: string) {\n super(`Message ${messageId} is corrupted: ${reason}`);\n this.name = \"MessageCorruptedError\";\n }\n}\n\n/**\n * Error thrown when there are no messages available in the queue (204)\n */\nexport class QueueEmptyError extends Error {\n constructor(queueName: string, consumerGroup: string) {\n super(\n `No messages available in queue \"${queueName}\" for consumer group \"${consumerGroup}\"`,\n );\n this.name = \"QueueEmptyError\";\n }\n}\n\n/**\n * Error thrown when a message is temporarily locked (423)\n */\nexport class MessageLockedError extends Error {\n public readonly retryAfter?: number;\n\n constructor(messageId: string, retryAfter?: number) {\n const retryMessage = retryAfter\n ? ` Retry after ${retryAfter} seconds.`\n : \" Try again later.\";\n super(`Message ${messageId} is temporarily locked.${retryMessage}`);\n this.name = \"MessageLockedError\";\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when authentication fails (401)\n */\nexport class UnauthorizedError extends Error {\n constructor(message: string = \"Missing or invalid authentication token\") {\n super(message);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * Error thrown when access is forbidden (403)\n */\nexport class ForbiddenError extends Error {\n constructor(\n message: string = \"Queue environment doesn't match token environment\",\n ) {\n super(message);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * Error thrown for bad requests (400)\n */\nexport class BadRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * Error thrown for internal server errors (500)\n */\nexport class InternalServerError extends Error {\n constructor(message: string = \"Unexpected server error\") {\n super(message);\n this.name = \"InternalServerError\";\n }\n}\n\n/**\n * Error thrown when batch limit parameter is invalid\n */\nexport class InvalidLimitError extends Error {\n constructor(limit: number, min: number = 1, max: number = 10) {\n super(`Invalid limit: ${limit}. Limit must be between ${min} and ${max}.`);\n this.name = \"InvalidLimitError\";\n }\n}\n","import { QueueClient } from \"./client\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n Message,\n MessageHandler,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the consume method\n */\nexport interface ConsumeOptions {\n /** The specific message ID to consume (if not provided, consumes next available message) */\n messageId?: string;\n /** Whether to skip downloading the payload (only allowed when messageId is provided) */\n skipPayload?: boolean;\n}\n\n/**\n * A ConsumerGroup represents a named group of consumers that process messages from a topic\n */\nexport class ConsumerGroup<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private consumerGroupName: string;\n private visibilityTimeout: number;\n private refreshInterval: number;\n private transport: Transport<T>;\n\n /**\n * Create a new ConsumerGroup instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to consume from\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration\n */\n constructor(\n client: QueueClient,\n topicName: string,\n consumerGroupName: string,\n options: ConsumerGroupOptions<T> = {},\n ) {\n this.client = client;\n this.topicName = topicName;\n this.consumerGroupName = consumerGroupName;\n this.visibilityTimeout = options.visibilityTimeoutSeconds || 30; // 30 seconds default\n this.refreshInterval = options.refreshInterval || 10; // 10 seconds default\n this.transport = options.transport || new JsonTransport<T>();\n }\n\n /**\n * Starts a background loop that periodically extends the visibility timeout for a message.\n * This prevents the message from becoming visible to other consumers while it's being processed.\n *\n * The extension loop runs every `refreshInterval` seconds and updates the message's\n * visibility timeout to `visibilityTimeout` seconds from the current time.\n *\n * @param messageId - The unique identifier of the message to extend visibility for\n * @param ticket - The receipt ticket that proves ownership of the message\n * @returns A function that when called will stop the extension loop\n *\n * @remarks\n * - The first extension attempt occurs after `refreshInterval` seconds, not immediately\n * - If an extension fails, the loop terminates with an error logged to console\n * - The returned stop function is idempotent - calling it multiple times is safe\n * - By default, the stop function returns immediately without waiting for in-flight\n * - Pass `true` to the stop function to wait for any in-flight extension to complete\n */\n private startVisibilityExtension(\n messageId: string,\n ticket: string,\n ): (waitForCompletion?: boolean) => Promise<void> {\n let isRunning = true;\n let resolveLifecycle: () => void;\n let timeoutId: NodeJS.Timeout | null = null;\n\n // Promise that tracks the actual termination of the extension loop\n const lifecyclePromise = new Promise<void>((resolve) => {\n resolveLifecycle = resolve;\n });\n\n const extend = async (): Promise<void> => {\n // Check if we should stop before attempting extension\n if (!isRunning) {\n resolveLifecycle();\n return;\n }\n\n try {\n // Extend the visibility timeout for another period\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId,\n ticket,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n });\n\n // Schedule next extension if still running\n if (isRunning) {\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n } else {\n // Signal that the loop has terminated after successful extension\n resolveLifecycle();\n }\n } catch (error) {\n // Log error and terminate the loop on failure\n console.error(\n `Failed to extend visibility for message ${messageId}:`,\n error,\n );\n resolveLifecycle();\n }\n };\n\n // Schedule the first extension attempt\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n\n // Return a function to stop the extension loop\n return async (waitForCompletion: boolean = false) => {\n // Signal the loop to stop\n isRunning = false;\n\n // Cancel any pending timeout to avoid unnecessary waiting\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n // Only wait for in-flight operations if explicitly requested\n if (waitForCompletion) {\n // Wait for the loop to actually terminate\n // This ensures any in-progress extension completes or fails\n await lifecyclePromise;\n } else {\n // Resolve the lifecycle immediately for any waiting operations\n // This allows immediate return without waiting for in-flight extensions\n resolveLifecycle();\n }\n };\n }\n\n /**\n * Process a single message with the given handler\n * @param message The message to process\n * @param handler Function to process the message\n */\n private async processMessage<TPayload>(\n message: Message<TPayload>,\n handler: MessageHandler<TPayload>,\n ): Promise<void> {\n const stopExtension = this.startVisibilityExtension(\n message.messageId,\n message.ticket,\n );\n\n try {\n const result = await handler(message.payload, {\n messageId: message.messageId,\n deliveryCount: message.deliveryCount,\n timestamp: message.timestamp,\n });\n // Stop extensions immediately - we don't need to wait for in-flight extensions\n // since we're about to delete or update the message visibility anyway\n await stopExtension();\n\n if (result && \"timeoutSeconds\" in result) {\n // Handle timeout request - set new visibility timeout instead of deleting\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n visibilityTimeoutSeconds: result.timeoutSeconds,\n });\n } else {\n // Normal completion - delete the message\n await this.client.deleteMessage({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n });\n }\n } catch (error) {\n // Stop extensions immediately on error - fail fast without waiting\n // for any in-flight extension attempts\n await stopExtension();\n\n // Clean up the message payload if the transport supports it and payload exists\n // Only call finalize for non-void payloads since transport is typed for T, not void\n if (\n this.transport.finalize &&\n message.payload !== undefined &&\n message.payload !== null\n ) {\n try {\n // Safe cast: when processMessage<T> is called, TPayload is T\n // when processMessage<void> is called, payload is undefined so this won't execute\n await this.transport.finalize(message.payload as T);\n } catch (finalizeError) {\n console.warn(\"Failed to finalize message payload:\", finalizeError);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Consume the next available message from the queue\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(handler: MessageHandler<T>): Promise<void>;\n\n /**\n * Consume a specific message by its ID with full payload\n * @param handler Function to process the message\n * @param options Consume options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<T>,\n options: { messageId: string; skipPayload?: false | undefined },\n ): Promise<void>;\n\n /**\n * Consume a specific message by its ID without downloading the payload (metadata only)\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Consume options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<void>,\n options: { messageId: string; skipPayload: true },\n ): Promise<void>;\n\n async consume(\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ConsumeOptions,\n ): Promise<void> {\n if (options?.messageId) {\n // Specific message mode\n if (options.skipPayload) {\n // Skip payload - like old handleMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n skipPayload: true,\n },\n this.transport,\n );\n await this.processMessage<void>(\n response.message,\n handler as MessageHandler<void>,\n );\n } else {\n // With payload - like old receiveMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n },\n this.transport,\n );\n await this.processMessage<T>(\n response.message,\n handler as MessageHandler<T>,\n );\n }\n } else {\n // Next message mode - like old receiveNextMessage\n let messageFound = false;\n\n for await (const message of this.client.receiveMessages<T>(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n limit: 1,\n },\n this.transport,\n )) {\n messageFound = true;\n await this.processMessage<T>(message, handler as MessageHandler<T>);\n break; // Process only one message\n }\n\n // If we get here without finding a message, the async generator\n // should have already thrown QueueEmptyError, but just in case\n if (!messageFound) {\n throw new Error(\"No messages available\");\n }\n }\n }\n\n /**\n * Get the consumer group name\n */\n get name(): string {\n return this.consumerGroupName;\n }\n\n /**\n * Get the topic name this consumer group is subscribed to\n */\n get topic(): string {\n return this.topicName;\n }\n}\n","import { QueueClient } from \"./client\";\nimport { ConsumerGroup } from \"./consumer-group\";\nimport { JsonTransport } from \"./transports\";\nimport type { ConsumerGroupOptions, PublishOptions, Transport } from \"./types\";\n\n/**\n * A Topic represents a named channel for publishing messages in a pub/sub pattern\n */\nexport class Topic<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private transport: Transport<T>;\n\n /**\n * Create a new Topic instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to work with\n * @param transport Optional serializer/deserializer for the payload (defaults to JSON)\n */\n constructor(\n client: QueueClient,\n topicName: string,\n transport?: Transport<T>,\n ) {\n this.client = client;\n this.topicName = topicName;\n this.transport = transport || new JsonTransport<T>();\n }\n\n /**\n * Publish a message to the topic\n * @param payload The data to publish\n * @param options Optional publish options\n * @returns An object containing the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async publish(\n payload: T,\n options?: PublishOptions,\n ): Promise<{ messageId: string }> {\n const result = await this.client.sendMessage<T>(\n {\n queueName: this.topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n this.transport,\n );\n return { messageId: result.messageId };\n }\n\n /**\n * Create a consumer group for this topic\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration for the consumer group\n * @returns A ConsumerGroup instance\n */\n consumerGroup<U = T>(\n consumerGroupName: string,\n options?: ConsumerGroupOptions<U>,\n ): ConsumerGroup<U> {\n // If no transport is provided in options, use the topic's transport if types match\n const consumerOptions: ConsumerGroupOptions<U> = {\n ...options,\n transport:\n options?.transport || (this.transport as unknown as Transport<U>),\n };\n\n return new ConsumerGroup<U>(\n this.client,\n this.topicName,\n consumerGroupName,\n consumerOptions,\n );\n }\n\n /**\n * Get the topic name\n */\n get name(): string {\n return this.topicName;\n }\n\n /**\n * Get the transport used by this topic\n */\n get serializer(): Transport<T> {\n return this.transport;\n }\n}\n","import { QueueClient } from \"./client\";\nimport type { ConsumeOptions } from \"./consumer-group\";\nimport { Topic } from \"./topic\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n MessageHandler,\n PublishOptions,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the send function\n */\nexport interface SendOptions<T = unknown> extends PublishOptions {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n}\n\n/**\n * Send a message to a topic (shorthand for topic creation and publishing)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to send to\n * @param payload The data to send\n * @param options Optional send options including transport and publish settings\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\nexport async function send<T = unknown>(\n topicName: string,\n payload: T,\n options?: SendOptions<T>,\n): Promise<{ messageId: string }> {\n const transport = options?.transport || new JsonTransport<T>();\n const client = new QueueClient();\n\n const result = await client.sendMessage<T>(\n {\n queueName: topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n transport,\n );\n\n return { messageId: result.messageId };\n}\n\n/**\n * Options for the receive function\n */\nexport interface ReceiveOptions<T = unknown>\n extends ConsumerGroupOptions<T>,\n ConsumeOptions {}\n\n/**\n * Receive a message from a topic (shorthand for topic and consumer group creation)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options?: ReceiveOptions<T>,\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID with full payload\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @param options Receive options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options: ReceiveOptions<T> & {\n messageId: string;\n skipPayload?: false | undefined;\n },\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID without downloading the payload (metadata only)\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Receive options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<void>,\n options: ReceiveOptions<T> & { messageId: string; skipPayload: true },\n): Promise<void>;\n\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ReceiveOptions<T>,\n): Promise<void> {\n const transport = options?.transport || new JsonTransport<T>();\n\n // Create topic with transport directly\n const client = new QueueClient();\n const topic = new Topic<T>(client, topicName, transport);\n\n // Create consumer group with options (excluding consume-specific options)\n const { messageId, skipPayload, ...consumerGroupOptions } = options || {};\n const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);\n\n // Call consume with the appropriate overload based on options\n if (messageId) {\n if (skipPayload) {\n // skipPayload: true case\n return consumer.consume(handler as MessageHandler<void>, {\n messageId,\n skipPayload: true,\n });\n } else {\n // messageId with payload case\n return consumer.consume(handler as MessageHandler<T>, { messageId });\n }\n } else {\n // No options case - next available message\n return consumer.consume(handler as MessageHandler<T>);\n }\n}\n","/**\n * Queue Callback utilities for handling incoming webhook payloads from Vercel triggers\n */\nimport { QueueClient } from \"./client\";\nimport { Topic } from \"./topic\";\nimport type { MessageHandler } from \"./types\";\n\n/**\n * CloudEvent specification for queue callbacks\n */\nexport interface CloudEvent<T = unknown> {\n type: string;\n source: string;\n id: string;\n datacontenttype: string;\n data: T;\n time?: string;\n specversion?: string;\n}\n\n/**\n * Configuration object with handlers for different topics and consumer groups\n */\ntype CallbackHandlers = {\n [topicName: string]: { [consumerGroup: string]: MessageHandler };\n};\n\n/**\n * Parsed callback request information\n */\nexport type ParsedCallbackRequest = {\n queueName: string;\n consumerGroup: string;\n messageId: string;\n};\n\n/**\n * Parse and validate callback request using CloudEvent specification\n *\n * Extracts queue information from CloudEvent format and validates\n * that all required fields are present.\n *\n * @param request The incoming webhook request\n * @returns Parsed queue information\n * @throws Error if required fields are missing\n *\n * @example\n * ```typescript\n * // In Next.js API route\n * export async function POST(request: Request) {\n * try {\n * const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);\n *\n * // Use the parsed information...\n * await myWorkflow.handleWebhook(queueName, consumerGroup, messageId);\n *\n * return Response.json({ status: \"success\" });\n * } catch (error) {\n * return Response.json({ error: error.message }, { status: 400 });\n * }\n * }\n * ```\n */\nexport async function parseCallbackRequest(\n request: Request,\n): Promise<ParsedCallbackRequest> {\n // Validate content type header\n const contentType = request.headers.get(\"content-type\");\n if (!contentType || !contentType.includes(\"application/cloudevents+json\")) {\n throw new Error(\n \"Invalid content type: expected 'application/cloudevents+json'\",\n );\n }\n\n let cloudEvent: CloudEvent;\n\n try {\n cloudEvent = (await request.json()) as CloudEvent;\n } catch (error) {\n throw new Error(\"Failed to parse CloudEvent from request body\");\n }\n\n // Validate CloudEvent structure\n if (\n !cloudEvent.type ||\n !cloudEvent.source ||\n !cloudEvent.id ||\n typeof cloudEvent.data !== \"object\" ||\n cloudEvent.data == null\n ) {\n throw new Error(\"Invalid CloudEvent: missing required fields\");\n }\n\n // Validate CloudEvent type\n if (cloudEvent.type !== \"com.vercel.queue.v1beta\") {\n throw new Error(\n `Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`,\n );\n }\n\n // Check for required data fields before destructuring\n const missingFields: string[] = [];\n if (!(\"queueName\" in cloudEvent.data)) missingFields.push(\"queueName\");\n if (!(\"consumerGroup\" in cloudEvent.data))\n missingFields.push(\"consumerGroup\");\n if (!(\"messageId\" in cloudEvent.data)) missingFields.push(\"messageId\");\n if (missingFields.length > 0) {\n throw new Error(\n `Missing required CloudEvent data fields: ${missingFields.join(\", \")}`,\n );\n }\n\n const { messageId, queueName, consumerGroup } = cloudEvent.data as {\n messageId: string;\n queueName: string;\n consumerGroup: string;\n };\n\n return {\n queueName,\n consumerGroup,\n messageId,\n };\n}\n\n/**\n * Simplified queue callback handler for Next.js route handlers\n *\n * Automatically extracts queue information from CloudEvent format\n * and routes to the appropriate handler based on topic and consumer group.\n *\n * @param handlers Object with topic-specific handlers organized by consumer groups\n * @returns A Next.js route handler function\n *\n * @example\n * ```typescript\n * // Single topic with multiple consumer groups\n * export const POST = handleCallback({\n * \"image-processing\": {\n * \"compress\": (message, metadata) => console.log(\"Compressing image\", message),\n * \"resize\": (message, metadata) => console.log(\"Resizing image\", message),\n * }\n * });\n *\n * // Multiple topics with consumer groups\n * export const POST = handleCallback({\n * \"user-events\": {\n * \"welcome\": (user, metadata) => console.log(\"Welcoming user\", user),\n * \"analytics\": (user, metadata) => console.log(\"Tracking user\", user),\n * },\n * \"order-events\": {\n * \"fulfillment\": (order, metadata) => console.log(\"Fulfilling order\", order),\n * \"notifications\": (order, metadata) => console.log(\"Notifying order\", order),\n * }\n * });\n * ```\n */\nexport function handleCallback(\n handlers: CallbackHandlers,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n // Parse the callback request\n const { queueName, consumerGroup, messageId } =\n await parseCallbackRequest(request);\n\n // Find the topic handler\n const topicHandler = handlers[queueName];\n\n if (!topicHandler) {\n const availableTopics = Object.keys(handlers).join(\", \");\n return Response.json(\n {\n error: `No handler found for topic: ${queueName}`,\n availableTopics,\n },\n { status: 404 },\n );\n }\n\n // Find the consumer group handler\n const consumerGroupHandler = topicHandler[consumerGroup];\n\n if (!consumerGroupHandler) {\n const availableGroups = Object.keys(topicHandler).join(\", \");\n return Response.json(\n {\n error: `No handler found for consumer group \"${consumerGroup}\" in topic \"${queueName}\".`,\n availableGroups,\n },\n { status: 404 },\n );\n }\n\n // Create client and process the message\n const client = new QueueClient();\n const topic = new Topic(client, queueName);\n const cg = topic.consumerGroup(consumerGroup);\n\n await cg.consume(consumerGroupHandler, { messageId });\n\n return Response.json({ status: \"success\" });\n } catch (error) {\n console.error(\"Queue callback error:\", error);\n\n // Handle parsing errors with appropriate status codes\n if (\n error instanceof Error &&\n (error.message.includes(\"Missing required CloudEvent data fields\") ||\n error.message.includes(\"Invalid CloudEvent\") ||\n error.message.includes(\"Invalid CloudEvent type\") ||\n error.message.includes(\"Invalid content type\") ||\n error.message.includes(\"Failed to parse CloudEvent\"))\n ) {\n return Response.json({ error: error.message }, { status: 400 });\n }\n\n return Response.json(\n { error: \"Failed to process queue message\" },\n { status: 500 },\n );\n }\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -73,6 +73,18 @@ var StreamTransport = class {
73
73
  // src/client.ts
74
74
  import { parseMultipartStream } from "mixpart";
75
75
 
76
+ // src/oidc.ts
77
+ function getVercelOidcToken() {
78
+ const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
79
+ const fromSymbol = globalThis;
80
+ const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
81
+ const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
82
+ if (!token) {
83
+ return null;
84
+ }
85
+ return token;
86
+ }
87
+
76
88
  // src/types.ts
77
89
  var MessageNotFoundError = class extends Error {
78
90
  constructor(messageId) {
@@ -175,24 +187,21 @@ function parseQueueHeaders(headers) {
175
187
  ticket
176
188
  };
177
189
  }
178
- var QueueClient = class _QueueClient {
190
+ var QueueClient = class {
179
191
  baseUrl;
192
+ basePath;
180
193
  token;
181
- /**
182
- * Internal default instance for use by convenience functions
183
- * @internal
184
- */
185
- static _defaultInstance = null;
186
194
  /**
187
195
  * Create a new Vercel Queue Service client
188
196
  * @param options Client configuration options (optional - will auto-detect Vercel Function environment)
189
197
  */
190
198
  constructor(options = {}) {
191
- this.baseUrl = options.baseUrl || "https://vqs.vercel.sh";
199
+ this.baseUrl = options.baseUrl || "https://api.vercel.com";
200
+ this.basePath = options.basePath || "/v1/queue/messages";
192
201
  if (options.token) {
193
202
  this.token = options.token;
194
203
  } else {
195
- const token = this.getVercelOidcTokenSync();
204
+ const token = getVercelOidcToken();
196
205
  if (!token) {
197
206
  throw new Error(
198
207
  "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'"
@@ -201,31 +210,6 @@ var QueueClient = class _QueueClient {
201
210
  this.token = token;
202
211
  }
203
212
  }
204
- /**
205
- * Get the default client instance for internal use by convenience functions
206
- * @internal
207
- */
208
- static _getDefaultInstance() {
209
- if (!this._defaultInstance) {
210
- this._defaultInstance = new _QueueClient();
211
- }
212
- return this._defaultInstance;
213
- }
214
- /**
215
- * Synchronously get OIDC token from environment
216
- * Used internally by constructor - mirrors the logic from getVercelOidcToken but synchronously
217
- */
218
- getVercelOidcTokenSync() {
219
- try {
220
- const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
221
- const fromSymbol = globalThis;
222
- const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
223
- const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
224
- return token || null;
225
- } catch {
226
- return null;
227
- }
228
- }
229
213
  /**
230
214
  * Send a message to a queue
231
215
  * @param options Send message options
@@ -253,7 +237,7 @@ var QueueClient = class _QueueClient {
253
237
  headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
254
238
  }
255
239
  const body = transport.serialize(payload);
256
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
240
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
257
241
  method: "POST",
258
242
  headers,
259
243
  body
@@ -317,7 +301,7 @@ var QueueClient = class _QueueClient {
317
301
  if (limit !== void 0) {
318
302
  headers.set("Vqs-Limit", limit.toString());
319
303
  }
320
- const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
304
+ const response = await fetch(`${this.baseUrl}${this.basePath}`, {
321
305
  method: "GET",
322
306
  headers
323
307
  });
@@ -399,7 +383,7 @@ var QueueClient = class _QueueClient {
399
383
  headers.set("Vqs-Skip-Payload", "1");
400
384
  }
401
385
  const response = await fetch(
402
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
386
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
403
387
  {
404
388
  method: "GET",
405
389
  headers
@@ -508,7 +492,7 @@ var QueueClient = class _QueueClient {
508
492
  async deleteMessage(options) {
509
493
  const { queueName, consumerGroup, messageId, ticket } = options;
510
494
  const response = await fetch(
511
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
495
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
512
496
  {
513
497
  method: "DELETE",
514
498
  headers: new Headers({
@@ -569,7 +553,7 @@ var QueueClient = class _QueueClient {
569
553
  visibilityTimeoutSeconds
570
554
  } = options;
571
555
  const response = await fetch(
572
- `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,
556
+ `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,
573
557
  {
574
558
  method: "PATCH",
575
559
  headers: new Headers({
@@ -887,7 +871,7 @@ var Topic = class {
887
871
  // src/factory.ts
888
872
  async function send(topicName, payload, options) {
889
873
  const transport = options?.transport || new JsonTransport();
890
- const client = QueueClient._getDefaultInstance();
874
+ const client = new QueueClient();
891
875
  const result = await client.sendMessage(
892
876
  {
893
877
  queueName: topicName,
@@ -901,7 +885,7 @@ async function send(topicName, payload, options) {
901
885
  }
902
886
  async function receive(topicName, consumerGroup, handler, options) {
903
887
  const transport = options?.transport || new JsonTransport();
904
- const client = QueueClient._getDefaultInstance();
888
+ const client = new QueueClient();
905
889
  const topic = new Topic(client, topicName, transport);
906
890
  const { messageId, skipPayload, ...consumerGroupOptions } = options || {};
907
891
  const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);
@@ -920,19 +904,38 @@ async function receive(topicName, consumerGroup, handler, options) {
920
904
  }
921
905
 
922
906
  // src/callback.ts
923
- function parseCallbackRequest(request) {
924
- const queueName = request.headers.get("Vqs-Queue-Name");
925
- const consumerGroup = request.headers.get("Vqs-Consumer-Group");
926
- const messageId = request.headers.get("Vqs-Message-Id");
927
- if (!queueName || !consumerGroup || !messageId) {
928
- const missingHeaders = [];
929
- if (!queueName) missingHeaders.push("Vqs-Queue-Name");
930
- if (!consumerGroup) missingHeaders.push("Vqs-Consumer-Group");
931
- if (!messageId) missingHeaders.push("Vqs-Message-Id");
907
+ async function parseCallbackRequest(request) {
908
+ const contentType = request.headers.get("content-type");
909
+ if (!contentType || !contentType.includes("application/cloudevents+json")) {
910
+ throw new Error(
911
+ "Invalid content type: expected 'application/cloudevents+json'"
912
+ );
913
+ }
914
+ let cloudEvent;
915
+ try {
916
+ cloudEvent = await request.json();
917
+ } catch (error) {
918
+ throw new Error("Failed to parse CloudEvent from request body");
919
+ }
920
+ if (!cloudEvent.type || !cloudEvent.source || !cloudEvent.id || typeof cloudEvent.data !== "object" || cloudEvent.data == null) {
921
+ throw new Error("Invalid CloudEvent: missing required fields");
922
+ }
923
+ if (cloudEvent.type !== "com.vercel.queue.v1beta") {
924
+ throw new Error(
925
+ `Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`
926
+ );
927
+ }
928
+ const missingFields = [];
929
+ if (!("queueName" in cloudEvent.data)) missingFields.push("queueName");
930
+ if (!("consumerGroup" in cloudEvent.data))
931
+ missingFields.push("consumerGroup");
932
+ if (!("messageId" in cloudEvent.data)) missingFields.push("messageId");
933
+ if (missingFields.length > 0) {
932
934
  throw new Error(
933
- `Missing required queue headers: ${missingHeaders.join(", ")}`
935
+ `Missing required CloudEvent data fields: ${missingFields.join(", ")}`
934
936
  );
935
937
  }
938
+ const { messageId, queueName, consumerGroup } = cloudEvent.data;
936
939
  return {
937
940
  queueName,
938
941
  consumerGroup,
@@ -942,7 +945,7 @@ function parseCallbackRequest(request) {
942
945
  function handleCallback(handlers) {
943
946
  return async (request) => {
944
947
  try {
945
- const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);
948
+ const { queueName, consumerGroup, messageId } = await parseCallbackRequest(request);
946
949
  const topicHandler = handlers[queueName];
947
950
  if (!topicHandler) {
948
951
  const availableTopics = Object.keys(handlers).join(", ");
@@ -972,7 +975,7 @@ function handleCallback(handlers) {
972
975
  return Response.json({ status: "success" });
973
976
  } catch (error) {
974
977
  console.error("Queue callback error:", error);
975
- if (error instanceof Error && error.message.includes("Missing required queue headers")) {
978
+ 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"))) {
976
979
  return Response.json({ error: error.message }, { status: 400 });
977
980
  }
978
981
  return Response.json(
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports.ts","../src/client.ts","../src/types.ts","../src/consumer-group.ts","../src/topic.ts","../src/factory.ts","../src/callback.ts"],"sourcesContent":["/**\n * Serializer/Deserializer interface for message payloads\n */\nexport interface Transport<T = unknown> {\n /**\n * Serialize a value to a buffer or stream for transmission\n */\n serialize(value: T): Buffer | ReadableStream<Uint8Array>;\n\n /**\n * Deserialize a readable stream back to the original value\n */\n deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;\n\n /**\n * Optional cleanup method for deserialized payloads that may contain resources\n * Should be called when the payload is no longer needed, especially in error cases\n * @param payload The deserialized payload to clean up\n */\n finalize?(payload: T): Promise<void>;\n\n /**\n * MIME type for this serialization format\n */\n contentType: string;\n}\n\n/**\n * Built-in JSON serializer/deserializer\n * This implementation reads the entire stream into memory for JSON parsing\n */\nexport class JsonTransport<T = unknown> implements Transport<T> {\n readonly contentType = \"application/json\";\n\n serialize(value: T): Buffer {\n return Buffer.from(JSON.stringify(value), \"utf8\");\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<T> {\n // JSON requires reading the entire payload to parse\n const reader = stream.getReader();\n let totalLength = 0;\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const buffer = Buffer.concat(chunks, totalLength);\n return JSON.parse(buffer.toString(\"utf8\"));\n }\n}\n\n/**\n * Built-in Buffer serializer/deserializer (reads entire stream into a Buffer)\n */\nexport class BufferTransport implements Transport<Buffer> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: Buffer): Buffer {\n return value;\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<Buffer> {\n // Buffer transport reads the entire stream into memory\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.length;\n }\n\n return Buffer.from(buffer);\n }\n}\n\n/**\n * Stream serializer/deserializer (pass-through for streaming binary data)\n * This is ideal for large payloads that don't need to be buffered in memory\n *\n * IMPORTANT: When using StreamTransport, you must call finalize(payload) when done\n * processing the message to prevent resource leaks, especially in error cases.\n * ConsumerGroup handles this automatically, but direct QueueClient usage requires manual cleanup.\n *\n * Example usage:\n * ```typescript\n * const transport = new StreamTransport();\n * try {\n * for await (const message of client.receiveMessages(options, transport)) {\n * // Process the stream...\n * const reader = message.payload.getReader();\n * // ... handle stream data\n * }\n * } catch (error) {\n * // Cleanup is handled automatically by ConsumerGroup\n * // or manually: await transport.finalize(message.payload);\n * }\n */\nexport class StreamTransport implements Transport<ReadableStream<Uint8Array>> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n // Pass through the stream directly without buffering\n return value;\n }\n\n async deserialize(\n stream: ReadableStream<Uint8Array>,\n ): Promise<ReadableStream<Uint8Array>> {\n // Pass through the stream directly without buffering\n return stream;\n }\n\n async finalize(payload: ReadableStream<Uint8Array>): Promise<void> {\n // Consume any remaining stream data to prevent resource leaks\n const reader = payload.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","import { parseMultipartStream } from \"mixpart\";\nimport type {\n ChangeVisibilityOptions,\n ChangeVisibilityResponse,\n DeleteMessageOptions,\n DeleteMessageResponse,\n Message,\n QueueClientOptions,\n ReceiveMessageByIdOptions,\n ReceiveMessageByIdResponse,\n ReceiveMessagesOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\nimport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n/**\n * Helper function to consume a ReadableStream to completion\n * This is necessary when we need to drain a stream to let the multipart parser proceed\n */\nasync function consumeStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<void> {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Helper function to parse queue headers into a partial message object\n * Handles both multipart message headers and HTTP response headers\n */\nfunction parseQueueHeaders(\n headers: Headers,\n): Omit<Message<unknown>, \"payload\"> | null {\n const messageId = headers.get(\"Vqs-Message-Id\");\n const deliveryCountStr = headers.get(\"Vqs-Delivery-Count\") || \"0\";\n const timestamp = headers.get(\"Vqs-Timestamp\");\n const contentType = headers.get(\"Content-Type\") || \"application/octet-stream\";\n const ticket = headers.get(\"Vqs-Ticket\");\n\n if (!messageId || !timestamp || !ticket) {\n return null;\n }\n\n const deliveryCount = parseInt(deliveryCountStr, 10);\n if (isNaN(deliveryCount)) {\n return null;\n }\n\n return {\n messageId,\n deliveryCount,\n timestamp,\n contentType,\n ticket,\n };\n}\n\n/**\n * Client for interacting with the Vercel Queue Service API\n */\nexport class QueueClient {\n private baseUrl: string;\n private token: string;\n\n /**\n * Internal default instance for use by convenience functions\n * @internal\n */\n private static _defaultInstance: QueueClient | null = null;\n\n /**\n * Create a new Vercel Queue Service client\n * @param options Client configuration options (optional - will auto-detect Vercel Function environment)\n */\n constructor(options: QueueClientOptions = {}) {\n this.baseUrl = options.baseUrl || \"https://vqs.vercel.sh\";\n\n if (options.token) {\n this.token = options.token;\n } else {\n // Try to get OIDC token from Vercel Function environment\n const token = this.getVercelOidcTokenSync();\n if (!token) {\n throw new Error(\n \"Failed to get OIDC token from Vercel Functions. \" +\n \"Make sure you are running in a Vercel Function environment, or provide a token explicitly.\\n\\n\" +\n \"To set up your environment:\\n\" +\n \"1. Link your project: 'vercel link'\\n\" +\n \"2. Pull environment variables: 'vercel env pull'\\n\" +\n \"3. Run with environment: 'dotenv -e .env.local -- your-command'\",\n );\n }\n this.token = token;\n }\n }\n\n /**\n * Get the default client instance for internal use by convenience functions\n * @internal\n */\n static _getDefaultInstance(): QueueClient {\n if (!this._defaultInstance) {\n this._defaultInstance = new QueueClient();\n }\n return this._defaultInstance;\n }\n\n /**\n * Synchronously get OIDC token from environment\n * Used internally by constructor - mirrors the logic from getVercelOidcToken but synchronously\n */\n private getVercelOidcTokenSync(): string | null {\n try {\n // Check for OIDC token in request context (same logic as async version)\n const SYMBOL_FOR_REQ_CONTEXT = Symbol.for(\"@vercel/request-context\");\n const fromSymbol = globalThis as any;\n const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};\n\n const token =\n context.headers?.[\"x-vercel-oidc-token\"] ??\n process.env.VERCEL_OIDC_TOKEN;\n\n return token || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Send a message to a queue\n * @param options Send message options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async sendMessage<T = unknown>(\n options: SendMessageOptions<T>,\n transport: Transport<T>,\n ): Promise<SendMessageResponse> {\n const { queueName, payload, idempotencyKey, retentionSeconds } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Content-Type\": transport.contentType,\n });\n\n if (process.env.VERCEL_DEPLOYMENT_ID) {\n headers.set(\"Vqs-Deployment-Id\", process.env.VERCEL_DEPLOYMENT_ID);\n }\n\n if (idempotencyKey) {\n headers.set(\"Vqs-Idempotency-Key\", idempotencyKey);\n }\n\n if (retentionSeconds !== undefined) {\n headers.set(\"Vqs-Retention-Seconds\", retentionSeconds.toString());\n }\n\n // Serialize the payload using the provided transport\n const body = transport.serialize(payload);\n\n const response = await fetch(`${this.baseUrl}/api/v2/messages`, {\n method: \"POST\",\n headers,\n body,\n });\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 409) {\n throw new Error(\"Duplicate idempotency key detected\");\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to send message: ${response.status} ${response.statusText}`,\n );\n }\n\n const responseData = (await response.json()) as SendMessageResponse;\n\n return responseData;\n }\n\n /**\n * Receive messages from a queue\n * @param options Receive messages options\n * @param transport Serializer/deserializer for the payload\n * @returns AsyncGenerator that yields messages as they arrive\n * @throws {InvalidLimitError} When limit parameter is not between 1 and 10\n * @throws {QueueEmptyError} When no messages are available (204)\n * @throws {MessageLockedError} When messages are temporarily locked (423)\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async *receiveMessages<T = unknown>(\n options: ReceiveMessagesOptions<T>,\n transport: Transport<T>,\n ): AsyncGenerator<Message<T>, void, unknown> {\n const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } =\n options;\n\n // Validate limit parameter\n if (limit !== undefined && (limit < 1 || limit > 10)) {\n throw new InvalidLimitError(limit);\n }\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (limit !== undefined) {\n headers.set(\"Vqs-Limit\", limit.toString());\n }\n\n const response = await fetch(`${this.baseUrl}/api/v2/messages`, {\n method: \"GET\",\n headers,\n });\n\n // Check for 204 No Content - queue is empty\n if (response.status === 204) {\n throw new QueueEmptyError(queueName, consumerGroup);\n }\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 423) {\n // Message locked - temporarily unavailable\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(\"next message\", retryAfter);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive messages: ${response.status} ${response.statusText}`,\n );\n }\n\n // Stream messages as they arrive from the multipart parser\n // Each message's payload stream must be consumed immediately for the parser to proceed\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse VQS headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n yield message;\n } catch (error) {\n console.warn(\"Failed to process multipart message:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n }\n }\n }\n\n /**\n * Receive a specific message by its ID from a queue\n * @param options Receive message by ID options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message or null if not found/available\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageLockedError} When the message is temporarily locked (423)\n * @throws {MessageNotAvailableError} When message exists but isn't available (409)\n * @throws {MessageCorruptedError} When message data is corrupted\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload: true },\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, true>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload?: false | undefined },\n transport: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, false>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T>,\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, boolean>> {\n const {\n queueName,\n consumerGroup,\n messageId,\n visibilityTimeoutSeconds,\n skipPayload,\n } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (skipPayload) {\n headers.set(\"Vqs-Skip-Payload\", \"1\");\n }\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"GET\",\n headers,\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n // Message not found\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 423) {\n // Message is temporarily locked\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(messageId, retryAfter);\n }\n\n if (response.status === 409) {\n // Message not available (wrong state or claimed by another consumer)\n throw new MessageNotAvailableError(messageId);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive message by ID: ${response.status} ${response.statusText}`,\n );\n }\n\n // Handle skipPayload case with 204 response\n if (skipPayload && response.status === 204) {\n const parsedHeaders = parseQueueHeaders(response.headers);\n\n if (!parsedHeaders) {\n throw new MessageCorruptedError(\n messageId,\n \"Missing required queue headers in 204 response\",\n );\n }\n\n const message: Message<void> = {\n ...parsedHeaders,\n payload: undefined as void,\n };\n\n return { message } as ReceiveMessageByIdResponse<T, boolean>;\n }\n\n // Handle regular multipart response\n if (!transport) {\n throw new Error(\"Transport is required when skipPayload is not true\");\n }\n\n // Parse multipart/mixed response using streaming parser\n try {\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse queue headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n return { message };\n } catch (error) {\n console.warn(\"Failed to deserialize message by ID:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n throw new MessageCorruptedError(\n messageId,\n `Failed to deserialize payload: ${error}`,\n );\n }\n }\n } catch (error) {\n if (error instanceof MessageCorruptedError) {\n throw error; // Re-throw our own errors\n }\n throw new MessageCorruptedError(\n messageId,\n `Failed to parse multipart response: ${error}`,\n );\n }\n\n // If we get here, no message was found in the multipart response\n throw new MessageNotFoundError(messageId);\n }\n\n /**\n * Delete a message (acknowledge processing)\n * @param options Delete message options\n * @returns Promise with delete status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be deleted (409)\n * @throws {BadRequestError} When ticket is missing or invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async deleteMessage(\n options: DeleteMessageOptions,\n ): Promise<DeleteMessageResponse> {\n const { queueName, consumerGroup, messageId, ticket } = options;\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"DELETE\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\"Missing or invalid ticket\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to delete message: ${response.status} ${response.statusText}`,\n );\n }\n\n return { deleted: true };\n }\n\n /**\n * Change the visibility timeout of a message\n * @param options Change visibility options\n * @returns Promise with update status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be updated (409)\n * @throws {BadRequestError} When ticket is missing or visibility timeout invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async changeVisibility(\n options: ChangeVisibilityOptions,\n ): Promise<ChangeVisibilityResponse> {\n const {\n queueName,\n consumerGroup,\n messageId,\n ticket,\n visibilityTimeoutSeconds,\n } = options;\n\n const response = await fetch(\n `${this.baseUrl}/api/v2/messages/${encodeURIComponent(messageId)}`,\n {\n method: \"PATCH\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n \"Vqs-Visibility-Timeout\": visibilityTimeoutSeconds.toString(),\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\n \"Missing ticket or invalid visibility timeout\",\n );\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to change visibility: ${response.status} ${response.statusText}`,\n );\n }\n\n return { updated: true };\n }\n}\n","/**\n * Vercel Queue Service client types\n */\nimport type { Transport } from \"./transports\";\n\n// Re-export transport interface for convenience\nexport type { Transport };\n\nexport interface QueueClientOptions {\n /**\n * Base URL for the Vercel Queue Service API\n * @default \"https://vqs.vercel.sh\"\n */\n baseUrl?: string;\n /**\n * Vercel function OIDC token\n * Can be obtained from x-vercel-oidc-token header in Vercel Serverless Functions\n * If not provided, will automatically attempt to retrieve from Vercel Function environment\n */\n token?: string;\n}\n\n/**\n * Shared options for publishing messages\n */\nexport interface PublishOptions {\n /**\n * Unique key to prevent duplicate message submissions\n * @default random UUID\n */\n idempotencyKey?: string;\n /**\n * Message retention time in seconds\n * @default 86400 (24 hours)\n * @min 60\n * @max 86400\n */\n retentionSeconds?: number;\n}\n\nexport interface SendMessageOptions<T = unknown> extends PublishOptions {\n /**\n * The queue name to send the message to\n */\n queueName: string;\n /**\n * The message payload\n */\n payload: T;\n}\n\nexport interface SendMessageResponse {\n /**\n * The generated message ID\n */\n messageId: string;\n}\n\nexport interface Message<T = unknown> {\n /**\n * The message ID\n */\n messageId: string;\n /**\n * The deserialized message payload\n * Note: If using streaming transports, ensure proper cleanup by calling transport.finalize(payload)\n * when done processing, especially in error cases\n */\n payload: T;\n /**\n * Number of times this message has been delivered\n */\n deliveryCount: number;\n /**\n * Timestamp when the message was created\n */\n timestamp: string;\n /**\n * MIME type of the message content\n */\n contentType: string;\n /**\n * Unique ticket for this message delivery (required for delete/patch operations)\n */\n ticket: string;\n}\n\nexport interface ReceiveMessagesOptions<T = unknown> {\n /**\n * The queue name to receive messages from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Maximum number of messages to retrieve\n * @default 10\n * @max 10\n */\n limit?: number;\n}\n\nexport interface DeleteMessageOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to delete\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n}\n\nexport interface DeleteMessageResponse {\n /**\n * Whether the message was successfully deleted\n */\n deleted: boolean;\n}\n\nexport interface ChangeVisibilityOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to update\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n /**\n * New visibility timeout in seconds\n */\n visibilityTimeoutSeconds: number;\n}\n\nexport interface ChangeVisibilityResponse {\n /**\n * Whether the visibility was successfully updated\n */\n updated: boolean;\n}\n\n/**\n * Result indicating the message should be timed out for retry later\n */\nexport interface MessageTimeoutResult {\n /**\n * Time in seconds before the message becomes visible again\n */\n timeoutSeconds: number;\n}\n\n/**\n * Result returned by message handlers\n */\nexport type MessageHandlerResult = void | MessageTimeoutResult;\n\n/**\n * Message metadata provided to handlers\n */\nexport interface MessageMetadata {\n messageId: string;\n deliveryCount: number;\n timestamp: string;\n}\n\n/**\n * Message handler function type\n */\nexport type MessageHandler<T = unknown> = (\n message: T,\n metadata: MessageMetadata,\n) => Promise<MessageHandlerResult> | MessageHandlerResult;\n\n/**\n * Options for creating a ConsumerGroup instance\n */\nexport interface ConsumerGroupOptions<T = unknown> {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 30\n */\n visibilityTimeoutSeconds?: number;\n /**\n * How often to refresh the visibility timeout during processing (in seconds)\n * @default 10\n */\n refreshInterval?: number;\n}\n\nexport interface ReceiveMessageByIdOptions<T = unknown> {\n /**\n * The queue name to receive the message from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to retrieve\n */\n messageId: string;\n /**\n * Time in seconds that the message will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Skip payload content and only return message metadata\n * When true, the server returns a 204 status with headers containing message metadata\n * @default false\n */\n skipPayload?: boolean;\n}\n\n// Response type that always contains a message (errors are thrown for failures)\nexport interface ReceiveMessageByIdResponse<\n T = unknown,\n TSkipPayload extends boolean = false,\n> {\n message: TSkipPayload extends true ? Message<void> : Message<T>;\n}\n\n/**\n * Error thrown when a message is not found (404)\n */\nexport class MessageNotFoundError extends Error {\n constructor(messageId: string) {\n super(`Message ${messageId} not found`);\n this.name = \"MessageNotFoundError\";\n }\n}\n\n/**\n * Error thrown when a message is not available for processing (409)\n * This can happen when the message is in the wrong state, already claimed, etc.\n */\nexport class MessageNotAvailableError extends Error {\n constructor(messageId: string, reason?: string) {\n super(\n `Message ${messageId} not available for processing${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"MessageNotAvailableError\";\n }\n}\n\n/**\n * Error thrown when message data is corrupted or can't be parsed\n */\nexport class MessageCorruptedError extends Error {\n constructor(messageId: string, reason: string) {\n super(`Message ${messageId} is corrupted: ${reason}`);\n this.name = \"MessageCorruptedError\";\n }\n}\n\n/**\n * Error thrown when there are no messages available in the queue (204)\n */\nexport class QueueEmptyError extends Error {\n constructor(queueName: string, consumerGroup: string) {\n super(\n `No messages available in queue \"${queueName}\" for consumer group \"${consumerGroup}\"`,\n );\n this.name = \"QueueEmptyError\";\n }\n}\n\n/**\n * Error thrown when a message is temporarily locked (423)\n */\nexport class MessageLockedError extends Error {\n public readonly retryAfter?: number;\n\n constructor(messageId: string, retryAfter?: number) {\n const retryMessage = retryAfter\n ? ` Retry after ${retryAfter} seconds.`\n : \" Try again later.\";\n super(`Message ${messageId} is temporarily locked.${retryMessage}`);\n this.name = \"MessageLockedError\";\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when authentication fails (401)\n */\nexport class UnauthorizedError extends Error {\n constructor(message: string = \"Missing or invalid authentication token\") {\n super(message);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * Error thrown when access is forbidden (403)\n */\nexport class ForbiddenError extends Error {\n constructor(\n message: string = \"Queue environment doesn't match token environment\",\n ) {\n super(message);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * Error thrown for bad requests (400)\n */\nexport class BadRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * Error thrown for internal server errors (500)\n */\nexport class InternalServerError extends Error {\n constructor(message: string = \"Unexpected server error\") {\n super(message);\n this.name = \"InternalServerError\";\n }\n}\n\n/**\n * Error thrown when batch limit parameter is invalid\n */\nexport class InvalidLimitError extends Error {\n constructor(limit: number, min: number = 1, max: number = 10) {\n super(`Invalid limit: ${limit}. Limit must be between ${min} and ${max}.`);\n this.name = \"InvalidLimitError\";\n }\n}\n","import { QueueClient } from \"./client\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n Message,\n MessageHandler,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the consume method\n */\nexport interface ConsumeOptions {\n /** The specific message ID to consume (if not provided, consumes next available message) */\n messageId?: string;\n /** Whether to skip downloading the payload (only allowed when messageId is provided) */\n skipPayload?: boolean;\n}\n\n/**\n * A ConsumerGroup represents a named group of consumers that process messages from a topic\n */\nexport class ConsumerGroup<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private consumerGroupName: string;\n private visibilityTimeout: number;\n private refreshInterval: number;\n private transport: Transport<T>;\n\n /**\n * Create a new ConsumerGroup instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to consume from\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration\n */\n constructor(\n client: QueueClient,\n topicName: string,\n consumerGroupName: string,\n options: ConsumerGroupOptions<T> = {},\n ) {\n this.client = client;\n this.topicName = topicName;\n this.consumerGroupName = consumerGroupName;\n this.visibilityTimeout = options.visibilityTimeoutSeconds || 30; // 30 seconds default\n this.refreshInterval = options.refreshInterval || 10; // 10 seconds default\n this.transport = options.transport || new JsonTransport<T>();\n }\n\n /**\n * Starts a background loop that periodically extends the visibility timeout for a message.\n * This prevents the message from becoming visible to other consumers while it's being processed.\n *\n * The extension loop runs every `refreshInterval` seconds and updates the message's\n * visibility timeout to `visibilityTimeout` seconds from the current time.\n *\n * @param messageId - The unique identifier of the message to extend visibility for\n * @param ticket - The receipt ticket that proves ownership of the message\n * @returns A function that when called will stop the extension loop\n *\n * @remarks\n * - The first extension attempt occurs after `refreshInterval` seconds, not immediately\n * - If an extension fails, the loop terminates with an error logged to console\n * - The returned stop function is idempotent - calling it multiple times is safe\n * - By default, the stop function returns immediately without waiting for in-flight\n * - Pass `true` to the stop function to wait for any in-flight extension to complete\n */\n private startVisibilityExtension(\n messageId: string,\n ticket: string,\n ): (waitForCompletion?: boolean) => Promise<void> {\n let isRunning = true;\n let resolveLifecycle: () => void;\n let timeoutId: NodeJS.Timeout | null = null;\n\n // Promise that tracks the actual termination of the extension loop\n const lifecyclePromise = new Promise<void>((resolve) => {\n resolveLifecycle = resolve;\n });\n\n const extend = async (): Promise<void> => {\n // Check if we should stop before attempting extension\n if (!isRunning) {\n resolveLifecycle();\n return;\n }\n\n try {\n // Extend the visibility timeout for another period\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId,\n ticket,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n });\n\n // Schedule next extension if still running\n if (isRunning) {\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n } else {\n // Signal that the loop has terminated after successful extension\n resolveLifecycle();\n }\n } catch (error) {\n // Log error and terminate the loop on failure\n console.error(\n `Failed to extend visibility for message ${messageId}:`,\n error,\n );\n resolveLifecycle();\n }\n };\n\n // Schedule the first extension attempt\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n\n // Return a function to stop the extension loop\n return async (waitForCompletion: boolean = false) => {\n // Signal the loop to stop\n isRunning = false;\n\n // Cancel any pending timeout to avoid unnecessary waiting\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n // Only wait for in-flight operations if explicitly requested\n if (waitForCompletion) {\n // Wait for the loop to actually terminate\n // This ensures any in-progress extension completes or fails\n await lifecyclePromise;\n } else {\n // Resolve the lifecycle immediately for any waiting operations\n // This allows immediate return without waiting for in-flight extensions\n resolveLifecycle();\n }\n };\n }\n\n /**\n * Process a single message with the given handler\n * @param message The message to process\n * @param handler Function to process the message\n */\n private async processMessage<TPayload>(\n message: Message<TPayload>,\n handler: MessageHandler<TPayload>,\n ): Promise<void> {\n const stopExtension = this.startVisibilityExtension(\n message.messageId,\n message.ticket,\n );\n\n try {\n const result = await handler(message.payload, {\n messageId: message.messageId,\n deliveryCount: message.deliveryCount,\n timestamp: message.timestamp,\n });\n // Stop extensions immediately - we don't need to wait for in-flight extensions\n // since we're about to delete or update the message visibility anyway\n await stopExtension();\n\n if (result && \"timeoutSeconds\" in result) {\n // Handle timeout request - set new visibility timeout instead of deleting\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n visibilityTimeoutSeconds: result.timeoutSeconds,\n });\n } else {\n // Normal completion - delete the message\n await this.client.deleteMessage({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n });\n }\n } catch (error) {\n // Stop extensions immediately on error - fail fast without waiting\n // for any in-flight extension attempts\n await stopExtension();\n\n // Clean up the message payload if the transport supports it and payload exists\n // Only call finalize for non-void payloads since transport is typed for T, not void\n if (\n this.transport.finalize &&\n message.payload !== undefined &&\n message.payload !== null\n ) {\n try {\n // Safe cast: when processMessage<T> is called, TPayload is T\n // when processMessage<void> is called, payload is undefined so this won't execute\n await this.transport.finalize(message.payload as T);\n } catch (finalizeError) {\n console.warn(\"Failed to finalize message payload:\", finalizeError);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Consume the next available message from the queue\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(handler: MessageHandler<T>): Promise<void>;\n\n /**\n * Consume a specific message by its ID with full payload\n * @param handler Function to process the message\n * @param options Consume options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<T>,\n options: { messageId: string; skipPayload?: false | undefined },\n ): Promise<void>;\n\n /**\n * Consume a specific message by its ID without downloading the payload (metadata only)\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Consume options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<void>,\n options: { messageId: string; skipPayload: true },\n ): Promise<void>;\n\n async consume(\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ConsumeOptions,\n ): Promise<void> {\n if (options?.messageId) {\n // Specific message mode\n if (options.skipPayload) {\n // Skip payload - like old handleMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n skipPayload: true,\n },\n this.transport,\n );\n await this.processMessage<void>(\n response.message,\n handler as MessageHandler<void>,\n );\n } else {\n // With payload - like old receiveMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n },\n this.transport,\n );\n await this.processMessage<T>(\n response.message,\n handler as MessageHandler<T>,\n );\n }\n } else {\n // Next message mode - like old receiveNextMessage\n let messageFound = false;\n\n for await (const message of this.client.receiveMessages<T>(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n limit: 1,\n },\n this.transport,\n )) {\n messageFound = true;\n await this.processMessage<T>(message, handler as MessageHandler<T>);\n break; // Process only one message\n }\n\n // If we get here without finding a message, the async generator\n // should have already thrown QueueEmptyError, but just in case\n if (!messageFound) {\n throw new Error(\"No messages available\");\n }\n }\n }\n\n /**\n * Get the consumer group name\n */\n get name(): string {\n return this.consumerGroupName;\n }\n\n /**\n * Get the topic name this consumer group is subscribed to\n */\n get topic(): string {\n return this.topicName;\n }\n}\n","import { QueueClient } from \"./client\";\nimport { ConsumerGroup } from \"./consumer-group\";\nimport { JsonTransport } from \"./transports\";\nimport type { ConsumerGroupOptions, PublishOptions, Transport } from \"./types\";\n\n/**\n * A Topic represents a named channel for publishing messages in a pub/sub pattern\n */\nexport class Topic<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private transport: Transport<T>;\n\n /**\n * Create a new Topic instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to work with\n * @param transport Optional serializer/deserializer for the payload (defaults to JSON)\n */\n constructor(\n client: QueueClient,\n topicName: string,\n transport?: Transport<T>,\n ) {\n this.client = client;\n this.topicName = topicName;\n this.transport = transport || new JsonTransport<T>();\n }\n\n /**\n * Publish a message to the topic\n * @param payload The data to publish\n * @param options Optional publish options\n * @returns An object containing the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async publish(\n payload: T,\n options?: PublishOptions,\n ): Promise<{ messageId: string }> {\n const result = await this.client.sendMessage<T>(\n {\n queueName: this.topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n this.transport,\n );\n return { messageId: result.messageId };\n }\n\n /**\n * Create a consumer group for this topic\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration for the consumer group\n * @returns A ConsumerGroup instance\n */\n consumerGroup<U = T>(\n consumerGroupName: string,\n options?: ConsumerGroupOptions<U>,\n ): ConsumerGroup<U> {\n // If no transport is provided in options, use the topic's transport if types match\n const consumerOptions: ConsumerGroupOptions<U> = {\n ...options,\n transport:\n options?.transport || (this.transport as unknown as Transport<U>),\n };\n\n return new ConsumerGroup<U>(\n this.client,\n this.topicName,\n consumerGroupName,\n consumerOptions,\n );\n }\n\n /**\n * Get the topic name\n */\n get name(): string {\n return this.topicName;\n }\n\n /**\n * Get the transport used by this topic\n */\n get serializer(): Transport<T> {\n return this.transport;\n }\n}\n","import { QueueClient } from \"./client\";\nimport type { ConsumeOptions } from \"./consumer-group\";\nimport { Topic } from \"./topic\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n MessageHandler,\n PublishOptions,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the send function\n */\nexport interface SendOptions<T = unknown> extends PublishOptions {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n}\n\n/**\n * Send a message to a topic (shorthand for topic creation and publishing)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to send to\n * @param payload The data to send\n * @param options Optional send options including transport and publish settings\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\nexport async function send<T = unknown>(\n topicName: string,\n payload: T,\n options?: SendOptions<T>,\n): Promise<{ messageId: string }> {\n const transport = options?.transport || new JsonTransport<T>();\n const client = QueueClient._getDefaultInstance();\n\n const result = await client.sendMessage<T>(\n {\n queueName: topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n transport,\n );\n\n return { messageId: result.messageId };\n}\n\n/**\n * Options for the receive function\n */\nexport interface ReceiveOptions<T = unknown>\n extends ConsumerGroupOptions<T>,\n ConsumeOptions {}\n\n/**\n * Receive a message from a topic (shorthand for topic and consumer group creation)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options?: ReceiveOptions<T>,\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID with full payload\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @param options Receive options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options: ReceiveOptions<T> & {\n messageId: string;\n skipPayload?: false | undefined;\n },\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID without downloading the payload (metadata only)\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Receive options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<void>,\n options: ReceiveOptions<T> & { messageId: string; skipPayload: true },\n): Promise<void>;\n\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ReceiveOptions<T>,\n): Promise<void> {\n const transport = options?.transport || new JsonTransport<T>();\n\n // Create topic with transport directly\n const client = QueueClient._getDefaultInstance();\n const topic = new Topic<T>(client, topicName, transport);\n\n // Create consumer group with options (excluding consume-specific options)\n const { messageId, skipPayload, ...consumerGroupOptions } = options || {};\n const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);\n\n // Call consume with the appropriate overload based on options\n if (messageId) {\n if (skipPayload) {\n // skipPayload: true case\n return consumer.consume(handler as MessageHandler<void>, {\n messageId,\n skipPayload: true,\n });\n } else {\n // messageId with payload case\n return consumer.consume(handler as MessageHandler<T>, { messageId });\n }\n } else {\n // No options case - next available message\n return consumer.consume(handler as MessageHandler<T>);\n }\n}\n","/**\n * Queue Callback utilities for handling incoming webhook payloads from Vercel triggers\n */\nimport { QueueClient } from \"./client\";\nimport { Topic } from \"./topic\";\nimport type { MessageHandler } from \"./types\";\n\n/**\n * Configuration object with handlers for different topics and consumer groups\n */\ntype CallbackHandlers = {\n [topicName: string]: { [consumerGroup: string]: MessageHandler };\n};\n\n/**\n * Parsed callback request information\n */\nexport type ParsedCallbackRequest = {\n queueName: string;\n consumerGroup: string;\n messageId: string;\n};\n\n/**\n * Parse and validate callback request headers\n *\n * Extracts queue information from Vercel-provided headers and validates\n * that all required headers are present.\n *\n * @param request The incoming webhook request\n * @returns Parsed queue information\n * @throws Error if required headers are missing\n *\n * @example\n * ```typescript\n * // In Next.js API route\n * export async function POST(request: Request) {\n * try {\n * const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);\n *\n * // Use the parsed information...\n * await myWorkflow.handleWebhook(queueName, consumerGroup, messageId);\n *\n * return Response.json({ status: \"success\" });\n * } catch (error) {\n * return Response.json({ error: error.message }, { status: 400 });\n * }\n * }\n * ```\n */\nexport function parseCallbackRequest(request: Request): ParsedCallbackRequest {\n // Extract queue information from Vercel-provided headers\n const queueName = request.headers.get(\"Vqs-Queue-Name\");\n const consumerGroup = request.headers.get(\"Vqs-Consumer-Group\");\n const messageId = request.headers.get(\"Vqs-Message-Id\");\n\n // Validate all required headers are present\n if (!queueName || !consumerGroup || !messageId) {\n const missingHeaders: string[] = [];\n if (!queueName) missingHeaders.push(\"Vqs-Queue-Name\");\n if (!consumerGroup) missingHeaders.push(\"Vqs-Consumer-Group\");\n if (!messageId) missingHeaders.push(\"Vqs-Message-Id\");\n\n throw new Error(\n `Missing required queue headers: ${missingHeaders.join(\", \")}`,\n );\n }\n\n return {\n queueName,\n consumerGroup,\n messageId,\n };\n}\n\n/**\n * Simplified queue callback handler for Next.js route handlers\n *\n * Automatically extracts queue information from Vercel-provided headers\n * and routes to the appropriate handler based on topic and consumer group.\n *\n * @param handlers Object with topic-specific handlers organized by consumer groups\n * @returns A Next.js route handler function\n *\n * @example\n * ```typescript\n * // Single topic with multiple consumer groups\n * export const POST = handleCallback({\n * \"image-processing\": {\n * \"compress\": (message, metadata) => console.log(\"Compressing image\", message),\n * \"resize\": (message, metadata) => console.log(\"Resizing image\", message),\n * }\n * });\n *\n * // Multiple topics with consumer groups\n * export const POST = handleCallback({\n * \"user-events\": {\n * \"welcome\": (user, metadata) => console.log(\"Welcoming user\", user),\n * \"analytics\": (user, metadata) => console.log(\"Tracking user\", user),\n * },\n * \"order-events\": {\n * \"fulfillment\": (order, metadata) => console.log(\"Fulfilling order\", order),\n * \"notifications\": (order, metadata) => console.log(\"Notifying order\", order),\n * }\n * });\n * ```\n */\nexport function handleCallback(\n handlers: CallbackHandlers,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n // Parse the callback request\n const { queueName, consumerGroup, messageId } =\n parseCallbackRequest(request);\n\n // Find the topic handler\n const topicHandler = handlers[queueName];\n\n if (!topicHandler) {\n const availableTopics = Object.keys(handlers).join(\", \");\n return Response.json(\n {\n error: `No handler found for topic: ${queueName}`,\n availableTopics,\n },\n { status: 404 },\n );\n }\n\n // Find the consumer group handler\n const consumerGroupHandler = topicHandler[consumerGroup];\n\n if (!consumerGroupHandler) {\n const availableGroups = Object.keys(topicHandler).join(\", \");\n return Response.json(\n {\n error: `No handler found for consumer group \"${consumerGroup}\" in topic \"${queueName}\".`,\n availableGroups,\n },\n { status: 404 },\n );\n }\n\n // Create client and process the message\n const client = new QueueClient();\n const topic = new Topic(client, queueName);\n const cg = topic.consumerGroup(consumerGroup);\n\n await cg.consume(consumerGroupHandler, { messageId });\n\n return Response.json({ status: \"success\" });\n } catch (error) {\n console.error(\"Queue callback error:\", error);\n\n // Handle parsing errors with appropriate status codes\n if (\n error instanceof Error &&\n error.message.includes(\"Missing required queue headers\")\n ) {\n return Response.json({ error: error.message }, { status: 400 });\n }\n\n return Response.json(\n { error: \"Failed to process queue message\" },\n { status: 500 },\n );\n }\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/transports.ts","../src/client.ts","../src/oidc.ts","../src/types.ts","../src/consumer-group.ts","../src/topic.ts","../src/factory.ts","../src/callback.ts"],"sourcesContent":["/**\n * Serializer/Deserializer interface for message payloads\n */\nexport interface Transport<T = unknown> {\n /**\n * Serialize a value to a buffer or stream for transmission\n */\n serialize(value: T): Buffer | ReadableStream<Uint8Array>;\n\n /**\n * Deserialize a readable stream back to the original value\n */\n deserialize(stream: ReadableStream<Uint8Array>): Promise<T>;\n\n /**\n * Optional cleanup method for deserialized payloads that may contain resources\n * Should be called when the payload is no longer needed, especially in error cases\n * @param payload The deserialized payload to clean up\n */\n finalize?(payload: T): Promise<void>;\n\n /**\n * MIME type for this serialization format\n */\n contentType: string;\n}\n\n/**\n * Built-in JSON serializer/deserializer\n * This implementation reads the entire stream into memory for JSON parsing\n */\nexport class JsonTransport<T = unknown> implements Transport<T> {\n readonly contentType = \"application/json\";\n\n serialize(value: T): Buffer {\n return Buffer.from(JSON.stringify(value), \"utf8\");\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<T> {\n // JSON requires reading the entire payload to parse\n const reader = stream.getReader();\n let totalLength = 0;\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n totalLength += value.length;\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const buffer = Buffer.concat(chunks, totalLength);\n return JSON.parse(buffer.toString(\"utf8\"));\n }\n}\n\n/**\n * Built-in Buffer serializer/deserializer (reads entire stream into a Buffer)\n */\nexport class BufferTransport implements Transport<Buffer> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: Buffer): Buffer {\n return value;\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<Buffer> {\n // Buffer transport reads the entire stream into memory\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n // Combine chunks into a single buffer\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\n const buffer = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n buffer.set(chunk, offset);\n offset += chunk.length;\n }\n\n return Buffer.from(buffer);\n }\n}\n\n/**\n * Stream serializer/deserializer (pass-through for streaming binary data)\n * This is ideal for large payloads that don't need to be buffered in memory\n *\n * IMPORTANT: When using StreamTransport, you must call finalize(payload) when done\n * processing the message to prevent resource leaks, especially in error cases.\n * ConsumerGroup handles this automatically, but direct QueueClient usage requires manual cleanup.\n *\n * Example usage:\n * ```typescript\n * const transport = new StreamTransport();\n * try {\n * for await (const message of client.receiveMessages(options, transport)) {\n * // Process the stream...\n * const reader = message.payload.getReader();\n * // ... handle stream data\n * }\n * } catch (error) {\n * // Cleanup is handled automatically by ConsumerGroup\n * // or manually: await transport.finalize(message.payload);\n * }\n */\nexport class StreamTransport implements Transport<ReadableStream<Uint8Array>> {\n readonly contentType = \"application/octet-stream\";\n\n serialize(value: ReadableStream<Uint8Array>): ReadableStream<Uint8Array> {\n // Pass through the stream directly without buffering\n return value;\n }\n\n async deserialize(\n stream: ReadableStream<Uint8Array>,\n ): Promise<ReadableStream<Uint8Array>> {\n // Pass through the stream directly without buffering\n return stream;\n }\n\n async finalize(payload: ReadableStream<Uint8Array>): Promise<void> {\n // Consume any remaining stream data to prevent resource leaks\n const reader = payload.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n","import { parseMultipartStream } from \"mixpart\";\nimport { getVercelOidcToken } from \"./oidc\";\nimport type {\n ChangeVisibilityOptions,\n ChangeVisibilityResponse,\n DeleteMessageOptions,\n DeleteMessageResponse,\n Message,\n QueueClientOptions,\n ReceiveMessageByIdOptions,\n ReceiveMessageByIdResponse,\n ReceiveMessagesOptions,\n SendMessageOptions,\n SendMessageResponse,\n Transport,\n} from \"./types\";\nimport {\n BadRequestError,\n ForbiddenError,\n InternalServerError,\n InvalidLimitError,\n MessageCorruptedError,\n MessageLockedError,\n MessageNotAvailableError,\n MessageNotFoundError,\n QueueEmptyError,\n UnauthorizedError,\n} from \"./types\";\n\n/**\n * Helper function to consume a ReadableStream to completion\n * This is necessary when we need to drain a stream to let the multipart parser proceed\n */\nasync function consumeStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<void> {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done } = await reader.read();\n if (done) break;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\n/**\n * Helper function to parse queue headers into a partial message object\n * Handles both multipart message headers and HTTP response headers\n */\nfunction parseQueueHeaders(\n headers: Headers,\n): Omit<Message<unknown>, \"payload\"> | null {\n const messageId = headers.get(\"Vqs-Message-Id\");\n const deliveryCountStr = headers.get(\"Vqs-Delivery-Count\") || \"0\";\n const timestamp = headers.get(\"Vqs-Timestamp\");\n const contentType = headers.get(\"Content-Type\") || \"application/octet-stream\";\n const ticket = headers.get(\"Vqs-Ticket\");\n\n if (!messageId || !timestamp || !ticket) {\n return null;\n }\n\n const deliveryCount = parseInt(deliveryCountStr, 10);\n if (isNaN(deliveryCount)) {\n return null;\n }\n\n return {\n messageId,\n deliveryCount,\n timestamp,\n contentType,\n ticket,\n };\n}\n\n/**\n * Client for interacting with the Vercel Queue Service API\n */\nexport class QueueClient {\n private baseUrl: string;\n private basePath: string;\n private token: string;\n\n /**\n * Create a new Vercel Queue Service client\n * @param options Client configuration options (optional - will auto-detect Vercel Function environment)\n */\n constructor(options: QueueClientOptions = {}) {\n this.baseUrl = options.baseUrl || \"https://api.vercel.com\";\n this.basePath = options.basePath || \"/v1/queue/messages\";\n\n if (options.token) {\n this.token = options.token;\n } else {\n // Try to get OIDC token from Vercel Function environment\n const token = getVercelOidcToken();\n if (!token) {\n throw new Error(\n \"Failed to get OIDC token from Vercel Functions. \" +\n \"Make sure you are running in a Vercel Function environment, or provide a token explicitly.\\n\\n\" +\n \"To set up your environment:\\n\" +\n \"1. Link your project: 'vercel link'\\n\" +\n \"2. Pull environment variables: 'vercel env pull'\\n\" +\n \"3. Run with environment: 'dotenv -e .env.local -- your-command'\",\n );\n }\n this.token = token;\n }\n }\n\n /**\n * Send a message to a queue\n * @param options Send message options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async sendMessage<T = unknown>(\n options: SendMessageOptions<T>,\n transport: Transport<T>,\n ): Promise<SendMessageResponse> {\n const { queueName, payload, idempotencyKey, retentionSeconds } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Content-Type\": transport.contentType,\n });\n\n if (process.env.VERCEL_DEPLOYMENT_ID) {\n headers.set(\"Vqs-Deployment-Id\", process.env.VERCEL_DEPLOYMENT_ID);\n }\n\n if (idempotencyKey) {\n headers.set(\"Vqs-Idempotency-Key\", idempotencyKey);\n }\n\n if (retentionSeconds !== undefined) {\n headers.set(\"Vqs-Retention-Seconds\", retentionSeconds.toString());\n }\n\n // Serialize the payload using the provided transport\n const body = transport.serialize(payload);\n\n const response = await fetch(`${this.baseUrl}${this.basePath}`, {\n method: \"POST\",\n headers,\n body,\n });\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 409) {\n throw new Error(\"Duplicate idempotency key detected\");\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to send message: ${response.status} ${response.statusText}`,\n );\n }\n\n const responseData = (await response.json()) as SendMessageResponse;\n\n return responseData;\n }\n\n /**\n * Receive messages from a queue\n * @param options Receive messages options\n * @param transport Serializer/deserializer for the payload\n * @returns AsyncGenerator that yields messages as they arrive\n * @throws {InvalidLimitError} When limit parameter is not between 1 and 10\n * @throws {QueueEmptyError} When no messages are available (204)\n * @throws {MessageLockedError} When messages are temporarily locked (423)\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async *receiveMessages<T = unknown>(\n options: ReceiveMessagesOptions<T>,\n transport: Transport<T>,\n ): AsyncGenerator<Message<T>, void, unknown> {\n const { queueName, consumerGroup, visibilityTimeoutSeconds, limit } =\n options;\n\n // Validate limit parameter\n if (limit !== undefined && (limit < 1 || limit > 10)) {\n throw new InvalidLimitError(limit);\n }\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (limit !== undefined) {\n headers.set(\"Vqs-Limit\", limit.toString());\n }\n\n const response = await fetch(`${this.baseUrl}${this.basePath}`, {\n method: \"GET\",\n headers,\n });\n\n // Check for 204 No Content - queue is empty\n if (response.status === 204) {\n throw new QueueEmptyError(queueName, consumerGroup);\n }\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 423) {\n // Message locked - temporarily unavailable\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(\"next message\", retryAfter);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive messages: ${response.status} ${response.statusText}`,\n );\n }\n\n // Stream messages as they arrive from the multipart parser\n // Each message's payload stream must be consumed immediately for the parser to proceed\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse VQS headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n yield message;\n } catch (error) {\n console.warn(\"Failed to process multipart message:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n }\n }\n }\n\n /**\n * Receive a specific message by its ID from a queue\n * @param options Receive message by ID options\n * @param transport Serializer/deserializer for the payload\n * @returns Promise with the message or null if not found/available\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageLockedError} When the message is temporarily locked (423)\n * @throws {MessageNotAvailableError} When message exists but isn't available (409)\n * @throws {MessageCorruptedError} When message data is corrupted\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload: true },\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, true>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T> & { skipPayload?: false | undefined },\n transport: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, false>>;\n async receiveMessageById<T = unknown>(\n options: ReceiveMessageByIdOptions<T>,\n transport?: Transport<T>,\n ): Promise<ReceiveMessageByIdResponse<T, boolean>> {\n const {\n queueName,\n consumerGroup,\n messageId,\n visibilityTimeoutSeconds,\n skipPayload,\n } = options;\n\n const headers = new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n Accept: \"multipart/mixed\",\n });\n\n if (visibilityTimeoutSeconds !== undefined) {\n headers.set(\n \"Vqs-Visibility-Timeout\",\n visibilityTimeoutSeconds.toString(),\n );\n }\n\n if (skipPayload) {\n headers.set(\"Vqs-Skip-Payload\", \"1\");\n }\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"GET\",\n headers,\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n const errorText = await response.text();\n throw new BadRequestError(errorText || \"Invalid parameters\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n // Message not found\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 423) {\n // Message is temporarily locked\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n let retryAfter: number | undefined;\n if (retryAfterHeader) {\n const parsed = parseInt(retryAfterHeader, 10);\n retryAfter = isNaN(parsed) ? undefined : parsed;\n }\n throw new MessageLockedError(messageId, retryAfter);\n }\n\n if (response.status === 409) {\n // Message not available (wrong state or claimed by another consumer)\n throw new MessageNotAvailableError(messageId);\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to receive message by ID: ${response.status} ${response.statusText}`,\n );\n }\n\n // Handle skipPayload case with 204 response\n if (skipPayload && response.status === 204) {\n const parsedHeaders = parseQueueHeaders(response.headers);\n\n if (!parsedHeaders) {\n throw new MessageCorruptedError(\n messageId,\n \"Missing required queue headers in 204 response\",\n );\n }\n\n const message: Message<void> = {\n ...parsedHeaders,\n payload: undefined as void,\n };\n\n return { message } as ReceiveMessageByIdResponse<T, boolean>;\n }\n\n // Handle regular multipart response\n if (!transport) {\n throw new Error(\"Transport is required when skipPayload is not true\");\n }\n\n // Parse multipart/mixed response using streaming parser\n try {\n for await (const multipartMessage of parseMultipartStream(response)) {\n try {\n // Parse queue headers using the helper function\n const parsedHeaders = parseQueueHeaders(multipartMessage.headers);\n\n if (!parsedHeaders) {\n console.warn(\"Missing required queue headers in multipart part\");\n // Still need to consume the payload stream to let the parser proceed\n await consumeStream(multipartMessage.payload);\n continue;\n }\n\n // Deserialize using the provided transport (must consume the stream)\n const deserializedPayload = await transport.deserialize(\n multipartMessage.payload,\n );\n\n const message: Message<T> = {\n ...parsedHeaders,\n payload: deserializedPayload,\n };\n\n return { message };\n } catch (error) {\n console.warn(\"Failed to deserialize message by ID:\", error);\n // If deserialization failed, we still need to consume the payload stream\n // to let the multipart parser proceed to the next message\n await consumeStream(multipartMessage.payload);\n throw new MessageCorruptedError(\n messageId,\n `Failed to deserialize payload: ${error}`,\n );\n }\n }\n } catch (error) {\n if (error instanceof MessageCorruptedError) {\n throw error; // Re-throw our own errors\n }\n throw new MessageCorruptedError(\n messageId,\n `Failed to parse multipart response: ${error}`,\n );\n }\n\n // If we get here, no message was found in the multipart response\n throw new MessageNotFoundError(messageId);\n }\n\n /**\n * Delete a message (acknowledge processing)\n * @param options Delete message options\n * @returns Promise with delete status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be deleted (409)\n * @throws {BadRequestError} When ticket is missing or invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async deleteMessage(\n options: DeleteMessageOptions,\n ): Promise<DeleteMessageResponse> {\n const { queueName, consumerGroup, messageId, ticket } = options;\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"DELETE\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\"Missing or invalid ticket\");\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to delete message: ${response.status} ${response.statusText}`,\n );\n }\n\n return { deleted: true };\n }\n\n /**\n * Change the visibility timeout of a message\n * @param options Change visibility options\n * @returns Promise with update status\n * @throws {MessageNotFoundError} When the message doesn't exist (404)\n * @throws {MessageNotAvailableError} When message can't be updated (409)\n * @throws {BadRequestError} When ticket is missing or visibility timeout invalid (400)\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async changeVisibility(\n options: ChangeVisibilityOptions,\n ): Promise<ChangeVisibilityResponse> {\n const {\n queueName,\n consumerGroup,\n messageId,\n ticket,\n visibilityTimeoutSeconds,\n } = options;\n\n const response = await fetch(\n `${this.baseUrl}${this.basePath}/${encodeURIComponent(messageId)}`,\n {\n method: \"PATCH\",\n headers: new Headers({\n Authorization: `Bearer ${this.token}`,\n \"Vqs-Queue-Name\": queueName,\n \"Vqs-Consumer-Group\": consumerGroup,\n \"Vqs-Ticket\": ticket,\n \"Vqs-Visibility-Timeout\": visibilityTimeoutSeconds.toString(),\n }),\n },\n );\n\n if (!response.ok) {\n if (response.status === 400) {\n throw new BadRequestError(\n \"Missing ticket or invalid visibility timeout\",\n );\n }\n if (response.status === 401) {\n throw new UnauthorizedError();\n }\n if (response.status === 403) {\n throw new ForbiddenError();\n }\n if (response.status === 404) {\n throw new MessageNotFoundError(messageId);\n }\n if (response.status === 409) {\n throw new MessageNotAvailableError(\n messageId,\n \"Invalid ticket, message not in correct state, or already processed\",\n );\n }\n if (response.status >= 500) {\n throw new InternalServerError(\n `Server error: ${response.status} ${response.statusText}`,\n );\n }\n throw new Error(\n `Failed to change visibility: ${response.status} ${response.statusText}`,\n );\n }\n\n return { updated: true };\n }\n}\n","// NOT SAFE TO CACHE\nexport function getVercelOidcToken(): string | null {\n const SYMBOL_FOR_REQ_CONTEXT = Symbol.for(\"@vercel/request-context\");\n const fromSymbol = globalThis as any;\n const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};\n\n const token =\n context.headers?.[\"x-vercel-oidc-token\"] ?? process.env.VERCEL_OIDC_TOKEN;\n\n if (!token) {\n return null;\n }\n\n return token;\n}\n","/**\n * Vercel Queue Service client types\n */\nimport type { Transport } from \"./transports\";\n\n// Re-export transport interface for convenience\nexport type { Transport };\n\nexport interface QueueClientOptions {\n /**\n * Base URL for the Vercel Queue Service API\n * @default \"https://api.vercel.com\"\n */\n baseUrl?: string;\n /**\n * Base path for API endpoints\n * @default \"/api/v2/messages\"\n */\n basePath?: string;\n /**\n * Vercel function OIDC token\n * Can be obtained from x-vercel-oidc-token header in Vercel Serverless Functions\n * If not provided, will automatically attempt to retrieve from Vercel Function environment\n */\n token?: string;\n}\n\n/**\n * Shared options for publishing messages\n */\nexport interface PublishOptions {\n /**\n * Unique key to prevent duplicate message submissions\n * @default random UUID\n */\n idempotencyKey?: string;\n /**\n * Message retention time in seconds\n * @default 86400 (24 hours)\n * @min 60\n * @max 86400\n */\n retentionSeconds?: number;\n}\n\nexport interface SendMessageOptions<T = unknown> extends PublishOptions {\n /**\n * The queue name to send the message to\n */\n queueName: string;\n /**\n * The message payload\n */\n payload: T;\n}\n\nexport interface SendMessageResponse {\n /**\n * The generated message ID\n */\n messageId: string;\n}\n\nexport interface Message<T = unknown> {\n /**\n * The message ID\n */\n messageId: string;\n /**\n * The deserialized message payload\n * Note: If using streaming transports, ensure proper cleanup by calling transport.finalize(payload)\n * when done processing, especially in error cases\n */\n payload: T;\n /**\n * Number of times this message has been delivered\n */\n deliveryCount: number;\n /**\n * Timestamp when the message was created\n */\n timestamp: string;\n /**\n * MIME type of the message content\n */\n contentType: string;\n /**\n * Unique ticket for this message delivery (required for delete/patch operations)\n */\n ticket: string;\n}\n\nexport interface ReceiveMessagesOptions<T = unknown> {\n /**\n * The queue name to receive messages from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Maximum number of messages to retrieve\n * @default 10\n * @max 10\n */\n limit?: number;\n}\n\nexport interface DeleteMessageOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to delete\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n}\n\nexport interface DeleteMessageResponse {\n /**\n * Whether the message was successfully deleted\n */\n deleted: boolean;\n}\n\nexport interface ChangeVisibilityOptions {\n /**\n * The queue name the message belongs to\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to update\n */\n messageId: string;\n /**\n * Ticket received from the message\n */\n ticket: string;\n /**\n * New visibility timeout in seconds\n */\n visibilityTimeoutSeconds: number;\n}\n\nexport interface ChangeVisibilityResponse {\n /**\n * Whether the visibility was successfully updated\n */\n updated: boolean;\n}\n\n/**\n * Result indicating the message should be timed out for retry later\n */\nexport interface MessageTimeoutResult {\n /**\n * Time in seconds before the message becomes visible again\n */\n timeoutSeconds: number;\n}\n\n/**\n * Result returned by message handlers\n */\nexport type MessageHandlerResult = void | MessageTimeoutResult;\n\n/**\n * Message metadata provided to handlers\n */\nexport interface MessageMetadata {\n messageId: string;\n deliveryCount: number;\n timestamp: string;\n}\n\n/**\n * Message handler function type\n */\nexport type MessageHandler<T = unknown> = (\n message: T,\n metadata: MessageMetadata,\n) => Promise<MessageHandlerResult> | MessageHandlerResult;\n\n/**\n * Options for creating a ConsumerGroup instance\n */\nexport interface ConsumerGroupOptions<T = unknown> {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n /**\n * Time in seconds that messages will be invisible to other consumers\n * @default 30\n */\n visibilityTimeoutSeconds?: number;\n /**\n * How often to refresh the visibility timeout during processing (in seconds)\n * @default 10\n */\n refreshInterval?: number;\n}\n\nexport interface ReceiveMessageByIdOptions<T = unknown> {\n /**\n * The queue name to receive the message from\n */\n queueName: string;\n /**\n * Consumer group name\n */\n consumerGroup: string;\n /**\n * The message ID to retrieve\n */\n messageId: string;\n /**\n * Time in seconds that the message will be invisible to other consumers\n * @default 900 (15 minutes)\n */\n visibilityTimeoutSeconds?: number;\n /**\n * Skip payload content and only return message metadata\n * When true, the server returns a 204 status with headers containing message metadata\n * @default false\n */\n skipPayload?: boolean;\n}\n\n// Response type that always contains a message (errors are thrown for failures)\nexport interface ReceiveMessageByIdResponse<\n T = unknown,\n TSkipPayload extends boolean = false,\n> {\n message: TSkipPayload extends true ? Message<void> : Message<T>;\n}\n\n/**\n * Error thrown when a message is not found (404)\n */\nexport class MessageNotFoundError extends Error {\n constructor(messageId: string) {\n super(`Message ${messageId} not found`);\n this.name = \"MessageNotFoundError\";\n }\n}\n\n/**\n * Error thrown when a message is not available for processing (409)\n * This can happen when the message is in the wrong state, already claimed, etc.\n */\nexport class MessageNotAvailableError extends Error {\n constructor(messageId: string, reason?: string) {\n super(\n `Message ${messageId} not available for processing${reason ? `: ${reason}` : \"\"}`,\n );\n this.name = \"MessageNotAvailableError\";\n }\n}\n\n/**\n * Error thrown when message data is corrupted or can't be parsed\n */\nexport class MessageCorruptedError extends Error {\n constructor(messageId: string, reason: string) {\n super(`Message ${messageId} is corrupted: ${reason}`);\n this.name = \"MessageCorruptedError\";\n }\n}\n\n/**\n * Error thrown when there are no messages available in the queue (204)\n */\nexport class QueueEmptyError extends Error {\n constructor(queueName: string, consumerGroup: string) {\n super(\n `No messages available in queue \"${queueName}\" for consumer group \"${consumerGroup}\"`,\n );\n this.name = \"QueueEmptyError\";\n }\n}\n\n/**\n * Error thrown when a message is temporarily locked (423)\n */\nexport class MessageLockedError extends Error {\n public readonly retryAfter?: number;\n\n constructor(messageId: string, retryAfter?: number) {\n const retryMessage = retryAfter\n ? ` Retry after ${retryAfter} seconds.`\n : \" Try again later.\";\n super(`Message ${messageId} is temporarily locked.${retryMessage}`);\n this.name = \"MessageLockedError\";\n this.retryAfter = retryAfter;\n }\n}\n\n/**\n * Error thrown when authentication fails (401)\n */\nexport class UnauthorizedError extends Error {\n constructor(message: string = \"Missing or invalid authentication token\") {\n super(message);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * Error thrown when access is forbidden (403)\n */\nexport class ForbiddenError extends Error {\n constructor(\n message: string = \"Queue environment doesn't match token environment\",\n ) {\n super(message);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * Error thrown for bad requests (400)\n */\nexport class BadRequestError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * Error thrown for internal server errors (500)\n */\nexport class InternalServerError extends Error {\n constructor(message: string = \"Unexpected server error\") {\n super(message);\n this.name = \"InternalServerError\";\n }\n}\n\n/**\n * Error thrown when batch limit parameter is invalid\n */\nexport class InvalidLimitError extends Error {\n constructor(limit: number, min: number = 1, max: number = 10) {\n super(`Invalid limit: ${limit}. Limit must be between ${min} and ${max}.`);\n this.name = \"InvalidLimitError\";\n }\n}\n","import { QueueClient } from \"./client\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n Message,\n MessageHandler,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the consume method\n */\nexport interface ConsumeOptions {\n /** The specific message ID to consume (if not provided, consumes next available message) */\n messageId?: string;\n /** Whether to skip downloading the payload (only allowed when messageId is provided) */\n skipPayload?: boolean;\n}\n\n/**\n * A ConsumerGroup represents a named group of consumers that process messages from a topic\n */\nexport class ConsumerGroup<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private consumerGroupName: string;\n private visibilityTimeout: number;\n private refreshInterval: number;\n private transport: Transport<T>;\n\n /**\n * Create a new ConsumerGroup instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to consume from\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration\n */\n constructor(\n client: QueueClient,\n topicName: string,\n consumerGroupName: string,\n options: ConsumerGroupOptions<T> = {},\n ) {\n this.client = client;\n this.topicName = topicName;\n this.consumerGroupName = consumerGroupName;\n this.visibilityTimeout = options.visibilityTimeoutSeconds || 30; // 30 seconds default\n this.refreshInterval = options.refreshInterval || 10; // 10 seconds default\n this.transport = options.transport || new JsonTransport<T>();\n }\n\n /**\n * Starts a background loop that periodically extends the visibility timeout for a message.\n * This prevents the message from becoming visible to other consumers while it's being processed.\n *\n * The extension loop runs every `refreshInterval` seconds and updates the message's\n * visibility timeout to `visibilityTimeout` seconds from the current time.\n *\n * @param messageId - The unique identifier of the message to extend visibility for\n * @param ticket - The receipt ticket that proves ownership of the message\n * @returns A function that when called will stop the extension loop\n *\n * @remarks\n * - The first extension attempt occurs after `refreshInterval` seconds, not immediately\n * - If an extension fails, the loop terminates with an error logged to console\n * - The returned stop function is idempotent - calling it multiple times is safe\n * - By default, the stop function returns immediately without waiting for in-flight\n * - Pass `true` to the stop function to wait for any in-flight extension to complete\n */\n private startVisibilityExtension(\n messageId: string,\n ticket: string,\n ): (waitForCompletion?: boolean) => Promise<void> {\n let isRunning = true;\n let resolveLifecycle: () => void;\n let timeoutId: NodeJS.Timeout | null = null;\n\n // Promise that tracks the actual termination of the extension loop\n const lifecyclePromise = new Promise<void>((resolve) => {\n resolveLifecycle = resolve;\n });\n\n const extend = async (): Promise<void> => {\n // Check if we should stop before attempting extension\n if (!isRunning) {\n resolveLifecycle();\n return;\n }\n\n try {\n // Extend the visibility timeout for another period\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId,\n ticket,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n });\n\n // Schedule next extension if still running\n if (isRunning) {\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n } else {\n // Signal that the loop has terminated after successful extension\n resolveLifecycle();\n }\n } catch (error) {\n // Log error and terminate the loop on failure\n console.error(\n `Failed to extend visibility for message ${messageId}:`,\n error,\n );\n resolveLifecycle();\n }\n };\n\n // Schedule the first extension attempt\n timeoutId = setTimeout(() => extend(), this.refreshInterval * 1000);\n\n // Return a function to stop the extension loop\n return async (waitForCompletion: boolean = false) => {\n // Signal the loop to stop\n isRunning = false;\n\n // Cancel any pending timeout to avoid unnecessary waiting\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n // Only wait for in-flight operations if explicitly requested\n if (waitForCompletion) {\n // Wait for the loop to actually terminate\n // This ensures any in-progress extension completes or fails\n await lifecyclePromise;\n } else {\n // Resolve the lifecycle immediately for any waiting operations\n // This allows immediate return without waiting for in-flight extensions\n resolveLifecycle();\n }\n };\n }\n\n /**\n * Process a single message with the given handler\n * @param message The message to process\n * @param handler Function to process the message\n */\n private async processMessage<TPayload>(\n message: Message<TPayload>,\n handler: MessageHandler<TPayload>,\n ): Promise<void> {\n const stopExtension = this.startVisibilityExtension(\n message.messageId,\n message.ticket,\n );\n\n try {\n const result = await handler(message.payload, {\n messageId: message.messageId,\n deliveryCount: message.deliveryCount,\n timestamp: message.timestamp,\n });\n // Stop extensions immediately - we don't need to wait for in-flight extensions\n // since we're about to delete or update the message visibility anyway\n await stopExtension();\n\n if (result && \"timeoutSeconds\" in result) {\n // Handle timeout request - set new visibility timeout instead of deleting\n await this.client.changeVisibility({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n visibilityTimeoutSeconds: result.timeoutSeconds,\n });\n } else {\n // Normal completion - delete the message\n await this.client.deleteMessage({\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: message.messageId,\n ticket: message.ticket,\n });\n }\n } catch (error) {\n // Stop extensions immediately on error - fail fast without waiting\n // for any in-flight extension attempts\n await stopExtension();\n\n // Clean up the message payload if the transport supports it and payload exists\n // Only call finalize for non-void payloads since transport is typed for T, not void\n if (\n this.transport.finalize &&\n message.payload !== undefined &&\n message.payload !== null\n ) {\n try {\n // Safe cast: when processMessage<T> is called, TPayload is T\n // when processMessage<void> is called, payload is undefined so this won't execute\n await this.transport.finalize(message.payload as T);\n } catch (finalizeError) {\n console.warn(\"Failed to finalize message payload:\", finalizeError);\n }\n }\n\n throw error;\n }\n }\n\n /**\n * Consume the next available message from the queue\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(handler: MessageHandler<T>): Promise<void>;\n\n /**\n * Consume a specific message by its ID with full payload\n * @param handler Function to process the message\n * @param options Consume options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<T>,\n options: { messageId: string; skipPayload?: false | undefined },\n ): Promise<void>;\n\n /**\n * Consume a specific message by its ID without downloading the payload (metadata only)\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Consume options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\n async consume(\n handler: MessageHandler<void>,\n options: { messageId: string; skipPayload: true },\n ): Promise<void>;\n\n async consume(\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ConsumeOptions,\n ): Promise<void> {\n if (options?.messageId) {\n // Specific message mode\n if (options.skipPayload) {\n // Skip payload - like old handleMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n skipPayload: true,\n },\n this.transport,\n );\n await this.processMessage<void>(\n response.message,\n handler as MessageHandler<void>,\n );\n } else {\n // With payload - like old receiveMessage\n const response = await this.client.receiveMessageById(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n messageId: options.messageId,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n },\n this.transport,\n );\n await this.processMessage<T>(\n response.message,\n handler as MessageHandler<T>,\n );\n }\n } else {\n // Next message mode - like old receiveNextMessage\n let messageFound = false;\n\n for await (const message of this.client.receiveMessages<T>(\n {\n queueName: this.topicName,\n consumerGroup: this.consumerGroupName,\n visibilityTimeoutSeconds: this.visibilityTimeout,\n limit: 1,\n },\n this.transport,\n )) {\n messageFound = true;\n await this.processMessage<T>(message, handler as MessageHandler<T>);\n break; // Process only one message\n }\n\n // If we get here without finding a message, the async generator\n // should have already thrown QueueEmptyError, but just in case\n if (!messageFound) {\n throw new Error(\"No messages available\");\n }\n }\n }\n\n /**\n * Get the consumer group name\n */\n get name(): string {\n return this.consumerGroupName;\n }\n\n /**\n * Get the topic name this consumer group is subscribed to\n */\n get topic(): string {\n return this.topicName;\n }\n}\n","import { QueueClient } from \"./client\";\nimport { ConsumerGroup } from \"./consumer-group\";\nimport { JsonTransport } from \"./transports\";\nimport type { ConsumerGroupOptions, PublishOptions, Transport } from \"./types\";\n\n/**\n * A Topic represents a named channel for publishing messages in a pub/sub pattern\n */\nexport class Topic<T = unknown> {\n private client: QueueClient;\n private topicName: string;\n private transport: Transport<T>;\n\n /**\n * Create a new Topic instance\n * @param client QueueClient instance to use for API calls\n * @param topicName Name of the topic to work with\n * @param transport Optional serializer/deserializer for the payload (defaults to JSON)\n */\n constructor(\n client: QueueClient,\n topicName: string,\n transport?: Transport<T>,\n ) {\n this.client = client;\n this.topicName = topicName;\n this.transport = transport || new JsonTransport<T>();\n }\n\n /**\n * Publish a message to the topic\n * @param payload The data to publish\n * @param options Optional publish options\n * @returns An object containing the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\n async publish(\n payload: T,\n options?: PublishOptions,\n ): Promise<{ messageId: string }> {\n const result = await this.client.sendMessage<T>(\n {\n queueName: this.topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n this.transport,\n );\n return { messageId: result.messageId };\n }\n\n /**\n * Create a consumer group for this topic\n * @param consumerGroupName Name of the consumer group\n * @param options Optional configuration for the consumer group\n * @returns A ConsumerGroup instance\n */\n consumerGroup<U = T>(\n consumerGroupName: string,\n options?: ConsumerGroupOptions<U>,\n ): ConsumerGroup<U> {\n // If no transport is provided in options, use the topic's transport if types match\n const consumerOptions: ConsumerGroupOptions<U> = {\n ...options,\n transport:\n options?.transport || (this.transport as unknown as Transport<U>),\n };\n\n return new ConsumerGroup<U>(\n this.client,\n this.topicName,\n consumerGroupName,\n consumerOptions,\n );\n }\n\n /**\n * Get the topic name\n */\n get name(): string {\n return this.topicName;\n }\n\n /**\n * Get the transport used by this topic\n */\n get serializer(): Transport<T> {\n return this.transport;\n }\n}\n","import { QueueClient } from \"./client\";\nimport type { ConsumeOptions } from \"./consumer-group\";\nimport { Topic } from \"./topic\";\nimport { JsonTransport } from \"./transports\";\nimport type {\n ConsumerGroupOptions,\n MessageHandler,\n PublishOptions,\n Transport,\n} from \"./types\";\n\n/**\n * Options for the send function\n */\nexport interface SendOptions<T = unknown> extends PublishOptions {\n /**\n * Serializer/deserializer for the payload\n * @default JsonTransport instance\n */\n transport?: Transport<T>;\n}\n\n/**\n * Send a message to a topic (shorthand for topic creation and publishing)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to send to\n * @param payload The data to send\n * @param options Optional send options including transport and publish settings\n * @returns Promise with the message ID\n * @throws {BadRequestError} When request parameters are invalid\n * @throws {UnauthorizedError} When authentication fails\n * @throws {ForbiddenError} When access is denied (environment mismatch)\n * @throws {InternalServerError} When server encounters an error\n */\nexport async function send<T = unknown>(\n topicName: string,\n payload: T,\n options?: SendOptions<T>,\n): Promise<{ messageId: string }> {\n const transport = options?.transport || new JsonTransport<T>();\n const client = new QueueClient();\n\n const result = await client.sendMessage<T>(\n {\n queueName: topicName,\n payload,\n idempotencyKey: options?.idempotencyKey,\n retentionSeconds: options?.retentionSeconds,\n },\n transport,\n );\n\n return { messageId: result.messageId };\n}\n\n/**\n * Options for the receive function\n */\nexport interface ReceiveOptions<T = unknown>\n extends ConsumerGroupOptions<T>,\n ConsumeOptions {}\n\n/**\n * Receive a message from a topic (shorthand for topic and consumer group creation)\n * Uses the default QueueClient with automatic OIDC token detection\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options?: ReceiveOptions<T>,\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID with full payload\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message\n * @param options Receive options with messageId specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T>,\n options: ReceiveOptions<T> & {\n messageId: string;\n skipPayload?: false | undefined;\n },\n): Promise<void>;\n\n/**\n * Receive a specific message by its ID without downloading the payload (metadata only)\n * @param topicName Name of the topic to receive from\n * @param consumerGroup Name of the consumer group\n * @param handler Function to process the message metadata (payload will be void)\n * @param options Receive options with messageId and skipPayload specified\n * @returns Promise that resolves when the message is processed\n * @throws All the same errors as the underlying client methods\n */\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<void>,\n options: ReceiveOptions<T> & { messageId: string; skipPayload: true },\n): Promise<void>;\n\nexport async function receive<T = unknown>(\n topicName: string,\n consumerGroup: string,\n handler: MessageHandler<T> | MessageHandler<void>,\n options?: ReceiveOptions<T>,\n): Promise<void> {\n const transport = options?.transport || new JsonTransport<T>();\n\n // Create topic with transport directly\n const client = new QueueClient();\n const topic = new Topic<T>(client, topicName, transport);\n\n // Create consumer group with options (excluding consume-specific options)\n const { messageId, skipPayload, ...consumerGroupOptions } = options || {};\n const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);\n\n // Call consume with the appropriate overload based on options\n if (messageId) {\n if (skipPayload) {\n // skipPayload: true case\n return consumer.consume(handler as MessageHandler<void>, {\n messageId,\n skipPayload: true,\n });\n } else {\n // messageId with payload case\n return consumer.consume(handler as MessageHandler<T>, { messageId });\n }\n } else {\n // No options case - next available message\n return consumer.consume(handler as MessageHandler<T>);\n }\n}\n","/**\n * Queue Callback utilities for handling incoming webhook payloads from Vercel triggers\n */\nimport { QueueClient } from \"./client\";\nimport { Topic } from \"./topic\";\nimport type { MessageHandler } from \"./types\";\n\n/**\n * CloudEvent specification for queue callbacks\n */\nexport interface CloudEvent<T = unknown> {\n type: string;\n source: string;\n id: string;\n datacontenttype: string;\n data: T;\n time?: string;\n specversion?: string;\n}\n\n/**\n * Configuration object with handlers for different topics and consumer groups\n */\ntype CallbackHandlers = {\n [topicName: string]: { [consumerGroup: string]: MessageHandler };\n};\n\n/**\n * Parsed callback request information\n */\nexport type ParsedCallbackRequest = {\n queueName: string;\n consumerGroup: string;\n messageId: string;\n};\n\n/**\n * Parse and validate callback request using CloudEvent specification\n *\n * Extracts queue information from CloudEvent format and validates\n * that all required fields are present.\n *\n * @param request The incoming webhook request\n * @returns Parsed queue information\n * @throws Error if required fields are missing\n *\n * @example\n * ```typescript\n * // In Next.js API route\n * export async function POST(request: Request) {\n * try {\n * const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);\n *\n * // Use the parsed information...\n * await myWorkflow.handleWebhook(queueName, consumerGroup, messageId);\n *\n * return Response.json({ status: \"success\" });\n * } catch (error) {\n * return Response.json({ error: error.message }, { status: 400 });\n * }\n * }\n * ```\n */\nexport async function parseCallbackRequest(\n request: Request,\n): Promise<ParsedCallbackRequest> {\n // Validate content type header\n const contentType = request.headers.get(\"content-type\");\n if (!contentType || !contentType.includes(\"application/cloudevents+json\")) {\n throw new Error(\n \"Invalid content type: expected 'application/cloudevents+json'\",\n );\n }\n\n let cloudEvent: CloudEvent;\n\n try {\n cloudEvent = (await request.json()) as CloudEvent;\n } catch (error) {\n throw new Error(\"Failed to parse CloudEvent from request body\");\n }\n\n // Validate CloudEvent structure\n if (\n !cloudEvent.type ||\n !cloudEvent.source ||\n !cloudEvent.id ||\n typeof cloudEvent.data !== \"object\" ||\n cloudEvent.data == null\n ) {\n throw new Error(\"Invalid CloudEvent: missing required fields\");\n }\n\n // Validate CloudEvent type\n if (cloudEvent.type !== \"com.vercel.queue.v1beta\") {\n throw new Error(\n `Invalid CloudEvent type: expected 'com.vercel.queue.v1beta', got '${cloudEvent.type}'`,\n );\n }\n\n // Check for required data fields before destructuring\n const missingFields: string[] = [];\n if (!(\"queueName\" in cloudEvent.data)) missingFields.push(\"queueName\");\n if (!(\"consumerGroup\" in cloudEvent.data))\n missingFields.push(\"consumerGroup\");\n if (!(\"messageId\" in cloudEvent.data)) missingFields.push(\"messageId\");\n if (missingFields.length > 0) {\n throw new Error(\n `Missing required CloudEvent data fields: ${missingFields.join(\", \")}`,\n );\n }\n\n const { messageId, queueName, consumerGroup } = cloudEvent.data as {\n messageId: string;\n queueName: string;\n consumerGroup: string;\n };\n\n return {\n queueName,\n consumerGroup,\n messageId,\n };\n}\n\n/**\n * Simplified queue callback handler for Next.js route handlers\n *\n * Automatically extracts queue information from CloudEvent format\n * and routes to the appropriate handler based on topic and consumer group.\n *\n * @param handlers Object with topic-specific handlers organized by consumer groups\n * @returns A Next.js route handler function\n *\n * @example\n * ```typescript\n * // Single topic with multiple consumer groups\n * export const POST = handleCallback({\n * \"image-processing\": {\n * \"compress\": (message, metadata) => console.log(\"Compressing image\", message),\n * \"resize\": (message, metadata) => console.log(\"Resizing image\", message),\n * }\n * });\n *\n * // Multiple topics with consumer groups\n * export const POST = handleCallback({\n * \"user-events\": {\n * \"welcome\": (user, metadata) => console.log(\"Welcoming user\", user),\n * \"analytics\": (user, metadata) => console.log(\"Tracking user\", user),\n * },\n * \"order-events\": {\n * \"fulfillment\": (order, metadata) => console.log(\"Fulfilling order\", order),\n * \"notifications\": (order, metadata) => console.log(\"Notifying order\", order),\n * }\n * });\n * ```\n */\nexport function handleCallback(\n handlers: CallbackHandlers,\n): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n try {\n // Parse the callback request\n const { queueName, consumerGroup, messageId } =\n await parseCallbackRequest(request);\n\n // Find the topic handler\n const topicHandler = handlers[queueName];\n\n if (!topicHandler) {\n const availableTopics = Object.keys(handlers).join(\", \");\n return Response.json(\n {\n error: `No handler found for topic: ${queueName}`,\n availableTopics,\n },\n { status: 404 },\n );\n }\n\n // Find the consumer group handler\n const consumerGroupHandler = topicHandler[consumerGroup];\n\n if (!consumerGroupHandler) {\n const availableGroups = Object.keys(topicHandler).join(\", \");\n return Response.json(\n {\n error: `No handler found for consumer group \"${consumerGroup}\" in topic \"${queueName}\".`,\n availableGroups,\n },\n { status: 404 },\n );\n }\n\n // Create client and process the message\n const client = new QueueClient();\n const topic = new Topic(client, queueName);\n const cg = topic.consumerGroup(consumerGroup);\n\n await cg.consume(consumerGroupHandler, { messageId });\n\n return Response.json({ status: \"success\" });\n } catch (error) {\n console.error(\"Queue callback error:\", error);\n\n // Handle parsing errors with appropriate status codes\n if (\n error instanceof Error &&\n (error.message.includes(\"Missing required CloudEvent data fields\") ||\n error.message.includes(\"Invalid CloudEvent\") ||\n error.message.includes(\"Invalid CloudEvent type\") ||\n error.message.includes(\"Invalid content type\") ||\n error.message.includes(\"Failed to parse CloudEvent\"))\n ) {\n return Response.json({ error: error.message }, { status: 400 });\n }\n\n return Response.json(\n { error: \"Failed to process queue message\" },\n { status: 500 },\n );\n }\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/queue",
3
- "version": "0.0.0-alpha.7",
3
+ "version": "0.0.0-alpha.9",
4
4
  "access": "restricted",
5
5
  "description": "A Node.js library for interacting with the Vercel Queue Service API",
6
6
  "main": "dist/index.js",