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