@vercel/queue 0.1.7 → 0.2.0

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
@@ -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);
@@ -1002,6 +1003,44 @@ Add a trigger to vercel.json:
1002
1003
  );
1003
1004
  }
1004
1005
  }
1006
+ function registerDevConsumer(options) {
1007
+ const {
1008
+ topic,
1009
+ client,
1010
+ handler,
1011
+ consumerGroup = "dev-consumer",
1012
+ visibilityTimeoutSeconds,
1013
+ retry
1014
+ } = options;
1015
+ const entry = {
1016
+ consumerGroup,
1017
+ handler,
1018
+ client,
1019
+ options: visibilityTimeoutSeconds !== void 0 || retry !== void 0 ? { visibilityTimeoutSeconds, retry } : void 0
1020
+ };
1021
+ const registry = getHandlerRegistry();
1022
+ const existing = registry.get(topic) ?? [];
1023
+ const existingIndex = existing.findIndex(
1024
+ (e) => e.consumerGroup === consumerGroup
1025
+ );
1026
+ if (existingIndex >= 0) {
1027
+ existing[existingIndex] = entry;
1028
+ } else {
1029
+ existing.push(entry);
1030
+ }
1031
+ registry.set(topic, existing);
1032
+ return () => {
1033
+ const current = registry.get(topic);
1034
+ if (!current) return;
1035
+ const filtered = current.filter((e) => e !== entry);
1036
+ if (filtered.length === current.length) return;
1037
+ if (filtered.length === 0) {
1038
+ registry.delete(topic);
1039
+ } else {
1040
+ registry.set(topic, filtered);
1041
+ }
1042
+ };
1043
+ }
1005
1044
  function lookupHandlers(topicName) {
1006
1045
  const registry = getHandlerRegistry();
1007
1046
  const result = [];
@@ -1640,7 +1679,7 @@ Cause: ${cause}`
1640
1679
  }
1641
1680
  console.debug("[VQS Debug] Request:", JSON.stringify(logData, null, 2));
1642
1681
  }
1643
- init.headers.set("User-Agent", `@vercel/queue/${"0.1.7"}`);
1682
+ init.headers.set("User-Agent", `@vercel/queue/${"0.2.0"}`);
1644
1683
  init.headers.set("Vqs-Client-Ts", (/* @__PURE__ */ new Date()).toISOString());
1645
1684
  const fetchInit = this.dispatcher ? { ...init, dispatcher: this.dispatcher } : init;
1646
1685
  const response = await fetch(url, fetchInit);
@@ -2330,6 +2369,7 @@ function handleCallback2(handler, options) {
2330
2369
  handleCallback,
2331
2370
  parseCallback,
2332
2371
  parseRawCallback,
2372
+ registerDevConsumer,
2333
2373
  send
2334
2374
  });
2335
2375
  //# sourceMappingURL=index.js.map