@vercel/queue 0.1.7 → 0.2.1
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 +68 -1
- package/dist/index.d.ts +68 -1
- package/dist/index.js +57 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -755,6 +755,73 @@ declare function handleCallback<T = unknown>(handler: MessageHandler<T>, options
|
|
|
755
755
|
retry?: RetryHandler;
|
|
756
756
|
}): (requestOrEvent: CallbackRequestInput) => Promise<Response>;
|
|
757
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Options for {@link registerDevConsumer}.
|
|
760
|
+
*/
|
|
761
|
+
interface RegisterDevConsumerOptions {
|
|
762
|
+
/**
|
|
763
|
+
* Topic name to subscribe to. Supports wildcard patterns (e.g. `"user-*"`).
|
|
764
|
+
*/
|
|
765
|
+
topic: string;
|
|
766
|
+
/**
|
|
767
|
+
* The QueueClient instance used for callback processing (visibility
|
|
768
|
+
* extensions, acks, etc.). Messages delivered to the handler are fetched
|
|
769
|
+
* via this client.
|
|
770
|
+
*/
|
|
771
|
+
client: QueueClient;
|
|
772
|
+
/**
|
|
773
|
+
* Function invoked with each message delivered to the topic.
|
|
774
|
+
*/
|
|
775
|
+
handler: MessageHandler;
|
|
776
|
+
/**
|
|
777
|
+
* Logical identifier for this consumer. Multiple consumers for the same
|
|
778
|
+
* topic must use distinct groups; re-registering with the same group
|
|
779
|
+
* replaces the previous handler (useful for HMR).
|
|
780
|
+
*
|
|
781
|
+
* @default "dev-consumer"
|
|
782
|
+
*/
|
|
783
|
+
consumerGroup?: string;
|
|
784
|
+
/**
|
|
785
|
+
* Lock duration for in-flight messages. Forwarded to `coreHandleCallback`.
|
|
786
|
+
*/
|
|
787
|
+
visibilityTimeoutSeconds?: number;
|
|
788
|
+
/**
|
|
789
|
+
* Called when the handler throws. Return `{ afterSeconds: N }` to schedule
|
|
790
|
+
* local re-delivery, or `{ acknowledge: true }` to drop the message.
|
|
791
|
+
*/
|
|
792
|
+
retry?: RetryHandler;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Register a consumer for a topic without relying on `vercel.json` route
|
|
796
|
+
* discovery or stack-trace-based caller detection.
|
|
797
|
+
*
|
|
798
|
+
* Intended for framework integrations (e.g. Nitro) where queue handlers are
|
|
799
|
+
* wired through a central dispatcher rather than per-file `handleCallback()`
|
|
800
|
+
* calls. The caller supplies the topic and a handler; `send()` in dev mode
|
|
801
|
+
* will route messages through it via the same retry/re-delivery machinery
|
|
802
|
+
* used for file-discovered handlers.
|
|
803
|
+
*
|
|
804
|
+
* Call only when `isDevMode()` is true. In production this has no effect on
|
|
805
|
+
* routing — messages are delivered by the Vercel Queue Service directly.
|
|
806
|
+
*
|
|
807
|
+
* @returns An unregister function. Calling it removes the handler that this
|
|
808
|
+
* call registered; if the entry was replaced (via re-registration with the
|
|
809
|
+
* same `consumerGroup`), the unregister is a no-op.
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```ts
|
|
813
|
+
* const unregister = registerDevConsumer({
|
|
814
|
+
* topic: "orders",
|
|
815
|
+
* client,
|
|
816
|
+
* handler: async (message, metadata) => {
|
|
817
|
+
* await dispatch(message, metadata);
|
|
818
|
+
* },
|
|
819
|
+
* consumerGroup: "nitro-vercel-queue",
|
|
820
|
+
* });
|
|
821
|
+
* ```
|
|
822
|
+
*/
|
|
823
|
+
declare function registerDevConsumer(options: RegisterDevConsumerOptions): () => void;
|
|
824
|
+
|
|
758
825
|
/**
|
|
759
826
|
* Core queue callback utilities for handling incoming webhook payloads
|
|
760
827
|
* from Vercel triggers using the CloudEvent specification.
|
|
@@ -828,4 +895,4 @@ declare function parseRawCallback(body: unknown, headers: Record<string, string
|
|
|
828
895
|
*/
|
|
829
896
|
declare function parseCallback(request: Request): Promise<ParsedCallbackRequest>;
|
|
830
897
|
|
|
831
|
-
export { BadRequestError, type BaseUrlResolver, BufferTransport, CLOUD_EVENT_TYPE_V1BETA, CLOUD_EVENT_TYPE_V2BETA, ConsumerDiscoveryError, ConsumerRegistryNotConfiguredError, DuplicateMessageError, ForbiddenError, InternalServerError, InvalidLimitError, JsonTransport, type Message, MessageAlreadyProcessedError, MessageCorruptedError, type MessageHandler, MessageLockedError, type MessageMetadata, MessageNotAvailableError, MessageNotFoundError, type ParsedCallbackRequest, type ParsedCallbackV1, type ParsedCallbackV2, PollingQueueClient, type PollingQueueClientOptions, QueueClient, type QueueClientOptions, QueueEmptyError, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type ReceiveResult, type RetryDirective, type RetryHandler, type SendOptions, type SendResult, StreamTransport, type Transport, UnauthorizedError, type VercelRegion, handleCallback, parseCallback, parseRawCallback, send };
|
|
898
|
+
export { BadRequestError, type BaseUrlResolver, BufferTransport, CLOUD_EVENT_TYPE_V1BETA, CLOUD_EVENT_TYPE_V2BETA, ConsumerDiscoveryError, ConsumerRegistryNotConfiguredError, DuplicateMessageError, ForbiddenError, InternalServerError, InvalidLimitError, JsonTransport, type Message, MessageAlreadyProcessedError, MessageCorruptedError, type MessageHandler, MessageLockedError, type MessageMetadata, MessageNotAvailableError, MessageNotFoundError, type ParsedCallbackRequest, type ParsedCallbackV1, type ParsedCallbackV2, PollingQueueClient, type PollingQueueClientOptions, QueueClient, type QueueClientOptions, QueueEmptyError, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type ReceiveResult, type RegisterDevConsumerOptions, type RetryDirective, type RetryHandler, type SendOptions, type SendResult, StreamTransport, type Transport, UnauthorizedError, type VercelRegion, handleCallback, parseCallback, parseRawCallback, registerDevConsumer, send };
|
package/dist/index.d.ts
CHANGED
|
@@ -755,6 +755,73 @@ declare function handleCallback<T = unknown>(handler: MessageHandler<T>, options
|
|
|
755
755
|
retry?: RetryHandler;
|
|
756
756
|
}): (requestOrEvent: CallbackRequestInput) => Promise<Response>;
|
|
757
757
|
|
|
758
|
+
/**
|
|
759
|
+
* Options for {@link registerDevConsumer}.
|
|
760
|
+
*/
|
|
761
|
+
interface RegisterDevConsumerOptions {
|
|
762
|
+
/**
|
|
763
|
+
* Topic name to subscribe to. Supports wildcard patterns (e.g. `"user-*"`).
|
|
764
|
+
*/
|
|
765
|
+
topic: string;
|
|
766
|
+
/**
|
|
767
|
+
* The QueueClient instance used for callback processing (visibility
|
|
768
|
+
* extensions, acks, etc.). Messages delivered to the handler are fetched
|
|
769
|
+
* via this client.
|
|
770
|
+
*/
|
|
771
|
+
client: QueueClient;
|
|
772
|
+
/**
|
|
773
|
+
* Function invoked with each message delivered to the topic.
|
|
774
|
+
*/
|
|
775
|
+
handler: MessageHandler;
|
|
776
|
+
/**
|
|
777
|
+
* Logical identifier for this consumer. Multiple consumers for the same
|
|
778
|
+
* topic must use distinct groups; re-registering with the same group
|
|
779
|
+
* replaces the previous handler (useful for HMR).
|
|
780
|
+
*
|
|
781
|
+
* @default "dev-consumer"
|
|
782
|
+
*/
|
|
783
|
+
consumerGroup?: string;
|
|
784
|
+
/**
|
|
785
|
+
* Lock duration for in-flight messages. Forwarded to `coreHandleCallback`.
|
|
786
|
+
*/
|
|
787
|
+
visibilityTimeoutSeconds?: number;
|
|
788
|
+
/**
|
|
789
|
+
* Called when the handler throws. Return `{ afterSeconds: N }` to schedule
|
|
790
|
+
* local re-delivery, or `{ acknowledge: true }` to drop the message.
|
|
791
|
+
*/
|
|
792
|
+
retry?: RetryHandler;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Register a consumer for a topic without relying on `vercel.json` route
|
|
796
|
+
* discovery or stack-trace-based caller detection.
|
|
797
|
+
*
|
|
798
|
+
* Intended for framework integrations (e.g. Nitro) where queue handlers are
|
|
799
|
+
* wired through a central dispatcher rather than per-file `handleCallback()`
|
|
800
|
+
* calls. The caller supplies the topic and a handler; `send()` in dev mode
|
|
801
|
+
* will route messages through it via the same retry/re-delivery machinery
|
|
802
|
+
* used for file-discovered handlers.
|
|
803
|
+
*
|
|
804
|
+
* Call only when `isDevMode()` is true. In production this has no effect on
|
|
805
|
+
* routing — messages are delivered by the Vercel Queue Service directly.
|
|
806
|
+
*
|
|
807
|
+
* @returns An unregister function. Calling it removes the handler that this
|
|
808
|
+
* call registered; if the entry was replaced (via re-registration with the
|
|
809
|
+
* same `consumerGroup`), the unregister is a no-op.
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```ts
|
|
813
|
+
* const unregister = registerDevConsumer({
|
|
814
|
+
* topic: "orders",
|
|
815
|
+
* client,
|
|
816
|
+
* handler: async (message, metadata) => {
|
|
817
|
+
* await dispatch(message, metadata);
|
|
818
|
+
* },
|
|
819
|
+
* consumerGroup: "nitro-vercel-queue",
|
|
820
|
+
* });
|
|
821
|
+
* ```
|
|
822
|
+
*/
|
|
823
|
+
declare function registerDevConsumer(options: RegisterDevConsumerOptions): () => void;
|
|
824
|
+
|
|
758
825
|
/**
|
|
759
826
|
* Core queue callback utilities for handling incoming webhook payloads
|
|
760
827
|
* from Vercel triggers using the CloudEvent specification.
|
|
@@ -828,4 +895,4 @@ declare function parseRawCallback(body: unknown, headers: Record<string, string
|
|
|
828
895
|
*/
|
|
829
896
|
declare function parseCallback(request: Request): Promise<ParsedCallbackRequest>;
|
|
830
897
|
|
|
831
|
-
export { BadRequestError, type BaseUrlResolver, BufferTransport, CLOUD_EVENT_TYPE_V1BETA, CLOUD_EVENT_TYPE_V2BETA, ConsumerDiscoveryError, ConsumerRegistryNotConfiguredError, DuplicateMessageError, ForbiddenError, InternalServerError, InvalidLimitError, JsonTransport, type Message, MessageAlreadyProcessedError, MessageCorruptedError, type MessageHandler, MessageLockedError, type MessageMetadata, MessageNotAvailableError, MessageNotFoundError, type ParsedCallbackRequest, type ParsedCallbackV1, type ParsedCallbackV2, PollingQueueClient, type PollingQueueClientOptions, QueueClient, type QueueClientOptions, QueueEmptyError, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type ReceiveResult, type RetryDirective, type RetryHandler, type SendOptions, type SendResult, StreamTransport, type Transport, UnauthorizedError, type VercelRegion, handleCallback, parseCallback, parseRawCallback, send };
|
|
898
|
+
export { BadRequestError, type BaseUrlResolver, BufferTransport, CLOUD_EVENT_TYPE_V1BETA, CLOUD_EVENT_TYPE_V2BETA, ConsumerDiscoveryError, ConsumerRegistryNotConfiguredError, DuplicateMessageError, ForbiddenError, InternalServerError, InvalidLimitError, JsonTransport, type Message, MessageAlreadyProcessedError, MessageCorruptedError, type MessageHandler, MessageLockedError, type MessageMetadata, MessageNotAvailableError, MessageNotFoundError, type ParsedCallbackRequest, type ParsedCallbackV1, type ParsedCallbackV2, PollingQueueClient, type PollingQueueClientOptions, QueueClient, type QueueClientOptions, QueueEmptyError, type ReceiveBatchOptions, type ReceiveByIdOptions, type ReceiveOptions, type ReceiveResult, type RegisterDevConsumerOptions, type RetryDirective, type RetryHandler, type SendOptions, type SendResult, StreamTransport, type Transport, UnauthorizedError, type VercelRegion, handleCallback, parseCallback, parseRawCallback, registerDevConsumer, send };
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ __export(index_exports, {
|
|
|
54
54
|
handleCallback: () => handleCallback2,
|
|
55
55
|
parseCallback: () => parseCallback,
|
|
56
56
|
parseRawCallback: () => parseRawCallback,
|
|
57
|
+
registerDevConsumer: () => registerDevConsumer,
|
|
57
58
|
send: () => send
|
|
58
59
|
});
|
|
59
60
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -657,7 +658,13 @@ function parseBinaryHeaders(headers) {
|
|
|
657
658
|
`Missing required CloudEvent headers: ${missingFields.join(", ")}`
|
|
658
659
|
);
|
|
659
660
|
}
|
|
660
|
-
const
|
|
661
|
+
const rawRegion = getHeader(headers, "ce-vqsregion") ?? void 0;
|
|
662
|
+
if (rawRegion !== void 0 && !/^[a-z]{2,5}[0-9]{1,2}$/.test(rawRegion)) {
|
|
663
|
+
throw new Error(
|
|
664
|
+
`Invalid ce-vqsregion header: ${JSON.stringify(rawRegion)}. Region must match /^[a-z]{2,5}[0-9]{1,2}$/ (e.g. "iad1", "lhr1").`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
const region = rawRegion;
|
|
661
668
|
const base = {
|
|
662
669
|
queueName,
|
|
663
670
|
consumerGroup,
|
|
@@ -1002,6 +1009,44 @@ Add a trigger to vercel.json:
|
|
|
1002
1009
|
);
|
|
1003
1010
|
}
|
|
1004
1011
|
}
|
|
1012
|
+
function registerDevConsumer(options) {
|
|
1013
|
+
const {
|
|
1014
|
+
topic,
|
|
1015
|
+
client,
|
|
1016
|
+
handler,
|
|
1017
|
+
consumerGroup = "dev-consumer",
|
|
1018
|
+
visibilityTimeoutSeconds,
|
|
1019
|
+
retry
|
|
1020
|
+
} = options;
|
|
1021
|
+
const entry = {
|
|
1022
|
+
consumerGroup,
|
|
1023
|
+
handler,
|
|
1024
|
+
client,
|
|
1025
|
+
options: visibilityTimeoutSeconds !== void 0 || retry !== void 0 ? { visibilityTimeoutSeconds, retry } : void 0
|
|
1026
|
+
};
|
|
1027
|
+
const registry = getHandlerRegistry();
|
|
1028
|
+
const existing = registry.get(topic) ?? [];
|
|
1029
|
+
const existingIndex = existing.findIndex(
|
|
1030
|
+
(e) => e.consumerGroup === consumerGroup
|
|
1031
|
+
);
|
|
1032
|
+
if (existingIndex >= 0) {
|
|
1033
|
+
existing[existingIndex] = entry;
|
|
1034
|
+
} else {
|
|
1035
|
+
existing.push(entry);
|
|
1036
|
+
}
|
|
1037
|
+
registry.set(topic, existing);
|
|
1038
|
+
return () => {
|
|
1039
|
+
const current = registry.get(topic);
|
|
1040
|
+
if (!current) return;
|
|
1041
|
+
const filtered = current.filter((e) => e !== entry);
|
|
1042
|
+
if (filtered.length === current.length) return;
|
|
1043
|
+
if (filtered.length === 0) {
|
|
1044
|
+
registry.delete(topic);
|
|
1045
|
+
} else {
|
|
1046
|
+
registry.set(topic, filtered);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1005
1050
|
function lookupHandlers(topicName) {
|
|
1006
1051
|
const registry = getHandlerRegistry();
|
|
1007
1052
|
const result = [];
|
|
@@ -1509,6 +1554,14 @@ function parseQueueHeaders(headers) {
|
|
|
1509
1554
|
receiptHandle
|
|
1510
1555
|
};
|
|
1511
1556
|
}
|
|
1557
|
+
var REGION_PATTERN = /^[a-z]{2,5}[0-9]{1,2}$/;
|
|
1558
|
+
function validateRegion(region) {
|
|
1559
|
+
if (!REGION_PATTERN.test(region)) {
|
|
1560
|
+
throw new Error(
|
|
1561
|
+
`Invalid region code: ${JSON.stringify(region)}. Region must match the pattern /^[a-z]{2,5}[0-9]{1,2}$/ (e.g. "iad1", "lhr1").`
|
|
1562
|
+
);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1512
1565
|
var DEFAULT_BASE_URL_RESOLVER = (region) => new URL(`https://${region}.vercel-queue.com`);
|
|
1513
1566
|
function resolveBaseUrl(region, resolver) {
|
|
1514
1567
|
return (resolver ?? DEFAULT_BASE_URL_RESOLVER)(region);
|
|
@@ -1526,6 +1579,7 @@ var ApiClient = class _ApiClient {
|
|
|
1526
1579
|
baseUrlResolver;
|
|
1527
1580
|
dispatcher;
|
|
1528
1581
|
constructor(options) {
|
|
1582
|
+
validateRegion(options.region);
|
|
1529
1583
|
this.region = options.region;
|
|
1530
1584
|
this.baseUrlResolver = options.resolveBaseUrl;
|
|
1531
1585
|
this.baseUrl = resolveBaseUrl(this.region, this.baseUrlResolver);
|
|
@@ -1640,7 +1694,7 @@ Cause: ${cause}`
|
|
|
1640
1694
|
}
|
|
1641
1695
|
console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
|
|
1642
1696
|
}
|
|
1643
|
-
init.headers.set("User-Agent", `@vercel/queue/${"0.1
|
|
1697
|
+
init.headers.set("User-Agent", `@vercel/queue/${"0.2.1"}`);
|
|
1644
1698
|
init.headers.set("Vqs-Client-Ts", (/* @__PURE__ */ new Date()).toISOString());
|
|
1645
1699
|
const fetchInit = this.dispatcher ? { ...init, dispatcher: this.dispatcher } : init;
|
|
1646
1700
|
const response = await fetch(url, fetchInit);
|
|
@@ -2330,6 +2384,7 @@ function handleCallback2(handler, options) {
|
|
|
2330
2384
|
handleCallback,
|
|
2331
2385
|
parseCallback,
|
|
2332
2386
|
parseRawCallback,
|
|
2387
|
+
registerDevConsumer,
|
|
2333
2388
|
send
|
|
2334
2389
|
});
|
|
2335
2390
|
//# sourceMappingURL=index.js.map
|