@upstash/qstash 2.0.0 → 2.1.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 +22 -12
- package/dist/index.d.ts +22 -12
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -372,7 +372,7 @@ type ClientConfig = {
|
|
|
372
372
|
*/
|
|
373
373
|
retry?: RetryConfig;
|
|
374
374
|
};
|
|
375
|
-
type PublishRequest = {
|
|
375
|
+
type PublishRequest<TBody = BodyInit> = {
|
|
376
376
|
/**
|
|
377
377
|
* The message to send.
|
|
378
378
|
*
|
|
@@ -380,7 +380,7 @@ type PublishRequest = {
|
|
|
380
380
|
*
|
|
381
381
|
* You can leave this empty if you want to send a message with no body.
|
|
382
382
|
*/
|
|
383
|
-
body?:
|
|
383
|
+
body?: TBody;
|
|
384
384
|
/**
|
|
385
385
|
* Optionally send along headers with the message.
|
|
386
386
|
* These headers will be sent to your destination.
|
|
@@ -458,11 +458,19 @@ type PublishRequest = {
|
|
|
458
458
|
* @default `POST`
|
|
459
459
|
*/
|
|
460
460
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
461
|
+
} & ({
|
|
461
462
|
/**
|
|
462
|
-
* The url
|
|
463
|
+
* The url where the message should be sent to.
|
|
463
464
|
*/
|
|
464
|
-
|
|
465
|
-
|
|
465
|
+
url: string;
|
|
466
|
+
topic?: never;
|
|
467
|
+
} | {
|
|
468
|
+
url?: never;
|
|
469
|
+
/**
|
|
470
|
+
* The url where the message should be sent to.
|
|
471
|
+
*/
|
|
472
|
+
topic: string;
|
|
473
|
+
});
|
|
466
474
|
type PublishJsonRequest = Omit<PublishRequest, "body"> & {
|
|
467
475
|
/**
|
|
468
476
|
* The message to send.
|
|
@@ -504,12 +512,12 @@ declare class Client {
|
|
|
504
512
|
* Create, read or delete schedules.
|
|
505
513
|
*/
|
|
506
514
|
get schedules(): Schedules;
|
|
507
|
-
publish(req:
|
|
515
|
+
publish<TRequest extends PublishRequest>(req: TRequest): Promise<PublishResponse<TRequest>>;
|
|
508
516
|
/**
|
|
509
517
|
* publishJSON is a utility wrapper around `publish` that automatically serializes the body
|
|
510
518
|
* and sets the `Content-Type` header to `application/json`.
|
|
511
519
|
*/
|
|
512
|
-
publishJSON(req:
|
|
520
|
+
publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest): Promise<PublishResponse<TRequest>>;
|
|
513
521
|
/**
|
|
514
522
|
* Retrieve your logs.
|
|
515
523
|
*
|
|
@@ -531,13 +539,15 @@ declare class Client {
|
|
|
531
539
|
*/
|
|
532
540
|
events(req?: EventsRequest): Promise<GetEventsResponse>;
|
|
533
541
|
}
|
|
534
|
-
type
|
|
542
|
+
type PublishToUrlResponse = {
|
|
535
543
|
messageId: string;
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
messageId?: never;
|
|
539
|
-
messageIds: string[];
|
|
544
|
+
url: string;
|
|
545
|
+
deduplicated?: boolean;
|
|
540
546
|
};
|
|
547
|
+
type PublishToTopicResponse = PublishToUrlResponse[];
|
|
548
|
+
type PublishResponse<R> = R extends {
|
|
549
|
+
url: string;
|
|
550
|
+
} ? PublishToUrlResponse : PublishToTopicResponse;
|
|
541
551
|
|
|
542
552
|
/**
|
|
543
553
|
* Result of 500 Internal Server Error
|
package/dist/index.d.ts
CHANGED
|
@@ -372,7 +372,7 @@ type ClientConfig = {
|
|
|
372
372
|
*/
|
|
373
373
|
retry?: RetryConfig;
|
|
374
374
|
};
|
|
375
|
-
type PublishRequest = {
|
|
375
|
+
type PublishRequest<TBody = BodyInit> = {
|
|
376
376
|
/**
|
|
377
377
|
* The message to send.
|
|
378
378
|
*
|
|
@@ -380,7 +380,7 @@ type PublishRequest = {
|
|
|
380
380
|
*
|
|
381
381
|
* You can leave this empty if you want to send a message with no body.
|
|
382
382
|
*/
|
|
383
|
-
body?:
|
|
383
|
+
body?: TBody;
|
|
384
384
|
/**
|
|
385
385
|
* Optionally send along headers with the message.
|
|
386
386
|
* These headers will be sent to your destination.
|
|
@@ -458,11 +458,19 @@ type PublishRequest = {
|
|
|
458
458
|
* @default `POST`
|
|
459
459
|
*/
|
|
460
460
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
461
|
+
} & ({
|
|
461
462
|
/**
|
|
462
|
-
* The url
|
|
463
|
+
* The url where the message should be sent to.
|
|
463
464
|
*/
|
|
464
|
-
|
|
465
|
-
|
|
465
|
+
url: string;
|
|
466
|
+
topic?: never;
|
|
467
|
+
} | {
|
|
468
|
+
url?: never;
|
|
469
|
+
/**
|
|
470
|
+
* The url where the message should be sent to.
|
|
471
|
+
*/
|
|
472
|
+
topic: string;
|
|
473
|
+
});
|
|
466
474
|
type PublishJsonRequest = Omit<PublishRequest, "body"> & {
|
|
467
475
|
/**
|
|
468
476
|
* The message to send.
|
|
@@ -504,12 +512,12 @@ declare class Client {
|
|
|
504
512
|
* Create, read or delete schedules.
|
|
505
513
|
*/
|
|
506
514
|
get schedules(): Schedules;
|
|
507
|
-
publish(req:
|
|
515
|
+
publish<TRequest extends PublishRequest>(req: TRequest): Promise<PublishResponse<TRequest>>;
|
|
508
516
|
/**
|
|
509
517
|
* publishJSON is a utility wrapper around `publish` that automatically serializes the body
|
|
510
518
|
* and sets the `Content-Type` header to `application/json`.
|
|
511
519
|
*/
|
|
512
|
-
publishJSON(req:
|
|
520
|
+
publishJSON<TBody = unknown, TRequest extends PublishRequest<TBody> = PublishRequest<TBody>>(req: TRequest): Promise<PublishResponse<TRequest>>;
|
|
513
521
|
/**
|
|
514
522
|
* Retrieve your logs.
|
|
515
523
|
*
|
|
@@ -531,13 +539,15 @@ declare class Client {
|
|
|
531
539
|
*/
|
|
532
540
|
events(req?: EventsRequest): Promise<GetEventsResponse>;
|
|
533
541
|
}
|
|
534
|
-
type
|
|
542
|
+
type PublishToUrlResponse = {
|
|
535
543
|
messageId: string;
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
messageId?: never;
|
|
539
|
-
messageIds: string[];
|
|
544
|
+
url: string;
|
|
545
|
+
deduplicated?: boolean;
|
|
540
546
|
};
|
|
547
|
+
type PublishToTopicResponse = PublishToUrlResponse[];
|
|
548
|
+
type PublishResponse<R> = R extends {
|
|
549
|
+
url: string;
|
|
550
|
+
} ? PublishToUrlResponse : PublishToTopicResponse;
|
|
541
551
|
|
|
542
552
|
/**
|
|
543
553
|
* Result of 500 Internal Server Error
|
package/dist/index.js
CHANGED
|
@@ -293,7 +293,7 @@ var Client = class {
|
|
|
293
293
|
}
|
|
294
294
|
publish(req) {
|
|
295
295
|
return _chunkEQTYEU4Ujs.__async.call(void 0, this, null, function* () {
|
|
296
|
-
var _a;
|
|
296
|
+
var _a, _b;
|
|
297
297
|
const headers = new Headers(req.headers);
|
|
298
298
|
headers.set("Upstash-Method", (_a = req.method) != null ? _a : "POST");
|
|
299
299
|
if (typeof req.delay !== "undefined") {
|
|
@@ -315,7 +315,7 @@ var Client = class {
|
|
|
315
315
|
headers.set("Upstash-Callback", req.callback);
|
|
316
316
|
}
|
|
317
317
|
const res = yield this.http.request({
|
|
318
|
-
path: ["v2", "publish", req.
|
|
318
|
+
path: ["v2", "publish", (_b = req.url) != null ? _b : req.topic],
|
|
319
319
|
body: req.body,
|
|
320
320
|
headers,
|
|
321
321
|
method: "POST"
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n","import { QstashError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n\n /**\n * A unique identifier for this message.\n */\n messageId: string\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string\n\n /**\n * The url where this message is sent to.\n */\n url: string\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>\n\n /**\n * The http body sent to your API\n */\n body?: string\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number\n\n /**\n * A unix timestamp (milliseconds) when this messages was crated.\n */\n createdAt: number\n\n /**\n * The callback url if configured.\n */\n callback?: string\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n}\n","import { Requester } from \"./http\";\nimport type { Message } from \"./messages\"\n\ntype DlqMessage = Message & {\n dlqId: string\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The url or topicName where the message should be sent to.\n */\n destination: string;\n};\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish(req: PublishRequest): Promise<PublishResponse> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n const res = await this.http.request<PublishResponse>({\n path: [\"v2\", \"publish\", req.destination],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON(req: PublishRequest): Promise<PublishResponse> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n const res = await this.publish({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\n\ntype PublishResponse =\n | {\n messageId: string;\n messageIds?: never;\n }\n | {\n messageId?: never;\n messageIds: string[];\n };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n","import { QstashError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n /**\n * A unique identifier for this message.\n */\n messageId: string;\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string;\n\n /**\n * The url where this message is sent to.\n */\n url: string;\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>;\n\n /**\n * The http body sent to your API\n */\n body?: string;\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number;\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number;\n\n /**\n * A unix timestamp (milliseconds) when this messages was crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: string;\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n}\n","import { Requester } from \"./http\";\nimport type { Message } from \"./messages\";\n\ntype DlqMessage = Message & {\n dlqId: string;\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest<TBody = BodyInit> = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: TBody;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n} & (\n | {\n /**\n * The url where the message should be sent to.\n */\n url: string;\n topic?: never;\n }\n | {\n url?: never;\n /**\n * The url where the message should be sent to.\n */\n topic: string;\n }\n);\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish<TRequest extends PublishRequest>(\n req: TRequest,\n ): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n const res = await this.http.request<PublishResponse<TRequest>>({\n path: [\"v2\", \"publish\", req.url ?? req.topic],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON<\n TBody = unknown,\n TRequest extends PublishRequest<TBody> = PublishRequest<TBody>,\n >(req: TRequest): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n // @ts-ignore it's just internal\n const res = await this.publish<TRequest>({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\ntype PublishToUrlResponse = {\n messageId: string;\n url: string;\n deduplicated?: boolean;\n};\n\ntype PublishToTopicResponse = PublishToUrlResponse[];\n\ntype PublishResponse<R> = R extends { url: string } ? PublishToUrlResponse : PublishToTopicResponse;\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -293,7 +293,7 @@ var Client = class {
|
|
|
293
293
|
}
|
|
294
294
|
publish(req) {
|
|
295
295
|
return __async(this, null, function* () {
|
|
296
|
-
var _a;
|
|
296
|
+
var _a, _b;
|
|
297
297
|
const headers = new Headers(req.headers);
|
|
298
298
|
headers.set("Upstash-Method", (_a = req.method) != null ? _a : "POST");
|
|
299
299
|
if (typeof req.delay !== "undefined") {
|
|
@@ -315,7 +315,7 @@ var Client = class {
|
|
|
315
315
|
headers.set("Upstash-Callback", req.callback);
|
|
316
316
|
}
|
|
317
317
|
const res = yield this.http.request({
|
|
318
|
-
path: ["v2", "publish", req.
|
|
318
|
+
path: ["v2", "publish", (_b = req.url) != null ? _b : req.topic],
|
|
319
319
|
body: req.body,
|
|
320
320
|
headers,
|
|
321
321
|
method: "POST"
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"sourcesContent":["/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n","import { QstashError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n\n /**\n * A unique identifier for this message.\n */\n messageId: string\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string\n\n /**\n * The url where this message is sent to.\n */\n url: string\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>\n\n /**\n * The http body sent to your API\n */\n body?: string\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number\n\n /**\n * A unix timestamp (milliseconds) when this messages was crated.\n */\n createdAt: number\n\n /**\n * The callback url if configured.\n */\n callback?: string\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n}\n","import { Requester } from \"./http\";\nimport type { Message } from \"./messages\"\n\ntype DlqMessage = Message & {\n dlqId: string\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The url or topicName where the message should be sent to.\n */\n destination: string;\n};\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish(req: PublishRequest): Promise<PublishResponse> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n const res = await this.http.request<PublishResponse>({\n path: [\"v2\", \"publish\", req.destination],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON(req: PublishRequest): Promise<PublishResponse> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n const res = await this.publish({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\n\ntype PublishResponse =\n | {\n messageId: string;\n messageIds?: never;\n }\n | {\n messageId?: never;\n messageIds: string[];\n };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client/error.ts","../src/client/http.ts","../src/client/topics.ts","../src/client/messages.ts","../src/client/schedules.ts","../src/client/dlq.ts","../src/client/client.ts"],"sourcesContent":["/**\n * Result of 500 Internal Server Error\n */\nexport class QstashError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"QstashError\";\n }\n}\n","import { QstashError } from \"./error\";\n\nexport type UpstashRequest = {\n /**\n * The path to the resource.\n */\n path: string[];\n\n /**\n * A BodyInit object or null to set request's body.\n */\n body?: BodyInit | null;\n\n /**\n * A Headers object, an object literal, or an array of two-item arrays to set\n * request's headers.\n */\n headers?: HeadersInit;\n\n /**\n * A boolean to set request's keepalive.\n */\n keepalive?: boolean;\n\n /**\n * A string to set request's method.\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\";\n\n query?: Record<string, string | number | boolean | undefined>;\n};\nexport type UpstashResponse<TResult> = TResult & { error?: string };\n\nexport interface Requester {\n request: <TResult = unknown>(req: UpstashRequest) => Promise<UpstashResponse<TResult>>;\n}\n\nexport type RetryConfig =\n | false\n | {\n /**\n * The number of retries to attempt before giving up.\n *\n * @default 5\n */\n retries?: number;\n /**\n * A backoff function receives the current retry cound and returns a number in milliseconds to wait before retrying.\n *\n * @default\n * ```ts\n * Math.exp(retryCount) * 50\n * ```\n */\n backoff?: (retryCount: number) => number;\n };\n\nexport type HttpClientConfig = {\n baseUrl: string;\n authorization: string;\n retry?: RetryConfig;\n};\n\nexport class HttpClient implements Requester {\n public readonly baseUrl: string;\n\n public readonly authorization: string;\n\n public readonly options?: { backend?: string };\n\n public retry: {\n attempts: number;\n backoff: (retryCount: number) => number;\n };\n\n public constructor(config: HttpClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n\n this.authorization = config.authorization;\n\n if (typeof config?.retry === \"boolean\" && config?.retry === false) {\n this.retry = {\n attempts: 1,\n backoff: () => 0,\n };\n } else {\n this.retry = {\n attempts: config.retry?.retries ? config.retry.retries + 1 : 5,\n backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50),\n };\n }\n }\n\n public async request<TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> {\n const headers = new Headers(req.headers);\n headers.set(\"Authorization\", this.authorization);\n\n const requestOptions: RequestInit & { backend?: string } = {\n method: req.method,\n headers,\n body: req.body,\n keepalive: req.keepalive,\n };\n\n const url = new URL([this.baseUrl, ...(req.path ?? [])].join(\"/\"));\n if (req.query) {\n for (const [key, value] of Object.entries(req.query)) {\n if (typeof value !== \"undefined\") {\n url.searchParams.set(key, value.toString());\n }\n }\n }\n\n let res: Response | null = null;\n let error: Error | null = null;\n for (let i = 0; i < this.retry.attempts; i++) {\n try {\n res = await fetch(url.toString(), requestOptions);\n break;\n } catch (err) {\n error = err as Error;\n await new Promise((r) => setTimeout(r, this.retry.backoff(i)));\n }\n }\n if (!res) {\n throw error ?? new Error(\"Exhausted all retries\");\n }\n\n if (res.status < 200 || res.status >= 300) {\n throw new QstashError((await res.text()) ?? res.statusText);\n }\n return (await res.json()) as UpstashResponse<TResult>;\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Endpoint = {\n /**\n * The name of the endpoint (optional)\n */\n name?: string;\n\n /**\n * The url of the endpoint\n */\n url: string;\n};\n\nexport type AddEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: Endpoint[];\n};\n\nexport type RemoveEndpointsRequest = {\n /**\n * The name of the topic.\n * Must be unique and only contain alphanumeric, hyphen, underscore and periods.\n */\n name: string;\n\n endpoints: (\n | {\n name: string;\n url?: string;\n }\n | {\n name?: string;\n url: string;\n }\n )[];\n};\n\nexport type Topic = {\n /**\n * The name of this topic.\n */\n name: string;\n\n /**\n * A list of all subscribed endpoints\n */\n endpoints: Endpoint[];\n};\n\nexport class Topics {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a new topic with the given name and endpoints\n */\n public async addEndpoints(req: AddEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"POST\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Remove endpoints from a topic.\n */\n public async removeEndpoints(req: RemoveEndpointsRequest): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", req.name],\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ endpoints: req.endpoints }),\n });\n }\n\n /**\n * Get a list of all topics.\n */\n public async list(): Promise<Topic[]> {\n return await this.http.request<Topic[]>({\n method: \"GET\",\n path: [\"v2\", \"topics\"],\n });\n }\n\n /**\n * Get a single topic\n */\n public async get(name: string): Promise<Topic> {\n return await this.http.request<Topic>({\n method: \"GET\",\n path: [\"v2\", \"topics\", name],\n });\n }\n\n /**\n * Delete a topic\n */\n public async delete(name: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"topics\", name],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Message = {\n /**\n * A unique identifier for this message.\n */\n messageId: string;\n\n /**\n * The topic name if this message was sent to a topic.\n */\n topicName?: string;\n\n /**\n * The url where this message is sent to.\n */\n url: string;\n\n /**\n * The http method used to deliver the message\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * The http headers sent along with the message to your API.\n */\n header?: Record<string, string[]>;\n\n /**\n * The http body sent to your API\n */\n body?: string;\n\n /**\n * Maxmimum number of retries.\n */\n maxRetries?: number;\n\n /**\n * A unix timestamp (milliseconds) after which this message may get delivered.\n */\n notBefore?: number;\n\n /**\n * A unix timestamp (milliseconds) when this messages was crated.\n */\n createdAt: number;\n\n /**\n * The callback url if configured.\n */\n callback?: string;\n};\n\nexport class Messages {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Get a message\n */\n public async get(messageId: string): Promise<Message> {\n return await this.http.request<Message>({\n method: \"GET\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n\n /**\n * Cancel a message\n */\n public async delete(messageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"messages\", messageId],\n });\n }\n}\n","import { Requester } from \"./http\";\n\nexport type Schedule = {\n scheduleId: string;\n cron: string;\n createdAt: number;\n destination: string;\n method: string;\n header?: Record<string, string[]>;\n body?: string;\n retries: number;\n delay?: number;\n callback?: string;\n};\n\nexport type CreateScheduleRequest = {\n /**\n * Either a URL or topic name\n */\n destination: string;\n\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: BodyInit;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n /**\n * Optionally specify a cron expression to repeatedly send this message to the destination.\n *\n * @default undefined\n */\n cron: string;\n};\n\nexport class Schedules {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * Create a schedule\n */\n public async create(req: CreateScheduleRequest): Promise<{ scheduleId: string }> {\n return await this.http.request({\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n path: [\"v2\", \"schedules\"],\n body: JSON.stringify(req),\n });\n }\n\n /**\n * Get a schedule\n */\n public async get(scheduleId: string): Promise<Schedule> {\n return await this.http.request<Schedule>({\n method: \"GET\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n\n /**\n * List your schedules\n */\n public async list(): Promise<Schedule[]> {\n return await this.http.request<Schedule[]>({\n method: \"GET\",\n path: [\"v2\", \"schedules\"],\n });\n }\n\n /**\n * Delete a schedule\n */\n public async delete(scheduleId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"schedules\", scheduleId],\n });\n }\n}\n","import { Requester } from \"./http\";\nimport type { Message } from \"./messages\";\n\ntype DlqMessage = Message & {\n dlqId: string;\n};\n\nexport class DLQ {\n private readonly http: Requester;\n\n constructor(http: Requester) {\n this.http = http;\n }\n\n /**\n * List messages in the dlq\n */\n public async listMessages(): Promise<DlqMessage[]> {\n return await this.http.request<DlqMessage[]>({\n method: \"GET\",\n path: [\"v2\", \"dlq\", \"messages\"],\n });\n }\n\n /**\n * Remove a message from the dlq using it's `dlqId`\n */\n public async delete(dlqMessageId: string): Promise<void> {\n return await this.http.request<void>({\n method: \"DELETE\",\n path: [\"v2\", \"dlq\", \"messages\", dlqMessageId],\n });\n }\n}\n","import { HttpClient, Requester, RetryConfig } from \"./http\";\nimport { Topics } from \"./topics\";\nimport { Messages } from \"./messages\";\nimport { Schedules } from \"./schedules\";\nimport { Event } from \"./types\";\nimport { DLQ } from \"./dlq\";\ntype ClientConfig = {\n /**\n * Url of the qstash api server.\n *\n * This is only used for testing.\n *\n * @default \"https://qstash.upstash.io\"\n */\n baseUrl?: string;\n\n /**\n * The authorization token from the upstash console.\n */\n token: string;\n\n /**\n * Configure how the client should retry requests.\n */\n retry?: RetryConfig;\n};\n\nexport type PublishRequest<TBody = BodyInit> = {\n /**\n * The message to send.\n *\n * This can be anything, but please set the `Content-Type` header accordingly.\n *\n * You can leave this empty if you want to send a message with no body.\n */\n body?: TBody;\n\n /**\n * Optionally send along headers with the message.\n * These headers will be sent to your destination.\n *\n * We highly recommend sending a `Content-Type` header along, as this will help your destination\n * server to understand the content of the message.\n */\n headers?: HeadersInit;\n\n /**\n * Optionally delay the delivery of this message.\n *\n * In seconds.\n *\n * @default undefined\n */\n delay?: number;\n\n /**\n * Optionally set the absolute delay of this message.\n * This will override the delay option.\n * The message will not delivered until the specified time.\n *\n * Unix timestamp in seconds.\n *\n * @default undefined\n */\n notBefore?: number;\n\n /**\n * Provide a unique id for deduplication. This id will be used to detect duplicate messages.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default undefined\n */\n deduplicationId?: string;\n\n /**\n * If true, the message content will get hashed and used as deduplication id.\n * If a duplicate message is detected, the request will be accepted but not enqueued.\n *\n * The content based hash includes the following values:\n * - All headers, except Upstash-Authorization, this includes all headers you are sending.\n * - The entire raw request body The destination from the url path\n *\n * We store deduplication ids for 90 days. Afterwards it is possible that the message with the\n * same deduplication id is delivered again.\n *\n * When scheduling a message, the deduplication happens before the schedule is created.\n *\n * @default false\n */\n contentBasedDeduplication?: boolean;\n\n /**\n * In case your destination server is unavaialble or returns a status code outside of the 200-299\n * range, we will retry the request after a certain amount of time.\n *\n * Configure how many times you would like the delivery to be retried\n *\n * @default The maximum retry quota associated with your account.\n */\n retries?: number;\n\n /**\n * Use a callback url to forward the response of your destination server to your callback url.\n *\n * The callback url must be publicly accessible\n *\n * @default undefined\n */\n callback?: string;\n\n /**\n * The method to use when sending a request to your API\n *\n * @default `POST`\n */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n} & (\n | {\n /**\n * The url where the message should be sent to.\n */\n url: string;\n topic?: never;\n }\n | {\n url?: never;\n /**\n * The url where the message should be sent to.\n */\n topic: string;\n }\n);\n\nexport type PublishJsonRequest = Omit<PublishRequest, \"body\"> & {\n /**\n * The message to send.\n * This can be anything as long as it can be serialized to JSON.\n */\n body: unknown;\n};\n\nexport type EventsRequest = {\n cursor?: number;\n};\n\nexport type GetEventsResponse = {\n cursor?: number;\n events: Event[];\n};\n\nexport class Client {\n public http: Requester;\n\n public constructor(config: ClientConfig) {\n this.http = new HttpClient({\n retry: config.retry,\n baseUrl: config.baseUrl ? config.baseUrl.replace(/\\/$/, \"\") : \"https://qstash.upstash.io\",\n authorization: `Bearer ${config.token}`,\n });\n }\n\n /**\n * Access the topic API.\n *\n * Create, read, update or delete topics.\n */\n public get topics(): Topics {\n return new Topics(this.http);\n }\n\n /**\n * Access the dlq API.\n *\n * List or remove messages from the DLQ.\n */\n public get dlq(): DLQ {\n return new DLQ(this.http);\n }\n\n /**\n * Access the message API.\n *\n * Read or cancel messages.\n */\n public get messages(): Messages {\n return new Messages(this.http);\n }\n\n /**\n * Access the schedule API.\n *\n * Create, read or delete schedules.\n */\n public get schedules(): Schedules {\n return new Schedules(this.http);\n }\n public async publish<TRequest extends PublishRequest>(\n req: TRequest,\n ): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n\n headers.set(\"Upstash-Method\", req.method ?? \"POST\");\n\n if (typeof req.delay !== \"undefined\") {\n headers.set(\"Upstash-Delay\", `${req.delay.toFixed()}s`);\n }\n\n if (typeof req.notBefore !== \"undefined\") {\n headers.set(\"Upstash-Not-Before\", req.notBefore.toFixed());\n }\n\n if (typeof req.deduplicationId !== \"undefined\") {\n headers.set(\"Upstash-Deduplication-Id\", req.deduplicationId);\n }\n\n if (typeof req.contentBasedDeduplication !== \"undefined\") {\n headers.set(\"Upstash-Content-Based-Deduplication\", \"true\");\n }\n\n if (typeof req.retries !== \"undefined\") {\n headers.set(\"Upstash-Retries\", req.retries.toFixed());\n }\n\n if (typeof req.callback !== \"undefined\") {\n headers.set(\"Upstash-Callback\", req.callback);\n }\n\n const res = await this.http.request<PublishResponse<TRequest>>({\n path: [\"v2\", \"publish\", req.url ?? req.topic],\n body: req.body,\n headers,\n method: \"POST\",\n });\n return res;\n }\n\n /**\n * publishJSON is a utility wrapper around `publish` that automatically serializes the body\n * and sets the `Content-Type` header to `application/json`.\n */\n public async publishJSON<\n TBody = unknown,\n TRequest extends PublishRequest<TBody> = PublishRequest<TBody>,\n >(req: TRequest): Promise<PublishResponse<TRequest>> {\n const headers = new Headers(req.headers);\n headers.set(\"Content-Type\", \"application/json\");\n\n // @ts-ignore it's just internal\n const res = await this.publish<TRequest>({\n ...req,\n headers,\n body: JSON.stringify(req.body),\n } as PublishRequest);\n return res;\n }\n\n /**\n * Retrieve your logs.\n *\n * The logs endpoint is paginated and returns only 100 logs at a time.\n * If you want to receive more logs, you can use the cursor to paginate.\n *\n * The cursor is a unix timestamp with millisecond precision\n *\n * @example\n * ```ts\n * let cursor = Date.now()\n * const logs: Log[] = []\n * while (cursor > 0) {\n * const res = await qstash.logs({ cursor })\n * logs.push(...res.logs)\n * cursor = res.cursor ?? 0\n * }\n * ```\n */\n public async events(req?: EventsRequest): Promise<GetEventsResponse> {\n const query: Record<string, number> = {};\n if (req?.cursor && req.cursor > 0) {\n query.cursor = req.cursor;\n }\n const res = await this.http.request<GetEventsResponse>({\n path: [\"v2\", \"events\"],\n method: \"GET\",\n query,\n });\n return res;\n }\n}\ntype PublishToUrlResponse = {\n messageId: string;\n url: string;\n deduplicated?: boolean;\n};\n\ntype PublishToTopicResponse = PublishToUrlResponse[];\n\ntype PublishResponse<R> = R extends { url: string } ? PublishToUrlResponse : PublishToTopicResponse;\n"],"mappings":"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","names":[]}
|