@upstash/qstash 2.8.3 → 2.9.0-rc
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/{chunk-5ACKA46J.mjs → chunk-NU64UBMT.mjs} +1 -1
- package/{chunk-TLUU4FA7.mjs → chunk-PB5UCB6Z.mjs} +6 -9
- package/{chunk-CR3B3DK3.mjs → chunk-WOMVRJIB.mjs} +640 -495
- package/{client-BpQp_dGA.d.ts → client-BVG9vt90.d.mts} +35 -5
- package/{client-BpQp_dGA.d.mts → client-BVG9vt90.d.ts} +35 -5
- package/cloudflare.d.mts +1 -1
- package/cloudflare.d.ts +1 -1
- package/cloudflare.js +812 -667
- package/cloudflare.mjs +1 -1
- package/h3.d.mts +1 -1
- package/h3.d.ts +1 -1
- package/h3.js +825 -683
- package/h3.mjs +3 -3
- package/hono.d.mts +1 -1
- package/hono.d.ts +1 -1
- package/hono.js +812 -667
- package/hono.mjs +1 -1
- package/index.d.mts +2 -2
- package/index.d.ts +2 -2
- package/index.js +637 -492
- package/index.mjs +2 -2
- package/nextjs.d.mts +1 -1
- package/nextjs.d.ts +1 -1
- package/nextjs.js +647 -511
- package/nextjs.mjs +16 -25
- package/nuxt.js +110 -12
- package/nuxt.mjs +3 -3
- package/package.json +1 -1
- package/solidjs.d.mts +1 -1
- package/solidjs.d.ts +1 -1
- package/solidjs.js +828 -682
- package/solidjs.mjs +9 -8
- package/svelte.d.mts +4 -4
- package/svelte.d.ts +4 -4
- package/svelte.js +830 -684
- package/svelte.mjs +11 -10
- package/workflow.d.mts +1 -1
- package/workflow.d.ts +1 -1
- package/workflow.js +812 -667
- package/workflow.mjs +1 -1
package/index.js
CHANGED
|
@@ -57,120 +57,170 @@ module.exports = __toCommonJS(src_exports);
|
|
|
57
57
|
// src/receiver.ts
|
|
58
58
|
var jose = __toESM(require("jose"));
|
|
59
59
|
var import_crypto_js = __toESM(require("crypto-js"));
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
|
|
61
|
+
// src/client/api/base.ts
|
|
62
|
+
var BaseProvider = class {
|
|
63
|
+
baseUrl;
|
|
64
|
+
token;
|
|
65
|
+
owner;
|
|
66
|
+
constructor(baseUrl, token, owner) {
|
|
67
|
+
this.baseUrl = baseUrl;
|
|
68
|
+
this.token = token;
|
|
69
|
+
this.owner = owner;
|
|
70
|
+
}
|
|
71
|
+
getUrl() {
|
|
72
|
+
return `${this.baseUrl}/${this.getRoute().join("/")}`;
|
|
64
73
|
}
|
|
65
74
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
|
|
76
|
+
// src/client/api/llm.ts
|
|
77
|
+
var LLMProvider = class extends BaseProvider {
|
|
78
|
+
apiKind = "llm";
|
|
79
|
+
organization;
|
|
80
|
+
method = "POST";
|
|
81
|
+
constructor(baseUrl, token, owner, organization) {
|
|
82
|
+
super(baseUrl, token, owner);
|
|
83
|
+
this.organization = organization;
|
|
72
84
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*
|
|
80
|
-
* If that fails, the signature is invalid and a `SignatureError` is thrown.
|
|
81
|
-
*/
|
|
82
|
-
async verify(request) {
|
|
83
|
-
let payload;
|
|
84
|
-
try {
|
|
85
|
-
payload = await this.verifyWithKey(this.currentSigningKey, request);
|
|
86
|
-
} catch {
|
|
87
|
-
payload = await this.verifyWithKey(this.nextSigningKey, request);
|
|
85
|
+
getRoute() {
|
|
86
|
+
return this.owner === "anthropic" ? ["v1", "messages"] : ["v1", "chat", "completions"];
|
|
87
|
+
}
|
|
88
|
+
getHeaders(options) {
|
|
89
|
+
if (this.owner === "upstash" && !options.analytics) {
|
|
90
|
+
return { "content-type": "application/json" };
|
|
88
91
|
}
|
|
89
|
-
this.
|
|
90
|
-
|
|
92
|
+
const header = this.owner === "anthropic" ? "x-api-key" : "authorization";
|
|
93
|
+
const headerValue = this.owner === "anthropic" ? this.token : `Bearer ${this.token}`;
|
|
94
|
+
const headers = {
|
|
95
|
+
[header]: headerValue,
|
|
96
|
+
"content-type": "application/json"
|
|
97
|
+
};
|
|
98
|
+
if (this.owner === "openai" && this.organization) {
|
|
99
|
+
headers["OpenAI-Organization"] = this.organization;
|
|
100
|
+
}
|
|
101
|
+
if (this.owner === "anthropic") {
|
|
102
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
103
|
+
}
|
|
104
|
+
return headers;
|
|
91
105
|
}
|
|
92
106
|
/**
|
|
93
|
-
*
|
|
107
|
+
* Checks if callback exists and adds analytics in place if it's set.
|
|
108
|
+
*
|
|
109
|
+
* @param request
|
|
110
|
+
* @param options
|
|
94
111
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
clockTolerance: request.clockTolerance
|
|
99
|
-
}).catch((error) => {
|
|
100
|
-
throw new SignatureError(error.message);
|
|
101
|
-
});
|
|
102
|
-
return jwt.payload;
|
|
103
|
-
}
|
|
104
|
-
verifyBodyAndUrl(payload, request) {
|
|
105
|
-
const p = payload;
|
|
106
|
-
if (request.url !== void 0 && p.sub !== request.url) {
|
|
107
|
-
throw new SignatureError(`invalid subject: ${p.sub}, want: ${request.url}`);
|
|
108
|
-
}
|
|
109
|
-
const bodyHash = import_crypto_js.default.SHA256(request.body).toString(import_crypto_js.default.enc.Base64url);
|
|
110
|
-
const padding = new RegExp(/=+$/);
|
|
111
|
-
if (p.body.replace(padding, "") !== bodyHash.replace(padding, "")) {
|
|
112
|
-
throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);
|
|
112
|
+
onFinish(providerInfo, options) {
|
|
113
|
+
if (options.analytics) {
|
|
114
|
+
return updateWithAnalytics(providerInfo, options.analytics);
|
|
113
115
|
}
|
|
116
|
+
return providerInfo;
|
|
114
117
|
}
|
|
115
118
|
};
|
|
119
|
+
var upstash = () => {
|
|
120
|
+
return new LLMProvider("https://qstash.upstash.io/llm", "", "upstash");
|
|
121
|
+
};
|
|
122
|
+
var openai = ({
|
|
123
|
+
token,
|
|
124
|
+
organization
|
|
125
|
+
}) => {
|
|
126
|
+
return new LLMProvider("https://api.openai.com", token, "openai", organization);
|
|
127
|
+
};
|
|
128
|
+
var anthropic = ({ token }) => {
|
|
129
|
+
return new LLMProvider("https://api.anthropic.com", token, "anthropic");
|
|
130
|
+
};
|
|
131
|
+
var custom = ({
|
|
132
|
+
baseUrl,
|
|
133
|
+
token
|
|
134
|
+
}) => {
|
|
135
|
+
const trimmedBaseUrl = baseUrl.replace(/\/(v1\/)?chat\/completions$/, "");
|
|
136
|
+
return new LLMProvider(trimmedBaseUrl, token, "custom");
|
|
137
|
+
};
|
|
116
138
|
|
|
117
|
-
// src/client/
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
139
|
+
// src/client/api/utils.ts
|
|
140
|
+
var getProviderInfo = (api, upstashToken) => {
|
|
141
|
+
const { name, provider, ...parameters } = api;
|
|
142
|
+
const finalProvider = provider ?? upstash();
|
|
143
|
+
if (finalProvider.owner === "upstash" && !finalProvider.token) {
|
|
144
|
+
finalProvider.token = upstashToken;
|
|
122
145
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
146
|
+
if (!finalProvider.baseUrl)
|
|
147
|
+
throw new TypeError("baseUrl cannot be empty or undefined!");
|
|
148
|
+
if (!finalProvider.token)
|
|
149
|
+
throw new TypeError("token cannot be empty or undefined!");
|
|
150
|
+
if (finalProvider.apiKind !== name) {
|
|
151
|
+
throw new TypeError(
|
|
152
|
+
`Unexpected api name. Expected '${finalProvider.apiKind}', received ${name}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
const providerInfo = {
|
|
156
|
+
url: finalProvider.getUrl(),
|
|
157
|
+
baseUrl: finalProvider.baseUrl,
|
|
158
|
+
route: finalProvider.getRoute(),
|
|
159
|
+
appendHeaders: finalProvider.getHeaders(parameters),
|
|
160
|
+
owner: finalProvider.owner,
|
|
161
|
+
method: finalProvider.method
|
|
162
|
+
};
|
|
163
|
+
return finalProvider.onFinish(providerInfo, parameters);
|
|
164
|
+
};
|
|
165
|
+
var safeJoinHeaders = (headers, record) => {
|
|
166
|
+
const joinedHeaders = new Headers(record);
|
|
167
|
+
for (const [header, value] of headers.entries()) {
|
|
168
|
+
joinedHeaders.set(header, value);
|
|
169
|
+
}
|
|
170
|
+
return joinedHeaders;
|
|
171
|
+
};
|
|
172
|
+
var processApi = (request, headers, upstashToken) => {
|
|
173
|
+
if (!request.api) {
|
|
174
|
+
request.headers = headers;
|
|
175
|
+
return request;
|
|
176
|
+
}
|
|
177
|
+
const { url, appendHeaders, owner, method } = getProviderInfo(request.api, upstashToken);
|
|
178
|
+
if (request.api.name === "llm") {
|
|
179
|
+
const callback = request.callback;
|
|
180
|
+
if (!callback) {
|
|
181
|
+
throw new TypeError("Callback cannot be undefined when using LLM api.");
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
...request,
|
|
185
|
+
method: request.method ?? method,
|
|
186
|
+
headers: safeJoinHeaders(headers, appendHeaders),
|
|
187
|
+
...owner === "upstash" && !request.api.analytics ? { api: { name: "llm" }, url: void 0, callback } : { url, api: void 0 }
|
|
130
188
|
};
|
|
131
|
-
|
|
132
|
-
method: "GET",
|
|
133
|
-
path: ["v2", "dlq"],
|
|
134
|
-
query: {
|
|
135
|
-
cursor: options?.cursor,
|
|
136
|
-
count: options?.count,
|
|
137
|
-
...filterPayload
|
|
138
|
-
}
|
|
139
|
-
});
|
|
189
|
+
} else {
|
|
140
190
|
return {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
};
|
|
147
|
-
}),
|
|
148
|
-
cursor: messagesPayload.cursor
|
|
191
|
+
...request,
|
|
192
|
+
method: request.method ?? method,
|
|
193
|
+
headers: safeJoinHeaders(headers, appendHeaders),
|
|
194
|
+
url,
|
|
195
|
+
api: void 0
|
|
149
196
|
};
|
|
150
197
|
}
|
|
151
|
-
/**
|
|
152
|
-
* Remove a message from the dlq using it's `dlqId`
|
|
153
|
-
*/
|
|
154
|
-
async delete(dlqMessageId) {
|
|
155
|
-
return await this.http.request({
|
|
156
|
-
method: "DELETE",
|
|
157
|
-
path: ["v2", "dlq", dlqMessageId],
|
|
158
|
-
parseResponseAsJson: false
|
|
159
|
-
// there is no response
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Remove multiple messages from the dlq using their `dlqId`s
|
|
164
|
-
*/
|
|
165
|
-
async deleteMany(request) {
|
|
166
|
-
return await this.http.request({
|
|
167
|
-
method: "DELETE",
|
|
168
|
-
path: ["v2", "dlq"],
|
|
169
|
-
headers: { "Content-Type": "application/json" },
|
|
170
|
-
body: JSON.stringify({ dlqIds: request.dlqIds })
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
198
|
};
|
|
199
|
+
function updateWithAnalytics(providerInfo, analytics) {
|
|
200
|
+
switch (analytics.name) {
|
|
201
|
+
case "helicone": {
|
|
202
|
+
providerInfo.appendHeaders["Helicone-Auth"] = `Bearer ${analytics.token}`;
|
|
203
|
+
if (providerInfo.owner === "upstash") {
|
|
204
|
+
updateProviderInfo(providerInfo, "https://qstash.helicone.ai", [
|
|
205
|
+
"llm",
|
|
206
|
+
...providerInfo.route
|
|
207
|
+
]);
|
|
208
|
+
} else {
|
|
209
|
+
providerInfo.appendHeaders["Helicone-Target-Url"] = providerInfo.baseUrl;
|
|
210
|
+
updateProviderInfo(providerInfo, "https://gateway.helicone.ai", providerInfo.route);
|
|
211
|
+
}
|
|
212
|
+
return providerInfo;
|
|
213
|
+
}
|
|
214
|
+
default: {
|
|
215
|
+
throw new Error("Unknown analytics provider");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function updateProviderInfo(providerInfo, baseUrl, route) {
|
|
220
|
+
providerInfo.baseUrl = baseUrl;
|
|
221
|
+
providerInfo.route = route;
|
|
222
|
+
providerInfo.url = `${baseUrl}/${route.join("/")}`;
|
|
223
|
+
}
|
|
174
224
|
|
|
175
225
|
// src/client/error.ts
|
|
176
226
|
var RATELIMIT_STATUS = 429;
|
|
@@ -230,26 +280,425 @@ var QStashWorkflowError = class extends QstashError {
|
|
|
230
280
|
this.name = "QStashWorkflowError";
|
|
231
281
|
}
|
|
232
282
|
};
|
|
233
|
-
var QStashWorkflowAbort = class extends Error {
|
|
234
|
-
stepInfo;
|
|
235
|
-
stepName;
|
|
236
|
-
constructor(stepName, stepInfo) {
|
|
237
|
-
super(
|
|
238
|
-
`This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
|
|
239
|
-
);
|
|
240
|
-
this.name = "QStashWorkflowAbort";
|
|
241
|
-
this.stepName = stepName;
|
|
242
|
-
this.stepInfo = stepInfo;
|
|
283
|
+
var QStashWorkflowAbort = class extends Error {
|
|
284
|
+
stepInfo;
|
|
285
|
+
stepName;
|
|
286
|
+
constructor(stepName, stepInfo) {
|
|
287
|
+
super(
|
|
288
|
+
`This is an Upstash Workflow error thrown after a step executes. It is expected to be raised. Make sure that you await for each step. Also, if you are using try/catch blocks, you should not wrap context.run/sleep/sleepUntil/call methods with try/catch. Aborting workflow after executing step '${stepName}'.`
|
|
289
|
+
);
|
|
290
|
+
this.name = "QStashWorkflowAbort";
|
|
291
|
+
this.stepName = stepName;
|
|
292
|
+
this.stepInfo = stepInfo;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var formatWorkflowError = (error) => {
|
|
296
|
+
return error instanceof Error ? {
|
|
297
|
+
error: error.name,
|
|
298
|
+
message: error.message
|
|
299
|
+
} : {
|
|
300
|
+
error: "Error",
|
|
301
|
+
message: "An error occured while executing workflow."
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// src/client/utils.ts
|
|
306
|
+
var isIgnoredHeader = (header) => {
|
|
307
|
+
const lowerCaseHeader = header.toLowerCase();
|
|
308
|
+
return lowerCaseHeader.startsWith("content-type") || lowerCaseHeader.startsWith("upstash-");
|
|
309
|
+
};
|
|
310
|
+
function prefixHeaders(headers) {
|
|
311
|
+
const keysToBePrefixed = [...headers.keys()].filter((key) => !isIgnoredHeader(key));
|
|
312
|
+
for (const key of keysToBePrefixed) {
|
|
313
|
+
const value = headers.get(key);
|
|
314
|
+
if (value !== null) {
|
|
315
|
+
headers.set(`Upstash-Forward-${key}`, value);
|
|
316
|
+
}
|
|
317
|
+
headers.delete(key);
|
|
318
|
+
}
|
|
319
|
+
return headers;
|
|
320
|
+
}
|
|
321
|
+
function wrapWithGlobalHeaders(headers, globalHeaders, telemetryHeaders) {
|
|
322
|
+
if (!globalHeaders) {
|
|
323
|
+
return headers;
|
|
324
|
+
}
|
|
325
|
+
const finalHeaders = new Headers(globalHeaders);
|
|
326
|
+
headers.forEach((value, key) => {
|
|
327
|
+
finalHeaders.set(key, value);
|
|
328
|
+
});
|
|
329
|
+
telemetryHeaders?.forEach((value, key) => {
|
|
330
|
+
if (!value)
|
|
331
|
+
return;
|
|
332
|
+
finalHeaders.append(key, value);
|
|
333
|
+
});
|
|
334
|
+
return finalHeaders;
|
|
335
|
+
}
|
|
336
|
+
function processHeaders(request) {
|
|
337
|
+
const headers = prefixHeaders(new Headers(request.headers));
|
|
338
|
+
headers.set("Upstash-Method", request.method ?? "POST");
|
|
339
|
+
if (request.delay !== void 0) {
|
|
340
|
+
if (typeof request.delay === "string") {
|
|
341
|
+
headers.set("Upstash-Delay", request.delay);
|
|
342
|
+
} else {
|
|
343
|
+
headers.set("Upstash-Delay", `${request.delay.toFixed(0)}s`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (request.notBefore !== void 0) {
|
|
347
|
+
headers.set("Upstash-Not-Before", request.notBefore.toFixed(0));
|
|
348
|
+
}
|
|
349
|
+
if (request.deduplicationId !== void 0) {
|
|
350
|
+
headers.set("Upstash-Deduplication-Id", request.deduplicationId);
|
|
351
|
+
}
|
|
352
|
+
if (request.contentBasedDeduplication) {
|
|
353
|
+
headers.set("Upstash-Content-Based-Deduplication", "true");
|
|
354
|
+
}
|
|
355
|
+
if (request.retries !== void 0) {
|
|
356
|
+
headers.set("Upstash-Retries", request.retries.toFixed(0));
|
|
357
|
+
}
|
|
358
|
+
if (request.retryDelay !== void 0) {
|
|
359
|
+
headers.set("Upstash-Retry-Delay", request.retryDelay);
|
|
360
|
+
}
|
|
361
|
+
if (request.callback !== void 0) {
|
|
362
|
+
headers.set("Upstash-Callback", request.callback);
|
|
363
|
+
}
|
|
364
|
+
if (request.failureCallback !== void 0) {
|
|
365
|
+
headers.set("Upstash-Failure-Callback", request.failureCallback);
|
|
366
|
+
}
|
|
367
|
+
if (request.timeout !== void 0) {
|
|
368
|
+
if (typeof request.timeout === "string") {
|
|
369
|
+
headers.set("Upstash-Timeout", request.timeout);
|
|
370
|
+
} else {
|
|
371
|
+
headers.set("Upstash-Timeout", `${request.timeout}s`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (request.flowControl?.key) {
|
|
375
|
+
const parallelism = request.flowControl.parallelism?.toString();
|
|
376
|
+
const rate = (request.flowControl.rate ?? request.flowControl.ratePerSecond)?.toString();
|
|
377
|
+
const period = typeof request.flowControl.period === "number" ? `${request.flowControl.period}s` : request.flowControl.period;
|
|
378
|
+
const controlValue = [
|
|
379
|
+
parallelism ? `parallelism=${parallelism}` : void 0,
|
|
380
|
+
rate ? `rate=${rate}` : void 0,
|
|
381
|
+
period ? `period=${period}` : void 0
|
|
382
|
+
].filter(Boolean);
|
|
383
|
+
if (controlValue.length === 0) {
|
|
384
|
+
throw new QstashError("Provide at least one of parallelism or ratePerSecond for flowControl");
|
|
385
|
+
}
|
|
386
|
+
headers.set("Upstash-Flow-Control-Key", request.flowControl.key);
|
|
387
|
+
headers.set("Upstash-Flow-Control-Value", controlValue.join(", "));
|
|
388
|
+
}
|
|
389
|
+
if (request.label !== void 0) {
|
|
390
|
+
headers.set("Upstash-Label", request.label);
|
|
391
|
+
}
|
|
392
|
+
return headers;
|
|
393
|
+
}
|
|
394
|
+
function getRequestPath(request) {
|
|
395
|
+
const nonApiPath = request.url ?? request.urlGroup ?? request.topic;
|
|
396
|
+
if (nonApiPath)
|
|
397
|
+
return nonApiPath;
|
|
398
|
+
if (request.api?.name === "llm")
|
|
399
|
+
return `api/llm`;
|
|
400
|
+
if (request.api?.name === "email") {
|
|
401
|
+
const providerInfo = getProviderInfo(request.api, "not-needed");
|
|
402
|
+
return providerInfo.baseUrl;
|
|
403
|
+
}
|
|
404
|
+
throw new QstashError(`Failed to infer request path for ${JSON.stringify(request)}`);
|
|
405
|
+
}
|
|
406
|
+
function decodeBase64(base64) {
|
|
407
|
+
try {
|
|
408
|
+
const binString = atob(base64);
|
|
409
|
+
const intArray = Uint8Array.from(binString, (m) => m.codePointAt(0));
|
|
410
|
+
return new TextDecoder().decode(intArray);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
try {
|
|
413
|
+
const result = atob(base64);
|
|
414
|
+
console.warn(
|
|
415
|
+
`Upstash QStash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
|
|
416
|
+
);
|
|
417
|
+
return result;
|
|
418
|
+
} catch (error2) {
|
|
419
|
+
console.warn(
|
|
420
|
+
`Upstash QStash: Failed to decode base64 "${base64}" with atob. Returning it as it is. ${error2}`
|
|
421
|
+
);
|
|
422
|
+
return base64;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function getRuntime() {
|
|
427
|
+
if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
|
|
428
|
+
return `bun@${process.versions.bun}`;
|
|
429
|
+
if (typeof EdgeRuntime === "string")
|
|
430
|
+
return "edge-light";
|
|
431
|
+
else if (typeof process === "object" && typeof process.version === "string")
|
|
432
|
+
return `node@${process.version}`;
|
|
433
|
+
return "";
|
|
434
|
+
}
|
|
435
|
+
function getSafeEnvironment() {
|
|
436
|
+
return typeof process === "undefined" ? {} : process.env;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/client/multi-region/utils.ts
|
|
440
|
+
var VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"];
|
|
441
|
+
var DEFAULT_QSTASH_URL = "https://qstash.upstash.io";
|
|
442
|
+
var getRegionFromEnvironment = (environment) => {
|
|
443
|
+
const region = environment.QSTASH_REGION;
|
|
444
|
+
return normalizeRegionHeader(region);
|
|
445
|
+
};
|
|
446
|
+
function readEnvironmentVariables(environmentVariables, environment, region) {
|
|
447
|
+
const result = {};
|
|
448
|
+
for (const variable of environmentVariables) {
|
|
449
|
+
const key = region ? `${region}_${variable}` : variable;
|
|
450
|
+
result[variable] = environment[key];
|
|
451
|
+
}
|
|
452
|
+
return result;
|
|
453
|
+
}
|
|
454
|
+
function readClientEnvironmentVariables(environment, region) {
|
|
455
|
+
return readEnvironmentVariables(["QSTASH_URL", "QSTASH_TOKEN"], environment, region);
|
|
456
|
+
}
|
|
457
|
+
function readReceiverEnvironmentVariables(environment, region) {
|
|
458
|
+
return readEnvironmentVariables(
|
|
459
|
+
["QSTASH_CURRENT_SIGNING_KEY", "QSTASH_NEXT_SIGNING_KEY"],
|
|
460
|
+
environment,
|
|
461
|
+
region
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
function normalizeRegionHeader(region) {
|
|
465
|
+
if (!region) {
|
|
466
|
+
return void 0;
|
|
467
|
+
}
|
|
468
|
+
region = region.replaceAll("-", "_").toUpperCase();
|
|
469
|
+
if (VALID_REGIONS.includes(region)) {
|
|
470
|
+
return region;
|
|
471
|
+
}
|
|
472
|
+
console.warn(
|
|
473
|
+
`[Upstash QStash] Invalid UPSTASH_REGION header value: "${region}". Expected one of: ${VALID_REGIONS.join(
|
|
474
|
+
", "
|
|
475
|
+
)}.`
|
|
476
|
+
);
|
|
477
|
+
return void 0;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/client/multi-region/incoming.ts
|
|
481
|
+
var getReceiverSigningKeys = ({
|
|
482
|
+
environment,
|
|
483
|
+
regionFromHeader,
|
|
484
|
+
config
|
|
485
|
+
}) => {
|
|
486
|
+
if (config?.currentSigningKey && config.nextSigningKey) {
|
|
487
|
+
return {
|
|
488
|
+
currentSigningKey: config.currentSigningKey,
|
|
489
|
+
nextSigningKey: config.nextSigningKey
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
const regionEnvironment = getRegionFromEnvironment(environment);
|
|
493
|
+
if (regionEnvironment) {
|
|
494
|
+
const regionHeader = normalizeRegionHeader(regionFromHeader);
|
|
495
|
+
if (regionHeader) {
|
|
496
|
+
const regionCreds = readReceiverEnvironmentVariables(environment, regionHeader);
|
|
497
|
+
if (regionCreds.QSTASH_CURRENT_SIGNING_KEY && regionCreds.QSTASH_NEXT_SIGNING_KEY) {
|
|
498
|
+
return {
|
|
499
|
+
currentSigningKey: regionCreds.QSTASH_CURRENT_SIGNING_KEY,
|
|
500
|
+
nextSigningKey: regionCreds.QSTASH_NEXT_SIGNING_KEY,
|
|
501
|
+
region: regionHeader
|
|
502
|
+
};
|
|
503
|
+
} else {
|
|
504
|
+
console.warn(
|
|
505
|
+
`[Upstash QStash] Signing keys not found for region "${regionHeader}". Falling back to default signing keys.`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
console.warn(
|
|
510
|
+
`[Upstash QStash] Invalid UPSTASH_REGION header value: "${regionFromHeader}". Expected one of: EU-CENTRAL-1, US-EAST-1. Falling back to default signing keys.`
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const defaultCreds = readReceiverEnvironmentVariables(environment);
|
|
515
|
+
if (defaultCreds.QSTASH_CURRENT_SIGNING_KEY && defaultCreds.QSTASH_NEXT_SIGNING_KEY) {
|
|
516
|
+
return {
|
|
517
|
+
currentSigningKey: defaultCreds.QSTASH_CURRENT_SIGNING_KEY,
|
|
518
|
+
nextSigningKey: defaultCreds.QSTASH_NEXT_SIGNING_KEY
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// src/client/multi-region/outgoing.ts
|
|
524
|
+
var getClientCredentials = (clientCredentialConfig) => {
|
|
525
|
+
const credentials = resolveCredentials(clientCredentialConfig);
|
|
526
|
+
return verifyCredentials(credentials);
|
|
527
|
+
};
|
|
528
|
+
var resolveCredentials = ({
|
|
529
|
+
environment,
|
|
530
|
+
config
|
|
531
|
+
}) => {
|
|
532
|
+
if (config?.baseUrl && config.token) {
|
|
533
|
+
return {
|
|
534
|
+
baseUrl: config.baseUrl,
|
|
535
|
+
token: config.token
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
const region = getRegionFromEnvironment(environment);
|
|
539
|
+
if (region) {
|
|
540
|
+
const regionCreds = readClientEnvironmentVariables(environment, region);
|
|
541
|
+
if (regionCreds.QSTASH_URL && regionCreds.QSTASH_TOKEN) {
|
|
542
|
+
return {
|
|
543
|
+
baseUrl: regionCreds.QSTASH_URL,
|
|
544
|
+
token: regionCreds.QSTASH_TOKEN,
|
|
545
|
+
region
|
|
546
|
+
};
|
|
547
|
+
} else {
|
|
548
|
+
console.warn(
|
|
549
|
+
`[Upstash QStash] QSTASH_REGION is set to "${region}" but credentials are missing. Expected ${region}_QSTASH_URL and ${region}_QSTASH_TOKEN. Falling back to default credentials.`
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const defaultCreds = readClientEnvironmentVariables(environment);
|
|
554
|
+
return {
|
|
555
|
+
baseUrl: config?.baseUrl ?? defaultCreds.QSTASH_URL ?? DEFAULT_QSTASH_URL,
|
|
556
|
+
token: config?.token ?? defaultCreds.QSTASH_TOKEN ?? ""
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
var verifyCredentials = (credentials) => {
|
|
560
|
+
const token = credentials.token;
|
|
561
|
+
let baseUrl = credentials.baseUrl;
|
|
562
|
+
baseUrl = baseUrl.replace(/\/$/, "");
|
|
563
|
+
if (baseUrl === "https://qstash.upstash.io/v2/publish") {
|
|
564
|
+
baseUrl = DEFAULT_QSTASH_URL;
|
|
565
|
+
}
|
|
566
|
+
if (!token) {
|
|
567
|
+
console.warn(
|
|
568
|
+
"[Upstash QStash] client token is not set. Either pass a token or set QSTASH_TOKEN env variable."
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
return { baseUrl, token };
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// src/receiver.ts
|
|
575
|
+
var SignatureError = class extends Error {
|
|
576
|
+
constructor(message) {
|
|
577
|
+
super(message);
|
|
578
|
+
this.name = "SignatureError";
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
var Receiver = class {
|
|
582
|
+
currentSigningKey;
|
|
583
|
+
nextSigningKey;
|
|
584
|
+
constructor(config) {
|
|
585
|
+
this.currentSigningKey = config?.currentSigningKey;
|
|
586
|
+
this.nextSigningKey = config?.nextSigningKey;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Verify the signature of a request.
|
|
590
|
+
*
|
|
591
|
+
* Tries to verify the signature with the current signing key.
|
|
592
|
+
* If that fails, maybe because you have rotated the keys recently, it will
|
|
593
|
+
* try to verify the signature with the next signing key.
|
|
594
|
+
*
|
|
595
|
+
* If that fails, the signature is invalid and a `SignatureError` is thrown.
|
|
596
|
+
*/
|
|
597
|
+
async verify(request) {
|
|
598
|
+
const environment = getSafeEnvironment();
|
|
599
|
+
const signingKeys = getReceiverSigningKeys({
|
|
600
|
+
environment,
|
|
601
|
+
regionFromHeader: request.upstashRegion,
|
|
602
|
+
config: {
|
|
603
|
+
currentSigningKey: this.currentSigningKey,
|
|
604
|
+
nextSigningKey: this.nextSigningKey
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
if (!signingKeys) {
|
|
608
|
+
throw new Error(
|
|
609
|
+
"[Upstash QStash] No signing keys available for verification. See the warning above for more details."
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
let payload;
|
|
613
|
+
try {
|
|
614
|
+
payload = await this.verifyWithKey(signingKeys.currentSigningKey, request);
|
|
615
|
+
} catch {
|
|
616
|
+
payload = await this.verifyWithKey(signingKeys.nextSigningKey, request);
|
|
617
|
+
}
|
|
618
|
+
this.verifyBodyAndUrl(payload, request);
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Verify signature with a specific signing key
|
|
623
|
+
*/
|
|
624
|
+
async verifyWithKey(key, request) {
|
|
625
|
+
const jwt = await jose.jwtVerify(request.signature, new TextEncoder().encode(key), {
|
|
626
|
+
issuer: "Upstash",
|
|
627
|
+
clockTolerance: request.clockTolerance
|
|
628
|
+
}).catch((error) => {
|
|
629
|
+
throw new SignatureError(error.message);
|
|
630
|
+
});
|
|
631
|
+
return jwt.payload;
|
|
632
|
+
}
|
|
633
|
+
verifyBodyAndUrl(payload, request) {
|
|
634
|
+
const p = payload;
|
|
635
|
+
if (request.url !== void 0 && p.sub !== request.url) {
|
|
636
|
+
throw new SignatureError(`invalid subject: ${p.sub}, want: ${request.url}`);
|
|
637
|
+
}
|
|
638
|
+
const bodyHash = import_crypto_js.default.SHA256(request.body).toString(import_crypto_js.default.enc.Base64url);
|
|
639
|
+
const padding = new RegExp(/=+$/);
|
|
640
|
+
if (p.body.replace(padding, "") !== bodyHash.replace(padding, "")) {
|
|
641
|
+
throw new SignatureError(`body hash does not match, want: ${p.body}, got: ${bodyHash}`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
// src/client/dlq.ts
|
|
647
|
+
var DLQ = class {
|
|
648
|
+
http;
|
|
649
|
+
constructor(http) {
|
|
650
|
+
this.http = http;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* List messages in the dlq
|
|
654
|
+
*/
|
|
655
|
+
async listMessages(options) {
|
|
656
|
+
const filterPayload = {
|
|
657
|
+
...options?.filter,
|
|
658
|
+
topicName: options?.filter?.urlGroup
|
|
659
|
+
};
|
|
660
|
+
const messagesPayload = await this.http.request({
|
|
661
|
+
method: "GET",
|
|
662
|
+
path: ["v2", "dlq"],
|
|
663
|
+
query: {
|
|
664
|
+
cursor: options?.cursor,
|
|
665
|
+
count: options?.count,
|
|
666
|
+
...filterPayload
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
return {
|
|
670
|
+
messages: messagesPayload.messages.map((message) => {
|
|
671
|
+
return {
|
|
672
|
+
...message,
|
|
673
|
+
urlGroup: message.topicName,
|
|
674
|
+
ratePerSecond: "rate" in message ? message.rate : void 0
|
|
675
|
+
};
|
|
676
|
+
}),
|
|
677
|
+
cursor: messagesPayload.cursor
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Remove a message from the dlq using it's `dlqId`
|
|
682
|
+
*/
|
|
683
|
+
async delete(dlqMessageId) {
|
|
684
|
+
return await this.http.request({
|
|
685
|
+
method: "DELETE",
|
|
686
|
+
path: ["v2", "dlq", dlqMessageId],
|
|
687
|
+
parseResponseAsJson: false
|
|
688
|
+
// there is no response
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* Remove multiple messages from the dlq using their `dlqId`s
|
|
693
|
+
*/
|
|
694
|
+
async deleteMany(request) {
|
|
695
|
+
return await this.http.request({
|
|
696
|
+
method: "DELETE",
|
|
697
|
+
path: ["v2", "dlq"],
|
|
698
|
+
headers: { "Content-Type": "application/json" },
|
|
699
|
+
body: JSON.stringify({ dlqIds: request.dlqIds })
|
|
700
|
+
});
|
|
243
701
|
}
|
|
244
|
-
};
|
|
245
|
-
var formatWorkflowError = (error) => {
|
|
246
|
-
return error instanceof Error ? {
|
|
247
|
-
error: error.name,
|
|
248
|
-
message: error.message
|
|
249
|
-
} : {
|
|
250
|
-
error: "Error",
|
|
251
|
-
message: "An error occured while executing workflow."
|
|
252
|
-
};
|
|
253
702
|
};
|
|
254
703
|
|
|
255
704
|
// src/client/http.ts
|
|
@@ -527,380 +976,85 @@ var Chat = class _Chat {
|
|
|
527
976
|
path: isAnalyticsEnabled ? [] : ["v1", "chat", "completions"],
|
|
528
977
|
method: "POST",
|
|
529
978
|
headers,
|
|
530
|
-
body,
|
|
531
|
-
baseUrl: analyticsConfig.baseURL
|
|
532
|
-
});
|
|
533
|
-
return response;
|
|
534
|
-
};
|
|
535
|
-
// Helper method to get the authorization token
|
|
536
|
-
getAuthorizationToken() {
|
|
537
|
-
const authHeader = String(this.http.authorization);
|
|
538
|
-
const match = /Bearer (.+)/.exec(authHeader);
|
|
539
|
-
if (!match) {
|
|
540
|
-
throw new Error("Invalid authorization header format");
|
|
541
|
-
}
|
|
542
|
-
return match[1];
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* Calls the Upstash completions api given a PromptRequest.
|
|
546
|
-
*
|
|
547
|
-
* Returns a ChatCompletion or a stream of ChatCompletionChunks
|
|
548
|
-
* if stream is enabled.
|
|
549
|
-
*
|
|
550
|
-
* @param request PromptRequest with system and user messages.
|
|
551
|
-
* Note that system parameter shouldn't be passed in the case of
|
|
552
|
-
* mistralai/Mistral-7B-Instruct-v0.2 model.
|
|
553
|
-
* @returns Chat completion or stream
|
|
554
|
-
*/
|
|
555
|
-
prompt = async (request) => {
|
|
556
|
-
const chatRequest = _Chat.toChatRequest(request);
|
|
557
|
-
return this.create(chatRequest);
|
|
558
|
-
};
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// src/client/messages.ts
|
|
562
|
-
var Messages = class {
|
|
563
|
-
http;
|
|
564
|
-
constructor(http) {
|
|
565
|
-
this.http = http;
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* Get a message
|
|
569
|
-
*/
|
|
570
|
-
async get(messageId) {
|
|
571
|
-
const messagePayload = await this.http.request({
|
|
572
|
-
method: "GET",
|
|
573
|
-
path: ["v2", "messages", messageId]
|
|
574
|
-
});
|
|
575
|
-
const message = {
|
|
576
|
-
...messagePayload,
|
|
577
|
-
urlGroup: messagePayload.topicName,
|
|
578
|
-
ratePerSecond: "rate" in messagePayload ? messagePayload.rate : void 0
|
|
579
|
-
};
|
|
580
|
-
return message;
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Cancel a message
|
|
584
|
-
*/
|
|
585
|
-
async delete(messageId) {
|
|
586
|
-
return await this.http.request({
|
|
587
|
-
method: "DELETE",
|
|
588
|
-
path: ["v2", "messages", messageId],
|
|
589
|
-
parseResponseAsJson: false
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
async deleteMany(messageIds) {
|
|
593
|
-
const result = await this.http.request({
|
|
594
|
-
method: "DELETE",
|
|
595
|
-
path: ["v2", "messages"],
|
|
596
|
-
headers: { "Content-Type": "application/json" },
|
|
597
|
-
body: JSON.stringify({ messageIds })
|
|
598
|
-
});
|
|
599
|
-
return result.cancelled;
|
|
600
|
-
}
|
|
601
|
-
async deleteAll() {
|
|
602
|
-
const result = await this.http.request({
|
|
603
|
-
method: "DELETE",
|
|
604
|
-
path: ["v2", "messages"]
|
|
605
|
-
});
|
|
606
|
-
return result.cancelled;
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
// src/client/api/base.ts
|
|
611
|
-
var BaseProvider = class {
|
|
612
|
-
baseUrl;
|
|
613
|
-
token;
|
|
614
|
-
owner;
|
|
615
|
-
constructor(baseUrl, token, owner) {
|
|
616
|
-
this.baseUrl = baseUrl;
|
|
617
|
-
this.token = token;
|
|
618
|
-
this.owner = owner;
|
|
619
|
-
}
|
|
620
|
-
getUrl() {
|
|
621
|
-
return `${this.baseUrl}/${this.getRoute().join("/")}`;
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
|
|
625
|
-
// src/client/api/llm.ts
|
|
626
|
-
var LLMProvider = class extends BaseProvider {
|
|
627
|
-
apiKind = "llm";
|
|
628
|
-
organization;
|
|
629
|
-
method = "POST";
|
|
630
|
-
constructor(baseUrl, token, owner, organization) {
|
|
631
|
-
super(baseUrl, token, owner);
|
|
632
|
-
this.organization = organization;
|
|
633
|
-
}
|
|
634
|
-
getRoute() {
|
|
635
|
-
return this.owner === "anthropic" ? ["v1", "messages"] : ["v1", "chat", "completions"];
|
|
636
|
-
}
|
|
637
|
-
getHeaders(options) {
|
|
638
|
-
if (this.owner === "upstash" && !options.analytics) {
|
|
639
|
-
return { "content-type": "application/json" };
|
|
640
|
-
}
|
|
641
|
-
const header = this.owner === "anthropic" ? "x-api-key" : "authorization";
|
|
642
|
-
const headerValue = this.owner === "anthropic" ? this.token : `Bearer ${this.token}`;
|
|
643
|
-
const headers = {
|
|
644
|
-
[header]: headerValue,
|
|
645
|
-
"content-type": "application/json"
|
|
646
|
-
};
|
|
647
|
-
if (this.owner === "openai" && this.organization) {
|
|
648
|
-
headers["OpenAI-Organization"] = this.organization;
|
|
649
|
-
}
|
|
650
|
-
if (this.owner === "anthropic") {
|
|
651
|
-
headers["anthropic-version"] = "2023-06-01";
|
|
652
|
-
}
|
|
653
|
-
return headers;
|
|
654
|
-
}
|
|
655
|
-
/**
|
|
656
|
-
* Checks if callback exists and adds analytics in place if it's set.
|
|
657
|
-
*
|
|
658
|
-
* @param request
|
|
659
|
-
* @param options
|
|
660
|
-
*/
|
|
661
|
-
onFinish(providerInfo, options) {
|
|
662
|
-
if (options.analytics) {
|
|
663
|
-
return updateWithAnalytics(providerInfo, options.analytics);
|
|
664
|
-
}
|
|
665
|
-
return providerInfo;
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
var upstash = () => {
|
|
669
|
-
return new LLMProvider("https://qstash.upstash.io/llm", "", "upstash");
|
|
670
|
-
};
|
|
671
|
-
var openai = ({
|
|
672
|
-
token,
|
|
673
|
-
organization
|
|
674
|
-
}) => {
|
|
675
|
-
return new LLMProvider("https://api.openai.com", token, "openai", organization);
|
|
676
|
-
};
|
|
677
|
-
var anthropic = ({ token }) => {
|
|
678
|
-
return new LLMProvider("https://api.anthropic.com", token, "anthropic");
|
|
679
|
-
};
|
|
680
|
-
var custom = ({
|
|
681
|
-
baseUrl,
|
|
682
|
-
token
|
|
683
|
-
}) => {
|
|
684
|
-
const trimmedBaseUrl = baseUrl.replace(/\/(v1\/)?chat\/completions$/, "");
|
|
685
|
-
return new LLMProvider(trimmedBaseUrl, token, "custom");
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
// src/client/api/utils.ts
|
|
689
|
-
var getProviderInfo = (api, upstashToken) => {
|
|
690
|
-
const { name, provider, ...parameters } = api;
|
|
691
|
-
const finalProvider = provider ?? upstash();
|
|
692
|
-
if (finalProvider.owner === "upstash" && !finalProvider.token) {
|
|
693
|
-
finalProvider.token = upstashToken;
|
|
694
|
-
}
|
|
695
|
-
if (!finalProvider.baseUrl)
|
|
696
|
-
throw new TypeError("baseUrl cannot be empty or undefined!");
|
|
697
|
-
if (!finalProvider.token)
|
|
698
|
-
throw new TypeError("token cannot be empty or undefined!");
|
|
699
|
-
if (finalProvider.apiKind !== name) {
|
|
700
|
-
throw new TypeError(
|
|
701
|
-
`Unexpected api name. Expected '${finalProvider.apiKind}', received ${name}`
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
const providerInfo = {
|
|
705
|
-
url: finalProvider.getUrl(),
|
|
706
|
-
baseUrl: finalProvider.baseUrl,
|
|
707
|
-
route: finalProvider.getRoute(),
|
|
708
|
-
appendHeaders: finalProvider.getHeaders(parameters),
|
|
709
|
-
owner: finalProvider.owner,
|
|
710
|
-
method: finalProvider.method
|
|
979
|
+
body,
|
|
980
|
+
baseUrl: analyticsConfig.baseURL
|
|
981
|
+
});
|
|
982
|
+
return response;
|
|
711
983
|
};
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
}
|
|
719
|
-
return joinedHeaders;
|
|
720
|
-
};
|
|
721
|
-
var processApi = (request, headers, upstashToken) => {
|
|
722
|
-
if (!request.api) {
|
|
723
|
-
request.headers = headers;
|
|
724
|
-
return request;
|
|
725
|
-
}
|
|
726
|
-
const { url, appendHeaders, owner, method } = getProviderInfo(request.api, upstashToken);
|
|
727
|
-
if (request.api.name === "llm") {
|
|
728
|
-
const callback = request.callback;
|
|
729
|
-
if (!callback) {
|
|
730
|
-
throw new TypeError("Callback cannot be undefined when using LLM api.");
|
|
984
|
+
// Helper method to get the authorization token
|
|
985
|
+
getAuthorizationToken() {
|
|
986
|
+
const authHeader = String(this.http.authorization);
|
|
987
|
+
const match = /Bearer (.+)/.exec(authHeader);
|
|
988
|
+
if (!match) {
|
|
989
|
+
throw new Error("Invalid authorization header format");
|
|
731
990
|
}
|
|
732
|
-
return
|
|
733
|
-
...request,
|
|
734
|
-
method: request.method ?? method,
|
|
735
|
-
headers: safeJoinHeaders(headers, appendHeaders),
|
|
736
|
-
...owner === "upstash" && !request.api.analytics ? { api: { name: "llm" }, url: void 0, callback } : { url, api: void 0 }
|
|
737
|
-
};
|
|
738
|
-
} else {
|
|
739
|
-
return {
|
|
740
|
-
...request,
|
|
741
|
-
method: request.method ?? method,
|
|
742
|
-
headers: safeJoinHeaders(headers, appendHeaders),
|
|
743
|
-
url,
|
|
744
|
-
api: void 0
|
|
745
|
-
};
|
|
991
|
+
return match[1];
|
|
746
992
|
}
|
|
993
|
+
/**
|
|
994
|
+
* Calls the Upstash completions api given a PromptRequest.
|
|
995
|
+
*
|
|
996
|
+
* Returns a ChatCompletion or a stream of ChatCompletionChunks
|
|
997
|
+
* if stream is enabled.
|
|
998
|
+
*
|
|
999
|
+
* @param request PromptRequest with system and user messages.
|
|
1000
|
+
* Note that system parameter shouldn't be passed in the case of
|
|
1001
|
+
* mistralai/Mistral-7B-Instruct-v0.2 model.
|
|
1002
|
+
* @returns Chat completion or stream
|
|
1003
|
+
*/
|
|
1004
|
+
prompt = async (request) => {
|
|
1005
|
+
const chatRequest = _Chat.toChatRequest(request);
|
|
1006
|
+
return this.create(chatRequest);
|
|
1007
|
+
};
|
|
747
1008
|
};
|
|
748
|
-
function updateWithAnalytics(providerInfo, analytics) {
|
|
749
|
-
switch (analytics.name) {
|
|
750
|
-
case "helicone": {
|
|
751
|
-
providerInfo.appendHeaders["Helicone-Auth"] = `Bearer ${analytics.token}`;
|
|
752
|
-
if (providerInfo.owner === "upstash") {
|
|
753
|
-
updateProviderInfo(providerInfo, "https://qstash.helicone.ai", [
|
|
754
|
-
"llm",
|
|
755
|
-
...providerInfo.route
|
|
756
|
-
]);
|
|
757
|
-
} else {
|
|
758
|
-
providerInfo.appendHeaders["Helicone-Target-Url"] = providerInfo.baseUrl;
|
|
759
|
-
updateProviderInfo(providerInfo, "https://gateway.helicone.ai", providerInfo.route);
|
|
760
|
-
}
|
|
761
|
-
return providerInfo;
|
|
762
|
-
}
|
|
763
|
-
default: {
|
|
764
|
-
throw new Error("Unknown analytics provider");
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
function updateProviderInfo(providerInfo, baseUrl, route) {
|
|
769
|
-
providerInfo.baseUrl = baseUrl;
|
|
770
|
-
providerInfo.route = route;
|
|
771
|
-
providerInfo.url = `${baseUrl}/${route.join("/")}`;
|
|
772
|
-
}
|
|
773
1009
|
|
|
774
|
-
// src/client/
|
|
775
|
-
var
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
function prefixHeaders(headers) {
|
|
780
|
-
const keysToBePrefixed = [...headers.keys()].filter((key) => !isIgnoredHeader(key));
|
|
781
|
-
for (const key of keysToBePrefixed) {
|
|
782
|
-
const value = headers.get(key);
|
|
783
|
-
if (value !== null) {
|
|
784
|
-
headers.set(`Upstash-Forward-${key}`, value);
|
|
785
|
-
}
|
|
786
|
-
headers.delete(key);
|
|
787
|
-
}
|
|
788
|
-
return headers;
|
|
789
|
-
}
|
|
790
|
-
function wrapWithGlobalHeaders(headers, globalHeaders, telemetryHeaders) {
|
|
791
|
-
if (!globalHeaders) {
|
|
792
|
-
return headers;
|
|
793
|
-
}
|
|
794
|
-
const finalHeaders = new Headers(globalHeaders);
|
|
795
|
-
headers.forEach((value, key) => {
|
|
796
|
-
finalHeaders.set(key, value);
|
|
797
|
-
});
|
|
798
|
-
telemetryHeaders?.forEach((value, key) => {
|
|
799
|
-
if (!value)
|
|
800
|
-
return;
|
|
801
|
-
finalHeaders.append(key, value);
|
|
802
|
-
});
|
|
803
|
-
return finalHeaders;
|
|
804
|
-
}
|
|
805
|
-
function processHeaders(request) {
|
|
806
|
-
const headers = prefixHeaders(new Headers(request.headers));
|
|
807
|
-
headers.set("Upstash-Method", request.method ?? "POST");
|
|
808
|
-
if (request.delay !== void 0) {
|
|
809
|
-
if (typeof request.delay === "string") {
|
|
810
|
-
headers.set("Upstash-Delay", request.delay);
|
|
811
|
-
} else {
|
|
812
|
-
headers.set("Upstash-Delay", `${request.delay.toFixed(0)}s`);
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
if (request.notBefore !== void 0) {
|
|
816
|
-
headers.set("Upstash-Not-Before", request.notBefore.toFixed(0));
|
|
817
|
-
}
|
|
818
|
-
if (request.deduplicationId !== void 0) {
|
|
819
|
-
headers.set("Upstash-Deduplication-Id", request.deduplicationId);
|
|
820
|
-
}
|
|
821
|
-
if (request.contentBasedDeduplication) {
|
|
822
|
-
headers.set("Upstash-Content-Based-Deduplication", "true");
|
|
823
|
-
}
|
|
824
|
-
if (request.retries !== void 0) {
|
|
825
|
-
headers.set("Upstash-Retries", request.retries.toFixed(0));
|
|
826
|
-
}
|
|
827
|
-
if (request.retryDelay !== void 0) {
|
|
828
|
-
headers.set("Upstash-Retry-Delay", request.retryDelay);
|
|
829
|
-
}
|
|
830
|
-
if (request.callback !== void 0) {
|
|
831
|
-
headers.set("Upstash-Callback", request.callback);
|
|
832
|
-
}
|
|
833
|
-
if (request.failureCallback !== void 0) {
|
|
834
|
-
headers.set("Upstash-Failure-Callback", request.failureCallback);
|
|
835
|
-
}
|
|
836
|
-
if (request.timeout !== void 0) {
|
|
837
|
-
if (typeof request.timeout === "string") {
|
|
838
|
-
headers.set("Upstash-Timeout", request.timeout);
|
|
839
|
-
} else {
|
|
840
|
-
headers.set("Upstash-Timeout", `${request.timeout}s`);
|
|
841
|
-
}
|
|
1010
|
+
// src/client/messages.ts
|
|
1011
|
+
var Messages = class {
|
|
1012
|
+
http;
|
|
1013
|
+
constructor(http) {
|
|
1014
|
+
this.http = http;
|
|
842
1015
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1016
|
+
/**
|
|
1017
|
+
* Get a message
|
|
1018
|
+
*/
|
|
1019
|
+
async get(messageId) {
|
|
1020
|
+
const messagePayload = await this.http.request({
|
|
1021
|
+
method: "GET",
|
|
1022
|
+
path: ["v2", "messages", messageId]
|
|
1023
|
+
});
|
|
1024
|
+
const message = {
|
|
1025
|
+
...messagePayload,
|
|
1026
|
+
urlGroup: messagePayload.topicName,
|
|
1027
|
+
ratePerSecond: "rate" in messagePayload ? messagePayload.rate : void 0
|
|
1028
|
+
};
|
|
1029
|
+
return message;
|
|
857
1030
|
}
|
|
858
|
-
|
|
859
|
-
|
|
1031
|
+
/**
|
|
1032
|
+
* Cancel a message
|
|
1033
|
+
*/
|
|
1034
|
+
async delete(messageId) {
|
|
1035
|
+
return await this.http.request({
|
|
1036
|
+
method: "DELETE",
|
|
1037
|
+
path: ["v2", "messages", messageId],
|
|
1038
|
+
parseResponseAsJson: false
|
|
1039
|
+
});
|
|
860
1040
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
return
|
|
869
|
-
if (request.api?.name === "email") {
|
|
870
|
-
const providerInfo = getProviderInfo(request.api, "not-needed");
|
|
871
|
-
return providerInfo.baseUrl;
|
|
1041
|
+
async deleteMany(messageIds) {
|
|
1042
|
+
const result = await this.http.request({
|
|
1043
|
+
method: "DELETE",
|
|
1044
|
+
path: ["v2", "messages"],
|
|
1045
|
+
headers: { "Content-Type": "application/json" },
|
|
1046
|
+
body: JSON.stringify({ messageIds })
|
|
1047
|
+
});
|
|
1048
|
+
return result.cancelled;
|
|
872
1049
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
return new TextDecoder().decode(intArray);
|
|
880
|
-
} catch (error) {
|
|
881
|
-
try {
|
|
882
|
-
const result = atob(base64);
|
|
883
|
-
console.warn(
|
|
884
|
-
`Upstash QStash: Failed while decoding base64 "${base64}". Decoding with atob and returning it instead. ${error}`
|
|
885
|
-
);
|
|
886
|
-
return result;
|
|
887
|
-
} catch (error2) {
|
|
888
|
-
console.warn(
|
|
889
|
-
`Upstash QStash: Failed to decode base64 "${base64}" with atob. Returning it as it is. ${error2}`
|
|
890
|
-
);
|
|
891
|
-
return base64;
|
|
892
|
-
}
|
|
1050
|
+
async deleteAll() {
|
|
1051
|
+
const result = await this.http.request({
|
|
1052
|
+
method: "DELETE",
|
|
1053
|
+
path: ["v2", "messages"]
|
|
1054
|
+
});
|
|
1055
|
+
return result.cancelled;
|
|
893
1056
|
}
|
|
894
|
-
}
|
|
895
|
-
function getRuntime() {
|
|
896
|
-
if (typeof process === "object" && typeof process.versions == "object" && process.versions.bun)
|
|
897
|
-
return `bun@${process.versions.bun}`;
|
|
898
|
-
if (typeof EdgeRuntime === "string")
|
|
899
|
-
return "edge-light";
|
|
900
|
-
else if (typeof process === "object" && typeof process.version === "string")
|
|
901
|
-
return `node@${process.version}`;
|
|
902
|
-
return "";
|
|
903
|
-
}
|
|
1057
|
+
};
|
|
904
1058
|
|
|
905
1059
|
// src/client/queue.ts
|
|
906
1060
|
var Queue = class {
|
|
@@ -1262,19 +1416,15 @@ var Workflow = class {
|
|
|
1262
1416
|
};
|
|
1263
1417
|
|
|
1264
1418
|
// version.ts
|
|
1265
|
-
var VERSION = "v2.
|
|
1419
|
+
var VERSION = "v2.9.0-rc";
|
|
1266
1420
|
|
|
1267
1421
|
// src/client/client.ts
|
|
1268
1422
|
var Client = class {
|
|
1269
1423
|
http;
|
|
1270
1424
|
token;
|
|
1271
1425
|
constructor(config) {
|
|
1272
|
-
const environment =
|
|
1273
|
-
|
|
1274
|
-
if (baseUrl === "https://qstash.upstash.io/v2/publish") {
|
|
1275
|
-
baseUrl = "https://qstash.upstash.io";
|
|
1276
|
-
}
|
|
1277
|
-
const token = config?.token ?? environment.QSTASH_TOKEN;
|
|
1426
|
+
const environment = getSafeEnvironment();
|
|
1427
|
+
const { baseUrl, token } = getClientCredentials({ environment, config });
|
|
1278
1428
|
const enableTelemetry = environment.UPSTASH_DISABLE_TELEMETRY ? false : config?.enableTelemetry ?? true;
|
|
1279
1429
|
const isCloudflare = typeof caches !== "undefined" && "default" in caches;
|
|
1280
1430
|
const telemetryHeaders = new Headers(
|
|
@@ -1293,11 +1443,6 @@ var Client = class {
|
|
|
1293
1443
|
//@ts-expect-error caused by undici and bunjs type overlap
|
|
1294
1444
|
telemetryHeaders
|
|
1295
1445
|
});
|
|
1296
|
-
if (!token) {
|
|
1297
|
-
console.warn(
|
|
1298
|
-
"[Upstash QStash] client token is not set. Either pass a token or set QSTASH_TOKEN env variable."
|
|
1299
|
-
);
|
|
1300
|
-
}
|
|
1301
1446
|
this.token = token;
|
|
1302
1447
|
}
|
|
1303
1448
|
/**
|