@upstash/redis 0.0.0-ci.998046a844b4998e6b7de8c128d5f41be5545cdf-20241002104435 → 0.0.0-ci.9a0f7fcd9dc38c0a4ce2b192f3f9c3542ccc791c-20251125190254
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/README.md +9 -0
- package/{chunk-K53GSI5K.mjs → chunk-WTYE7OV3.mjs} +807 -90
- package/cloudflare.d.mts +3 -3
- package/cloudflare.d.ts +3 -3
- package/cloudflare.js +822 -113
- package/cloudflare.mjs +16 -14
- package/fastly.d.mts +2 -2
- package/fastly.d.ts +2 -2
- package/fastly.js +817 -108
- package/fastly.mjs +11 -9
- package/nodejs.d.mts +14 -6
- package/nodejs.d.ts +14 -6
- package/nodejs.js +832 -118
- package/nodejs.mjs +26 -19
- package/package.json +1 -1
- package/{zmscore-BLgYk16R.d.mts → zmscore-xbfRql7X.d.mts} +626 -56
- package/{zmscore-BLgYk16R.d.ts → zmscore-xbfRql7X.d.ts} +626 -56
|
@@ -8,22 +8,75 @@ var __export = (target, all) => {
|
|
|
8
8
|
var error_exports = {};
|
|
9
9
|
__export(error_exports, {
|
|
10
10
|
UpstashError: () => UpstashError,
|
|
11
|
+
UpstashJSONParseError: () => UpstashJSONParseError,
|
|
11
12
|
UrlError: () => UrlError
|
|
12
13
|
});
|
|
13
14
|
var UpstashError = class extends Error {
|
|
14
|
-
constructor(message) {
|
|
15
|
-
super(message);
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
16
17
|
this.name = "UpstashError";
|
|
17
18
|
}
|
|
18
19
|
};
|
|
19
20
|
var UrlError = class extends Error {
|
|
20
21
|
constructor(url) {
|
|
21
22
|
super(
|
|
22
|
-
`Upstash Redis client was passed an invalid URL. You should pass
|
|
23
|
+
`Upstash Redis client was passed an invalid URL. You should pass a URL starting with https. Received: "${url}". `
|
|
23
24
|
);
|
|
24
25
|
this.name = "UrlError";
|
|
25
26
|
}
|
|
26
27
|
};
|
|
28
|
+
var UpstashJSONParseError = class extends UpstashError {
|
|
29
|
+
constructor(body, options) {
|
|
30
|
+
const truncatedBody = body.length > 200 ? body.slice(0, 200) + "..." : body;
|
|
31
|
+
super(`Unable to parse response body: ${truncatedBody}`, options);
|
|
32
|
+
this.name = "UpstashJSONParseError";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// pkg/util.ts
|
|
37
|
+
function parseRecursive(obj) {
|
|
38
|
+
const parsed = Array.isArray(obj) ? obj.map((o) => {
|
|
39
|
+
try {
|
|
40
|
+
return parseRecursive(o);
|
|
41
|
+
} catch {
|
|
42
|
+
return o;
|
|
43
|
+
}
|
|
44
|
+
}) : JSON.parse(obj);
|
|
45
|
+
if (typeof parsed === "number" && parsed.toString() !== obj) {
|
|
46
|
+
return obj;
|
|
47
|
+
}
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
function parseResponse(result) {
|
|
51
|
+
try {
|
|
52
|
+
return parseRecursive(result);
|
|
53
|
+
} catch {
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function deserializeScanResponse(result) {
|
|
58
|
+
return [result[0], ...parseResponse(result.slice(1))];
|
|
59
|
+
}
|
|
60
|
+
function deserializeScanWithTypesResponse(result) {
|
|
61
|
+
const [cursor, keys] = result;
|
|
62
|
+
const parsedKeys = [];
|
|
63
|
+
for (let i = 0; i < keys.length; i += 2) {
|
|
64
|
+
parsedKeys.push({ key: keys[i], type: keys[i + 1] });
|
|
65
|
+
}
|
|
66
|
+
return [cursor, parsedKeys];
|
|
67
|
+
}
|
|
68
|
+
function mergeHeaders(...headers) {
|
|
69
|
+
const merged = {};
|
|
70
|
+
for (const header of headers) {
|
|
71
|
+
if (!header) continue;
|
|
72
|
+
for (const [key, value] of Object.entries(header)) {
|
|
73
|
+
if (value !== void 0 && value !== null) {
|
|
74
|
+
merged[key] = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return merged;
|
|
79
|
+
}
|
|
27
80
|
|
|
28
81
|
// pkg/http.ts
|
|
29
82
|
var HttpClient = class {
|
|
@@ -32,6 +85,7 @@ var HttpClient = class {
|
|
|
32
85
|
options;
|
|
33
86
|
readYourWrites;
|
|
34
87
|
upstashSyncToken = "";
|
|
88
|
+
hasCredentials;
|
|
35
89
|
retry;
|
|
36
90
|
constructor(config) {
|
|
37
91
|
this.options = {
|
|
@@ -45,15 +99,16 @@ var HttpClient = class {
|
|
|
45
99
|
};
|
|
46
100
|
this.upstashSyncToken = "";
|
|
47
101
|
this.readYourWrites = config.readYourWrites ?? true;
|
|
48
|
-
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
102
|
+
this.baseUrl = (config.baseUrl || "").replace(/\/$/, "");
|
|
49
103
|
const urlRegex = /^https?:\/\/[^\s#$./?].\S*$/;
|
|
50
|
-
if (!urlRegex.test(this.baseUrl)) {
|
|
104
|
+
if (this.baseUrl && !urlRegex.test(this.baseUrl)) {
|
|
51
105
|
throw new UrlError(this.baseUrl);
|
|
52
106
|
}
|
|
53
107
|
this.headers = {
|
|
54
108
|
"Content-Type": "application/json",
|
|
55
109
|
...config.headers
|
|
56
110
|
};
|
|
111
|
+
this.hasCredentials = Boolean(this.baseUrl && this.headers.authorization.split(" ")[1]);
|
|
57
112
|
if (this.options.responseEncoding === "base64") {
|
|
58
113
|
this.headers["Upstash-Encoding"] = "base64";
|
|
59
114
|
}
|
|
@@ -71,20 +126,30 @@ var HttpClient = class {
|
|
|
71
126
|
this.headers = merge(this.headers, "Upstash-Telemetry-Sdk", telemetry.sdk);
|
|
72
127
|
}
|
|
73
128
|
async request(req) {
|
|
129
|
+
const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
|
|
130
|
+
const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
|
|
131
|
+
const isEventStream = requestHeaders.Accept === "text/event-stream";
|
|
132
|
+
const signal = req.signal ?? this.options.signal;
|
|
133
|
+
const isSignalFunction = typeof signal === "function";
|
|
74
134
|
const requestOptions = {
|
|
75
135
|
//@ts-expect-error this should throw due to bun regression
|
|
76
136
|
cache: this.options.cache,
|
|
77
137
|
method: "POST",
|
|
78
|
-
headers:
|
|
138
|
+
headers: requestHeaders,
|
|
79
139
|
body: JSON.stringify(req.body),
|
|
80
140
|
keepalive: this.options.keepAlive,
|
|
81
141
|
agent: this.options.agent,
|
|
82
|
-
signal:
|
|
142
|
+
signal: isSignalFunction ? signal() : signal,
|
|
83
143
|
/**
|
|
84
144
|
* Fastly specific
|
|
85
145
|
*/
|
|
86
146
|
backend: this.options.backend
|
|
87
147
|
};
|
|
148
|
+
if (!this.hasCredentials) {
|
|
149
|
+
console.warn(
|
|
150
|
+
"[Upstash Redis] Redis client was initialized without url or token. Failed to execute command."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
88
153
|
if (this.readYourWrites) {
|
|
89
154
|
const newHeader = this.upstashSyncToken;
|
|
90
155
|
this.headers["upstash-sync-token"] = newHeader;
|
|
@@ -93,35 +158,83 @@ var HttpClient = class {
|
|
|
93
158
|
let error = null;
|
|
94
159
|
for (let i = 0; i <= this.retry.attempts; i++) {
|
|
95
160
|
try {
|
|
96
|
-
res = await fetch(
|
|
161
|
+
res = await fetch(requestUrl, requestOptions);
|
|
97
162
|
break;
|
|
98
163
|
} catch (error_) {
|
|
99
|
-
if (
|
|
164
|
+
if (requestOptions.signal?.aborted && isSignalFunction) {
|
|
165
|
+
throw error_;
|
|
166
|
+
} else if (requestOptions.signal?.aborted) {
|
|
100
167
|
const myBlob = new Blob([
|
|
101
|
-
JSON.stringify({ result:
|
|
168
|
+
JSON.stringify({ result: requestOptions.signal.reason ?? "Aborted" })
|
|
102
169
|
]);
|
|
103
170
|
const myOptions = {
|
|
104
171
|
status: 200,
|
|
105
|
-
statusText:
|
|
172
|
+
statusText: requestOptions.signal.reason ?? "Aborted"
|
|
106
173
|
};
|
|
107
174
|
res = new Response(myBlob, myOptions);
|
|
108
175
|
break;
|
|
109
176
|
}
|
|
110
177
|
error = error_;
|
|
111
|
-
|
|
178
|
+
if (i < this.retry.attempts) {
|
|
179
|
+
await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
|
|
180
|
+
}
|
|
112
181
|
}
|
|
113
182
|
}
|
|
114
183
|
if (!res) {
|
|
115
184
|
throw error ?? new Error("Exhausted all retries");
|
|
116
185
|
}
|
|
117
|
-
const body = await res.json();
|
|
118
186
|
if (!res.ok) {
|
|
119
|
-
|
|
187
|
+
let body2;
|
|
188
|
+
const rawBody2 = await res.text();
|
|
189
|
+
try {
|
|
190
|
+
body2 = JSON.parse(rawBody2);
|
|
191
|
+
} catch (error2) {
|
|
192
|
+
throw new UpstashJSONParseError(rawBody2, { cause: error2 });
|
|
193
|
+
}
|
|
194
|
+
throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
|
|
120
195
|
}
|
|
121
196
|
if (this.readYourWrites) {
|
|
122
197
|
const headers = res.headers;
|
|
123
198
|
this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
|
|
124
199
|
}
|
|
200
|
+
if (isEventStream && req && req.onMessage && res.body) {
|
|
201
|
+
const reader = res.body.getReader();
|
|
202
|
+
const decoder = new TextDecoder();
|
|
203
|
+
(async () => {
|
|
204
|
+
try {
|
|
205
|
+
while (true) {
|
|
206
|
+
const { value, done } = await reader.read();
|
|
207
|
+
if (done) break;
|
|
208
|
+
const chunk = decoder.decode(value);
|
|
209
|
+
const lines = chunk.split("\n");
|
|
210
|
+
for (const line of lines) {
|
|
211
|
+
if (line.startsWith("data: ")) {
|
|
212
|
+
const data = line.slice(6);
|
|
213
|
+
req.onMessage?.(data);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
} catch (error2) {
|
|
218
|
+
if (error2 instanceof Error && error2.name === "AbortError") {
|
|
219
|
+
} else {
|
|
220
|
+
console.error("Stream reading error:", error2);
|
|
221
|
+
}
|
|
222
|
+
} finally {
|
|
223
|
+
try {
|
|
224
|
+
await reader.cancel();
|
|
225
|
+
} catch {
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
})();
|
|
229
|
+
return { result: 1 };
|
|
230
|
+
}
|
|
231
|
+
let body;
|
|
232
|
+
const rawBody = await res.text();
|
|
233
|
+
try {
|
|
234
|
+
body = JSON.parse(rawBody);
|
|
235
|
+
} catch (error2) {
|
|
236
|
+
throw new UpstashJSONParseError(rawBody, { cause: error2 });
|
|
237
|
+
}
|
|
125
238
|
if (this.readYourWrites) {
|
|
126
239
|
const headers = res.headers;
|
|
127
240
|
this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
|
|
@@ -192,31 +305,6 @@ function merge(obj, key, value) {
|
|
|
192
305
|
return obj;
|
|
193
306
|
}
|
|
194
307
|
|
|
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
308
|
// pkg/commands/command.ts
|
|
221
309
|
var defaultSerializer = (c) => {
|
|
222
310
|
switch (typeof c) {
|
|
@@ -234,6 +322,11 @@ var Command = class {
|
|
|
234
322
|
command;
|
|
235
323
|
serialize;
|
|
236
324
|
deserialize;
|
|
325
|
+
headers;
|
|
326
|
+
path;
|
|
327
|
+
onMessage;
|
|
328
|
+
isStreaming;
|
|
329
|
+
signal;
|
|
237
330
|
/**
|
|
238
331
|
* Create a new command instance.
|
|
239
332
|
*
|
|
@@ -243,6 +336,11 @@ var Command = class {
|
|
|
243
336
|
this.serialize = defaultSerializer;
|
|
244
337
|
this.deserialize = opts?.automaticDeserialization === void 0 || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
|
|
245
338
|
this.command = command.map((c) => this.serialize(c));
|
|
339
|
+
this.headers = opts?.headers;
|
|
340
|
+
this.path = opts?.path;
|
|
341
|
+
this.onMessage = opts?.streamOptions?.onMessage;
|
|
342
|
+
this.isStreaming = opts?.streamOptions?.isStreaming ?? false;
|
|
343
|
+
this.signal = opts?.streamOptions?.signal;
|
|
246
344
|
if (opts?.latencyLogging) {
|
|
247
345
|
const originalExec = this.exec.bind(this);
|
|
248
346
|
this.exec = async (client) => {
|
|
@@ -263,7 +361,12 @@ var Command = class {
|
|
|
263
361
|
async exec(client) {
|
|
264
362
|
const { result, error } = await client.request({
|
|
265
363
|
body: this.command,
|
|
266
|
-
|
|
364
|
+
path: this.path,
|
|
365
|
+
upstashSyncToken: client.upstashSyncToken,
|
|
366
|
+
headers: this.headers,
|
|
367
|
+
onMessage: this.onMessage,
|
|
368
|
+
isStreaming: this.isStreaming,
|
|
369
|
+
signal: this.signal
|
|
267
370
|
});
|
|
268
371
|
if (error) {
|
|
269
372
|
throw new UpstashError(error);
|
|
@@ -281,9 +384,9 @@ function deserialize(result) {
|
|
|
281
384
|
return null;
|
|
282
385
|
}
|
|
283
386
|
const obj = {};
|
|
284
|
-
|
|
285
|
-
const key = result
|
|
286
|
-
const value = result
|
|
387
|
+
for (let i = 0; i < result.length; i += 2) {
|
|
388
|
+
const key = result[i];
|
|
389
|
+
const value = result[i + 1];
|
|
287
390
|
try {
|
|
288
391
|
obj[key] = JSON.parse(value);
|
|
289
392
|
} catch {
|
|
@@ -425,6 +528,13 @@ var EchoCommand = class extends Command {
|
|
|
425
528
|
}
|
|
426
529
|
};
|
|
427
530
|
|
|
531
|
+
// pkg/commands/evalRo.ts
|
|
532
|
+
var EvalROCommand = class extends Command {
|
|
533
|
+
constructor([script, keys, args], opts) {
|
|
534
|
+
super(["eval_ro", script, keys.length, ...keys, ...args ?? []], opts);
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
|
|
428
538
|
// pkg/commands/eval.ts
|
|
429
539
|
var EvalCommand = class extends Command {
|
|
430
540
|
constructor([script, keys, args], opts) {
|
|
@@ -432,6 +542,13 @@ var EvalCommand = class extends Command {
|
|
|
432
542
|
}
|
|
433
543
|
};
|
|
434
544
|
|
|
545
|
+
// pkg/commands/evalshaRo.ts
|
|
546
|
+
var EvalshaROCommand = class extends Command {
|
|
547
|
+
constructor([sha, keys, args], opts) {
|
|
548
|
+
super(["evalsha_ro", sha, keys.length, ...keys, ...args ?? []], opts);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
435
552
|
// pkg/commands/evalsha.ts
|
|
436
553
|
var EvalshaCommand = class extends Command {
|
|
437
554
|
constructor([sha, keys, args], opts) {
|
|
@@ -439,6 +556,14 @@ var EvalshaCommand = class extends Command {
|
|
|
439
556
|
}
|
|
440
557
|
};
|
|
441
558
|
|
|
559
|
+
// pkg/commands/exec.ts
|
|
560
|
+
var ExecCommand = class extends Command {
|
|
561
|
+
constructor(cmd, opts) {
|
|
562
|
+
const normalizedCmd = cmd.map((arg) => typeof arg === "string" ? arg : String(arg));
|
|
563
|
+
super(normalizedCmd, opts);
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
|
|
442
567
|
// pkg/commands/exists.ts
|
|
443
568
|
var ExistsCommand = class extends Command {
|
|
444
569
|
constructor(cmd, opts) {
|
|
@@ -655,6 +780,27 @@ var GetDelCommand = class extends Command {
|
|
|
655
780
|
}
|
|
656
781
|
};
|
|
657
782
|
|
|
783
|
+
// pkg/commands/getex.ts
|
|
784
|
+
var GetExCommand = class extends Command {
|
|
785
|
+
constructor([key, opts], cmdOpts) {
|
|
786
|
+
const command = ["getex", key];
|
|
787
|
+
if (opts) {
|
|
788
|
+
if ("ex" in opts && typeof opts.ex === "number") {
|
|
789
|
+
command.push("ex", opts.ex);
|
|
790
|
+
} else if ("px" in opts && typeof opts.px === "number") {
|
|
791
|
+
command.push("px", opts.px);
|
|
792
|
+
} else if ("exat" in opts && typeof opts.exat === "number") {
|
|
793
|
+
command.push("exat", opts.exat);
|
|
794
|
+
} else if ("pxat" in opts && typeof opts.pxat === "number") {
|
|
795
|
+
command.push("pxat", opts.pxat);
|
|
796
|
+
} else if ("persist" in opts && opts.persist) {
|
|
797
|
+
command.push("persist");
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
super(command, cmdOpts);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
|
|
658
804
|
// pkg/commands/getrange.ts
|
|
659
805
|
var GetRangeCommand = class extends Command {
|
|
660
806
|
constructor(cmd, opts) {
|
|
@@ -683,6 +829,122 @@ var HExistsCommand = class extends Command {
|
|
|
683
829
|
}
|
|
684
830
|
};
|
|
685
831
|
|
|
832
|
+
// pkg/commands/hexpire.ts
|
|
833
|
+
var HExpireCommand = class extends Command {
|
|
834
|
+
constructor(cmd, opts) {
|
|
835
|
+
const [key, fields, seconds, option] = cmd;
|
|
836
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
837
|
+
super(
|
|
838
|
+
[
|
|
839
|
+
"hexpire",
|
|
840
|
+
key,
|
|
841
|
+
seconds,
|
|
842
|
+
...option ? [option] : [],
|
|
843
|
+
"FIELDS",
|
|
844
|
+
fieldArray.length,
|
|
845
|
+
...fieldArray
|
|
846
|
+
],
|
|
847
|
+
opts
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
// pkg/commands/hexpireat.ts
|
|
853
|
+
var HExpireAtCommand = class extends Command {
|
|
854
|
+
constructor(cmd, opts) {
|
|
855
|
+
const [key, fields, timestamp, option] = cmd;
|
|
856
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
857
|
+
super(
|
|
858
|
+
[
|
|
859
|
+
"hexpireat",
|
|
860
|
+
key,
|
|
861
|
+
timestamp,
|
|
862
|
+
...option ? [option] : [],
|
|
863
|
+
"FIELDS",
|
|
864
|
+
fieldArray.length,
|
|
865
|
+
...fieldArray
|
|
866
|
+
],
|
|
867
|
+
opts
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// pkg/commands/hexpiretime.ts
|
|
873
|
+
var HExpireTimeCommand = class extends Command {
|
|
874
|
+
constructor(cmd, opts) {
|
|
875
|
+
const [key, fields] = cmd;
|
|
876
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
877
|
+
super(["hexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
// pkg/commands/hpersist.ts
|
|
882
|
+
var HPersistCommand = class extends Command {
|
|
883
|
+
constructor(cmd, opts) {
|
|
884
|
+
const [key, fields] = cmd;
|
|
885
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
886
|
+
super(["hpersist", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
887
|
+
}
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
// pkg/commands/hpexpire.ts
|
|
891
|
+
var HPExpireCommand = class extends Command {
|
|
892
|
+
constructor(cmd, opts) {
|
|
893
|
+
const [key, fields, milliseconds, option] = cmd;
|
|
894
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
895
|
+
super(
|
|
896
|
+
[
|
|
897
|
+
"hpexpire",
|
|
898
|
+
key,
|
|
899
|
+
milliseconds,
|
|
900
|
+
...option ? [option] : [],
|
|
901
|
+
"FIELDS",
|
|
902
|
+
fieldArray.length,
|
|
903
|
+
...fieldArray
|
|
904
|
+
],
|
|
905
|
+
opts
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
// pkg/commands/hpexpireat.ts
|
|
911
|
+
var HPExpireAtCommand = class extends Command {
|
|
912
|
+
constructor(cmd, opts) {
|
|
913
|
+
const [key, fields, timestamp, option] = cmd;
|
|
914
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
915
|
+
super(
|
|
916
|
+
[
|
|
917
|
+
"hpexpireat",
|
|
918
|
+
key,
|
|
919
|
+
timestamp,
|
|
920
|
+
...option ? [option] : [],
|
|
921
|
+
"FIELDS",
|
|
922
|
+
fieldArray.length,
|
|
923
|
+
...fieldArray
|
|
924
|
+
],
|
|
925
|
+
opts
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
// pkg/commands/hpexpiretime.ts
|
|
931
|
+
var HPExpireTimeCommand = class extends Command {
|
|
932
|
+
constructor(cmd, opts) {
|
|
933
|
+
const [key, fields] = cmd;
|
|
934
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
935
|
+
super(["hpexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// pkg/commands/hpttl.ts
|
|
940
|
+
var HPTtlCommand = class extends Command {
|
|
941
|
+
constructor(cmd, opts) {
|
|
942
|
+
const [key, fields] = cmd;
|
|
943
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
944
|
+
super(["hpttl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
|
|
686
948
|
// pkg/commands/hget.ts
|
|
687
949
|
var HGetCommand = class extends Command {
|
|
688
950
|
constructor(cmd, opts) {
|
|
@@ -696,9 +958,9 @@ function deserialize2(result) {
|
|
|
696
958
|
return null;
|
|
697
959
|
}
|
|
698
960
|
const obj = {};
|
|
699
|
-
|
|
700
|
-
const key = result
|
|
701
|
-
const value = result
|
|
961
|
+
for (let i = 0; i < result.length; i += 2) {
|
|
962
|
+
const key = result[i];
|
|
963
|
+
const value = result[i + 1];
|
|
702
964
|
try {
|
|
703
965
|
const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
|
|
704
966
|
obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
|
|
@@ -814,6 +1076,15 @@ var HStrLenCommand = class extends Command {
|
|
|
814
1076
|
}
|
|
815
1077
|
};
|
|
816
1078
|
|
|
1079
|
+
// pkg/commands/httl.ts
|
|
1080
|
+
var HTtlCommand = class extends Command {
|
|
1081
|
+
constructor(cmd, opts) {
|
|
1082
|
+
const [key, fields] = cmd;
|
|
1083
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
1084
|
+
super(["httl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
|
|
817
1088
|
// pkg/commands/hvals.ts
|
|
818
1089
|
var HValsCommand = class extends Command {
|
|
819
1090
|
constructor(cmd, opts) {
|
|
@@ -933,6 +1204,14 @@ var JsonGetCommand = class extends Command {
|
|
|
933
1204
|
}
|
|
934
1205
|
};
|
|
935
1206
|
|
|
1207
|
+
// pkg/commands/json_merge.ts
|
|
1208
|
+
var JsonMergeCommand = class extends Command {
|
|
1209
|
+
constructor(cmd, opts) {
|
|
1210
|
+
const command = ["JSON.MERGE", ...cmd];
|
|
1211
|
+
super(command, opts);
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
|
|
936
1215
|
// pkg/commands/json_mget.ts
|
|
937
1216
|
var JsonMGetCommand = class extends Command {
|
|
938
1217
|
constructor(cmd, opts) {
|
|
@@ -1293,11 +1572,14 @@ var ScanCommand = class extends Command {
|
|
|
1293
1572
|
if (typeof opts?.count === "number") {
|
|
1294
1573
|
command.push("count", opts.count);
|
|
1295
1574
|
}
|
|
1296
|
-
if (opts
|
|
1575
|
+
if (opts && "withType" in opts && opts.withType === true) {
|
|
1576
|
+
command.push("withtype");
|
|
1577
|
+
} else if (opts && "type" in opts && opts.type && opts.type.length > 0) {
|
|
1297
1578
|
command.push("type", opts.type);
|
|
1298
1579
|
}
|
|
1299
1580
|
super(command, {
|
|
1300
|
-
|
|
1581
|
+
// @ts-expect-error ignore types here
|
|
1582
|
+
deserialize: opts?.withType ? deserializeScanWithTypesResponse : deserializeScanResponse,
|
|
1301
1583
|
...cmdOpts
|
|
1302
1584
|
});
|
|
1303
1585
|
}
|
|
@@ -1723,15 +2005,15 @@ var XPendingCommand = class extends Command {
|
|
|
1723
2005
|
function deserialize4(result) {
|
|
1724
2006
|
const obj = {};
|
|
1725
2007
|
for (const e of result) {
|
|
1726
|
-
|
|
1727
|
-
const streamId = e
|
|
1728
|
-
const entries = e
|
|
2008
|
+
for (let i = 0; i < e.length; i += 2) {
|
|
2009
|
+
const streamId = e[i];
|
|
2010
|
+
const entries = e[i + 1];
|
|
1729
2011
|
if (!(streamId in obj)) {
|
|
1730
2012
|
obj[streamId] = {};
|
|
1731
2013
|
}
|
|
1732
|
-
|
|
1733
|
-
const field = entries
|
|
1734
|
-
const value = entries
|
|
2014
|
+
for (let j = 0; j < entries.length; j += 2) {
|
|
2015
|
+
const field = entries[j];
|
|
2016
|
+
const value = entries[j + 1];
|
|
1735
2017
|
try {
|
|
1736
2018
|
obj[streamId][field] = JSON.parse(value);
|
|
1737
2019
|
} catch {
|
|
@@ -1820,15 +2102,15 @@ var XRevRangeCommand = class extends Command {
|
|
|
1820
2102
|
function deserialize5(result) {
|
|
1821
2103
|
const obj = {};
|
|
1822
2104
|
for (const e of result) {
|
|
1823
|
-
|
|
1824
|
-
const streamId = e
|
|
1825
|
-
const entries = e
|
|
2105
|
+
for (let i = 0; i < e.length; i += 2) {
|
|
2106
|
+
const streamId = e[i];
|
|
2107
|
+
const entries = e[i + 1];
|
|
1826
2108
|
if (!(streamId in obj)) {
|
|
1827
2109
|
obj[streamId] = {};
|
|
1828
2110
|
}
|
|
1829
|
-
|
|
1830
|
-
const field = entries
|
|
1831
|
-
const value = entries
|
|
2111
|
+
for (let j = 0; j < entries.length; j += 2) {
|
|
2112
|
+
const field = entries[j];
|
|
2113
|
+
const value = entries[j + 1];
|
|
1832
2114
|
try {
|
|
1833
2115
|
obj[streamId][field] = JSON.parse(value);
|
|
1834
2116
|
} catch {
|
|
@@ -2115,9 +2397,9 @@ var Pipeline = class {
|
|
|
2115
2397
|
this.multiExec = opts.multiExec ?? false;
|
|
2116
2398
|
if (this.commandOptions?.latencyLogging) {
|
|
2117
2399
|
const originalExec = this.exec.bind(this);
|
|
2118
|
-
this.exec = async () => {
|
|
2400
|
+
this.exec = async (options) => {
|
|
2119
2401
|
const start = performance.now();
|
|
2120
|
-
const result = await originalExec();
|
|
2402
|
+
const result = await (options ? originalExec(options) : originalExec());
|
|
2121
2403
|
const end = performance.now();
|
|
2122
2404
|
const loggerResult = (end - start).toFixed(2);
|
|
2123
2405
|
console.log(
|
|
@@ -2127,19 +2409,7 @@ var Pipeline = class {
|
|
|
2127
2409
|
};
|
|
2128
2410
|
}
|
|
2129
2411
|
}
|
|
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 () => {
|
|
2412
|
+
exec = async (options) => {
|
|
2143
2413
|
if (this.commands.length === 0) {
|
|
2144
2414
|
throw new Error("Pipeline is empty");
|
|
2145
2415
|
}
|
|
@@ -2148,7 +2418,12 @@ var Pipeline = class {
|
|
|
2148
2418
|
path,
|
|
2149
2419
|
body: Object.values(this.commands).map((c) => c.command)
|
|
2150
2420
|
});
|
|
2151
|
-
return res.map(({ error, result }, i) => {
|
|
2421
|
+
return options?.keepErrors ? res.map(({ error, result }, i) => {
|
|
2422
|
+
return {
|
|
2423
|
+
error,
|
|
2424
|
+
result: this.commands[i].deserialize(result)
|
|
2425
|
+
};
|
|
2426
|
+
}) : res.map(({ error, result }, i) => {
|
|
2152
2427
|
if (error) {
|
|
2153
2428
|
throw new UpstashError(
|
|
2154
2429
|
`Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}`
|
|
@@ -2234,10 +2509,18 @@ var Pipeline = class {
|
|
|
2234
2509
|
* @see https://redis.io/commands/echo
|
|
2235
2510
|
*/
|
|
2236
2511
|
echo = (...args) => this.chain(new EchoCommand(args, this.commandOptions));
|
|
2512
|
+
/**
|
|
2513
|
+
* @see https://redis.io/commands/eval_ro
|
|
2514
|
+
*/
|
|
2515
|
+
evalRo = (...args) => this.chain(new EvalROCommand(args, this.commandOptions));
|
|
2237
2516
|
/**
|
|
2238
2517
|
* @see https://redis.io/commands/eval
|
|
2239
2518
|
*/
|
|
2240
2519
|
eval = (...args) => this.chain(new EvalCommand(args, this.commandOptions));
|
|
2520
|
+
/**
|
|
2521
|
+
* @see https://redis.io/commands/evalsha_ro
|
|
2522
|
+
*/
|
|
2523
|
+
evalshaRo = (...args) => this.chain(new EvalshaROCommand(args, this.commandOptions));
|
|
2241
2524
|
/**
|
|
2242
2525
|
* @see https://redis.io/commands/evalsha
|
|
2243
2526
|
*/
|
|
@@ -2298,6 +2581,10 @@ var Pipeline = class {
|
|
|
2298
2581
|
* @see https://redis.io/commands/getdel
|
|
2299
2582
|
*/
|
|
2300
2583
|
getdel = (...args) => this.chain(new GetDelCommand(args, this.commandOptions));
|
|
2584
|
+
/**
|
|
2585
|
+
* @see https://redis.io/commands/getex
|
|
2586
|
+
*/
|
|
2587
|
+
getex = (...args) => this.chain(new GetExCommand(args, this.commandOptions));
|
|
2301
2588
|
/**
|
|
2302
2589
|
* @see https://redis.io/commands/getrange
|
|
2303
2590
|
*/
|
|
@@ -2314,6 +2601,42 @@ var Pipeline = class {
|
|
|
2314
2601
|
* @see https://redis.io/commands/hexists
|
|
2315
2602
|
*/
|
|
2316
2603
|
hexists = (...args) => this.chain(new HExistsCommand(args, this.commandOptions));
|
|
2604
|
+
/**
|
|
2605
|
+
* @see https://redis.io/commands/hexpire
|
|
2606
|
+
*/
|
|
2607
|
+
hexpire = (...args) => this.chain(new HExpireCommand(args, this.commandOptions));
|
|
2608
|
+
/**
|
|
2609
|
+
* @see https://redis.io/commands/hexpireat
|
|
2610
|
+
*/
|
|
2611
|
+
hexpireat = (...args) => this.chain(new HExpireAtCommand(args, this.commandOptions));
|
|
2612
|
+
/**
|
|
2613
|
+
* @see https://redis.io/commands/hexpiretime
|
|
2614
|
+
*/
|
|
2615
|
+
hexpiretime = (...args) => this.chain(new HExpireTimeCommand(args, this.commandOptions));
|
|
2616
|
+
/**
|
|
2617
|
+
* @see https://redis.io/commands/httl
|
|
2618
|
+
*/
|
|
2619
|
+
httl = (...args) => this.chain(new HTtlCommand(args, this.commandOptions));
|
|
2620
|
+
/**
|
|
2621
|
+
* @see https://redis.io/commands/hpexpire
|
|
2622
|
+
*/
|
|
2623
|
+
hpexpire = (...args) => this.chain(new HPExpireCommand(args, this.commandOptions));
|
|
2624
|
+
/**
|
|
2625
|
+
* @see https://redis.io/commands/hpexpireat
|
|
2626
|
+
*/
|
|
2627
|
+
hpexpireat = (...args) => this.chain(new HPExpireAtCommand(args, this.commandOptions));
|
|
2628
|
+
/**
|
|
2629
|
+
* @see https://redis.io/commands/hpexpiretime
|
|
2630
|
+
*/
|
|
2631
|
+
hpexpiretime = (...args) => this.chain(new HPExpireTimeCommand(args, this.commandOptions));
|
|
2632
|
+
/**
|
|
2633
|
+
* @see https://redis.io/commands/hpttl
|
|
2634
|
+
*/
|
|
2635
|
+
hpttl = (...args) => this.chain(new HPTtlCommand(args, this.commandOptions));
|
|
2636
|
+
/**
|
|
2637
|
+
* @see https://redis.io/commands/hpersist
|
|
2638
|
+
*/
|
|
2639
|
+
hpersist = (...args) => this.chain(new HPersistCommand(args, this.commandOptions));
|
|
2317
2640
|
/**
|
|
2318
2641
|
* @see https://redis.io/commands/hget
|
|
2319
2642
|
*/
|
|
@@ -2831,6 +3154,10 @@ var Pipeline = class {
|
|
|
2831
3154
|
* @see https://redis.io/commands/json.get
|
|
2832
3155
|
*/
|
|
2833
3156
|
get: (...args) => this.chain(new JsonGetCommand(args, this.commandOptions)),
|
|
3157
|
+
/**
|
|
3158
|
+
* @see https://redis.io/commands/json.merge
|
|
3159
|
+
*/
|
|
3160
|
+
merge: (...args) => this.chain(new JsonMergeCommand(args, this.commandOptions)),
|
|
2834
3161
|
/**
|
|
2835
3162
|
* @see https://redis.io/commands/json.mget
|
|
2836
3163
|
*/
|
|
@@ -2884,6 +3211,24 @@ var Pipeline = class {
|
|
|
2884
3211
|
};
|
|
2885
3212
|
|
|
2886
3213
|
// pkg/auto-pipeline.ts
|
|
3214
|
+
var EXCLUDE_COMMANDS = /* @__PURE__ */ new Set([
|
|
3215
|
+
"scan",
|
|
3216
|
+
"keys",
|
|
3217
|
+
"flushdb",
|
|
3218
|
+
"flushall",
|
|
3219
|
+
"dbsize",
|
|
3220
|
+
"hscan",
|
|
3221
|
+
"hgetall",
|
|
3222
|
+
"hkeys",
|
|
3223
|
+
"lrange",
|
|
3224
|
+
"sscan",
|
|
3225
|
+
"smembers",
|
|
3226
|
+
"xrange",
|
|
3227
|
+
"xrevrange",
|
|
3228
|
+
"zscan",
|
|
3229
|
+
"zrange",
|
|
3230
|
+
"exec"
|
|
3231
|
+
]);
|
|
2887
3232
|
function createAutoPipelineProxy(_redis, json) {
|
|
2888
3233
|
const redis = _redis;
|
|
2889
3234
|
if (!redis.autoPipelineExecutor) {
|
|
@@ -2898,7 +3243,8 @@ function createAutoPipelineProxy(_redis, json) {
|
|
|
2898
3243
|
return createAutoPipelineProxy(redis2, true);
|
|
2899
3244
|
}
|
|
2900
3245
|
const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
|
|
2901
|
-
|
|
3246
|
+
const isCommandExcluded = EXCLUDE_COMMANDS.has(command);
|
|
3247
|
+
if (commandInRedisButNotPipeline || isCommandExcluded) {
|
|
2902
3248
|
return redis2[command];
|
|
2903
3249
|
}
|
|
2904
3250
|
const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
|
|
@@ -2942,7 +3288,7 @@ var AutoPipelineExecutor = class {
|
|
|
2942
3288
|
executeWithPipeline(pipeline);
|
|
2943
3289
|
const pipelineDone = this.deferExecution().then(() => {
|
|
2944
3290
|
if (!this.pipelinePromises.has(pipeline)) {
|
|
2945
|
-
const pipelinePromise = pipeline.exec();
|
|
3291
|
+
const pipelinePromise = pipeline.exec({ keepErrors: true });
|
|
2946
3292
|
this.pipelineCounter += 1;
|
|
2947
3293
|
this.pipelinePromises.set(pipeline, pipelinePromise);
|
|
2948
3294
|
this.activePipeline = null;
|
|
@@ -2950,7 +3296,11 @@ var AutoPipelineExecutor = class {
|
|
|
2950
3296
|
return this.pipelinePromises.get(pipeline);
|
|
2951
3297
|
});
|
|
2952
3298
|
const results = await pipelineDone;
|
|
2953
|
-
|
|
3299
|
+
const commandResult = results[index];
|
|
3300
|
+
if (commandResult.error) {
|
|
3301
|
+
throw new UpstashError(`Command failed: ${commandResult.error}`);
|
|
3302
|
+
}
|
|
3303
|
+
return commandResult.result;
|
|
2954
3304
|
}
|
|
2955
3305
|
async deferExecution() {
|
|
2956
3306
|
await Promise.resolve();
|
|
@@ -2958,28 +3308,230 @@ var AutoPipelineExecutor = class {
|
|
|
2958
3308
|
}
|
|
2959
3309
|
};
|
|
2960
3310
|
|
|
3311
|
+
// pkg/commands/psubscribe.ts
|
|
3312
|
+
var PSubscribeCommand = class extends Command {
|
|
3313
|
+
constructor(cmd, opts) {
|
|
3314
|
+
const sseHeaders = {
|
|
3315
|
+
Accept: "text/event-stream",
|
|
3316
|
+
"Cache-Control": "no-cache",
|
|
3317
|
+
Connection: "keep-alive"
|
|
3318
|
+
};
|
|
3319
|
+
super([], {
|
|
3320
|
+
...opts,
|
|
3321
|
+
headers: sseHeaders,
|
|
3322
|
+
path: ["psubscribe", ...cmd],
|
|
3323
|
+
streamOptions: {
|
|
3324
|
+
isStreaming: true,
|
|
3325
|
+
onMessage: opts?.streamOptions?.onMessage,
|
|
3326
|
+
signal: opts?.streamOptions?.signal
|
|
3327
|
+
}
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
};
|
|
3331
|
+
|
|
3332
|
+
// pkg/commands/subscribe.ts
|
|
3333
|
+
var Subscriber = class extends EventTarget {
|
|
3334
|
+
subscriptions;
|
|
3335
|
+
client;
|
|
3336
|
+
listeners;
|
|
3337
|
+
opts;
|
|
3338
|
+
constructor(client, channels, isPattern = false, opts) {
|
|
3339
|
+
super();
|
|
3340
|
+
this.client = client;
|
|
3341
|
+
this.subscriptions = /* @__PURE__ */ new Map();
|
|
3342
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
3343
|
+
this.opts = opts;
|
|
3344
|
+
for (const channel of channels) {
|
|
3345
|
+
if (isPattern) {
|
|
3346
|
+
this.subscribeToPattern(channel);
|
|
3347
|
+
} else {
|
|
3348
|
+
this.subscribeToChannel(channel);
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
subscribeToChannel(channel) {
|
|
3353
|
+
const controller = new AbortController();
|
|
3354
|
+
const command = new SubscribeCommand([channel], {
|
|
3355
|
+
streamOptions: {
|
|
3356
|
+
signal: controller.signal,
|
|
3357
|
+
onMessage: (data) => this.handleMessage(data, false)
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
3360
|
+
command.exec(this.client).catch((error) => {
|
|
3361
|
+
if (error.name !== "AbortError") {
|
|
3362
|
+
this.dispatchToListeners("error", error);
|
|
3363
|
+
}
|
|
3364
|
+
});
|
|
3365
|
+
this.subscriptions.set(channel, {
|
|
3366
|
+
command,
|
|
3367
|
+
controller,
|
|
3368
|
+
isPattern: false
|
|
3369
|
+
});
|
|
3370
|
+
}
|
|
3371
|
+
subscribeToPattern(pattern) {
|
|
3372
|
+
const controller = new AbortController();
|
|
3373
|
+
const command = new PSubscribeCommand([pattern], {
|
|
3374
|
+
streamOptions: {
|
|
3375
|
+
signal: controller.signal,
|
|
3376
|
+
onMessage: (data) => this.handleMessage(data, true)
|
|
3377
|
+
}
|
|
3378
|
+
});
|
|
3379
|
+
command.exec(this.client).catch((error) => {
|
|
3380
|
+
if (error.name !== "AbortError") {
|
|
3381
|
+
this.dispatchToListeners("error", error);
|
|
3382
|
+
}
|
|
3383
|
+
});
|
|
3384
|
+
this.subscriptions.set(pattern, {
|
|
3385
|
+
command,
|
|
3386
|
+
controller,
|
|
3387
|
+
isPattern: true
|
|
3388
|
+
});
|
|
3389
|
+
}
|
|
3390
|
+
handleMessage(data, isPattern) {
|
|
3391
|
+
const messageData = data.replace(/^data:\s*/, "");
|
|
3392
|
+
const firstCommaIndex = messageData.indexOf(",");
|
|
3393
|
+
const secondCommaIndex = messageData.indexOf(",", firstCommaIndex + 1);
|
|
3394
|
+
const thirdCommaIndex = isPattern ? messageData.indexOf(",", secondCommaIndex + 1) : -1;
|
|
3395
|
+
if (firstCommaIndex !== -1 && secondCommaIndex !== -1) {
|
|
3396
|
+
const type = messageData.slice(0, firstCommaIndex);
|
|
3397
|
+
if (isPattern && type === "pmessage" && thirdCommaIndex !== -1) {
|
|
3398
|
+
const pattern = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
|
|
3399
|
+
const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
|
|
3400
|
+
const messageStr = messageData.slice(thirdCommaIndex + 1);
|
|
3401
|
+
try {
|
|
3402
|
+
const message = this.opts?.automaticDeserialization === false ? messageStr : JSON.parse(messageStr);
|
|
3403
|
+
this.dispatchToListeners("pmessage", { pattern, channel, message });
|
|
3404
|
+
this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
|
|
3407
|
+
}
|
|
3408
|
+
} else {
|
|
3409
|
+
const channel = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
|
|
3410
|
+
const messageStr = messageData.slice(secondCommaIndex + 1);
|
|
3411
|
+
try {
|
|
3412
|
+
if (type === "subscribe" || type === "psubscribe" || type === "unsubscribe" || type === "punsubscribe") {
|
|
3413
|
+
const count = Number.parseInt(messageStr);
|
|
3414
|
+
this.dispatchToListeners(type, count);
|
|
3415
|
+
} else {
|
|
3416
|
+
const message = this.opts?.automaticDeserialization === false ? messageStr : parseWithTryCatch(messageStr);
|
|
3417
|
+
this.dispatchToListeners(type, { channel, message });
|
|
3418
|
+
this.dispatchToListeners(`${type}:${channel}`, { channel, message });
|
|
3419
|
+
}
|
|
3420
|
+
} catch (error) {
|
|
3421
|
+
this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
dispatchToListeners(type, data) {
|
|
3427
|
+
const listeners = this.listeners.get(type);
|
|
3428
|
+
if (listeners) {
|
|
3429
|
+
for (const listener of listeners) {
|
|
3430
|
+
listener(data);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
on(type, listener) {
|
|
3435
|
+
if (!this.listeners.has(type)) {
|
|
3436
|
+
this.listeners.set(type, /* @__PURE__ */ new Set());
|
|
3437
|
+
}
|
|
3438
|
+
this.listeners.get(type)?.add(listener);
|
|
3439
|
+
}
|
|
3440
|
+
removeAllListeners() {
|
|
3441
|
+
this.listeners.clear();
|
|
3442
|
+
}
|
|
3443
|
+
async unsubscribe(channels) {
|
|
3444
|
+
if (channels) {
|
|
3445
|
+
for (const channel of channels) {
|
|
3446
|
+
const subscription = this.subscriptions.get(channel);
|
|
3447
|
+
if (subscription) {
|
|
3448
|
+
try {
|
|
3449
|
+
subscription.controller.abort();
|
|
3450
|
+
} catch {
|
|
3451
|
+
}
|
|
3452
|
+
this.subscriptions.delete(channel);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
} else {
|
|
3456
|
+
for (const subscription of this.subscriptions.values()) {
|
|
3457
|
+
try {
|
|
3458
|
+
subscription.controller.abort();
|
|
3459
|
+
} catch {
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
this.subscriptions.clear();
|
|
3463
|
+
this.removeAllListeners();
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
getSubscribedChannels() {
|
|
3467
|
+
return [...this.subscriptions.keys()];
|
|
3468
|
+
}
|
|
3469
|
+
};
|
|
3470
|
+
var SubscribeCommand = class extends Command {
|
|
3471
|
+
constructor(cmd, opts) {
|
|
3472
|
+
const sseHeaders = {
|
|
3473
|
+
Accept: "text/event-stream",
|
|
3474
|
+
"Cache-Control": "no-cache",
|
|
3475
|
+
Connection: "keep-alive"
|
|
3476
|
+
};
|
|
3477
|
+
super([], {
|
|
3478
|
+
...opts,
|
|
3479
|
+
headers: sseHeaders,
|
|
3480
|
+
path: ["subscribe", ...cmd],
|
|
3481
|
+
streamOptions: {
|
|
3482
|
+
isStreaming: true,
|
|
3483
|
+
onMessage: opts?.streamOptions?.onMessage,
|
|
3484
|
+
signal: opts?.streamOptions?.signal
|
|
3485
|
+
}
|
|
3486
|
+
});
|
|
3487
|
+
}
|
|
3488
|
+
};
|
|
3489
|
+
var parseWithTryCatch = (str) => {
|
|
3490
|
+
try {
|
|
3491
|
+
return JSON.parse(str);
|
|
3492
|
+
} catch {
|
|
3493
|
+
return str;
|
|
3494
|
+
}
|
|
3495
|
+
};
|
|
3496
|
+
|
|
2961
3497
|
// pkg/script.ts
|
|
2962
|
-
import
|
|
2963
|
-
import sha1 from "crypto-js/sha1.js";
|
|
3498
|
+
import { subtle } from "uncrypto";
|
|
2964
3499
|
var Script = class {
|
|
2965
3500
|
script;
|
|
3501
|
+
/**
|
|
3502
|
+
* @deprecated This property is initialized to an empty string and will be set in the init method
|
|
3503
|
+
* asynchronously. Do not use this property immidiately after the constructor.
|
|
3504
|
+
*
|
|
3505
|
+
* This property is only exposed for backwards compatibility and will be removed in the
|
|
3506
|
+
* future major release.
|
|
3507
|
+
*/
|
|
2966
3508
|
sha1;
|
|
2967
3509
|
redis;
|
|
2968
3510
|
constructor(redis, script) {
|
|
2969
3511
|
this.redis = redis;
|
|
2970
|
-
this.sha1 = this.digest(script);
|
|
2971
3512
|
this.script = script;
|
|
3513
|
+
this.sha1 = "";
|
|
3514
|
+
void this.init(script);
|
|
3515
|
+
}
|
|
3516
|
+
/**
|
|
3517
|
+
* Initialize the script by computing its SHA-1 hash.
|
|
3518
|
+
*/
|
|
3519
|
+
async init(script) {
|
|
3520
|
+
if (this.sha1) return;
|
|
3521
|
+
this.sha1 = await this.digest(script);
|
|
2972
3522
|
}
|
|
2973
3523
|
/**
|
|
2974
3524
|
* Send an `EVAL` command to redis.
|
|
2975
3525
|
*/
|
|
2976
3526
|
async eval(keys, args) {
|
|
3527
|
+
await this.init(this.script);
|
|
2977
3528
|
return await this.redis.eval(this.script, keys, args);
|
|
2978
3529
|
}
|
|
2979
3530
|
/**
|
|
2980
3531
|
* Calculates the sha1 hash of the script and then calls `EVALSHA`.
|
|
2981
3532
|
*/
|
|
2982
3533
|
async evalsha(keys, args) {
|
|
3534
|
+
await this.init(this.script);
|
|
2983
3535
|
return await this.redis.evalsha(this.sha1, keys, args);
|
|
2984
3536
|
}
|
|
2985
3537
|
/**
|
|
@@ -2989,6 +3541,7 @@ var Script = class {
|
|
|
2989
3541
|
* Following calls will be able to use the cached script
|
|
2990
3542
|
*/
|
|
2991
3543
|
async exec(keys, args) {
|
|
3544
|
+
await this.init(this.script);
|
|
2992
3545
|
const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
|
|
2993
3546
|
if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
|
|
2994
3547
|
return await this.redis.eval(this.script, keys, args);
|
|
@@ -3000,8 +3553,75 @@ var Script = class {
|
|
|
3000
3553
|
/**
|
|
3001
3554
|
* Compute the sha1 hash of the script and return its hex representation.
|
|
3002
3555
|
*/
|
|
3003
|
-
digest(s) {
|
|
3004
|
-
|
|
3556
|
+
async digest(s) {
|
|
3557
|
+
const data = new TextEncoder().encode(s);
|
|
3558
|
+
const hashBuffer = await subtle.digest("SHA-1", data);
|
|
3559
|
+
const hashArray = [...new Uint8Array(hashBuffer)];
|
|
3560
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3561
|
+
}
|
|
3562
|
+
};
|
|
3563
|
+
|
|
3564
|
+
// pkg/scriptRo.ts
|
|
3565
|
+
import { subtle as subtle2 } from "uncrypto";
|
|
3566
|
+
var ScriptRO = class {
|
|
3567
|
+
script;
|
|
3568
|
+
/**
|
|
3569
|
+
* @deprecated This property is initialized to an empty string and will be set in the init method
|
|
3570
|
+
* asynchronously. Do not use this property immidiately after the constructor.
|
|
3571
|
+
*
|
|
3572
|
+
* This property is only exposed for backwards compatibility and will be removed in the
|
|
3573
|
+
* future major release.
|
|
3574
|
+
*/
|
|
3575
|
+
sha1;
|
|
3576
|
+
redis;
|
|
3577
|
+
constructor(redis, script) {
|
|
3578
|
+
this.redis = redis;
|
|
3579
|
+
this.sha1 = "";
|
|
3580
|
+
this.script = script;
|
|
3581
|
+
void this.init(script);
|
|
3582
|
+
}
|
|
3583
|
+
async init(script) {
|
|
3584
|
+
if (this.sha1) return;
|
|
3585
|
+
this.sha1 = await this.digest(script);
|
|
3586
|
+
}
|
|
3587
|
+
/**
|
|
3588
|
+
* Send an `EVAL_RO` command to redis.
|
|
3589
|
+
*/
|
|
3590
|
+
async evalRo(keys, args) {
|
|
3591
|
+
await this.init(this.script);
|
|
3592
|
+
return await this.redis.evalRo(this.script, keys, args);
|
|
3593
|
+
}
|
|
3594
|
+
/**
|
|
3595
|
+
* Calculates the sha1 hash of the script and then calls `EVALSHA_RO`.
|
|
3596
|
+
*/
|
|
3597
|
+
async evalshaRo(keys, args) {
|
|
3598
|
+
await this.init(this.script);
|
|
3599
|
+
return await this.redis.evalshaRo(this.sha1, keys, args);
|
|
3600
|
+
}
|
|
3601
|
+
/**
|
|
3602
|
+
* Optimistically try to run `EVALSHA_RO` first.
|
|
3603
|
+
* If the script is not loaded in redis, it will fall back and try again with `EVAL_RO`.
|
|
3604
|
+
*
|
|
3605
|
+
* Following calls will be able to use the cached script
|
|
3606
|
+
*/
|
|
3607
|
+
async exec(keys, args) {
|
|
3608
|
+
await this.init(this.script);
|
|
3609
|
+
const res = await this.redis.evalshaRo(this.sha1, keys, args).catch(async (error) => {
|
|
3610
|
+
if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
|
|
3611
|
+
return await this.redis.evalRo(this.script, keys, args);
|
|
3612
|
+
}
|
|
3613
|
+
throw error;
|
|
3614
|
+
});
|
|
3615
|
+
return res;
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Compute the sha1 hash of the script and return its hex representation.
|
|
3619
|
+
*/
|
|
3620
|
+
async digest(s) {
|
|
3621
|
+
const data = new TextEncoder().encode(s);
|
|
3622
|
+
const hashBuffer = await subtle2.digest("SHA-1", data);
|
|
3623
|
+
const hashArray = [...new Uint8Array(hashBuffer)];
|
|
3624
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3005
3625
|
}
|
|
3006
3626
|
};
|
|
3007
3627
|
|
|
@@ -3079,6 +3699,10 @@ var Redis = class {
|
|
|
3079
3699
|
* @see https://redis.io/commands/json.get
|
|
3080
3700
|
*/
|
|
3081
3701
|
get: (...args) => new JsonGetCommand(args, this.opts).exec(this.client),
|
|
3702
|
+
/**
|
|
3703
|
+
* @see https://redis.io/commands/json.merge
|
|
3704
|
+
*/
|
|
3705
|
+
merge: (...args) => new JsonMergeCommand(args, this.opts).exec(this.client),
|
|
3082
3706
|
/**
|
|
3083
3707
|
* @see https://redis.io/commands/json.mget
|
|
3084
3708
|
*/
|
|
@@ -3148,8 +3772,36 @@ var Redis = class {
|
|
|
3148
3772
|
} catch {
|
|
3149
3773
|
}
|
|
3150
3774
|
};
|
|
3151
|
-
|
|
3152
|
-
|
|
3775
|
+
/**
|
|
3776
|
+
* Creates a new script.
|
|
3777
|
+
*
|
|
3778
|
+
* Scripts offer the ability to optimistically try to execute a script without having to send the
|
|
3779
|
+
* entire script to the server. If the script is loaded on the server, it tries again by sending
|
|
3780
|
+
* the entire script. Afterwards, the script is cached on the server.
|
|
3781
|
+
*
|
|
3782
|
+
* @param script - The script to create
|
|
3783
|
+
* @param opts - Optional options to pass to the script `{ readonly?: boolean }`
|
|
3784
|
+
* @returns A new script
|
|
3785
|
+
*
|
|
3786
|
+
* @example
|
|
3787
|
+
* ```ts
|
|
3788
|
+
* const redis = new Redis({...})
|
|
3789
|
+
*
|
|
3790
|
+
* const script = redis.createScript<string>("return ARGV[1];")
|
|
3791
|
+
* const arg1 = await script.eval([], ["Hello World"])
|
|
3792
|
+
* expect(arg1, "Hello World")
|
|
3793
|
+
* ```
|
|
3794
|
+
* @example
|
|
3795
|
+
* ```ts
|
|
3796
|
+
* const redis = new Redis({...})
|
|
3797
|
+
*
|
|
3798
|
+
* const script = redis.createScript<string>("return ARGV[1];", { readonly: true })
|
|
3799
|
+
* const arg1 = await script.evalRo([], ["Hello World"])
|
|
3800
|
+
* expect(arg1, "Hello World")
|
|
3801
|
+
* ```
|
|
3802
|
+
*/
|
|
3803
|
+
createScript(script, opts) {
|
|
3804
|
+
return opts?.readonly ? new ScriptRO(this, script) : new Script(this, script);
|
|
3153
3805
|
}
|
|
3154
3806
|
/**
|
|
3155
3807
|
* Create a new pipeline that allows you to send requests in bulk.
|
|
@@ -3236,14 +3888,26 @@ var Redis = class {
|
|
|
3236
3888
|
* @see https://redis.io/commands/echo
|
|
3237
3889
|
*/
|
|
3238
3890
|
echo = (...args) => new EchoCommand(args, this.opts).exec(this.client);
|
|
3891
|
+
/**
|
|
3892
|
+
* @see https://redis.io/commands/eval_ro
|
|
3893
|
+
*/
|
|
3894
|
+
evalRo = (...args) => new EvalROCommand(args, this.opts).exec(this.client);
|
|
3239
3895
|
/**
|
|
3240
3896
|
* @see https://redis.io/commands/eval
|
|
3241
3897
|
*/
|
|
3242
3898
|
eval = (...args) => new EvalCommand(args, this.opts).exec(this.client);
|
|
3899
|
+
/**
|
|
3900
|
+
* @see https://redis.io/commands/evalsha_ro
|
|
3901
|
+
*/
|
|
3902
|
+
evalshaRo = (...args) => new EvalshaROCommand(args, this.opts).exec(this.client);
|
|
3243
3903
|
/**
|
|
3244
3904
|
* @see https://redis.io/commands/evalsha
|
|
3245
3905
|
*/
|
|
3246
3906
|
evalsha = (...args) => new EvalshaCommand(args, this.opts).exec(this.client);
|
|
3907
|
+
/**
|
|
3908
|
+
* Generic method to execute any Redis command.
|
|
3909
|
+
*/
|
|
3910
|
+
exec = (args) => new ExecCommand(args, this.opts).exec(this.client);
|
|
3247
3911
|
/**
|
|
3248
3912
|
* @see https://redis.io/commands/exists
|
|
3249
3913
|
*/
|
|
@@ -3300,6 +3964,10 @@ var Redis = class {
|
|
|
3300
3964
|
* @see https://redis.io/commands/getdel
|
|
3301
3965
|
*/
|
|
3302
3966
|
getdel = (...args) => new GetDelCommand(args, this.opts).exec(this.client);
|
|
3967
|
+
/**
|
|
3968
|
+
* @see https://redis.io/commands/getex
|
|
3969
|
+
*/
|
|
3970
|
+
getex = (...args) => new GetExCommand(args, this.opts).exec(this.client);
|
|
3303
3971
|
/**
|
|
3304
3972
|
* @see https://redis.io/commands/getrange
|
|
3305
3973
|
*/
|
|
@@ -3316,6 +3984,42 @@ var Redis = class {
|
|
|
3316
3984
|
* @see https://redis.io/commands/hexists
|
|
3317
3985
|
*/
|
|
3318
3986
|
hexists = (...args) => new HExistsCommand(args, this.opts).exec(this.client);
|
|
3987
|
+
/**
|
|
3988
|
+
* @see https://redis.io/commands/hexpire
|
|
3989
|
+
*/
|
|
3990
|
+
hexpire = (...args) => new HExpireCommand(args, this.opts).exec(this.client);
|
|
3991
|
+
/**
|
|
3992
|
+
* @see https://redis.io/commands/hexpireat
|
|
3993
|
+
*/
|
|
3994
|
+
hexpireat = (...args) => new HExpireAtCommand(args, this.opts).exec(this.client);
|
|
3995
|
+
/**
|
|
3996
|
+
* @see https://redis.io/commands/hexpiretime
|
|
3997
|
+
*/
|
|
3998
|
+
hexpiretime = (...args) => new HExpireTimeCommand(args, this.opts).exec(this.client);
|
|
3999
|
+
/**
|
|
4000
|
+
* @see https://redis.io/commands/httl
|
|
4001
|
+
*/
|
|
4002
|
+
httl = (...args) => new HTtlCommand(args, this.opts).exec(this.client);
|
|
4003
|
+
/**
|
|
4004
|
+
* @see https://redis.io/commands/hpexpire
|
|
4005
|
+
*/
|
|
4006
|
+
hpexpire = (...args) => new HPExpireCommand(args, this.opts).exec(this.client);
|
|
4007
|
+
/**
|
|
4008
|
+
* @see https://redis.io/commands/hpexpireat
|
|
4009
|
+
*/
|
|
4010
|
+
hpexpireat = (...args) => new HPExpireAtCommand(args, this.opts).exec(this.client);
|
|
4011
|
+
/**
|
|
4012
|
+
* @see https://redis.io/commands/hpexpiretime
|
|
4013
|
+
*/
|
|
4014
|
+
hpexpiretime = (...args) => new HPExpireTimeCommand(args, this.opts).exec(this.client);
|
|
4015
|
+
/**
|
|
4016
|
+
* @see https://redis.io/commands/hpttl
|
|
4017
|
+
*/
|
|
4018
|
+
hpttl = (...args) => new HPTtlCommand(args, this.opts).exec(this.client);
|
|
4019
|
+
/**
|
|
4020
|
+
* @see https://redis.io/commands/hpersist
|
|
4021
|
+
*/
|
|
4022
|
+
hpersist = (...args) => new HPersistCommand(args, this.opts).exec(this.client);
|
|
3319
4023
|
/**
|
|
3320
4024
|
* @see https://redis.io/commands/hget
|
|
3321
4025
|
*/
|
|
@@ -3484,6 +4188,13 @@ var Redis = class {
|
|
|
3484
4188
|
* @see https://redis.io/commands/psetex
|
|
3485
4189
|
*/
|
|
3486
4190
|
psetex = (key, ttl, value) => new PSetEXCommand([key, ttl, value], this.opts).exec(this.client);
|
|
4191
|
+
/**
|
|
4192
|
+
* @see https://redis.io/commands/psubscribe
|
|
4193
|
+
*/
|
|
4194
|
+
psubscribe = (patterns) => {
|
|
4195
|
+
const patternArray = Array.isArray(patterns) ? patterns : [patterns];
|
|
4196
|
+
return new Subscriber(this.client, patternArray, true, this.opts);
|
|
4197
|
+
};
|
|
3487
4198
|
/**
|
|
3488
4199
|
* @see https://redis.io/commands/pttl
|
|
3489
4200
|
*/
|
|
@@ -3520,10 +4231,9 @@ var Redis = class {
|
|
|
3520
4231
|
* @see https://redis.io/commands/sadd
|
|
3521
4232
|
*/
|
|
3522
4233
|
sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
scan = (...args) => new ScanCommand(args, this.opts).exec(this.client);
|
|
4234
|
+
scan(cursor, opts) {
|
|
4235
|
+
return new ScanCommand([cursor, opts], this.opts).exec(this.client);
|
|
4236
|
+
}
|
|
3527
4237
|
/**
|
|
3528
4238
|
* @see https://redis.io/commands/scard
|
|
3529
4239
|
*/
|
|
@@ -3612,6 +4322,13 @@ var Redis = class {
|
|
|
3612
4322
|
* @see https://redis.io/commands/strlen
|
|
3613
4323
|
*/
|
|
3614
4324
|
strlen = (...args) => new StrLenCommand(args, this.opts).exec(this.client);
|
|
4325
|
+
/**
|
|
4326
|
+
* @see https://redis.io/commands/subscribe
|
|
4327
|
+
*/
|
|
4328
|
+
subscribe = (channels) => {
|
|
4329
|
+
const channelArray = Array.isArray(channels) ? channels : [channels];
|
|
4330
|
+
return new Subscriber(this.client, channelArray, false, this.opts);
|
|
4331
|
+
};
|
|
3615
4332
|
/**
|
|
3616
4333
|
* @see https://redis.io/commands/sunion
|
|
3617
4334
|
*/
|