@vercel/queue 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -14
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +241 -43
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +241 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/index.mjs
CHANGED
|
@@ -78,6 +78,8 @@ import { parseMultipartStream } from "mixpart";
|
|
|
78
78
|
import * as fs from "fs";
|
|
79
79
|
import * as net from "net";
|
|
80
80
|
import * as path from "path";
|
|
81
|
+
import { minimatch } from "minimatch";
|
|
82
|
+
import pc from "picocolors";
|
|
81
83
|
|
|
82
84
|
// src/types.ts
|
|
83
85
|
var MessageNotFoundError = class extends Error {
|
|
@@ -340,11 +342,12 @@ var ConsumerGroup = class {
|
|
|
340
342
|
message.receiptHandle,
|
|
341
343
|
options
|
|
342
344
|
);
|
|
345
|
+
const DEFAULT_RETENTION_MS = 864e5;
|
|
343
346
|
const metadata = {
|
|
344
347
|
messageId: message.messageId,
|
|
345
348
|
deliveryCount: message.deliveryCount,
|
|
346
349
|
createdAt: message.createdAt,
|
|
347
|
-
expiresAt: message.expiresAt,
|
|
350
|
+
expiresAt: message.expiresAt ?? new Date(message.createdAt.getTime() + DEFAULT_RETENTION_MS),
|
|
348
351
|
topicName: this.topicName,
|
|
349
352
|
consumerGroup: this.consumerGroupName,
|
|
350
353
|
region: this.client.getRegion()
|
|
@@ -498,7 +501,9 @@ var Topic = class {
|
|
|
498
501
|
invokeDevHandlers(
|
|
499
502
|
this.topicName,
|
|
500
503
|
result.messageId,
|
|
501
|
-
this.client.getRegion()
|
|
504
|
+
this.client.getRegion(),
|
|
505
|
+
options?.delaySeconds,
|
|
506
|
+
options?.retentionSeconds
|
|
502
507
|
);
|
|
503
508
|
}
|
|
504
509
|
return { messageId: result.messageId };
|
|
@@ -704,12 +709,30 @@ async function handleCallback(handler, request, options) {
|
|
|
704
709
|
}
|
|
705
710
|
|
|
706
711
|
// src/dev.ts
|
|
712
|
+
var PREFIX = pc.cyan("[queue]");
|
|
713
|
+
var OK = pc.green("\u2713");
|
|
714
|
+
var FAIL = pc.red("\u2717");
|
|
715
|
+
var RETRY = pc.yellow("\u21BB");
|
|
707
716
|
function isDevMode() {
|
|
708
717
|
return process.env.NODE_ENV === "development";
|
|
709
718
|
}
|
|
710
719
|
var ROUTE_MAPPINGS_KEY = Symbol.for("@vercel/queue.devRouteMappings");
|
|
711
720
|
function filePathToConsumerGroup(filePath) {
|
|
712
|
-
|
|
721
|
+
let result = "";
|
|
722
|
+
for (const char of filePath) {
|
|
723
|
+
if (char === "_") {
|
|
724
|
+
result += "__";
|
|
725
|
+
} else if (char === "/") {
|
|
726
|
+
result += "_S";
|
|
727
|
+
} else if (char === ".") {
|
|
728
|
+
result += "_D";
|
|
729
|
+
} else if (/[A-Za-z0-9-]/.test(char)) {
|
|
730
|
+
result += char;
|
|
731
|
+
} else {
|
|
732
|
+
result += "_" + char.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0");
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return result;
|
|
713
736
|
}
|
|
714
737
|
function getDevRouteMappings() {
|
|
715
738
|
const g = globalThis;
|
|
@@ -734,21 +757,22 @@ function getDevRouteMappings() {
|
|
|
734
757
|
if (!trigger.type?.startsWith("queue/") || !trigger.topic) continue;
|
|
735
758
|
if (trigger.type !== "queue/v2beta") {
|
|
736
759
|
console.warn(
|
|
737
|
-
|
|
760
|
+
`${PREFIX} Unsupported trigger type "${trigger.type}" for topic "${trigger.topic}" in ${filePath}. Use "queue/v2beta" instead.`
|
|
738
761
|
);
|
|
739
762
|
continue;
|
|
740
763
|
}
|
|
741
764
|
mappings.push({
|
|
742
765
|
filePath,
|
|
743
766
|
topic: trigger.topic,
|
|
744
|
-
consumer: filePathToConsumerGroup(filePath)
|
|
767
|
+
consumer: filePathToConsumerGroup(filePath),
|
|
768
|
+
retryAfterSeconds: trigger.retryAfterSeconds
|
|
745
769
|
});
|
|
746
770
|
}
|
|
747
771
|
}
|
|
748
772
|
g[ROUTE_MAPPINGS_KEY] = mappings.length > 0 ? mappings : null;
|
|
749
773
|
return g[ROUTE_MAPPINGS_KEY];
|
|
750
774
|
} catch (error) {
|
|
751
|
-
console.warn(
|
|
775
|
+
console.warn(`${PREFIX} Failed to read vercel.json:`, error);
|
|
752
776
|
g[ROUTE_MAPPINGS_KEY] = null;
|
|
753
777
|
return null;
|
|
754
778
|
}
|
|
@@ -763,6 +787,20 @@ function findMatchingRoutes(topicName) {
|
|
|
763
787
|
return mapping.topic === topicName;
|
|
764
788
|
});
|
|
765
789
|
}
|
|
790
|
+
function findRetryAfterSeconds(topicName, consumerGroup) {
|
|
791
|
+
const routes = findMatchingRoutes(topicName);
|
|
792
|
+
const route = routes.find((r) => r.consumer === consumerGroup);
|
|
793
|
+
return route?.retryAfterSeconds;
|
|
794
|
+
}
|
|
795
|
+
function stripSrcPrefix(filePath) {
|
|
796
|
+
if (/^src\/(app|pages|server)\//.test(filePath)) {
|
|
797
|
+
return filePath.slice(4);
|
|
798
|
+
}
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
function matchesFunctionsPattern(sourceFile, pattern) {
|
|
802
|
+
return sourceFile === pattern || minimatch(sourceFile, pattern);
|
|
803
|
+
}
|
|
766
804
|
function findMappingsForFile(absolutePath) {
|
|
767
805
|
const mappings = getDevRouteMappings();
|
|
768
806
|
if (!mappings) return [];
|
|
@@ -774,7 +812,10 @@ function findMappingsForFile(absolutePath) {
|
|
|
774
812
|
return [];
|
|
775
813
|
}
|
|
776
814
|
const normalized = relative2.replace(/\\/g, "/");
|
|
777
|
-
|
|
815
|
+
const stripped = stripSrcPrefix(normalized);
|
|
816
|
+
return mappings.filter(
|
|
817
|
+
(m) => matchesFunctionsPattern(normalized, m.filePath) || stripped !== null && matchesFunctionsPattern(stripped, m.filePath)
|
|
818
|
+
);
|
|
778
819
|
}
|
|
779
820
|
function parseFrameFilePath(line) {
|
|
780
821
|
let match = line.match(/\((.+?):\d+:\d+\)/);
|
|
@@ -868,7 +909,7 @@ function registerDevHandler(handler, client, options, _testCallerPath) {
|
|
|
868
909
|
const callerPath = _testCallerPath ?? extractCallerFilePath();
|
|
869
910
|
if (!callerPath) {
|
|
870
911
|
console.warn(
|
|
871
|
-
|
|
912
|
+
`${PREFIX} Could not determine caller file path for handler registration.`
|
|
872
913
|
);
|
|
873
914
|
return;
|
|
874
915
|
}
|
|
@@ -880,6 +921,9 @@ function registerDevHandler(handler, client, options, _testCallerPath) {
|
|
|
880
921
|
);
|
|
881
922
|
if (!registered) {
|
|
882
923
|
const allMappings = getDevRouteMappings();
|
|
924
|
+
if (allMappings && allMappings.length > 0) {
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
883
927
|
const cwd = process.cwd();
|
|
884
928
|
let relative2;
|
|
885
929
|
try {
|
|
@@ -887,19 +931,8 @@ function registerDevHandler(handler, client, options, _testCallerPath) {
|
|
|
887
931
|
} catch {
|
|
888
932
|
relative2 = callerPath;
|
|
889
933
|
}
|
|
890
|
-
if (allMappings && allMappings.length > 0) {
|
|
891
|
-
const configuredFiles = Array.from(
|
|
892
|
-
new Set(allMappings.map((m) => m.filePath))
|
|
893
|
-
);
|
|
894
|
-
console.warn(
|
|
895
|
-
`[Dev Mode] handleCallback() in ${relative2} does not match any queue route in vercel.json. This handler won't receive messages.
|
|
896
|
-
Configured queue routes: [${configuredFiles.join(", ")}]
|
|
897
|
-
If this path is a bundled chunk, keep handleCallback()/handleNodeCallback() at module scope and let dev-mode route priming load the mapped file.`
|
|
898
|
-
);
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
934
|
console.warn(
|
|
902
|
-
|
|
935
|
+
`${PREFIX} handleCallback() in ${relative2} has no matching experimentalTriggers in vercel.json. This handler won't receive messages.
|
|
903
936
|
|
|
904
937
|
Add a trigger to vercel.json:
|
|
905
938
|
"${relative2}": {
|
|
@@ -1023,7 +1056,7 @@ async function invokeWithRetry(handler, request, options) {
|
|
|
1023
1056
|
}
|
|
1024
1057
|
}
|
|
1025
1058
|
function filePathToUrlPath(filePath) {
|
|
1026
|
-
let urlPath = filePath.replace(/^app\//, "/").replace(/^pages\//, "/").replace(/^server\//, "/").replace(/^src\/routes\//, "/").replace(/\/route\.(ts|mts|js|mjs|tsx|jsx)$/, "").replace(/\/\+server\.(ts|mts|js|mjs|tsx|jsx)$/, "").replace(/\.(ts|mts|js|mjs|tsx|jsx)$/, "");
|
|
1059
|
+
let urlPath = filePath.replace(/^src\/app\//, "/").replace(/^src\/pages\//, "/").replace(/^src\/server\//, "/").replace(/^src\/routes\//, "/").replace(/^app\//, "/").replace(/^pages\//, "/").replace(/^server\//, "/").replace(/\/route\.(ts|mts|js|mjs|tsx|jsx)$/, "").replace(/\/\+server\.(ts|mts|js|mjs|tsx|jsx)$/, "").replace(/\.(ts|mts|js|mjs|tsx|jsx)$/, "");
|
|
1027
1060
|
if (!urlPath.startsWith("/")) {
|
|
1028
1061
|
urlPath = "/" + urlPath;
|
|
1029
1062
|
}
|
|
@@ -1116,7 +1149,7 @@ function buildNoHandlerWarning(topicName, routes, diagnostics) {
|
|
|
1116
1149
|
Import failures: ` + diagnostics.importFailures.slice(0, 2).map((f) => `${f.filePath} (${f.reason})`).join("; ") : "";
|
|
1117
1150
|
const primeSummary = diagnostics.primeFailures.length > 0 ? `
|
|
1118
1151
|
Prime failures: ` + diagnostics.primeFailures.slice(0, 3).map((f) => `${f.url} (${f.reason})`).join("; ") : "";
|
|
1119
|
-
return
|
|
1152
|
+
return `${PREFIX} No registered handler for topic "${topicName}". vercel.json maps this topic to [${files.join(", ")}] but auto-loading failed.
|
|
1120
1153
|
${portSummary}${importSummary}${primeSummary}
|
|
1121
1154
|
Ensure your dev server is running, set PORT if needed, and confirm mapped route files call handleCallback()/handleNodeCallback() at module scope.
|
|
1122
1155
|
` + (suggestedUrls.length > 0 ? `Try opening: ${suggestedUrls.join(" or ")}` : "Set PORT (or NEXT_PORT/NUXT_PORT/VITE_PORT) and try sending again.");
|
|
@@ -1126,18 +1159,106 @@ function isHandlerRegistered(topicName, consumerGroup) {
|
|
|
1126
1159
|
(h) => h.consumerGroup === consumerGroup
|
|
1127
1160
|
);
|
|
1128
1161
|
}
|
|
1129
|
-
|
|
1162
|
+
var DEV_REDELIVERY_MAX_DELAY_S = 10;
|
|
1163
|
+
var DEV_REDELIVERY_DEFAULT_DELAY_S = 2;
|
|
1164
|
+
var DEV_REDELIVERY_MAX_ATTEMPTS = 10;
|
|
1165
|
+
var DEFAULT_RETENTION_S = 86400;
|
|
1166
|
+
function scheduleDevRedelivery(ctx, delayS) {
|
|
1167
|
+
const cappedDelay = Math.min(Math.max(delayS, 0), DEV_REDELIVERY_MAX_DELAY_S);
|
|
1168
|
+
console.log(
|
|
1169
|
+
`${PREFIX} ${RETRY} Scheduling re-delivery in ${cappedDelay}s: topic="${ctx.topicName}" consumer="${ctx.consumerGroup}" messageId="${ctx.messageId}"`
|
|
1170
|
+
);
|
|
1171
|
+
setTimeout(async () => {
|
|
1172
|
+
const nextDeliveryCount = ctx.deliveryCount + 1;
|
|
1173
|
+
const expiresAt = new Date(
|
|
1174
|
+
ctx.createdAt.getTime() + ctx.retentionSeconds * 1e3
|
|
1175
|
+
);
|
|
1176
|
+
if (Date.now() >= expiresAt.getTime()) {
|
|
1177
|
+
console.log(
|
|
1178
|
+
`${PREFIX} Message expired, stopping retries: topic="${ctx.topicName}" messageId="${ctx.messageId}"`
|
|
1179
|
+
);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
if (nextDeliveryCount > DEV_REDELIVERY_MAX_ATTEMPTS) {
|
|
1183
|
+
console.log(
|
|
1184
|
+
`${PREFIX} Max re-deliveries (${DEV_REDELIVERY_MAX_ATTEMPTS}) reached: topic="${ctx.topicName}" messageId="${ctx.messageId}"`
|
|
1185
|
+
);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
const metadata = {
|
|
1189
|
+
messageId: ctx.messageId,
|
|
1190
|
+
deliveryCount: nextDeliveryCount,
|
|
1191
|
+
createdAt: ctx.createdAt,
|
|
1192
|
+
expiresAt,
|
|
1193
|
+
topicName: ctx.topicName,
|
|
1194
|
+
consumerGroup: ctx.consumerGroup,
|
|
1195
|
+
region: ctx.region
|
|
1196
|
+
};
|
|
1197
|
+
console.log(
|
|
1198
|
+
`${PREFIX} Re-delivering: topic="${ctx.topicName}" consumer="${ctx.consumerGroup}" messageId="${ctx.messageId}" deliveryCount=${nextDeliveryCount}`
|
|
1199
|
+
);
|
|
1200
|
+
let succeeded = true;
|
|
1201
|
+
let nextRetryAfterS = null;
|
|
1202
|
+
let nextAcknowledged = false;
|
|
1203
|
+
try {
|
|
1204
|
+
await ctx.handler(ctx.payload, metadata);
|
|
1205
|
+
} catch (error) {
|
|
1206
|
+
succeeded = false;
|
|
1207
|
+
if (ctx.retry) {
|
|
1208
|
+
let directive;
|
|
1209
|
+
try {
|
|
1210
|
+
directive = ctx.retry(error, metadata);
|
|
1211
|
+
} catch (retryErr) {
|
|
1212
|
+
console.warn(`${PREFIX} retry handler threw:`, retryErr);
|
|
1213
|
+
}
|
|
1214
|
+
if (directive && "afterSeconds" in directive) {
|
|
1215
|
+
nextRetryAfterS = directive.afterSeconds;
|
|
1216
|
+
} else if (directive && "acknowledge" in directive) {
|
|
1217
|
+
nextAcknowledged = true;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
if (!nextAcknowledged) {
|
|
1221
|
+
console.error(
|
|
1222
|
+
`${PREFIX} ${FAIL} Handler error on re-delivery: topic="${ctx.topicName}" messageId="${ctx.messageId}"`,
|
|
1223
|
+
error
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
if (succeeded) {
|
|
1228
|
+
console.log(
|
|
1229
|
+
`${PREFIX} ${OK} Message processed on re-delivery: topic="${ctx.topicName}" consumer="${ctx.consumerGroup}" messageId="${ctx.messageId}"`
|
|
1230
|
+
);
|
|
1231
|
+
} else if (nextAcknowledged) {
|
|
1232
|
+
console.log(
|
|
1233
|
+
`${PREFIX} ${OK} Message acknowledged (will not retry): topic="${ctx.topicName}" consumer="${ctx.consumerGroup}" messageId="${ctx.messageId}"`
|
|
1234
|
+
);
|
|
1235
|
+
} else {
|
|
1236
|
+
const nextDelay = nextRetryAfterS ?? ctx.defaultRetryDelayS;
|
|
1237
|
+
scheduleDevRedelivery(
|
|
1238
|
+
{ ...ctx, deliveryCount: nextDeliveryCount },
|
|
1239
|
+
nextDelay
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
}, cappedDelay * 1e3);
|
|
1243
|
+
}
|
|
1244
|
+
function invokeDevHandlers(topicName, messageId, region, delaySeconds, retentionSeconds) {
|
|
1130
1245
|
if (delaySeconds && delaySeconds > 0) {
|
|
1131
1246
|
console.log(
|
|
1132
|
-
|
|
1247
|
+
`${PREFIX} Message sent with delay: topic="${topicName}" messageId="${messageId}" delay=${delaySeconds}s`
|
|
1133
1248
|
);
|
|
1134
1249
|
setTimeout(() => {
|
|
1135
|
-
invokeDevHandlers(
|
|
1250
|
+
invokeDevHandlers(
|
|
1251
|
+
topicName,
|
|
1252
|
+
messageId,
|
|
1253
|
+
region,
|
|
1254
|
+
void 0,
|
|
1255
|
+
retentionSeconds
|
|
1256
|
+
);
|
|
1136
1257
|
}, delaySeconds * 1e3);
|
|
1137
1258
|
return;
|
|
1138
1259
|
}
|
|
1139
1260
|
console.log(
|
|
1140
|
-
|
|
1261
|
+
`${PREFIX} Message sent: topic="${topicName}" messageId="${messageId}"`
|
|
1141
1262
|
);
|
|
1142
1263
|
(async () => {
|
|
1143
1264
|
let handlers = lookupHandlers(topicName);
|
|
@@ -1164,7 +1285,7 @@ function invokeDevHandlers(topicName, messageId, region, delaySeconds) {
|
|
|
1164
1285
|
);
|
|
1165
1286
|
} else {
|
|
1166
1287
|
console.warn(
|
|
1167
|
-
|
|
1288
|
+
`${PREFIX} No registered handler for topic "${topicName}".
|
|
1168
1289
|
Ensure vercel.json has a matching experimentalTriggers entry and the route file calls handleCallback().`
|
|
1169
1290
|
);
|
|
1170
1291
|
}
|
|
@@ -1172,9 +1293,36 @@ Ensure vercel.json has a matching experimentalTriggers entry and the route file
|
|
|
1172
1293
|
}
|
|
1173
1294
|
const consumerGroups = handlers.map((h) => h.consumerGroup);
|
|
1174
1295
|
console.log(
|
|
1175
|
-
|
|
1296
|
+
`${PREFIX} Invoking handlers for topic="${topicName}" messageId="${messageId}" \u2192 consumers: [${consumerGroups.join(", ")}]`
|
|
1176
1297
|
);
|
|
1298
|
+
const effectiveRetention = retentionSeconds ?? DEFAULT_RETENTION_S;
|
|
1177
1299
|
for (const entry of handlers) {
|
|
1300
|
+
let capturedPayload;
|
|
1301
|
+
let capturedCreatedAt = /* @__PURE__ */ new Date();
|
|
1302
|
+
let capturedDeliveryCount = 1;
|
|
1303
|
+
let handlerSucceeded = true;
|
|
1304
|
+
let retryAfterS = null;
|
|
1305
|
+
let retryAcknowledged = false;
|
|
1306
|
+
const wrappedHandler = async (message, metadata) => {
|
|
1307
|
+
capturedPayload = message;
|
|
1308
|
+
capturedCreatedAt = metadata.createdAt;
|
|
1309
|
+
capturedDeliveryCount = metadata.deliveryCount;
|
|
1310
|
+
try {
|
|
1311
|
+
await entry.handler(message, metadata);
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
handlerSucceeded = false;
|
|
1314
|
+
throw error;
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
const wrappedRetry = entry.options?.retry ? (error, metadata) => {
|
|
1318
|
+
const directive = entry.options.retry(error, metadata);
|
|
1319
|
+
if (directive && "afterSeconds" in directive) {
|
|
1320
|
+
retryAfterS = directive.afterSeconds;
|
|
1321
|
+
} else if (directive && "acknowledge" in directive) {
|
|
1322
|
+
retryAcknowledged = true;
|
|
1323
|
+
}
|
|
1324
|
+
return directive;
|
|
1325
|
+
} : void 0;
|
|
1178
1326
|
const request = {
|
|
1179
1327
|
queueName: topicName,
|
|
1180
1328
|
consumerGroup: entry.consumerGroup,
|
|
@@ -1184,18 +1332,47 @@ Ensure vercel.json has a matching experimentalTriggers entry and the route file
|
|
|
1184
1332
|
const callbackOptions = {
|
|
1185
1333
|
client: entry.client,
|
|
1186
1334
|
visibilityTimeoutSeconds: entry.options?.visibilityTimeoutSeconds,
|
|
1187
|
-
retry:
|
|
1335
|
+
retry: wrappedRetry
|
|
1188
1336
|
};
|
|
1337
|
+
const consumerDefaultDelay = Math.min(
|
|
1338
|
+
findRetryAfterSeconds(topicName, entry.consumerGroup) ?? DEV_REDELIVERY_DEFAULT_DELAY_S,
|
|
1339
|
+
DEV_REDELIVERY_MAX_DELAY_S
|
|
1340
|
+
);
|
|
1341
|
+
const buildRedeliveryCtx = () => ({
|
|
1342
|
+
handler: entry.handler,
|
|
1343
|
+
retry: entry.options?.retry,
|
|
1344
|
+
payload: capturedPayload,
|
|
1345
|
+
topicName,
|
|
1346
|
+
consumerGroup: entry.consumerGroup,
|
|
1347
|
+
messageId,
|
|
1348
|
+
region,
|
|
1349
|
+
createdAt: capturedCreatedAt,
|
|
1350
|
+
retentionSeconds: effectiveRetention,
|
|
1351
|
+
deliveryCount: capturedDeliveryCount,
|
|
1352
|
+
defaultRetryDelayS: consumerDefaultDelay
|
|
1353
|
+
});
|
|
1189
1354
|
try {
|
|
1190
|
-
await invokeWithRetry(
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1355
|
+
await invokeWithRetry(wrappedHandler, request, callbackOptions);
|
|
1356
|
+
if (handlerSucceeded) {
|
|
1357
|
+
console.log(
|
|
1358
|
+
`${PREFIX} ${OK} Message processed: topic="${topicName}" consumer="${entry.consumerGroup}" messageId="${messageId}"`
|
|
1359
|
+
);
|
|
1360
|
+
} else if (retryAcknowledged) {
|
|
1361
|
+
console.log(
|
|
1362
|
+
`${PREFIX} ${OK} Message acknowledged (will not retry): topic="${topicName}" consumer="${entry.consumerGroup}" messageId="${messageId}"`
|
|
1363
|
+
);
|
|
1364
|
+
} else if (retryAfterS !== null) {
|
|
1365
|
+
const devDelay = Math.min(retryAfterS, DEV_REDELIVERY_MAX_DELAY_S);
|
|
1366
|
+
scheduleDevRedelivery(buildRedeliveryCtx(), devDelay);
|
|
1367
|
+
}
|
|
1194
1368
|
} catch (error) {
|
|
1195
1369
|
console.error(
|
|
1196
|
-
|
|
1370
|
+
`${PREFIX} ${FAIL} Handler failed: topic="${topicName}" consumer="${entry.consumerGroup}" messageId="${messageId}"`,
|
|
1197
1371
|
error
|
|
1198
1372
|
);
|
|
1373
|
+
if (!handlerSucceeded) {
|
|
1374
|
+
scheduleDevRedelivery(buildRedeliveryCtx(), consumerDefaultDelay);
|
|
1375
|
+
}
|
|
1199
1376
|
}
|
|
1200
1377
|
}
|
|
1201
1378
|
})();
|
|
@@ -1207,6 +1384,10 @@ function clearDevState() {
|
|
|
1207
1384
|
}
|
|
1208
1385
|
if (process.env.NODE_ENV === "test" || process.env.VITEST) {
|
|
1209
1386
|
globalThis.__clearDevState = clearDevState;
|
|
1387
|
+
globalThis.__filePathToConsumerGroup = filePathToConsumerGroup;
|
|
1388
|
+
globalThis.__filePathToUrlPath = filePathToUrlPath;
|
|
1389
|
+
globalThis.__matchesFunctionsPattern = matchesFunctionsPattern;
|
|
1390
|
+
globalThis.__stripSrcPrefix = stripSrcPrefix;
|
|
1210
1391
|
}
|
|
1211
1392
|
|
|
1212
1393
|
// src/oidc.ts
|
|
@@ -1250,6 +1431,7 @@ function parseQueueHeaders(headers) {
|
|
|
1250
1431
|
const timestamp = headers.get("Vqs-Timestamp");
|
|
1251
1432
|
const contentType = headers.get("Content-Type") || "application/octet-stream";
|
|
1252
1433
|
const receiptHandle = headers.get("Vqs-Receipt-Handle");
|
|
1434
|
+
const expiresAtStr = headers.get("Vqs-Expires-At");
|
|
1253
1435
|
if (!messageId || !timestamp || !receiptHandle) {
|
|
1254
1436
|
return null;
|
|
1255
1437
|
}
|
|
@@ -1261,6 +1443,7 @@ function parseQueueHeaders(headers) {
|
|
|
1261
1443
|
messageId,
|
|
1262
1444
|
deliveryCount,
|
|
1263
1445
|
createdAt: new Date(timestamp),
|
|
1446
|
+
expiresAt: expiresAtStr ? new Date(expiresAtStr) : void 0,
|
|
1264
1447
|
contentType,
|
|
1265
1448
|
receiptHandle
|
|
1266
1449
|
};
|
|
@@ -1344,13 +1527,25 @@ var ApiClient = class _ApiClient {
|
|
|
1344
1527
|
if (this.providedToken) {
|
|
1345
1528
|
return this.providedToken;
|
|
1346
1529
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1530
|
+
try {
|
|
1531
|
+
return await getVercelOidcToken();
|
|
1532
|
+
} catch (err) {
|
|
1533
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
1349
1534
|
throw new Error(
|
|
1350
|
-
|
|
1535
|
+
isDevMode() ? `Failed to get OIDC token for local development.
|
|
1536
|
+
|
|
1537
|
+
To fix this, pull your environment variables with Vercel CLI:
|
|
1538
|
+
\`vercel env pull\`
|
|
1539
|
+
|
|
1540
|
+
Cause: ${cause}` : `Failed to get OIDC token. This usually means the function is running outside of a Vercel Function environment.
|
|
1541
|
+
|
|
1542
|
+
To fix this, either:
|
|
1543
|
+
- Deploy to Vercel (OIDC tokens are provisioned automatically)
|
|
1544
|
+
- Provide a token explicitly: \`new QueueClient({ token: '...' })\`
|
|
1545
|
+
|
|
1546
|
+
Cause: ${cause}`
|
|
1351
1547
|
);
|
|
1352
1548
|
}
|
|
1353
|
-
return token;
|
|
1354
1549
|
}
|
|
1355
1550
|
buildUrl(queueName, ...pathSegments) {
|
|
1356
1551
|
const encodedQueue = encodeURIComponent(queueName);
|
|
@@ -1381,7 +1576,7 @@ var ApiClient = class _ApiClient {
|
|
|
1381
1576
|
}
|
|
1382
1577
|
console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
|
|
1383
1578
|
}
|
|
1384
|
-
init.headers.set("User-Agent", `@vercel/queue/${"0.1.
|
|
1579
|
+
init.headers.set("User-Agent", `@vercel/queue/${"0.1.3"}`);
|
|
1385
1580
|
init.headers.set("Vqs-Client-Ts", (/* @__PURE__ */ new Date()).toISOString());
|
|
1386
1581
|
const response = await fetch(url, init);
|
|
1387
1582
|
if (isDebugEnabled()) {
|
|
@@ -1756,9 +1951,11 @@ function resolveRegion(region) {
|
|
|
1756
1951
|
if (region) return region;
|
|
1757
1952
|
const fromEnv = process.env.VERCEL_REGION;
|
|
1758
1953
|
if (fromEnv) return fromEnv;
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1954
|
+
if (!isDevMode()) {
|
|
1955
|
+
console.warn(
|
|
1956
|
+
`[QueueClient] Region not detected \u2014 defaulting to "${DEFAULT_REGION}". On Vercel this is set automatically via VERCEL_REGION. To silence this warning, pass region explicitly: new QueueClient({ region: "iad1" })`
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1762
1959
|
return DEFAULT_REGION;
|
|
1763
1960
|
}
|
|
1764
1961
|
var QueueClient = class {
|
|
@@ -1796,7 +1993,8 @@ var QueueClient = class {
|
|
|
1796
1993
|
topicName,
|
|
1797
1994
|
result.messageId,
|
|
1798
1995
|
api.getRegion(),
|
|
1799
|
-
options?.delaySeconds
|
|
1996
|
+
options?.delaySeconds,
|
|
1997
|
+
options?.retentionSeconds
|
|
1800
1998
|
);
|
|
1801
1999
|
}
|
|
1802
2000
|
return { messageId: result.messageId };
|