@vercel/queue 0.0.0-alpha.5 → 0.0.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23,11 +23,8 @@ __export(index_exports, {
23
23
  BadRequestError: () => BadRequestError,
24
24
  BufferTransport: () => BufferTransport,
25
25
  ConsumerGroup: () => ConsumerGroup,
26
- FailedDependencyError: () => FailedDependencyError,
27
- FifoOrderingViolationError: () => FifoOrderingViolationError,
28
26
  ForbiddenError: () => ForbiddenError,
29
27
  InternalServerError: () => InternalServerError,
30
- InvalidCallbackError: () => InvalidCallbackError,
31
28
  InvalidLimitError: () => InvalidLimitError,
32
29
  JsonTransport: () => JsonTransport,
33
30
  MessageCorruptedError: () => MessageCorruptedError,
@@ -50,116 +47,6 @@ module.exports = __toCommonJS(index_exports);
50
47
  // src/client.ts
51
48
  var import_mixpart = require("mixpart");
52
49
 
53
- // src/local.ts
54
- var import_node_child_process = require("child_process");
55
- function isLocalhostWithPort(url) {
56
- try {
57
- const parsedUrl = new URL(url);
58
- const isLocalhost = parsedUrl.hostname === "localhost";
59
- const port = parsedUrl.port ? parseInt(parsedUrl.port, 10) : 0;
60
- return { isLocalhost, port };
61
- } catch {
62
- return { isLocalhost: false };
63
- }
64
- }
65
- function isSupportedPlatform() {
66
- const platform = process.platform;
67
- return platform === "darwin" || platform === "linux";
68
- }
69
- function processDevelopmentCallbacks(callbacks) {
70
- const isDevelopment = process.env.NODE_ENV === "development";
71
- if (!isDevelopment) {
72
- return [];
73
- }
74
- if (!isSupportedPlatform()) {
75
- const hasLocalhostCallbacks = Object.values(callbacks).some((config) => {
76
- const { isLocalhost } = isLocalhostWithPort(config.url);
77
- return isLocalhost;
78
- });
79
- if (hasLocalhostCallbacks) {
80
- console.warn(
81
- `Queue Development Mode: Localhost callbacks are not supported on ${process.platform}. Localhost callback handling requires bash, nc, and curl which are available on macOS and Linux only. Consider using a production callback URL or developing on a supported platform.`
82
- );
83
- }
84
- return [];
85
- }
86
- const localhostCallbacks = [];
87
- Object.entries(callbacks).forEach(([group, config]) => {
88
- const { isLocalhost, port } = isLocalhostWithPort(config.url);
89
- if (isLocalhost && port && port > 0) {
90
- localhostCallbacks.push({ group, config, port });
91
- } else {
92
- console.warn(
93
- `Queue Development Mode: Skipping non-localhost callback for group "${group}": ${config.url}. Only localhost callbacks with explicit ports are supported in development.`
94
- );
95
- }
96
- });
97
- return localhostCallbacks;
98
- }
99
- function fireLocalhostCallbacks(localhostCallbacks, queueName, responseData) {
100
- localhostCallbacks.forEach(({ group, config, port }) => {
101
- const callbackHeaders = new Headers();
102
- callbackHeaders.set("Vqs-Message-Id", responseData.messageId);
103
- callbackHeaders.set("Vqs-Queue-Name", queueName);
104
- callbackHeaders.set("Vqs-Consumer-Group", group);
105
- fireAndForgetWaitForHttpReady(
106
- config.url,
107
- port,
108
- config.delay || 0,
109
- 3,
110
- // Default retry frequency
111
- callbackHeaders
112
- );
113
- });
114
- }
115
- function fireAndForgetWaitForHttpReady(url, port, initialDelaySeconds = 0, retryFrequencySeconds = 3, headers) {
116
- if (!isSupportedPlatform()) {
117
- console.warn(
118
- `Queue: fireAndForgetWaitForHttpReady is not supported on ${process.platform}. This function requires bash, nc, and curl which are available on macOS and Linux only.`
119
- );
120
- return;
121
- }
122
- let headerArgs = "";
123
- if (headers) {
124
- const headerArray = [];
125
- headers.forEach((value, key) => {
126
- headerArray.push(`-H '${key}: ${value}'`);
127
- });
128
- headerArgs = headerArray.join(" ");
129
- }
130
- const bashScript = `
131
- # Wait for any initial boot time
132
- sleep ${initialDelaySeconds}
133
-
134
- missed=0
135
- while true; do
136
- # 1) Check if TCP port is listening
137
- if nc -z localhost ${port} 2>/dev/null; then
138
- missed=0
139
- # 2) If port is open, try HTTP POST check
140
- if curl -sSL --fail -o /dev/null -X POST ${headerArgs} "${url}"; then
141
- # Success: port is up AND HTTP returned 2xx (following redirects)
142
- exit 0
143
- fi
144
- else
145
- # Port was closed\u2014increment miss counter
146
- ((missed+=1))
147
- # If closed twice in a row, give up immediately
148
- if [ "$missed" -ge 2 ]; then
149
- exit 1
150
- fi
151
- fi
152
- # Wait before next cycle
153
- sleep ${retryFrequencySeconds}
154
- done
155
- `;
156
- const childProcess = (0, import_node_child_process.spawn)("bash", ["-c", bashScript], {
157
- stdio: "ignore",
158
- detached: true
159
- });
160
- childProcess.unref();
161
- }
162
-
163
50
  // src/types.ts
164
51
  var MessageNotFoundError = class extends Error {
165
52
  constructor(messageId) {
@@ -175,12 +62,6 @@ var MessageNotAvailableError = class extends Error {
175
62
  this.name = "MessageNotAvailableError";
176
63
  }
177
64
  };
178
- var FifoOrderingViolationError = class extends Error {
179
- constructor(messageId, reason) {
180
- super(`FIFO ordering violation for message ${messageId}: ${reason}`);
181
- this.name = "FifoOrderingViolationError";
182
- }
183
- };
184
65
  var MessageCorruptedError = class extends Error {
185
66
  constructor(messageId, reason) {
186
67
  super(`Message ${messageId} is corrupted: ${reason}`);
@@ -222,14 +103,6 @@ var BadRequestError = class extends Error {
222
103
  this.name = "BadRequestError";
223
104
  }
224
105
  };
225
- var FailedDependencyError = class extends Error {
226
- constructor(messageId) {
227
- super(
228
- `Failed dependency: FIFO ordering violation for message ${messageId}`
229
- );
230
- this.name = "FailedDependencyError";
231
- }
232
- };
233
106
  var InternalServerError = class extends Error {
234
107
  constructor(message = "Unexpected server error") {
235
108
  super(message);
@@ -242,12 +115,6 @@ var InvalidLimitError = class extends Error {
242
115
  this.name = "InvalidLimitError";
243
116
  }
244
117
  };
245
- var InvalidCallbackError = class extends Error {
246
- constructor(message) {
247
- super(message);
248
- this.name = "InvalidCallbackError";
249
- }
250
- };
251
118
 
252
119
  // src/client.ts
253
120
  async function consumeStream(stream) {
@@ -344,7 +211,7 @@ var QueueClient = class _QueueClient {
344
211
  * @throws {InternalServerError} When server encounters an error
345
212
  */
346
213
  async sendMessage(options, transport) {
347
- const { queueName, payload, idempotencyKey, retentionSeconds, callback } = options;
214
+ const { queueName, payload, idempotencyKey, retentionSeconds } = options;
348
215
  const headers = new Headers({
349
216
  Authorization: `Bearer ${this.token}`,
350
217
  "Vqs-Queue-Name": queueName,
@@ -359,34 +226,6 @@ var QueueClient = class _QueueClient {
359
226
  if (retentionSeconds !== void 0) {
360
227
  headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
361
228
  }
362
- let normalizedCallbacks;
363
- if (callback) {
364
- if ("url" in callback && typeof callback.url === "string") {
365
- normalizedCallbacks = { default: callback };
366
- } else {
367
- normalizedCallbacks = callback;
368
- }
369
- }
370
- let localhostCallbacks = [];
371
- if (normalizedCallbacks) {
372
- const isDevelopment = process.env.NODE_ENV === "development";
373
- if (isDevelopment) {
374
- localhostCallbacks = processDevelopmentCallbacks(normalizedCallbacks);
375
- } else {
376
- const endpoints = Object.entries(normalizedCallbacks).map(
377
- ([group, config]) => `${group}=${Buffer.from(config.url).toString("base64")}`
378
- ).join(",");
379
- headers.set("Vqs-Callback-Url", endpoints);
380
- const delays = Object.entries(normalizedCallbacks).filter(([, config]) => config.delay !== void 0).map(([group, config]) => `${group}=${config.delay}`).join(",");
381
- if (delays) {
382
- headers.set("Vqs-Callback-Delay", delays);
383
- }
384
- const frequencies = Object.entries(normalizedCallbacks).filter(([, config]) => config.frequency !== void 0).map(([group, config]) => `${group}=${config.frequency}`).join(",");
385
- if (frequencies) {
386
- headers.set("Vqs-Callback-Frequency", frequencies);
387
- }
388
- }
389
- }
390
229
  const body = transport.serialize(payload);
391
230
  const response = await fetch(`${this.baseUrl}/api/v2/messages`, {
392
231
  method: "POST",
@@ -417,9 +256,6 @@ var QueueClient = class _QueueClient {
417
256
  );
418
257
  }
419
258
  const responseData = await response.json();
420
- if (localhostCallbacks.length > 0) {
421
- fireLocalhostCallbacks(localhostCallbacks, queueName, responseData);
422
- }
423
259
  return responseData;
424
260
  }
425
261
  /**
@@ -429,7 +265,7 @@ var QueueClient = class _QueueClient {
429
265
  * @returns AsyncGenerator that yields messages as they arrive
430
266
  * @throws {InvalidLimitError} When limit parameter is not between 1 and 10
431
267
  * @throws {QueueEmptyError} When no messages are available (204)
432
- * @throws {MessageLockedError} When FIFO queue has locked messages (423)
268
+ * @throws {MessageLockedError} When messages are temporarily locked (423)
433
269
  * @throws {BadRequestError} When request parameters are invalid
434
270
  * @throws {UnauthorizedError} When authentication fails
435
271
  * @throws {ForbiddenError} When access is denied (environment mismatch)
@@ -480,7 +316,7 @@ var QueueClient = class _QueueClient {
480
316
  const parsed = parseInt(retryAfterHeader, 10);
481
317
  retryAfter = isNaN(parsed) ? void 0 : parsed;
482
318
  }
483
- throw new MessageLockedError("next message in FIFO queue", retryAfter);
319
+ throw new MessageLockedError("next message", retryAfter);
484
320
  }
485
321
  if (response.status >= 500) {
486
322
  throw new InternalServerError(
@@ -566,9 +402,6 @@ var QueueClient = class _QueueClient {
566
402
  }
567
403
  throw new MessageLockedError(messageId, retryAfter);
568
404
  }
569
- if (response.status === 424) {
570
- throw new FailedDependencyError(messageId);
571
- }
572
405
  if (response.status === 409) {
573
406
  throw new MessageNotAvailableError(messageId);
574
407
  }
@@ -764,24 +597,20 @@ var JsonTransport = class {
764
597
  }
765
598
  async deserialize(stream) {
766
599
  const reader = stream.getReader();
600
+ let totalLength = 0;
767
601
  const chunks = [];
768
602
  try {
769
603
  while (true) {
770
604
  const { done, value } = await reader.read();
771
605
  if (done) break;
772
606
  chunks.push(value);
607
+ totalLength += value.length;
773
608
  }
774
609
  } finally {
775
610
  reader.releaseLock();
776
611
  }
777
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
778
- const buffer = new Uint8Array(totalLength);
779
- let offset = 0;
780
- for (const chunk of chunks) {
781
- buffer.set(chunk, offset);
782
- offset += chunk.length;
783
- }
784
- return JSON.parse(Buffer.from(buffer).toString("utf8"));
612
+ const buffer = Buffer.concat(chunks, totalLength);
613
+ return JSON.parse(buffer.toString("utf8"));
785
614
  }
786
615
  };
787
616
  var BufferTransport = class {
@@ -1063,8 +892,7 @@ var Topic = class {
1063
892
  queueName: this.topicName,
1064
893
  payload,
1065
894
  idempotencyKey: options?.idempotencyKey,
1066
- retentionSeconds: options?.retentionSeconds,
1067
- callback: options?.callback
895
+ retentionSeconds: options?.retentionSeconds
1068
896
  },
1069
897
  this.transport
1070
898
  );
@@ -1115,8 +943,7 @@ async function send(topicName, payload, options) {
1115
943
  queueName: topicName,
1116
944
  payload,
1117
945
  idempotencyKey: options?.idempotencyKey,
1118
- retentionSeconds: options?.retentionSeconds,
1119
- callback: options?.callback
946
+ retentionSeconds: options?.retentionSeconds
1120
947
  },
1121
948
  transport
1122
949
  );
@@ -1143,23 +970,22 @@ async function receive(topicName, consumerGroup, handler, options) {
1143
970
 
1144
971
  // src/callback.ts
1145
972
  function parseCallbackRequest(request) {
1146
- const headers = request.headers;
1147
- const messageId = headers.get("Vqs-Message-Id");
1148
- const queueName = headers.get("Vqs-Queue-Name");
1149
- const consumerGroup = headers.get("Vqs-Consumer-Group");
1150
- const missingHeaders = [];
1151
- if (!messageId) missingHeaders.push("Vqs-Message-Id");
1152
- if (!queueName) missingHeaders.push("Vqs-Queue-Name");
1153
- if (!consumerGroup) missingHeaders.push("Vqs-Consumer-Group");
1154
- if (missingHeaders.length > 0) {
1155
- throw new InvalidCallbackError(
1156
- `Missing required queue callback headers: ${missingHeaders.join(", ")}`
973
+ const queueName = request.headers.get("Vqs-Queue-Name");
974
+ const consumerGroup = request.headers.get("Vqs-Consumer-Group");
975
+ const messageId = request.headers.get("Vqs-Message-Id");
976
+ if (!queueName || !consumerGroup || !messageId) {
977
+ const missingHeaders = [];
978
+ if (!queueName) missingHeaders.push("Vqs-Queue-Name");
979
+ if (!consumerGroup) missingHeaders.push("Vqs-Consumer-Group");
980
+ if (!messageId) missingHeaders.push("Vqs-Message-Id");
981
+ throw new Error(
982
+ `Missing required queue headers: ${missingHeaders.join(", ")}`
1157
983
  );
1158
984
  }
1159
985
  return {
1160
- messageId,
1161
986
  queueName,
1162
- consumerGroup
987
+ consumerGroup,
988
+ messageId
1163
989
  };
1164
990
  }
1165
991
  function handleCallback(handlers) {
@@ -1168,41 +994,38 @@ function handleCallback(handlers) {
1168
994
  const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);
1169
995
  const topicHandler = handlers[queueName];
1170
996
  if (!topicHandler) {
1171
- throw new Error(`No handler found for topic: ${queueName}`);
997
+ const availableTopics = Object.keys(handlers).join(", ");
998
+ return Response.json(
999
+ {
1000
+ error: `No handler found for topic: ${queueName}`,
1001
+ availableTopics
1002
+ },
1003
+ { status: 404 }
1004
+ );
1172
1005
  }
1173
- let actualHandler;
1174
- if (typeof topicHandler === "function") {
1175
- if (consumerGroup !== "default") {
1176
- throw new Error(
1177
- `Topic "${queueName}" has a single handler but received consumer group "${consumerGroup}". Expected "default".`
1178
- );
1179
- }
1180
- actualHandler = topicHandler;
1181
- } else {
1182
- const consumerGroupHandler = topicHandler[consumerGroup];
1183
- if (!consumerGroupHandler) {
1184
- const availableGroups = Object.keys(topicHandler).join(", ");
1185
- throw new Error(
1186
- `No handler found for consumer group "${consumerGroup}" in topic "${queueName}". Available groups: ${availableGroups}`
1187
- );
1188
- }
1189
- actualHandler = consumerGroupHandler;
1006
+ const consumerGroupHandler = topicHandler[consumerGroup];
1007
+ if (!consumerGroupHandler) {
1008
+ const availableGroups = Object.keys(topicHandler).join(", ");
1009
+ return Response.json(
1010
+ {
1011
+ error: `No handler found for consumer group "${consumerGroup}" in topic "${queueName}".`,
1012
+ availableGroups
1013
+ },
1014
+ { status: 404 }
1015
+ );
1190
1016
  }
1191
1017
  const client = new QueueClient();
1192
1018
  const topic = new Topic(client, queueName);
1193
1019
  const cg = topic.consumerGroup(consumerGroup);
1194
- await cg.consume(actualHandler, { messageId });
1020
+ await cg.consume(consumerGroupHandler, { messageId });
1195
1021
  return Response.json({ status: "success" });
1196
1022
  } catch (error) {
1197
- console.error("Callback error:", error);
1198
- if (error instanceof InvalidCallbackError) {
1199
- return Response.json(
1200
- { error: "Invalid callback request" },
1201
- { status: 400 }
1202
- );
1023
+ console.error("Queue callback error:", error);
1024
+ if (error instanceof Error && error.message.includes("Missing required queue headers")) {
1025
+ return Response.json({ error: error.message }, { status: 400 });
1203
1026
  }
1204
1027
  return Response.json(
1205
- { error: "Failed to process callback" },
1028
+ { error: "Failed to process queue message" },
1206
1029
  { status: 500 }
1207
1030
  );
1208
1031
  }
@@ -1213,11 +1036,8 @@ function handleCallback(handlers) {
1213
1036
  BadRequestError,
1214
1037
  BufferTransport,
1215
1038
  ConsumerGroup,
1216
- FailedDependencyError,
1217
- FifoOrderingViolationError,
1218
1039
  ForbiddenError,
1219
1040
  InternalServerError,
1220
- InvalidCallbackError,
1221
1041
  InvalidLimitError,
1222
1042
  JsonTransport,
1223
1043
  MessageCorruptedError,