@upstash/redis 1.35.0-canary → 1.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{dist/chunk-Q4ZBDYYE.mjs → chunk-AIBLSL5D.mjs} +782 -89
- package/cloudflare.d.mts +55 -0
- package/cloudflare.d.ts +55 -0
- package/{dist/cloudflare.js → cloudflare.js} +796 -111
- package/{dist/cloudflare.mjs → cloudflare.mjs} +15 -13
- package/fastly.d.mts +48 -0
- package/fastly.d.ts +48 -0
- package/{dist/fastly.js → fastly.js} +792 -107
- package/{dist/fastly.mjs → fastly.mjs} +11 -9
- package/nodejs.d.mts +73 -0
- package/nodejs.d.ts +73 -0
- package/{dist/nodejs.js → nodejs.js} +799 -113
- package/{dist/nodejs.mjs → nodejs.mjs} +18 -15
- package/package.json +1 -1
- package/{dist/zmscore-BhX8yEQc.d.mts → zmscore-BshEAkn7.d.mts} +591 -46
- package/{dist/zmscore-BhX8yEQc.d.ts → zmscore-BshEAkn7.d.ts} +591 -46
- package/dist/cloudflare.d.mts +0 -55
- package/dist/cloudflare.d.ts +0 -55
- package/dist/fastly.d.mts +0 -48
- package/dist/fastly.d.ts +0 -48
- package/dist/nodejs.d.mts +0 -73
- package/dist/nodejs.d.ts +0 -73
|
@@ -19,12 +19,57 @@ var UpstashError = class extends Error {
|
|
|
19
19
|
var UrlError = class extends Error {
|
|
20
20
|
constructor(url) {
|
|
21
21
|
super(
|
|
22
|
-
`Upstash Redis client was passed an invalid URL. You should pass
|
|
22
|
+
`Upstash Redis client was passed an invalid URL. You should pass a URL starting with https. Received: "${url}". `
|
|
23
23
|
);
|
|
24
24
|
this.name = "UrlError";
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
// pkg/util.ts
|
|
29
|
+
function parseRecursive(obj) {
|
|
30
|
+
const parsed = Array.isArray(obj) ? obj.map((o) => {
|
|
31
|
+
try {
|
|
32
|
+
return parseRecursive(o);
|
|
33
|
+
} catch {
|
|
34
|
+
return o;
|
|
35
|
+
}
|
|
36
|
+
}) : JSON.parse(obj);
|
|
37
|
+
if (typeof parsed === "number" && parsed.toString() !== obj) {
|
|
38
|
+
return obj;
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
function parseResponse(result) {
|
|
43
|
+
try {
|
|
44
|
+
return parseRecursive(result);
|
|
45
|
+
} catch {
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function deserializeScanResponse(result) {
|
|
50
|
+
return [result[0], ...parseResponse(result.slice(1))];
|
|
51
|
+
}
|
|
52
|
+
function deserializeScanWithTypesResponse(result) {
|
|
53
|
+
const [cursor, keys] = result;
|
|
54
|
+
const parsedKeys = [];
|
|
55
|
+
for (let i = 0; i < keys.length; i += 2) {
|
|
56
|
+
parsedKeys.push({ key: keys[i], type: keys[i + 1] });
|
|
57
|
+
}
|
|
58
|
+
return [cursor, parsedKeys];
|
|
59
|
+
}
|
|
60
|
+
function mergeHeaders(...headers) {
|
|
61
|
+
const merged = {};
|
|
62
|
+
for (const header of headers) {
|
|
63
|
+
if (!header) continue;
|
|
64
|
+
for (const [key, value] of Object.entries(header)) {
|
|
65
|
+
if (value !== void 0 && value !== null) {
|
|
66
|
+
merged[key] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return merged;
|
|
71
|
+
}
|
|
72
|
+
|
|
28
73
|
// pkg/http.ts
|
|
29
74
|
var HttpClient = class {
|
|
30
75
|
baseUrl;
|
|
@@ -32,6 +77,7 @@ var HttpClient = class {
|
|
|
32
77
|
options;
|
|
33
78
|
readYourWrites;
|
|
34
79
|
upstashSyncToken = "";
|
|
80
|
+
hasCredentials;
|
|
35
81
|
retry;
|
|
36
82
|
constructor(config) {
|
|
37
83
|
this.options = {
|
|
@@ -45,15 +91,16 @@ var HttpClient = class {
|
|
|
45
91
|
};
|
|
46
92
|
this.upstashSyncToken = "";
|
|
47
93
|
this.readYourWrites = config.readYourWrites ?? true;
|
|
48
|
-
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
94
|
+
this.baseUrl = (config.baseUrl || "").replace(/\/$/, "");
|
|
49
95
|
const urlRegex = /^https?:\/\/[^\s#$./?].\S*$/;
|
|
50
|
-
if (!urlRegex.test(this.baseUrl)) {
|
|
96
|
+
if (this.baseUrl && !urlRegex.test(this.baseUrl)) {
|
|
51
97
|
throw new UrlError(this.baseUrl);
|
|
52
98
|
}
|
|
53
99
|
this.headers = {
|
|
54
100
|
"Content-Type": "application/json",
|
|
55
101
|
...config.headers
|
|
56
102
|
};
|
|
103
|
+
this.hasCredentials = Boolean(this.baseUrl && this.headers.authorization.split(" ")[1]);
|
|
57
104
|
if (this.options.responseEncoding === "base64") {
|
|
58
105
|
this.headers["Upstash-Encoding"] = "base64";
|
|
59
106
|
}
|
|
@@ -71,20 +118,30 @@ var HttpClient = class {
|
|
|
71
118
|
this.headers = merge(this.headers, "Upstash-Telemetry-Sdk", telemetry.sdk);
|
|
72
119
|
}
|
|
73
120
|
async request(req) {
|
|
121
|
+
const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
|
|
122
|
+
const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
|
|
123
|
+
const isEventStream = requestHeaders.Accept === "text/event-stream";
|
|
124
|
+
const signal = req.signal ?? this.options.signal;
|
|
125
|
+
const isSignalFunction = typeof signal === "function";
|
|
74
126
|
const requestOptions = {
|
|
75
127
|
//@ts-expect-error this should throw due to bun regression
|
|
76
128
|
cache: this.options.cache,
|
|
77
129
|
method: "POST",
|
|
78
|
-
headers:
|
|
130
|
+
headers: requestHeaders,
|
|
79
131
|
body: JSON.stringify(req.body),
|
|
80
132
|
keepalive: this.options.keepAlive,
|
|
81
133
|
agent: this.options.agent,
|
|
82
|
-
signal:
|
|
134
|
+
signal: isSignalFunction ? signal() : signal,
|
|
83
135
|
/**
|
|
84
136
|
* Fastly specific
|
|
85
137
|
*/
|
|
86
138
|
backend: this.options.backend
|
|
87
139
|
};
|
|
140
|
+
if (!this.hasCredentials) {
|
|
141
|
+
console.warn(
|
|
142
|
+
"[Upstash Redis] Redis client was initialized without url or token. Failed to execute command."
|
|
143
|
+
);
|
|
144
|
+
}
|
|
88
145
|
if (this.readYourWrites) {
|
|
89
146
|
const newHeader = this.upstashSyncToken;
|
|
90
147
|
this.headers["upstash-sync-token"] = newHeader;
|
|
@@ -93,35 +150,71 @@ var HttpClient = class {
|
|
|
93
150
|
let error = null;
|
|
94
151
|
for (let i = 0; i <= this.retry.attempts; i++) {
|
|
95
152
|
try {
|
|
96
|
-
res = await fetch(
|
|
153
|
+
res = await fetch(requestUrl, requestOptions);
|
|
97
154
|
break;
|
|
98
155
|
} catch (error_) {
|
|
99
|
-
if (
|
|
156
|
+
if (requestOptions.signal?.aborted && isSignalFunction) {
|
|
157
|
+
throw error_;
|
|
158
|
+
} else if (requestOptions.signal?.aborted) {
|
|
100
159
|
const myBlob = new Blob([
|
|
101
|
-
JSON.stringify({ result:
|
|
160
|
+
JSON.stringify({ result: requestOptions.signal.reason ?? "Aborted" })
|
|
102
161
|
]);
|
|
103
162
|
const myOptions = {
|
|
104
163
|
status: 200,
|
|
105
|
-
statusText:
|
|
164
|
+
statusText: requestOptions.signal.reason ?? "Aborted"
|
|
106
165
|
};
|
|
107
166
|
res = new Response(myBlob, myOptions);
|
|
108
167
|
break;
|
|
109
168
|
}
|
|
110
169
|
error = error_;
|
|
111
|
-
|
|
170
|
+
if (i < this.retry.attempts) {
|
|
171
|
+
await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
|
|
172
|
+
}
|
|
112
173
|
}
|
|
113
174
|
}
|
|
114
175
|
if (!res) {
|
|
115
176
|
throw error ?? new Error("Exhausted all retries");
|
|
116
177
|
}
|
|
117
|
-
const body = await res.json();
|
|
118
178
|
if (!res.ok) {
|
|
119
|
-
|
|
179
|
+
const body2 = await res.json();
|
|
180
|
+
throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
|
|
120
181
|
}
|
|
121
182
|
if (this.readYourWrites) {
|
|
122
183
|
const headers = res.headers;
|
|
123
184
|
this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
|
|
124
185
|
}
|
|
186
|
+
if (isEventStream && req && req.onMessage && res.body) {
|
|
187
|
+
const reader = res.body.getReader();
|
|
188
|
+
const decoder = new TextDecoder();
|
|
189
|
+
(async () => {
|
|
190
|
+
try {
|
|
191
|
+
while (true) {
|
|
192
|
+
const { value, done } = await reader.read();
|
|
193
|
+
if (done) break;
|
|
194
|
+
const chunk = decoder.decode(value);
|
|
195
|
+
const lines = chunk.split("\n");
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
if (line.startsWith("data: ")) {
|
|
198
|
+
const data = line.slice(6);
|
|
199
|
+
req.onMessage?.(data);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} catch (error2) {
|
|
204
|
+
if (error2 instanceof Error && error2.name === "AbortError") {
|
|
205
|
+
} else {
|
|
206
|
+
console.error("Stream reading error:", error2);
|
|
207
|
+
}
|
|
208
|
+
} finally {
|
|
209
|
+
try {
|
|
210
|
+
await reader.cancel();
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
return { result: 1 };
|
|
216
|
+
}
|
|
217
|
+
const body = await res.json();
|
|
125
218
|
if (this.readYourWrites) {
|
|
126
219
|
const headers = res.headers;
|
|
127
220
|
this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
|
|
@@ -192,31 +285,6 @@ function merge(obj, key, value) {
|
|
|
192
285
|
return obj;
|
|
193
286
|
}
|
|
194
287
|
|
|
195
|
-
// pkg/util.ts
|
|
196
|
-
function parseRecursive(obj) {
|
|
197
|
-
const parsed = Array.isArray(obj) ? obj.map((o) => {
|
|
198
|
-
try {
|
|
199
|
-
return parseRecursive(o);
|
|
200
|
-
} catch {
|
|
201
|
-
return o;
|
|
202
|
-
}
|
|
203
|
-
}) : JSON.parse(obj);
|
|
204
|
-
if (typeof parsed === "number" && parsed.toString() !== obj) {
|
|
205
|
-
return obj;
|
|
206
|
-
}
|
|
207
|
-
return parsed;
|
|
208
|
-
}
|
|
209
|
-
function parseResponse(result) {
|
|
210
|
-
try {
|
|
211
|
-
return parseRecursive(result);
|
|
212
|
-
} catch {
|
|
213
|
-
return result;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function deserializeScanResponse(result) {
|
|
217
|
-
return [result[0], ...parseResponse(result.slice(1))];
|
|
218
|
-
}
|
|
219
|
-
|
|
220
288
|
// pkg/commands/command.ts
|
|
221
289
|
var defaultSerializer = (c) => {
|
|
222
290
|
switch (typeof c) {
|
|
@@ -234,6 +302,11 @@ var Command = class {
|
|
|
234
302
|
command;
|
|
235
303
|
serialize;
|
|
236
304
|
deserialize;
|
|
305
|
+
headers;
|
|
306
|
+
path;
|
|
307
|
+
onMessage;
|
|
308
|
+
isStreaming;
|
|
309
|
+
signal;
|
|
237
310
|
/**
|
|
238
311
|
* Create a new command instance.
|
|
239
312
|
*
|
|
@@ -243,6 +316,11 @@ var Command = class {
|
|
|
243
316
|
this.serialize = defaultSerializer;
|
|
244
317
|
this.deserialize = opts?.automaticDeserialization === void 0 || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
|
|
245
318
|
this.command = command.map((c) => this.serialize(c));
|
|
319
|
+
this.headers = opts?.headers;
|
|
320
|
+
this.path = opts?.path;
|
|
321
|
+
this.onMessage = opts?.streamOptions?.onMessage;
|
|
322
|
+
this.isStreaming = opts?.streamOptions?.isStreaming ?? false;
|
|
323
|
+
this.signal = opts?.streamOptions?.signal;
|
|
246
324
|
if (opts?.latencyLogging) {
|
|
247
325
|
const originalExec = this.exec.bind(this);
|
|
248
326
|
this.exec = async (client) => {
|
|
@@ -263,7 +341,12 @@ var Command = class {
|
|
|
263
341
|
async exec(client) {
|
|
264
342
|
const { result, error } = await client.request({
|
|
265
343
|
body: this.command,
|
|
266
|
-
|
|
344
|
+
path: this.path,
|
|
345
|
+
upstashSyncToken: client.upstashSyncToken,
|
|
346
|
+
headers: this.headers,
|
|
347
|
+
onMessage: this.onMessage,
|
|
348
|
+
isStreaming: this.isStreaming,
|
|
349
|
+
signal: this.signal
|
|
267
350
|
});
|
|
268
351
|
if (error) {
|
|
269
352
|
throw new UpstashError(error);
|
|
@@ -281,9 +364,9 @@ function deserialize(result) {
|
|
|
281
364
|
return null;
|
|
282
365
|
}
|
|
283
366
|
const obj = {};
|
|
284
|
-
|
|
285
|
-
const key = result
|
|
286
|
-
const value = result
|
|
367
|
+
for (let i = 0; i < result.length; i += 2) {
|
|
368
|
+
const key = result[i];
|
|
369
|
+
const value = result[i + 1];
|
|
287
370
|
try {
|
|
288
371
|
obj[key] = JSON.parse(value);
|
|
289
372
|
} catch {
|
|
@@ -425,6 +508,13 @@ var EchoCommand = class extends Command {
|
|
|
425
508
|
}
|
|
426
509
|
};
|
|
427
510
|
|
|
511
|
+
// pkg/commands/evalRo.ts
|
|
512
|
+
var EvalROCommand = class extends Command {
|
|
513
|
+
constructor([script, keys, args], opts) {
|
|
514
|
+
super(["eval_ro", script, keys.length, ...keys, ...args ?? []], opts);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
428
518
|
// pkg/commands/eval.ts
|
|
429
519
|
var EvalCommand = class extends Command {
|
|
430
520
|
constructor([script, keys, args], opts) {
|
|
@@ -432,6 +522,13 @@ var EvalCommand = class extends Command {
|
|
|
432
522
|
}
|
|
433
523
|
};
|
|
434
524
|
|
|
525
|
+
// pkg/commands/evalshaRo.ts
|
|
526
|
+
var EvalshaROCommand = class extends Command {
|
|
527
|
+
constructor([sha, keys, args], opts) {
|
|
528
|
+
super(["evalsha_ro", sha, keys.length, ...keys, ...args ?? []], opts);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
435
532
|
// pkg/commands/evalsha.ts
|
|
436
533
|
var EvalshaCommand = class extends Command {
|
|
437
534
|
constructor([sha, keys, args], opts) {
|
|
@@ -439,6 +536,14 @@ var EvalshaCommand = class extends Command {
|
|
|
439
536
|
}
|
|
440
537
|
};
|
|
441
538
|
|
|
539
|
+
// pkg/commands/exec.ts
|
|
540
|
+
var ExecCommand = class extends Command {
|
|
541
|
+
constructor(cmd, opts) {
|
|
542
|
+
const normalizedCmd = cmd.map((arg) => typeof arg === "string" ? arg : String(arg));
|
|
543
|
+
super(normalizedCmd, opts);
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
|
|
442
547
|
// pkg/commands/exists.ts
|
|
443
548
|
var ExistsCommand = class extends Command {
|
|
444
549
|
constructor(cmd, opts) {
|
|
@@ -655,6 +760,27 @@ var GetDelCommand = class extends Command {
|
|
|
655
760
|
}
|
|
656
761
|
};
|
|
657
762
|
|
|
763
|
+
// pkg/commands/getex.ts
|
|
764
|
+
var GetExCommand = class extends Command {
|
|
765
|
+
constructor([key, opts], cmdOpts) {
|
|
766
|
+
const command = ["getex", key];
|
|
767
|
+
if (opts) {
|
|
768
|
+
if ("ex" in opts && typeof opts.ex === "number") {
|
|
769
|
+
command.push("ex", opts.ex);
|
|
770
|
+
} else if ("px" in opts && typeof opts.px === "number") {
|
|
771
|
+
command.push("px", opts.px);
|
|
772
|
+
} else if ("exat" in opts && typeof opts.exat === "number") {
|
|
773
|
+
command.push("exat", opts.exat);
|
|
774
|
+
} else if ("pxat" in opts && typeof opts.pxat === "number") {
|
|
775
|
+
command.push("pxat", opts.pxat);
|
|
776
|
+
} else if ("persist" in opts && opts.persist) {
|
|
777
|
+
command.push("persist");
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
super(command, cmdOpts);
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
|
|
658
784
|
// pkg/commands/getrange.ts
|
|
659
785
|
var GetRangeCommand = class extends Command {
|
|
660
786
|
constructor(cmd, opts) {
|
|
@@ -683,6 +809,122 @@ var HExistsCommand = class extends Command {
|
|
|
683
809
|
}
|
|
684
810
|
};
|
|
685
811
|
|
|
812
|
+
// pkg/commands/hexpire.ts
|
|
813
|
+
var HExpireCommand = class extends Command {
|
|
814
|
+
constructor(cmd, opts) {
|
|
815
|
+
const [key, fields, seconds, option] = cmd;
|
|
816
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
817
|
+
super(
|
|
818
|
+
[
|
|
819
|
+
"hexpire",
|
|
820
|
+
key,
|
|
821
|
+
seconds,
|
|
822
|
+
...option ? [option] : [],
|
|
823
|
+
"FIELDS",
|
|
824
|
+
fieldArray.length,
|
|
825
|
+
...fieldArray
|
|
826
|
+
],
|
|
827
|
+
opts
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
// pkg/commands/hexpireat.ts
|
|
833
|
+
var HExpireAtCommand = class extends Command {
|
|
834
|
+
constructor(cmd, opts) {
|
|
835
|
+
const [key, fields, timestamp, option] = cmd;
|
|
836
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
837
|
+
super(
|
|
838
|
+
[
|
|
839
|
+
"hexpireat",
|
|
840
|
+
key,
|
|
841
|
+
timestamp,
|
|
842
|
+
...option ? [option] : [],
|
|
843
|
+
"FIELDS",
|
|
844
|
+
fieldArray.length,
|
|
845
|
+
...fieldArray
|
|
846
|
+
],
|
|
847
|
+
opts
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
// pkg/commands/hexpiretime.ts
|
|
853
|
+
var HExpireTimeCommand = class extends Command {
|
|
854
|
+
constructor(cmd, opts) {
|
|
855
|
+
const [key, fields] = cmd;
|
|
856
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
857
|
+
super(["hexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
// pkg/commands/hpersist.ts
|
|
862
|
+
var HPersistCommand = class extends Command {
|
|
863
|
+
constructor(cmd, opts) {
|
|
864
|
+
const [key, fields] = cmd;
|
|
865
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
866
|
+
super(["hpersist", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
// pkg/commands/hpexpire.ts
|
|
871
|
+
var HPExpireCommand = class extends Command {
|
|
872
|
+
constructor(cmd, opts) {
|
|
873
|
+
const [key, fields, milliseconds, option] = cmd;
|
|
874
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
875
|
+
super(
|
|
876
|
+
[
|
|
877
|
+
"hpexpire",
|
|
878
|
+
key,
|
|
879
|
+
milliseconds,
|
|
880
|
+
...option ? [option] : [],
|
|
881
|
+
"FIELDS",
|
|
882
|
+
fieldArray.length,
|
|
883
|
+
...fieldArray
|
|
884
|
+
],
|
|
885
|
+
opts
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
// pkg/commands/hpexpireat.ts
|
|
891
|
+
var HPExpireAtCommand = class extends Command {
|
|
892
|
+
constructor(cmd, opts) {
|
|
893
|
+
const [key, fields, timestamp, option] = cmd;
|
|
894
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
895
|
+
super(
|
|
896
|
+
[
|
|
897
|
+
"hpexpireat",
|
|
898
|
+
key,
|
|
899
|
+
timestamp,
|
|
900
|
+
...option ? [option] : [],
|
|
901
|
+
"FIELDS",
|
|
902
|
+
fieldArray.length,
|
|
903
|
+
...fieldArray
|
|
904
|
+
],
|
|
905
|
+
opts
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
// pkg/commands/hpexpiretime.ts
|
|
911
|
+
var HPExpireTimeCommand = class extends Command {
|
|
912
|
+
constructor(cmd, opts) {
|
|
913
|
+
const [key, fields] = cmd;
|
|
914
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
915
|
+
super(["hpexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
// pkg/commands/hpttl.ts
|
|
920
|
+
var HPTtlCommand = class extends Command {
|
|
921
|
+
constructor(cmd, opts) {
|
|
922
|
+
const [key, fields] = cmd;
|
|
923
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
924
|
+
super(["hpttl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
925
|
+
}
|
|
926
|
+
};
|
|
927
|
+
|
|
686
928
|
// pkg/commands/hget.ts
|
|
687
929
|
var HGetCommand = class extends Command {
|
|
688
930
|
constructor(cmd, opts) {
|
|
@@ -696,9 +938,9 @@ function deserialize2(result) {
|
|
|
696
938
|
return null;
|
|
697
939
|
}
|
|
698
940
|
const obj = {};
|
|
699
|
-
|
|
700
|
-
const key = result
|
|
701
|
-
const value = result
|
|
941
|
+
for (let i = 0; i < result.length; i += 2) {
|
|
942
|
+
const key = result[i];
|
|
943
|
+
const value = result[i + 1];
|
|
702
944
|
try {
|
|
703
945
|
const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
|
|
704
946
|
obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
|
|
@@ -814,6 +1056,15 @@ var HStrLenCommand = class extends Command {
|
|
|
814
1056
|
}
|
|
815
1057
|
};
|
|
816
1058
|
|
|
1059
|
+
// pkg/commands/httl.ts
|
|
1060
|
+
var HTtlCommand = class extends Command {
|
|
1061
|
+
constructor(cmd, opts) {
|
|
1062
|
+
const [key, fields] = cmd;
|
|
1063
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
1064
|
+
super(["httl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
|
|
817
1068
|
// pkg/commands/hvals.ts
|
|
818
1069
|
var HValsCommand = class extends Command {
|
|
819
1070
|
constructor(cmd, opts) {
|
|
@@ -933,6 +1184,14 @@ var JsonGetCommand = class extends Command {
|
|
|
933
1184
|
}
|
|
934
1185
|
};
|
|
935
1186
|
|
|
1187
|
+
// pkg/commands/json_merge.ts
|
|
1188
|
+
var JsonMergeCommand = class extends Command {
|
|
1189
|
+
constructor(cmd, opts) {
|
|
1190
|
+
const command = ["JSON.MERGE", ...cmd];
|
|
1191
|
+
super(command, opts);
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
|
|
936
1195
|
// pkg/commands/json_mget.ts
|
|
937
1196
|
var JsonMGetCommand = class extends Command {
|
|
938
1197
|
constructor(cmd, opts) {
|
|
@@ -1293,11 +1552,14 @@ var ScanCommand = class extends Command {
|
|
|
1293
1552
|
if (typeof opts?.count === "number") {
|
|
1294
1553
|
command.push("count", opts.count);
|
|
1295
1554
|
}
|
|
1296
|
-
if (opts
|
|
1555
|
+
if (opts && "withType" in opts && opts.withType === true) {
|
|
1556
|
+
command.push("withtype");
|
|
1557
|
+
} else if (opts && "type" in opts && opts.type && opts.type.length > 0) {
|
|
1297
1558
|
command.push("type", opts.type);
|
|
1298
1559
|
}
|
|
1299
1560
|
super(command, {
|
|
1300
|
-
|
|
1561
|
+
// @ts-expect-error ignore types here
|
|
1562
|
+
deserialize: opts?.withType ? deserializeScanWithTypesResponse : deserializeScanResponse,
|
|
1301
1563
|
...cmdOpts
|
|
1302
1564
|
});
|
|
1303
1565
|
}
|
|
@@ -1723,15 +1985,15 @@ var XPendingCommand = class extends Command {
|
|
|
1723
1985
|
function deserialize4(result) {
|
|
1724
1986
|
const obj = {};
|
|
1725
1987
|
for (const e of result) {
|
|
1726
|
-
|
|
1727
|
-
const streamId = e
|
|
1728
|
-
const entries = e
|
|
1988
|
+
for (let i = 0; i < e.length; i += 2) {
|
|
1989
|
+
const streamId = e[i];
|
|
1990
|
+
const entries = e[i + 1];
|
|
1729
1991
|
if (!(streamId in obj)) {
|
|
1730
1992
|
obj[streamId] = {};
|
|
1731
1993
|
}
|
|
1732
|
-
|
|
1733
|
-
const field = entries
|
|
1734
|
-
const value = entries
|
|
1994
|
+
for (let j = 0; j < entries.length; j += 2) {
|
|
1995
|
+
const field = entries[j];
|
|
1996
|
+
const value = entries[j + 1];
|
|
1735
1997
|
try {
|
|
1736
1998
|
obj[streamId][field] = JSON.parse(value);
|
|
1737
1999
|
} catch {
|
|
@@ -1820,15 +2082,15 @@ var XRevRangeCommand = class extends Command {
|
|
|
1820
2082
|
function deserialize5(result) {
|
|
1821
2083
|
const obj = {};
|
|
1822
2084
|
for (const e of result) {
|
|
1823
|
-
|
|
1824
|
-
const streamId = e
|
|
1825
|
-
const entries = e
|
|
2085
|
+
for (let i = 0; i < e.length; i += 2) {
|
|
2086
|
+
const streamId = e[i];
|
|
2087
|
+
const entries = e[i + 1];
|
|
1826
2088
|
if (!(streamId in obj)) {
|
|
1827
2089
|
obj[streamId] = {};
|
|
1828
2090
|
}
|
|
1829
|
-
|
|
1830
|
-
const field = entries
|
|
1831
|
-
const value = entries
|
|
2091
|
+
for (let j = 0; j < entries.length; j += 2) {
|
|
2092
|
+
const field = entries[j];
|
|
2093
|
+
const value = entries[j + 1];
|
|
1832
2094
|
try {
|
|
1833
2095
|
obj[streamId][field] = JSON.parse(value);
|
|
1834
2096
|
} catch {
|
|
@@ -2115,9 +2377,9 @@ var Pipeline = class {
|
|
|
2115
2377
|
this.multiExec = opts.multiExec ?? false;
|
|
2116
2378
|
if (this.commandOptions?.latencyLogging) {
|
|
2117
2379
|
const originalExec = this.exec.bind(this);
|
|
2118
|
-
this.exec = async () => {
|
|
2380
|
+
this.exec = async (options) => {
|
|
2119
2381
|
const start = performance.now();
|
|
2120
|
-
const result = await originalExec();
|
|
2382
|
+
const result = await (options ? originalExec(options) : originalExec());
|
|
2121
2383
|
const end = performance.now();
|
|
2122
2384
|
const loggerResult = (end - start).toFixed(2);
|
|
2123
2385
|
console.log(
|
|
@@ -2127,19 +2389,7 @@ var Pipeline = class {
|
|
|
2127
2389
|
};
|
|
2128
2390
|
}
|
|
2129
2391
|
}
|
|
2130
|
-
|
|
2131
|
-
* Send the pipeline request to upstash.
|
|
2132
|
-
*
|
|
2133
|
-
* Returns an array with the results of all pipelined commands.
|
|
2134
|
-
*
|
|
2135
|
-
* If all commands are statically chained from start to finish, types are inferred. You can still define a return type manually if necessary though:
|
|
2136
|
-
* ```ts
|
|
2137
|
-
* const p = redis.pipeline()
|
|
2138
|
-
* p.get("key")
|
|
2139
|
-
* const result = p.exec<[{ greeting: string }]>()
|
|
2140
|
-
* ```
|
|
2141
|
-
*/
|
|
2142
|
-
exec = async () => {
|
|
2392
|
+
exec = async (options) => {
|
|
2143
2393
|
if (this.commands.length === 0) {
|
|
2144
2394
|
throw new Error("Pipeline is empty");
|
|
2145
2395
|
}
|
|
@@ -2148,7 +2398,12 @@ var Pipeline = class {
|
|
|
2148
2398
|
path,
|
|
2149
2399
|
body: Object.values(this.commands).map((c) => c.command)
|
|
2150
2400
|
});
|
|
2151
|
-
return res.map(({ error, result }, i) => {
|
|
2401
|
+
return options?.keepErrors ? res.map(({ error, result }, i) => {
|
|
2402
|
+
return {
|
|
2403
|
+
error,
|
|
2404
|
+
result: this.commands[i].deserialize(result)
|
|
2405
|
+
};
|
|
2406
|
+
}) : res.map(({ error, result }, i) => {
|
|
2152
2407
|
if (error) {
|
|
2153
2408
|
throw new UpstashError(
|
|
2154
2409
|
`Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}`
|
|
@@ -2234,10 +2489,18 @@ var Pipeline = class {
|
|
|
2234
2489
|
* @see https://redis.io/commands/echo
|
|
2235
2490
|
*/
|
|
2236
2491
|
echo = (...args) => this.chain(new EchoCommand(args, this.commandOptions));
|
|
2492
|
+
/**
|
|
2493
|
+
* @see https://redis.io/commands/eval_ro
|
|
2494
|
+
*/
|
|
2495
|
+
evalRo = (...args) => this.chain(new EvalROCommand(args, this.commandOptions));
|
|
2237
2496
|
/**
|
|
2238
2497
|
* @see https://redis.io/commands/eval
|
|
2239
2498
|
*/
|
|
2240
2499
|
eval = (...args) => this.chain(new EvalCommand(args, this.commandOptions));
|
|
2500
|
+
/**
|
|
2501
|
+
* @see https://redis.io/commands/evalsha_ro
|
|
2502
|
+
*/
|
|
2503
|
+
evalshaRo = (...args) => this.chain(new EvalshaROCommand(args, this.commandOptions));
|
|
2241
2504
|
/**
|
|
2242
2505
|
* @see https://redis.io/commands/evalsha
|
|
2243
2506
|
*/
|
|
@@ -2298,6 +2561,10 @@ var Pipeline = class {
|
|
|
2298
2561
|
* @see https://redis.io/commands/getdel
|
|
2299
2562
|
*/
|
|
2300
2563
|
getdel = (...args) => this.chain(new GetDelCommand(args, this.commandOptions));
|
|
2564
|
+
/**
|
|
2565
|
+
* @see https://redis.io/commands/getex
|
|
2566
|
+
*/
|
|
2567
|
+
getex = (...args) => this.chain(new GetExCommand(args, this.commandOptions));
|
|
2301
2568
|
/**
|
|
2302
2569
|
* @see https://redis.io/commands/getrange
|
|
2303
2570
|
*/
|
|
@@ -2314,6 +2581,42 @@ var Pipeline = class {
|
|
|
2314
2581
|
* @see https://redis.io/commands/hexists
|
|
2315
2582
|
*/
|
|
2316
2583
|
hexists = (...args) => this.chain(new HExistsCommand(args, this.commandOptions));
|
|
2584
|
+
/**
|
|
2585
|
+
* @see https://redis.io/commands/hexpire
|
|
2586
|
+
*/
|
|
2587
|
+
hexpire = (...args) => this.chain(new HExpireCommand(args, this.commandOptions));
|
|
2588
|
+
/**
|
|
2589
|
+
* @see https://redis.io/commands/hexpireat
|
|
2590
|
+
*/
|
|
2591
|
+
hexpireat = (...args) => this.chain(new HExpireAtCommand(args, this.commandOptions));
|
|
2592
|
+
/**
|
|
2593
|
+
* @see https://redis.io/commands/hexpiretime
|
|
2594
|
+
*/
|
|
2595
|
+
hexpiretime = (...args) => this.chain(new HExpireTimeCommand(args, this.commandOptions));
|
|
2596
|
+
/**
|
|
2597
|
+
* @see https://redis.io/commands/httl
|
|
2598
|
+
*/
|
|
2599
|
+
httl = (...args) => this.chain(new HTtlCommand(args, this.commandOptions));
|
|
2600
|
+
/**
|
|
2601
|
+
* @see https://redis.io/commands/hpexpire
|
|
2602
|
+
*/
|
|
2603
|
+
hpexpire = (...args) => this.chain(new HPExpireCommand(args, this.commandOptions));
|
|
2604
|
+
/**
|
|
2605
|
+
* @see https://redis.io/commands/hpexpireat
|
|
2606
|
+
*/
|
|
2607
|
+
hpexpireat = (...args) => this.chain(new HPExpireAtCommand(args, this.commandOptions));
|
|
2608
|
+
/**
|
|
2609
|
+
* @see https://redis.io/commands/hpexpiretime
|
|
2610
|
+
*/
|
|
2611
|
+
hpexpiretime = (...args) => this.chain(new HPExpireTimeCommand(args, this.commandOptions));
|
|
2612
|
+
/**
|
|
2613
|
+
* @see https://redis.io/commands/hpttl
|
|
2614
|
+
*/
|
|
2615
|
+
hpttl = (...args) => this.chain(new HPTtlCommand(args, this.commandOptions));
|
|
2616
|
+
/**
|
|
2617
|
+
* @see https://redis.io/commands/hpersist
|
|
2618
|
+
*/
|
|
2619
|
+
hpersist = (...args) => this.chain(new HPersistCommand(args, this.commandOptions));
|
|
2317
2620
|
/**
|
|
2318
2621
|
* @see https://redis.io/commands/hget
|
|
2319
2622
|
*/
|
|
@@ -2831,6 +3134,10 @@ var Pipeline = class {
|
|
|
2831
3134
|
* @see https://redis.io/commands/json.get
|
|
2832
3135
|
*/
|
|
2833
3136
|
get: (...args) => this.chain(new JsonGetCommand(args, this.commandOptions)),
|
|
3137
|
+
/**
|
|
3138
|
+
* @see https://redis.io/commands/json.merge
|
|
3139
|
+
*/
|
|
3140
|
+
merge: (...args) => this.chain(new JsonMergeCommand(args, this.commandOptions)),
|
|
2834
3141
|
/**
|
|
2835
3142
|
* @see https://redis.io/commands/json.mget
|
|
2836
3143
|
*/
|
|
@@ -2884,6 +3191,23 @@ var Pipeline = class {
|
|
|
2884
3191
|
};
|
|
2885
3192
|
|
|
2886
3193
|
// pkg/auto-pipeline.ts
|
|
3194
|
+
var EXCLUDE_COMMANDS = /* @__PURE__ */ new Set([
|
|
3195
|
+
"scan",
|
|
3196
|
+
"keys",
|
|
3197
|
+
"flushdb",
|
|
3198
|
+
"flushall",
|
|
3199
|
+
"dbsize",
|
|
3200
|
+
"hscan",
|
|
3201
|
+
"hgetall",
|
|
3202
|
+
"hkeys",
|
|
3203
|
+
"lrange",
|
|
3204
|
+
"sscan",
|
|
3205
|
+
"smembers",
|
|
3206
|
+
"xrange",
|
|
3207
|
+
"xrevrange",
|
|
3208
|
+
"zscan",
|
|
3209
|
+
"zrange"
|
|
3210
|
+
]);
|
|
2887
3211
|
function createAutoPipelineProxy(_redis, json) {
|
|
2888
3212
|
const redis = _redis;
|
|
2889
3213
|
if (!redis.autoPipelineExecutor) {
|
|
@@ -2898,7 +3222,8 @@ function createAutoPipelineProxy(_redis, json) {
|
|
|
2898
3222
|
return createAutoPipelineProxy(redis2, true);
|
|
2899
3223
|
}
|
|
2900
3224
|
const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
|
|
2901
|
-
|
|
3225
|
+
const isCommandExcluded = EXCLUDE_COMMANDS.has(command);
|
|
3226
|
+
if (commandInRedisButNotPipeline || isCommandExcluded) {
|
|
2902
3227
|
return redis2[command];
|
|
2903
3228
|
}
|
|
2904
3229
|
const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
|
|
@@ -2942,7 +3267,7 @@ var AutoPipelineExecutor = class {
|
|
|
2942
3267
|
executeWithPipeline(pipeline);
|
|
2943
3268
|
const pipelineDone = this.deferExecution().then(() => {
|
|
2944
3269
|
if (!this.pipelinePromises.has(pipeline)) {
|
|
2945
|
-
const pipelinePromise = pipeline.exec();
|
|
3270
|
+
const pipelinePromise = pipeline.exec({ keepErrors: true });
|
|
2946
3271
|
this.pipelineCounter += 1;
|
|
2947
3272
|
this.pipelinePromises.set(pipeline, pipelinePromise);
|
|
2948
3273
|
this.activePipeline = null;
|
|
@@ -2950,7 +3275,11 @@ var AutoPipelineExecutor = class {
|
|
|
2950
3275
|
return this.pipelinePromises.get(pipeline);
|
|
2951
3276
|
});
|
|
2952
3277
|
const results = await pipelineDone;
|
|
2953
|
-
|
|
3278
|
+
const commandResult = results[index];
|
|
3279
|
+
if (commandResult.error) {
|
|
3280
|
+
throw new UpstashError(`Command failed: ${commandResult.error}`);
|
|
3281
|
+
}
|
|
3282
|
+
return commandResult.result;
|
|
2954
3283
|
}
|
|
2955
3284
|
async deferExecution() {
|
|
2956
3285
|
await Promise.resolve();
|
|
@@ -2958,28 +3287,221 @@ var AutoPipelineExecutor = class {
|
|
|
2958
3287
|
}
|
|
2959
3288
|
};
|
|
2960
3289
|
|
|
3290
|
+
// pkg/commands/psubscribe.ts
|
|
3291
|
+
var PSubscribeCommand = class extends Command {
|
|
3292
|
+
constructor(cmd, opts) {
|
|
3293
|
+
const sseHeaders = {
|
|
3294
|
+
Accept: "text/event-stream",
|
|
3295
|
+
"Cache-Control": "no-cache",
|
|
3296
|
+
Connection: "keep-alive"
|
|
3297
|
+
};
|
|
3298
|
+
super([], {
|
|
3299
|
+
...opts,
|
|
3300
|
+
headers: sseHeaders,
|
|
3301
|
+
path: ["psubscribe", ...cmd],
|
|
3302
|
+
streamOptions: {
|
|
3303
|
+
isStreaming: true,
|
|
3304
|
+
onMessage: opts?.streamOptions?.onMessage,
|
|
3305
|
+
signal: opts?.streamOptions?.signal
|
|
3306
|
+
}
|
|
3307
|
+
});
|
|
3308
|
+
}
|
|
3309
|
+
};
|
|
3310
|
+
|
|
3311
|
+
// pkg/commands/subscribe.ts
|
|
3312
|
+
var Subscriber = class extends EventTarget {
|
|
3313
|
+
subscriptions;
|
|
3314
|
+
client;
|
|
3315
|
+
listeners;
|
|
3316
|
+
constructor(client, channels, isPattern = false) {
|
|
3317
|
+
super();
|
|
3318
|
+
this.client = client;
|
|
3319
|
+
this.subscriptions = /* @__PURE__ */ new Map();
|
|
3320
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
3321
|
+
for (const channel of channels) {
|
|
3322
|
+
if (isPattern) {
|
|
3323
|
+
this.subscribeToPattern(channel);
|
|
3324
|
+
} else {
|
|
3325
|
+
this.subscribeToChannel(channel);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
subscribeToChannel(channel) {
|
|
3330
|
+
const controller = new AbortController();
|
|
3331
|
+
const command = new SubscribeCommand([channel], {
|
|
3332
|
+
streamOptions: {
|
|
3333
|
+
signal: controller.signal,
|
|
3334
|
+
onMessage: (data) => this.handleMessage(data, false)
|
|
3335
|
+
}
|
|
3336
|
+
});
|
|
3337
|
+
command.exec(this.client).catch((error) => {
|
|
3338
|
+
if (error.name !== "AbortError") {
|
|
3339
|
+
this.dispatchToListeners("error", error);
|
|
3340
|
+
}
|
|
3341
|
+
});
|
|
3342
|
+
this.subscriptions.set(channel, {
|
|
3343
|
+
command,
|
|
3344
|
+
controller,
|
|
3345
|
+
isPattern: false
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
subscribeToPattern(pattern) {
|
|
3349
|
+
const controller = new AbortController();
|
|
3350
|
+
const command = new PSubscribeCommand([pattern], {
|
|
3351
|
+
streamOptions: {
|
|
3352
|
+
signal: controller.signal,
|
|
3353
|
+
onMessage: (data) => this.handleMessage(data, true)
|
|
3354
|
+
}
|
|
3355
|
+
});
|
|
3356
|
+
command.exec(this.client).catch((error) => {
|
|
3357
|
+
if (error.name !== "AbortError") {
|
|
3358
|
+
this.dispatchToListeners("error", error);
|
|
3359
|
+
}
|
|
3360
|
+
});
|
|
3361
|
+
this.subscriptions.set(pattern, {
|
|
3362
|
+
command,
|
|
3363
|
+
controller,
|
|
3364
|
+
isPattern: true
|
|
3365
|
+
});
|
|
3366
|
+
}
|
|
3367
|
+
handleMessage(data, isPattern) {
|
|
3368
|
+
const messageData = data.replace(/^data:\s*/, "");
|
|
3369
|
+
const firstCommaIndex = messageData.indexOf(",");
|
|
3370
|
+
const secondCommaIndex = messageData.indexOf(",", firstCommaIndex + 1);
|
|
3371
|
+
const thirdCommaIndex = isPattern ? messageData.indexOf(",", secondCommaIndex + 1) : -1;
|
|
3372
|
+
if (firstCommaIndex !== -1 && secondCommaIndex !== -1) {
|
|
3373
|
+
const type = messageData.slice(0, firstCommaIndex);
|
|
3374
|
+
if (isPattern && type === "pmessage" && thirdCommaIndex !== -1) {
|
|
3375
|
+
const pattern = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
|
|
3376
|
+
const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
|
|
3377
|
+
const messageStr = messageData.slice(thirdCommaIndex + 1);
|
|
3378
|
+
try {
|
|
3379
|
+
const message = JSON.parse(messageStr);
|
|
3380
|
+
this.dispatchToListeners("pmessage", { pattern, channel, message });
|
|
3381
|
+
this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
|
|
3382
|
+
} catch (error) {
|
|
3383
|
+
this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
|
|
3384
|
+
}
|
|
3385
|
+
} else {
|
|
3386
|
+
const channel = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
|
|
3387
|
+
const messageStr = messageData.slice(secondCommaIndex + 1);
|
|
3388
|
+
try {
|
|
3389
|
+
if (type === "subscribe" || type === "psubscribe" || type === "unsubscribe" || type === "punsubscribe") {
|
|
3390
|
+
const count = Number.parseInt(messageStr);
|
|
3391
|
+
this.dispatchToListeners(type, count);
|
|
3392
|
+
} else {
|
|
3393
|
+
const message = JSON.parse(messageStr);
|
|
3394
|
+
this.dispatchToListeners(type, { channel, message });
|
|
3395
|
+
this.dispatchToListeners(`${type}:${channel}`, { channel, message });
|
|
3396
|
+
}
|
|
3397
|
+
} catch (error) {
|
|
3398
|
+
this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
dispatchToListeners(type, data) {
|
|
3404
|
+
const listeners = this.listeners.get(type);
|
|
3405
|
+
if (listeners) {
|
|
3406
|
+
for (const listener of listeners) {
|
|
3407
|
+
listener(data);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
on(type, listener) {
|
|
3412
|
+
if (!this.listeners.has(type)) {
|
|
3413
|
+
this.listeners.set(type, /* @__PURE__ */ new Set());
|
|
3414
|
+
}
|
|
3415
|
+
this.listeners.get(type)?.add(listener);
|
|
3416
|
+
}
|
|
3417
|
+
removeAllListeners() {
|
|
3418
|
+
this.listeners.clear();
|
|
3419
|
+
}
|
|
3420
|
+
async unsubscribe(channels) {
|
|
3421
|
+
if (channels) {
|
|
3422
|
+
for (const channel of channels) {
|
|
3423
|
+
const subscription = this.subscriptions.get(channel);
|
|
3424
|
+
if (subscription) {
|
|
3425
|
+
try {
|
|
3426
|
+
subscription.controller.abort();
|
|
3427
|
+
} catch {
|
|
3428
|
+
}
|
|
3429
|
+
this.subscriptions.delete(channel);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
} else {
|
|
3433
|
+
for (const subscription of this.subscriptions.values()) {
|
|
3434
|
+
try {
|
|
3435
|
+
subscription.controller.abort();
|
|
3436
|
+
} catch {
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
this.subscriptions.clear();
|
|
3440
|
+
this.removeAllListeners();
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
getSubscribedChannels() {
|
|
3444
|
+
return [...this.subscriptions.keys()];
|
|
3445
|
+
}
|
|
3446
|
+
};
|
|
3447
|
+
var SubscribeCommand = class extends Command {
|
|
3448
|
+
constructor(cmd, opts) {
|
|
3449
|
+
const sseHeaders = {
|
|
3450
|
+
Accept: "text/event-stream",
|
|
3451
|
+
"Cache-Control": "no-cache",
|
|
3452
|
+
Connection: "keep-alive"
|
|
3453
|
+
};
|
|
3454
|
+
super([], {
|
|
3455
|
+
...opts,
|
|
3456
|
+
headers: sseHeaders,
|
|
3457
|
+
path: ["subscribe", ...cmd],
|
|
3458
|
+
streamOptions: {
|
|
3459
|
+
isStreaming: true,
|
|
3460
|
+
onMessage: opts?.streamOptions?.onMessage,
|
|
3461
|
+
signal: opts?.streamOptions?.signal
|
|
3462
|
+
}
|
|
3463
|
+
});
|
|
3464
|
+
}
|
|
3465
|
+
};
|
|
3466
|
+
|
|
2961
3467
|
// pkg/script.ts
|
|
2962
|
-
import
|
|
2963
|
-
import sha1 from "crypto-js/sha1.js";
|
|
3468
|
+
import { subtle } from "uncrypto";
|
|
2964
3469
|
var Script = class {
|
|
2965
3470
|
script;
|
|
3471
|
+
/**
|
|
3472
|
+
* @deprecated This property is initialized to an empty string and will be set in the init method
|
|
3473
|
+
* asynchronously. Do not use this property immidiately after the constructor.
|
|
3474
|
+
*
|
|
3475
|
+
* This property is only exposed for backwards compatibility and will be removed in the
|
|
3476
|
+
* future major release.
|
|
3477
|
+
*/
|
|
2966
3478
|
sha1;
|
|
2967
3479
|
redis;
|
|
2968
3480
|
constructor(redis, script) {
|
|
2969
3481
|
this.redis = redis;
|
|
2970
|
-
this.sha1 = this.digest(script);
|
|
2971
3482
|
this.script = script;
|
|
3483
|
+
this.sha1 = "";
|
|
3484
|
+
void this.init(script);
|
|
3485
|
+
}
|
|
3486
|
+
/**
|
|
3487
|
+
* Initialize the script by computing its SHA-1 hash.
|
|
3488
|
+
*/
|
|
3489
|
+
async init(script) {
|
|
3490
|
+
if (this.sha1) return;
|
|
3491
|
+
this.sha1 = await this.digest(script);
|
|
2972
3492
|
}
|
|
2973
3493
|
/**
|
|
2974
3494
|
* Send an `EVAL` command to redis.
|
|
2975
3495
|
*/
|
|
2976
3496
|
async eval(keys, args) {
|
|
3497
|
+
await this.init(this.script);
|
|
2977
3498
|
return await this.redis.eval(this.script, keys, args);
|
|
2978
3499
|
}
|
|
2979
3500
|
/**
|
|
2980
3501
|
* Calculates the sha1 hash of the script and then calls `EVALSHA`.
|
|
2981
3502
|
*/
|
|
2982
3503
|
async evalsha(keys, args) {
|
|
3504
|
+
await this.init(this.script);
|
|
2983
3505
|
return await this.redis.evalsha(this.sha1, keys, args);
|
|
2984
3506
|
}
|
|
2985
3507
|
/**
|
|
@@ -2989,6 +3511,7 @@ var Script = class {
|
|
|
2989
3511
|
* Following calls will be able to use the cached script
|
|
2990
3512
|
*/
|
|
2991
3513
|
async exec(keys, args) {
|
|
3514
|
+
await this.init(this.script);
|
|
2992
3515
|
const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
|
|
2993
3516
|
if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
|
|
2994
3517
|
return await this.redis.eval(this.script, keys, args);
|
|
@@ -3000,8 +3523,75 @@ var Script = class {
|
|
|
3000
3523
|
/**
|
|
3001
3524
|
* Compute the sha1 hash of the script and return its hex representation.
|
|
3002
3525
|
*/
|
|
3003
|
-
digest(s) {
|
|
3004
|
-
|
|
3526
|
+
async digest(s) {
|
|
3527
|
+
const data = new TextEncoder().encode(s);
|
|
3528
|
+
const hashBuffer = await subtle.digest("SHA-1", data);
|
|
3529
|
+
const hashArray = [...new Uint8Array(hashBuffer)];
|
|
3530
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3531
|
+
}
|
|
3532
|
+
};
|
|
3533
|
+
|
|
3534
|
+
// pkg/scriptRo.ts
|
|
3535
|
+
import { subtle as subtle2 } from "uncrypto";
|
|
3536
|
+
var ScriptRO = class {
|
|
3537
|
+
script;
|
|
3538
|
+
/**
|
|
3539
|
+
* @deprecated This property is initialized to an empty string and will be set in the init method
|
|
3540
|
+
* asynchronously. Do not use this property immidiately after the constructor.
|
|
3541
|
+
*
|
|
3542
|
+
* This property is only exposed for backwards compatibility and will be removed in the
|
|
3543
|
+
* future major release.
|
|
3544
|
+
*/
|
|
3545
|
+
sha1;
|
|
3546
|
+
redis;
|
|
3547
|
+
constructor(redis, script) {
|
|
3548
|
+
this.redis = redis;
|
|
3549
|
+
this.sha1 = "";
|
|
3550
|
+
this.script = script;
|
|
3551
|
+
void this.init(script);
|
|
3552
|
+
}
|
|
3553
|
+
async init(script) {
|
|
3554
|
+
if (this.sha1) return;
|
|
3555
|
+
this.sha1 = await this.digest(script);
|
|
3556
|
+
}
|
|
3557
|
+
/**
|
|
3558
|
+
* Send an `EVAL_RO` command to redis.
|
|
3559
|
+
*/
|
|
3560
|
+
async evalRo(keys, args) {
|
|
3561
|
+
await this.init(this.script);
|
|
3562
|
+
return await this.redis.evalRo(this.script, keys, args);
|
|
3563
|
+
}
|
|
3564
|
+
/**
|
|
3565
|
+
* Calculates the sha1 hash of the script and then calls `EVALSHA_RO`.
|
|
3566
|
+
*/
|
|
3567
|
+
async evalshaRo(keys, args) {
|
|
3568
|
+
await this.init(this.script);
|
|
3569
|
+
return await this.redis.evalshaRo(this.sha1, keys, args);
|
|
3570
|
+
}
|
|
3571
|
+
/**
|
|
3572
|
+
* Optimistically try to run `EVALSHA_RO` first.
|
|
3573
|
+
* If the script is not loaded in redis, it will fall back and try again with `EVAL_RO`.
|
|
3574
|
+
*
|
|
3575
|
+
* Following calls will be able to use the cached script
|
|
3576
|
+
*/
|
|
3577
|
+
async exec(keys, args) {
|
|
3578
|
+
await this.init(this.script);
|
|
3579
|
+
const res = await this.redis.evalshaRo(this.sha1, keys, args).catch(async (error) => {
|
|
3580
|
+
if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
|
|
3581
|
+
return await this.redis.evalRo(this.script, keys, args);
|
|
3582
|
+
}
|
|
3583
|
+
throw error;
|
|
3584
|
+
});
|
|
3585
|
+
return res;
|
|
3586
|
+
}
|
|
3587
|
+
/**
|
|
3588
|
+
* Compute the sha1 hash of the script and return its hex representation.
|
|
3589
|
+
*/
|
|
3590
|
+
async digest(s) {
|
|
3591
|
+
const data = new TextEncoder().encode(s);
|
|
3592
|
+
const hashBuffer = await subtle2.digest("SHA-1", data);
|
|
3593
|
+
const hashArray = [...new Uint8Array(hashBuffer)];
|
|
3594
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3005
3595
|
}
|
|
3006
3596
|
};
|
|
3007
3597
|
|
|
@@ -3031,6 +3621,12 @@ var Redis = class {
|
|
|
3031
3621
|
}
|
|
3032
3622
|
this.enableAutoPipelining = opts?.enableAutoPipelining ?? true;
|
|
3033
3623
|
}
|
|
3624
|
+
get readYourWritesSyncToken() {
|
|
3625
|
+
return this.client.upstashSyncToken;
|
|
3626
|
+
}
|
|
3627
|
+
set readYourWritesSyncToken(session) {
|
|
3628
|
+
this.client.upstashSyncToken = session;
|
|
3629
|
+
}
|
|
3034
3630
|
get json() {
|
|
3035
3631
|
return {
|
|
3036
3632
|
/**
|
|
@@ -3073,6 +3669,10 @@ var Redis = class {
|
|
|
3073
3669
|
* @see https://redis.io/commands/json.get
|
|
3074
3670
|
*/
|
|
3075
3671
|
get: (...args) => new JsonGetCommand(args, this.opts).exec(this.client),
|
|
3672
|
+
/**
|
|
3673
|
+
* @see https://redis.io/commands/json.merge
|
|
3674
|
+
*/
|
|
3675
|
+
merge: (...args) => new JsonMergeCommand(args, this.opts).exec(this.client),
|
|
3076
3676
|
/**
|
|
3077
3677
|
* @see https://redis.io/commands/json.mget
|
|
3078
3678
|
*/
|
|
@@ -3142,8 +3742,36 @@ var Redis = class {
|
|
|
3142
3742
|
} catch {
|
|
3143
3743
|
}
|
|
3144
3744
|
};
|
|
3145
|
-
|
|
3146
|
-
|
|
3745
|
+
/**
|
|
3746
|
+
* Creates a new script.
|
|
3747
|
+
*
|
|
3748
|
+
* Scripts offer the ability to optimistically try to execute a script without having to send the
|
|
3749
|
+
* entire script to the server. If the script is loaded on the server, it tries again by sending
|
|
3750
|
+
* the entire script. Afterwards, the script is cached on the server.
|
|
3751
|
+
*
|
|
3752
|
+
* @param script - The script to create
|
|
3753
|
+
* @param opts - Optional options to pass to the script `{ readonly?: boolean }`
|
|
3754
|
+
* @returns A new script
|
|
3755
|
+
*
|
|
3756
|
+
* @example
|
|
3757
|
+
* ```ts
|
|
3758
|
+
* const redis = new Redis({...})
|
|
3759
|
+
*
|
|
3760
|
+
* const script = redis.createScript<string>("return ARGV[1];")
|
|
3761
|
+
* const arg1 = await script.eval([], ["Hello World"])
|
|
3762
|
+
* expect(arg1, "Hello World")
|
|
3763
|
+
* ```
|
|
3764
|
+
* @example
|
|
3765
|
+
* ```ts
|
|
3766
|
+
* const redis = new Redis({...})
|
|
3767
|
+
*
|
|
3768
|
+
* const script = redis.createScript<string>("return ARGV[1];", { readonly: true })
|
|
3769
|
+
* const arg1 = await script.evalRo([], ["Hello World"])
|
|
3770
|
+
* expect(arg1, "Hello World")
|
|
3771
|
+
* ```
|
|
3772
|
+
*/
|
|
3773
|
+
createScript(script, opts) {
|
|
3774
|
+
return opts?.readonly ? new ScriptRO(this, script) : new Script(this, script);
|
|
3147
3775
|
}
|
|
3148
3776
|
/**
|
|
3149
3777
|
* Create a new pipeline that allows you to send requests in bulk.
|
|
@@ -3230,14 +3858,26 @@ var Redis = class {
|
|
|
3230
3858
|
* @see https://redis.io/commands/echo
|
|
3231
3859
|
*/
|
|
3232
3860
|
echo = (...args) => new EchoCommand(args, this.opts).exec(this.client);
|
|
3861
|
+
/**
|
|
3862
|
+
* @see https://redis.io/commands/eval_ro
|
|
3863
|
+
*/
|
|
3864
|
+
evalRo = (...args) => new EvalROCommand(args, this.opts).exec(this.client);
|
|
3233
3865
|
/**
|
|
3234
3866
|
* @see https://redis.io/commands/eval
|
|
3235
3867
|
*/
|
|
3236
3868
|
eval = (...args) => new EvalCommand(args, this.opts).exec(this.client);
|
|
3869
|
+
/**
|
|
3870
|
+
* @see https://redis.io/commands/evalsha_ro
|
|
3871
|
+
*/
|
|
3872
|
+
evalshaRo = (...args) => new EvalshaROCommand(args, this.opts).exec(this.client);
|
|
3237
3873
|
/**
|
|
3238
3874
|
* @see https://redis.io/commands/evalsha
|
|
3239
3875
|
*/
|
|
3240
3876
|
evalsha = (...args) => new EvalshaCommand(args, this.opts).exec(this.client);
|
|
3877
|
+
/**
|
|
3878
|
+
* Generic method to execute any Redis command.
|
|
3879
|
+
*/
|
|
3880
|
+
exec = (args) => new ExecCommand(args, this.opts).exec(this.client);
|
|
3241
3881
|
/**
|
|
3242
3882
|
* @see https://redis.io/commands/exists
|
|
3243
3883
|
*/
|
|
@@ -3294,6 +3934,10 @@ var Redis = class {
|
|
|
3294
3934
|
* @see https://redis.io/commands/getdel
|
|
3295
3935
|
*/
|
|
3296
3936
|
getdel = (...args) => new GetDelCommand(args, this.opts).exec(this.client);
|
|
3937
|
+
/**
|
|
3938
|
+
* @see https://redis.io/commands/getex
|
|
3939
|
+
*/
|
|
3940
|
+
getex = (...args) => new GetExCommand(args, this.opts).exec(this.client);
|
|
3297
3941
|
/**
|
|
3298
3942
|
* @see https://redis.io/commands/getrange
|
|
3299
3943
|
*/
|
|
@@ -3310,6 +3954,42 @@ var Redis = class {
|
|
|
3310
3954
|
* @see https://redis.io/commands/hexists
|
|
3311
3955
|
*/
|
|
3312
3956
|
hexists = (...args) => new HExistsCommand(args, this.opts).exec(this.client);
|
|
3957
|
+
/**
|
|
3958
|
+
* @see https://redis.io/commands/hexpire
|
|
3959
|
+
*/
|
|
3960
|
+
hexpire = (...args) => new HExpireCommand(args, this.opts).exec(this.client);
|
|
3961
|
+
/**
|
|
3962
|
+
* @see https://redis.io/commands/hexpireat
|
|
3963
|
+
*/
|
|
3964
|
+
hexpireat = (...args) => new HExpireAtCommand(args, this.opts).exec(this.client);
|
|
3965
|
+
/**
|
|
3966
|
+
* @see https://redis.io/commands/hexpiretime
|
|
3967
|
+
*/
|
|
3968
|
+
hexpiretime = (...args) => new HExpireTimeCommand(args, this.opts).exec(this.client);
|
|
3969
|
+
/**
|
|
3970
|
+
* @see https://redis.io/commands/httl
|
|
3971
|
+
*/
|
|
3972
|
+
httl = (...args) => new HTtlCommand(args, this.opts).exec(this.client);
|
|
3973
|
+
/**
|
|
3974
|
+
* @see https://redis.io/commands/hpexpire
|
|
3975
|
+
*/
|
|
3976
|
+
hpexpire = (...args) => new HPExpireCommand(args, this.opts).exec(this.client);
|
|
3977
|
+
/**
|
|
3978
|
+
* @see https://redis.io/commands/hpexpireat
|
|
3979
|
+
*/
|
|
3980
|
+
hpexpireat = (...args) => new HPExpireAtCommand(args, this.opts).exec(this.client);
|
|
3981
|
+
/**
|
|
3982
|
+
* @see https://redis.io/commands/hpexpiretime
|
|
3983
|
+
*/
|
|
3984
|
+
hpexpiretime = (...args) => new HPExpireTimeCommand(args, this.opts).exec(this.client);
|
|
3985
|
+
/**
|
|
3986
|
+
* @see https://redis.io/commands/hpttl
|
|
3987
|
+
*/
|
|
3988
|
+
hpttl = (...args) => new HPTtlCommand(args, this.opts).exec(this.client);
|
|
3989
|
+
/**
|
|
3990
|
+
* @see https://redis.io/commands/hpersist
|
|
3991
|
+
*/
|
|
3992
|
+
hpersist = (...args) => new HPersistCommand(args, this.opts).exec(this.client);
|
|
3313
3993
|
/**
|
|
3314
3994
|
* @see https://redis.io/commands/hget
|
|
3315
3995
|
*/
|
|
@@ -3478,6 +4158,13 @@ var Redis = class {
|
|
|
3478
4158
|
* @see https://redis.io/commands/psetex
|
|
3479
4159
|
*/
|
|
3480
4160
|
psetex = (key, ttl, value) => new PSetEXCommand([key, ttl, value], this.opts).exec(this.client);
|
|
4161
|
+
/**
|
|
4162
|
+
* @see https://redis.io/commands/psubscribe
|
|
4163
|
+
*/
|
|
4164
|
+
psubscribe = (patterns) => {
|
|
4165
|
+
const patternArray = Array.isArray(patterns) ? patterns : [patterns];
|
|
4166
|
+
return new Subscriber(this.client, patternArray, true);
|
|
4167
|
+
};
|
|
3481
4168
|
/**
|
|
3482
4169
|
* @see https://redis.io/commands/pttl
|
|
3483
4170
|
*/
|
|
@@ -3514,10 +4201,9 @@ var Redis = class {
|
|
|
3514
4201
|
* @see https://redis.io/commands/sadd
|
|
3515
4202
|
*/
|
|
3516
4203
|
sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
scan = (...args) => new ScanCommand(args, this.opts).exec(this.client);
|
|
4204
|
+
scan(cursor, opts) {
|
|
4205
|
+
return new ScanCommand([cursor, opts], this.opts).exec(this.client);
|
|
4206
|
+
}
|
|
3521
4207
|
/**
|
|
3522
4208
|
* @see https://redis.io/commands/scard
|
|
3523
4209
|
*/
|
|
@@ -3606,6 +4292,13 @@ var Redis = class {
|
|
|
3606
4292
|
* @see https://redis.io/commands/strlen
|
|
3607
4293
|
*/
|
|
3608
4294
|
strlen = (...args) => new StrLenCommand(args, this.opts).exec(this.client);
|
|
4295
|
+
/**
|
|
4296
|
+
* @see https://redis.io/commands/subscribe
|
|
4297
|
+
*/
|
|
4298
|
+
subscribe = (channels) => {
|
|
4299
|
+
const channelArray = Array.isArray(channels) ? channels : [channels];
|
|
4300
|
+
return new Subscriber(this.client, channelArray);
|
|
4301
|
+
};
|
|
3609
4302
|
/**
|
|
3610
4303
|
* @see https://redis.io/commands/sunion
|
|
3611
4304
|
*/
|
|
@@ -3787,7 +4480,7 @@ var Redis = class {
|
|
|
3787
4480
|
};
|
|
3788
4481
|
|
|
3789
4482
|
// version.ts
|
|
3790
|
-
var VERSION = "v1.35.
|
|
4483
|
+
var VERSION = "v1.35.1";
|
|
3791
4484
|
|
|
3792
4485
|
export {
|
|
3793
4486
|
error_exports,
|