@vercel/queue 0.0.0-alpha.2 → 0.0.0-alpha.4
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 +409 -282
- package/dist/index.d.mts +184 -111
- package/dist/index.d.ts +184 -111
- package/dist/index.js +196 -287
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +192 -285
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
// src/oidc.ts
|
|
2
|
-
async function getVercelOidcToken() {
|
|
3
|
-
const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
|
|
4
|
-
const fromSymbol = globalThis;
|
|
5
|
-
const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
|
|
6
|
-
const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
|
|
7
|
-
if (!token) {
|
|
8
|
-
throw new Error(
|
|
9
|
-
`The 'x-vercel-oidc-token' header is missing from the request. Do you have the OIDC option enabled in the Vercel project settings?`
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
return token;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
1
|
// src/client.ts
|
|
16
2
|
import { parseMultipartStream } from "mixpart";
|
|
17
3
|
|
|
@@ -141,13 +127,9 @@ var MessageNotAvailableError = class extends Error {
|
|
|
141
127
|
}
|
|
142
128
|
};
|
|
143
129
|
var FifoOrderingViolationError = class extends Error {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
super(
|
|
147
|
-
`FIFO ordering violation for message ${messageId}: ${reason}. Process message ${nextMessageId} first.`
|
|
148
|
-
);
|
|
130
|
+
constructor(messageId, reason) {
|
|
131
|
+
super(`FIFO ordering violation for message ${messageId}: ${reason}`);
|
|
149
132
|
this.name = "FifoOrderingViolationError";
|
|
150
|
-
this.nextMessageId = nextMessageId;
|
|
151
133
|
}
|
|
152
134
|
};
|
|
153
135
|
var MessageCorruptedError = class extends Error {
|
|
@@ -192,13 +174,11 @@ var BadRequestError = class extends Error {
|
|
|
192
174
|
}
|
|
193
175
|
};
|
|
194
176
|
var FailedDependencyError = class extends Error {
|
|
195
|
-
|
|
196
|
-
constructor(messageId, nextMessageId) {
|
|
177
|
+
constructor(messageId) {
|
|
197
178
|
super(
|
|
198
|
-
`Failed dependency: FIFO ordering violation for message ${messageId}
|
|
179
|
+
`Failed dependency: FIFO ordering violation for message ${messageId}`
|
|
199
180
|
);
|
|
200
181
|
this.name = "FailedDependencyError";
|
|
201
|
-
this.nextMessageId = nextMessageId;
|
|
202
182
|
}
|
|
203
183
|
};
|
|
204
184
|
var InternalServerError = class extends Error {
|
|
@@ -256,32 +236,53 @@ function parseQueueHeaders(headers) {
|
|
|
256
236
|
var QueueClient = class _QueueClient {
|
|
257
237
|
baseUrl;
|
|
258
238
|
token;
|
|
239
|
+
/**
|
|
240
|
+
* Internal default instance for use by createTopic and other convenience functions
|
|
241
|
+
* @internal
|
|
242
|
+
*/
|
|
243
|
+
static _defaultInstance = null;
|
|
259
244
|
/**
|
|
260
245
|
* Create a new Vercel Queue Service client
|
|
261
|
-
* @param options Client configuration options
|
|
246
|
+
* @param options Client configuration options (optional - will auto-detect Vercel Function environment)
|
|
262
247
|
*/
|
|
263
|
-
constructor(options) {
|
|
248
|
+
constructor(options = {}) {
|
|
264
249
|
this.baseUrl = options.baseUrl || "https://vqs.vercel.sh";
|
|
265
|
-
|
|
250
|
+
if (options.token) {
|
|
251
|
+
this.token = options.token;
|
|
252
|
+
} else {
|
|
253
|
+
const token = this.getVercelOidcTokenSync();
|
|
254
|
+
if (!token) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
"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'"
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
this.token = token;
|
|
260
|
+
}
|
|
266
261
|
}
|
|
267
262
|
/**
|
|
268
|
-
*
|
|
269
|
-
*
|
|
270
|
-
* Always creates a fresh instance since OIDC tokens expire after 15 minutes
|
|
271
|
-
* @param baseUrl Optional base URL override
|
|
272
|
-
* @returns Promise resolving to a new QueueClient instance
|
|
263
|
+
* Get the default client instance for internal use by convenience functions
|
|
264
|
+
* @internal
|
|
273
265
|
*/
|
|
274
|
-
static
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
266
|
+
static _getDefaultInstance() {
|
|
267
|
+
if (!this._defaultInstance) {
|
|
268
|
+
this._defaultInstance = new _QueueClient();
|
|
269
|
+
}
|
|
270
|
+
return this._defaultInstance;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Synchronously get OIDC token from environment
|
|
274
|
+
* Used internally by constructor - mirrors the logic from getVercelOidcToken but synchronously
|
|
275
|
+
*/
|
|
276
|
+
getVercelOidcTokenSync() {
|
|
277
|
+
try {
|
|
278
|
+
const SYMBOL_FOR_REQ_CONTEXT = Symbol.for("@vercel/request-context");
|
|
279
|
+
const fromSymbol = globalThis;
|
|
280
|
+
const context = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]?.get?.() ?? {};
|
|
281
|
+
const token = context.headers?.["x-vercel-oidc-token"] ?? process.env.VERCEL_OIDC_TOKEN;
|
|
282
|
+
return token || null;
|
|
283
|
+
} catch {
|
|
284
|
+
return null;
|
|
280
285
|
}
|
|
281
|
-
return new _QueueClient({
|
|
282
|
-
token,
|
|
283
|
-
baseUrl
|
|
284
|
-
});
|
|
285
286
|
}
|
|
286
287
|
/**
|
|
287
288
|
* Send a message to a queue
|
|
@@ -294,7 +295,7 @@ var QueueClient = class _QueueClient {
|
|
|
294
295
|
* @throws {InternalServerError} When server encounters an error
|
|
295
296
|
*/
|
|
296
297
|
async sendMessage(options, transport) {
|
|
297
|
-
const { queueName, payload, idempotencyKey, retentionSeconds,
|
|
298
|
+
const { queueName, payload, idempotencyKey, retentionSeconds, callback } = options;
|
|
298
299
|
const headers = new Headers({
|
|
299
300
|
Authorization: `Bearer ${this.token}`,
|
|
300
301
|
"Vqs-Queue-Name": queueName,
|
|
@@ -306,21 +307,29 @@ var QueueClient = class _QueueClient {
|
|
|
306
307
|
if (retentionSeconds !== void 0) {
|
|
307
308
|
headers.set("Vqs-Retention-Seconds", retentionSeconds.toString());
|
|
308
309
|
}
|
|
310
|
+
let normalizedCallbacks;
|
|
311
|
+
if (callback) {
|
|
312
|
+
if ("url" in callback && typeof callback.url === "string") {
|
|
313
|
+
normalizedCallbacks = { default: callback };
|
|
314
|
+
} else {
|
|
315
|
+
normalizedCallbacks = callback;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
309
318
|
let localhostCallbacks = [];
|
|
310
|
-
if (
|
|
319
|
+
if (normalizedCallbacks) {
|
|
311
320
|
const isDevelopment = process.env.NODE_ENV === "development";
|
|
312
321
|
if (isDevelopment) {
|
|
313
|
-
localhostCallbacks = processDevelopmentCallbacks(
|
|
322
|
+
localhostCallbacks = processDevelopmentCallbacks(normalizedCallbacks);
|
|
314
323
|
} else {
|
|
315
|
-
const endpoints = Object.entries(
|
|
324
|
+
const endpoints = Object.entries(normalizedCallbacks).map(
|
|
316
325
|
([group, config]) => `${group}=${Buffer.from(config.url).toString("base64")}`
|
|
317
326
|
).join(",");
|
|
318
327
|
headers.set("Vqs-Callback-Url", endpoints);
|
|
319
|
-
const delays = Object.entries(
|
|
328
|
+
const delays = Object.entries(normalizedCallbacks).filter(([, config]) => config.delay !== void 0).map(([group, config]) => `${group}=${config.delay}`).join(",");
|
|
320
329
|
if (delays) {
|
|
321
330
|
headers.set("Vqs-Callback-Delay", delays);
|
|
322
331
|
}
|
|
323
|
-
const frequencies = Object.entries(
|
|
332
|
+
const frequencies = Object.entries(normalizedCallbacks).filter(([, config]) => config.frequency !== void 0).map(([group, config]) => `${group}=${config.frequency}`).join(",");
|
|
324
333
|
if (frequencies) {
|
|
325
334
|
headers.set("Vqs-Callback-Frequency", frequencies);
|
|
326
335
|
}
|
|
@@ -506,36 +515,9 @@ var QueueClient = class _QueueClient {
|
|
|
506
515
|
throw new MessageLockedError(messageId, retryAfter);
|
|
507
516
|
}
|
|
508
517
|
if (response.status === 424) {
|
|
509
|
-
|
|
510
|
-
const errorData = await response.json();
|
|
511
|
-
if (errorData.meta?.nextMessageId) {
|
|
512
|
-
throw new FailedDependencyError(
|
|
513
|
-
messageId,
|
|
514
|
-
errorData.meta.nextMessageId
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
} catch (parseError) {
|
|
518
|
-
if (parseError instanceof FailedDependencyError) {
|
|
519
|
-
throw parseError;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
throw new MessageNotAvailableError(
|
|
523
|
-
messageId,
|
|
524
|
-
"FIFO ordering violation"
|
|
525
|
-
);
|
|
518
|
+
throw new FailedDependencyError(messageId);
|
|
526
519
|
}
|
|
527
520
|
if (response.status === 409) {
|
|
528
|
-
try {
|
|
529
|
-
const errorData = await response.json();
|
|
530
|
-
if (errorData.nextMessageId) {
|
|
531
|
-
throw new FifoOrderingViolationError(
|
|
532
|
-
messageId,
|
|
533
|
-
errorData.nextMessageId,
|
|
534
|
-
errorData.error
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
} catch (parseError) {
|
|
538
|
-
}
|
|
539
521
|
throw new MessageNotAvailableError(messageId);
|
|
540
522
|
}
|
|
541
523
|
if (response.status >= 500) {
|
|
@@ -897,7 +879,11 @@ var ConsumerGroup = class {
|
|
|
897
879
|
message.ticket
|
|
898
880
|
);
|
|
899
881
|
try {
|
|
900
|
-
const result = await handler(message
|
|
882
|
+
const result = await handler(message.payload, {
|
|
883
|
+
messageId: message.messageId,
|
|
884
|
+
deliveryCount: message.deliveryCount,
|
|
885
|
+
timestamp: message.timestamp
|
|
886
|
+
});
|
|
901
887
|
await stopExtension();
|
|
902
888
|
if (result && "timeoutSeconds" in result) {
|
|
903
889
|
await this.client.changeVisibility({
|
|
@@ -927,219 +913,58 @@ var ConsumerGroup = class {
|
|
|
927
913
|
throw error;
|
|
928
914
|
}
|
|
929
915
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
* @param options Processing options
|
|
935
|
-
* @returns Promise that resolves when processing stops (due to signal or error)
|
|
936
|
-
*/
|
|
937
|
-
async subscribe(signal, handler, options = {}) {
|
|
938
|
-
const pollingInterval = options.pollingInterval || 1e3;
|
|
939
|
-
while (!signal.aborted) {
|
|
940
|
-
try {
|
|
941
|
-
for await (const message of this.client.receiveMessages(
|
|
916
|
+
async consume(handler, options) {
|
|
917
|
+
if (options?.messageId) {
|
|
918
|
+
if (options.skipPayload) {
|
|
919
|
+
const response = await this.client.receiveMessageById(
|
|
942
920
|
{
|
|
943
921
|
queueName: this.topicName,
|
|
944
922
|
consumerGroup: this.consumerGroupName,
|
|
923
|
+
messageId: options.messageId,
|
|
945
924
|
visibilityTimeoutSeconds: this.visibilityTimeout,
|
|
946
|
-
|
|
947
|
-
// Always process one message at a time
|
|
925
|
+
skipPayload: true
|
|
948
926
|
},
|
|
949
927
|
this.transport
|
|
950
|
-
)
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
988
|
-
continue;
|
|
989
|
-
}
|
|
990
|
-
if (error instanceof MessageLockedError) {
|
|
991
|
-
const waitTime = error.retryAfter ? error.retryAfter * 1e3 : pollingInterval;
|
|
992
|
-
if (!signal.aborted) {
|
|
993
|
-
await new Promise((resolve) => {
|
|
994
|
-
const timeoutId = setTimeout(resolve, waitTime);
|
|
995
|
-
signal.addEventListener(
|
|
996
|
-
"abort",
|
|
997
|
-
() => {
|
|
998
|
-
clearTimeout(timeoutId);
|
|
999
|
-
resolve();
|
|
1000
|
-
},
|
|
1001
|
-
{ once: true }
|
|
1002
|
-
);
|
|
1003
|
-
});
|
|
1004
|
-
}
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
console.error("Error polling topic:", error);
|
|
1008
|
-
throw error;
|
|
928
|
+
);
|
|
929
|
+
await this.processMessage(
|
|
930
|
+
response.message,
|
|
931
|
+
handler
|
|
932
|
+
);
|
|
933
|
+
} else {
|
|
934
|
+
const response = await this.client.receiveMessageById(
|
|
935
|
+
{
|
|
936
|
+
queueName: this.topicName,
|
|
937
|
+
consumerGroup: this.consumerGroupName,
|
|
938
|
+
messageId: options.messageId,
|
|
939
|
+
visibilityTimeoutSeconds: this.visibilityTimeout
|
|
940
|
+
},
|
|
941
|
+
this.transport
|
|
942
|
+
);
|
|
943
|
+
await this.processMessage(
|
|
944
|
+
response.message,
|
|
945
|
+
handler
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
} else {
|
|
949
|
+
let messageFound = false;
|
|
950
|
+
for await (const message of this.client.receiveMessages(
|
|
951
|
+
{
|
|
952
|
+
queueName: this.topicName,
|
|
953
|
+
consumerGroup: this.consumerGroupName,
|
|
954
|
+
visibilityTimeoutSeconds: this.visibilityTimeout,
|
|
955
|
+
limit: 1
|
|
956
|
+
},
|
|
957
|
+
this.transport
|
|
958
|
+
)) {
|
|
959
|
+
messageFound = true;
|
|
960
|
+
await this.processMessage(message, handler);
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
if (!messageFound) {
|
|
964
|
+
throw new Error("No messages available");
|
|
1009
965
|
}
|
|
1010
966
|
}
|
|
1011
967
|
}
|
|
1012
|
-
/**
|
|
1013
|
-
* Receive and process a specific message by its ID with full payload
|
|
1014
|
-
* @param messageId The ID of the message to receive and process
|
|
1015
|
-
* @param handler Function to process the message with full payload
|
|
1016
|
-
* @returns Promise that resolves when the message is processed or rejects with specific errors
|
|
1017
|
-
* @throws {MessageNotFoundError} When the message doesn't exist (404)
|
|
1018
|
-
* @throws {MessageNotAvailableError} When the message exists but isn't available for processing (409)
|
|
1019
|
-
* @throws {MessageLockedError} When the message is temporarily locked (423)
|
|
1020
|
-
* @throws {FifoOrderingViolationError} When there's a FIFO ordering violation (409 with nextMessageId)
|
|
1021
|
-
* @throws {FailedDependencyError} When FIFO ordering is violated (424)
|
|
1022
|
-
* @throws {MessageCorruptedError} When the message data is corrupted
|
|
1023
|
-
* @throws {BadRequestError} When request parameters are invalid
|
|
1024
|
-
* @throws {UnauthorizedError} When authentication fails
|
|
1025
|
-
* @throws {ForbiddenError} When access is denied
|
|
1026
|
-
* @throws {InternalServerError} When server encounters an error
|
|
1027
|
-
*/
|
|
1028
|
-
async receiveMessage(messageId, handler) {
|
|
1029
|
-
const response = await this.client.receiveMessageById(
|
|
1030
|
-
{
|
|
1031
|
-
queueName: this.topicName,
|
|
1032
|
-
consumerGroup: this.consumerGroupName,
|
|
1033
|
-
messageId,
|
|
1034
|
-
visibilityTimeoutSeconds: this.visibilityTimeout
|
|
1035
|
-
},
|
|
1036
|
-
this.transport
|
|
1037
|
-
);
|
|
1038
|
-
await this.processMessage(response.message, handler);
|
|
1039
|
-
}
|
|
1040
|
-
/**
|
|
1041
|
-
* Receive and process the next available message from the queue
|
|
1042
|
-
* @param handler Function to process the message
|
|
1043
|
-
* @returns Promise that resolves when the message is processed or rejects with specific errors
|
|
1044
|
-
* @throws {QueueEmptyError} When no messages are available in the queue (204)
|
|
1045
|
-
* @throws {MessageLockedError} When the next message in a FIFO queue is locked (423)
|
|
1046
|
-
* @throws {BadRequestError} When request parameters are invalid
|
|
1047
|
-
* @throws {UnauthorizedError} When authentication fails
|
|
1048
|
-
* @throws {ForbiddenError} When access is denied
|
|
1049
|
-
* @throws {InternalServerError} When server encounters an error
|
|
1050
|
-
*/
|
|
1051
|
-
async receiveNextMessage(handler) {
|
|
1052
|
-
let messageFound = false;
|
|
1053
|
-
for await (const message of this.client.receiveMessages(
|
|
1054
|
-
{
|
|
1055
|
-
queueName: this.topicName,
|
|
1056
|
-
consumerGroup: this.consumerGroupName,
|
|
1057
|
-
visibilityTimeoutSeconds: this.visibilityTimeout,
|
|
1058
|
-
limit: 1
|
|
1059
|
-
},
|
|
1060
|
-
this.transport
|
|
1061
|
-
)) {
|
|
1062
|
-
messageFound = true;
|
|
1063
|
-
await this.processMessage(message, handler);
|
|
1064
|
-
break;
|
|
1065
|
-
}
|
|
1066
|
-
if (!messageFound) {
|
|
1067
|
-
throw new Error("No messages available");
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
/**
|
|
1071
|
-
* Receive and process multiple next available messages from the queue
|
|
1072
|
-
* @param limit Number of messages to process (1-10)
|
|
1073
|
-
* @param handler Function to process each message
|
|
1074
|
-
* @returns Promise that resolves to an array of PromiseSettledResult (same as Promise.allSettled)
|
|
1075
|
-
* @throws {InvalidLimitError} When limit parameter is not between 1 and 10
|
|
1076
|
-
* @throws {QueueEmptyError} When no messages are available in the queue (204)
|
|
1077
|
-
* @throws {MessageLockedError} When the next message in a FIFO queue is locked (423)
|
|
1078
|
-
* @throws {BadRequestError} When request parameters are invalid
|
|
1079
|
-
* @throws {UnauthorizedError} When authentication fails
|
|
1080
|
-
* @throws {ForbiddenError} When access is denied
|
|
1081
|
-
* @throws {InternalServerError} When server encounters an error
|
|
1082
|
-
*/
|
|
1083
|
-
async receiveNextMessages(limit, handler) {
|
|
1084
|
-
if (limit < 1 || limit > 10) {
|
|
1085
|
-
throw new InvalidLimitError(limit);
|
|
1086
|
-
}
|
|
1087
|
-
const processingPromises = [];
|
|
1088
|
-
let messageCount = 0;
|
|
1089
|
-
for await (const message of this.client.receiveMessages(
|
|
1090
|
-
{
|
|
1091
|
-
queueName: this.topicName,
|
|
1092
|
-
consumerGroup: this.consumerGroupName,
|
|
1093
|
-
visibilityTimeoutSeconds: this.visibilityTimeout,
|
|
1094
|
-
limit
|
|
1095
|
-
},
|
|
1096
|
-
this.transport
|
|
1097
|
-
)) {
|
|
1098
|
-
messageCount++;
|
|
1099
|
-
const wrappedPromise = this.processMessage(message, handler).then(
|
|
1100
|
-
(value) => ({
|
|
1101
|
-
status: "fulfilled",
|
|
1102
|
-
value
|
|
1103
|
-
}),
|
|
1104
|
-
(reason) => ({ status: "rejected", reason })
|
|
1105
|
-
);
|
|
1106
|
-
processingPromises.push(wrappedPromise);
|
|
1107
|
-
}
|
|
1108
|
-
if (messageCount === 0) {
|
|
1109
|
-
throw new Error("No messages available");
|
|
1110
|
-
}
|
|
1111
|
-
const results = await Promise.all(processingPromises);
|
|
1112
|
-
return results;
|
|
1113
|
-
}
|
|
1114
|
-
/**
|
|
1115
|
-
* Handle a specific message by its ID without downloading the payload (metadata only)
|
|
1116
|
-
* @param messageId The ID of the message to handle
|
|
1117
|
-
* @param handler Function to process the message metadata (payload will be void)
|
|
1118
|
-
* @returns Promise that resolves when the message is handled or rejects with specific errors
|
|
1119
|
-
* @throws {MessageNotFoundError} When the message doesn't exist (404)
|
|
1120
|
-
* @throws {MessageNotAvailableError} When the message exists but isn't available for processing (409)
|
|
1121
|
-
* @throws {MessageLockedError} When the message is temporarily locked (423)
|
|
1122
|
-
* @throws {FifoOrderingViolationError} When there's a FIFO ordering violation (409 with nextMessageId)
|
|
1123
|
-
* @throws {FailedDependencyError} When FIFO ordering is violated (424)
|
|
1124
|
-
* @throws {MessageCorruptedError} When the message data is corrupted
|
|
1125
|
-
* @throws {BadRequestError} When request parameters are invalid
|
|
1126
|
-
* @throws {UnauthorizedError} When authentication fails
|
|
1127
|
-
* @throws {ForbiddenError} When access is denied
|
|
1128
|
-
* @throws {InternalServerError} When server encounters an error
|
|
1129
|
-
*/
|
|
1130
|
-
async handleMessage(messageId, handler) {
|
|
1131
|
-
const response = await this.client.receiveMessageById(
|
|
1132
|
-
{
|
|
1133
|
-
queueName: this.topicName,
|
|
1134
|
-
consumerGroup: this.consumerGroupName,
|
|
1135
|
-
messageId,
|
|
1136
|
-
visibilityTimeoutSeconds: this.visibilityTimeout,
|
|
1137
|
-
skipPayload: true
|
|
1138
|
-
},
|
|
1139
|
-
this.transport
|
|
1140
|
-
);
|
|
1141
|
-
await this.processMessage(response.message, handler);
|
|
1142
|
-
}
|
|
1143
968
|
/**
|
|
1144
969
|
* Get the consumer group name
|
|
1145
970
|
*/
|
|
@@ -1187,7 +1012,7 @@ var Topic = class {
|
|
|
1187
1012
|
payload,
|
|
1188
1013
|
idempotencyKey: options?.idempotencyKey,
|
|
1189
1014
|
retentionSeconds: options?.retentionSeconds,
|
|
1190
|
-
|
|
1015
|
+
callback: options?.callback
|
|
1191
1016
|
},
|
|
1192
1017
|
this.transport
|
|
1193
1018
|
);
|
|
@@ -1226,9 +1051,43 @@ var Topic = class {
|
|
|
1226
1051
|
};
|
|
1227
1052
|
|
|
1228
1053
|
// src/factory.ts
|
|
1229
|
-
function createTopic(
|
|
1054
|
+
function createTopic(topicName, transport) {
|
|
1055
|
+
const client = QueueClient._getDefaultInstance();
|
|
1230
1056
|
return new Topic(client, topicName, transport);
|
|
1231
1057
|
}
|
|
1058
|
+
async function send(topicName, payload, options) {
|
|
1059
|
+
const transport = options?.transport || new JsonTransport();
|
|
1060
|
+
const client = QueueClient._getDefaultInstance();
|
|
1061
|
+
const result = await client.sendMessage(
|
|
1062
|
+
{
|
|
1063
|
+
queueName: topicName,
|
|
1064
|
+
payload,
|
|
1065
|
+
idempotencyKey: options?.idempotencyKey,
|
|
1066
|
+
retentionSeconds: options?.retentionSeconds,
|
|
1067
|
+
callback: options?.callback
|
|
1068
|
+
},
|
|
1069
|
+
transport
|
|
1070
|
+
);
|
|
1071
|
+
return { messageId: result.messageId };
|
|
1072
|
+
}
|
|
1073
|
+
async function receive(topicName, consumerGroup, handler, options) {
|
|
1074
|
+
const transport = options?.transport || new JsonTransport();
|
|
1075
|
+
const topic = createTopic(topicName, transport);
|
|
1076
|
+
const { messageId, skipPayload, ...consumerGroupOptions } = options || {};
|
|
1077
|
+
const consumer = topic.consumerGroup(consumerGroup, consumerGroupOptions);
|
|
1078
|
+
if (messageId) {
|
|
1079
|
+
if (skipPayload) {
|
|
1080
|
+
return consumer.consume(handler, {
|
|
1081
|
+
messageId,
|
|
1082
|
+
skipPayload: true
|
|
1083
|
+
});
|
|
1084
|
+
} else {
|
|
1085
|
+
return consumer.consume(handler, { messageId });
|
|
1086
|
+
}
|
|
1087
|
+
} else {
|
|
1088
|
+
return consumer.consume(handler);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1232
1091
|
|
|
1233
1092
|
// src/callback.ts
|
|
1234
1093
|
function parseCallbackRequest(request) {
|
|
@@ -1251,6 +1110,52 @@ function parseCallbackRequest(request) {
|
|
|
1251
1110
|
consumerGroup
|
|
1252
1111
|
};
|
|
1253
1112
|
}
|
|
1113
|
+
function handleCallback(handlers) {
|
|
1114
|
+
return async (request) => {
|
|
1115
|
+
try {
|
|
1116
|
+
const { queueName, consumerGroup, messageId } = parseCallbackRequest(request);
|
|
1117
|
+
const topicHandler = handlers[queueName];
|
|
1118
|
+
if (!topicHandler) {
|
|
1119
|
+
throw new Error(`No handler found for topic: ${queueName}`);
|
|
1120
|
+
}
|
|
1121
|
+
let actualHandler;
|
|
1122
|
+
if (typeof topicHandler === "function") {
|
|
1123
|
+
if (consumerGroup !== "default") {
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
`Topic "${queueName}" has a single handler but received consumer group "${consumerGroup}". Expected "default".`
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
actualHandler = topicHandler;
|
|
1129
|
+
} else {
|
|
1130
|
+
const consumerGroupHandler = topicHandler[consumerGroup];
|
|
1131
|
+
if (!consumerGroupHandler) {
|
|
1132
|
+
const availableGroups = Object.keys(topicHandler).join(", ");
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`No handler found for consumer group "${consumerGroup}" in topic "${queueName}". Available groups: ${availableGroups}`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
actualHandler = consumerGroupHandler;
|
|
1138
|
+
}
|
|
1139
|
+
const client = new QueueClient();
|
|
1140
|
+
const topic = new Topic(client, queueName);
|
|
1141
|
+
const cg = topic.consumerGroup(consumerGroup);
|
|
1142
|
+
await cg.consume(actualHandler, { messageId });
|
|
1143
|
+
return Response.json({ status: "success" });
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
console.error("Callback error:", error);
|
|
1146
|
+
if (error instanceof InvalidCallbackError) {
|
|
1147
|
+
return Response.json(
|
|
1148
|
+
{ error: "Invalid callback request" },
|
|
1149
|
+
{ status: 400 }
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
return Response.json(
|
|
1153
|
+
{ error: "Failed to process callback" },
|
|
1154
|
+
{ status: 500 }
|
|
1155
|
+
);
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1254
1159
|
export {
|
|
1255
1160
|
BadRequestError,
|
|
1256
1161
|
BufferTransport,
|
|
@@ -1272,7 +1177,9 @@ export {
|
|
|
1272
1177
|
Topic,
|
|
1273
1178
|
UnauthorizedError,
|
|
1274
1179
|
createTopic,
|
|
1275
|
-
|
|
1276
|
-
parseCallbackRequest
|
|
1180
|
+
handleCallback,
|
|
1181
|
+
parseCallbackRequest,
|
|
1182
|
+
receive,
|
|
1183
|
+
send
|
|
1277
1184
|
};
|
|
1278
1185
|
//# sourceMappingURL=index.mjs.map
|