@upstash/redis 0.0.0-ci.9722909577fc3b6b939d0c937c6ba5f8e8287ee4 → 0.0.0-ci.9784fcbc264b04c2dc251a1935df1597fb95be92-20251208080748

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/nodejs.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,36 +15,98 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // platforms/nodejs.ts
31
21
  var nodejs_exports = {};
32
22
  __export(nodejs_exports, {
33
- Redis: () => Redis2
23
+ Redis: () => Redis2,
24
+ errors: () => error_exports
34
25
  });
35
26
  module.exports = __toCommonJS(nodejs_exports);
36
27
 
37
28
  // pkg/error.ts
29
+ var error_exports = {};
30
+ __export(error_exports, {
31
+ UpstashError: () => UpstashError,
32
+ UpstashJSONParseError: () => UpstashJSONParseError,
33
+ UrlError: () => UrlError
34
+ });
38
35
  var UpstashError = class extends Error {
39
- constructor(message) {
40
- super(message);
36
+ constructor(message, options) {
37
+ super(message, options);
41
38
  this.name = "UpstashError";
42
39
  }
43
40
  };
41
+ var UrlError = class extends Error {
42
+ constructor(url) {
43
+ super(
44
+ `Upstash Redis client was passed an invalid URL. You should pass a URL starting with https. Received: "${url}". `
45
+ );
46
+ this.name = "UrlError";
47
+ }
48
+ };
49
+ var UpstashJSONParseError = class extends UpstashError {
50
+ constructor(body, options) {
51
+ const truncatedBody = body.length > 200 ? body.slice(0, 200) + "..." : body;
52
+ super(`Unable to parse response body: ${truncatedBody}`, options);
53
+ this.name = "UpstashJSONParseError";
54
+ }
55
+ };
56
+
57
+ // pkg/util.ts
58
+ function parseRecursive(obj) {
59
+ const parsed = Array.isArray(obj) ? obj.map((o) => {
60
+ try {
61
+ return parseRecursive(o);
62
+ } catch {
63
+ return o;
64
+ }
65
+ }) : JSON.parse(obj);
66
+ if (typeof parsed === "number" && parsed.toString() !== obj) {
67
+ return obj;
68
+ }
69
+ return parsed;
70
+ }
71
+ function parseResponse(result) {
72
+ try {
73
+ return parseRecursive(result);
74
+ } catch {
75
+ return result;
76
+ }
77
+ }
78
+ function deserializeScanResponse(result) {
79
+ return [result[0], ...parseResponse(result.slice(1))];
80
+ }
81
+ function deserializeScanWithTypesResponse(result) {
82
+ const [cursor, keys] = result;
83
+ const parsedKeys = [];
84
+ for (let i = 0; i < keys.length; i += 2) {
85
+ parsedKeys.push({ key: keys[i], type: keys[i + 1] });
86
+ }
87
+ return [cursor, parsedKeys];
88
+ }
89
+ function mergeHeaders(...headers) {
90
+ const merged = {};
91
+ for (const header of headers) {
92
+ if (!header) continue;
93
+ for (const [key, value] of Object.entries(header)) {
94
+ if (value !== void 0 && value !== null) {
95
+ merged[key] = value;
96
+ }
97
+ }
98
+ }
99
+ return merged;
100
+ }
44
101
 
45
102
  // pkg/http.ts
46
103
  var HttpClient = class {
47
104
  baseUrl;
48
105
  headers;
49
106
  options;
107
+ readYourWrites;
108
+ upstashSyncToken = "";
109
+ hasCredentials;
50
110
  retry;
51
111
  constructor(config) {
52
112
  this.options = {
@@ -54,76 +114,153 @@ var HttpClient = class {
54
114
  agent: config.agent,
55
115
  responseEncoding: config.responseEncoding ?? "base64",
56
116
  // default to base64
57
- cache: config.cache
117
+ cache: config.cache,
118
+ signal: config.signal,
119
+ keepAlive: config.keepAlive ?? true
58
120
  };
59
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
121
+ this.upstashSyncToken = "";
122
+ this.readYourWrites = config.readYourWrites ?? true;
123
+ this.baseUrl = (config.baseUrl || "").replace(/\/$/, "");
124
+ const urlRegex = /^https?:\/\/[^\s#$./?].\S*$/;
125
+ if (this.baseUrl && !urlRegex.test(this.baseUrl)) {
126
+ throw new UrlError(this.baseUrl);
127
+ }
60
128
  this.headers = {
61
129
  "Content-Type": "application/json",
62
130
  ...config.headers
63
131
  };
132
+ this.hasCredentials = Boolean(this.baseUrl && this.headers.authorization.split(" ")[1]);
64
133
  if (this.options.responseEncoding === "base64") {
65
134
  this.headers["Upstash-Encoding"] = "base64";
66
135
  }
67
- if (typeof config?.retry === "boolean" && config?.retry === false) {
68
- this.retry = {
69
- attempts: 1,
70
- backoff: () => 0
71
- };
72
- } else {
73
- this.retry = {
74
- attempts: config?.retry?.retries ?? 5,
75
- backoff: config?.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50)
76
- };
77
- }
136
+ this.retry = typeof config.retry === "boolean" && !config.retry ? {
137
+ attempts: 1,
138
+ backoff: () => 0
139
+ } : {
140
+ attempts: config.retry?.retries ?? 5,
141
+ backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50)
142
+ };
78
143
  }
79
144
  mergeTelemetry(telemetry) {
80
- function merge(obj, key, value) {
81
- if (!value) {
82
- return obj;
83
- }
84
- if (obj[key]) {
85
- obj[key] = [obj[key], value].join(",");
86
- } else {
87
- obj[key] = value;
88
- }
89
- return obj;
90
- }
91
145
  this.headers = merge(this.headers, "Upstash-Telemetry-Runtime", telemetry.runtime);
92
146
  this.headers = merge(this.headers, "Upstash-Telemetry-Platform", telemetry.platform);
93
147
  this.headers = merge(this.headers, "Upstash-Telemetry-Sdk", telemetry.sdk);
94
148
  }
95
149
  async request(req) {
150
+ const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
151
+ const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
152
+ const isEventStream = requestHeaders.Accept === "text/event-stream";
153
+ const signal = req.signal ?? this.options.signal;
154
+ const isSignalFunction = typeof signal === "function";
96
155
  const requestOptions = {
156
+ //@ts-expect-error this should throw due to bun regression
97
157
  cache: this.options.cache,
98
158
  method: "POST",
99
- headers: this.headers,
159
+ headers: requestHeaders,
100
160
  body: JSON.stringify(req.body),
101
- keepalive: true,
102
- agent: this.options?.agent,
161
+ keepalive: this.options.keepAlive,
162
+ agent: this.options.agent,
163
+ signal: isSignalFunction ? signal() : signal,
103
164
  /**
104
165
  * Fastly specific
105
166
  */
106
- backend: this.options?.backend
167
+ backend: this.options.backend
107
168
  };
169
+ if (!this.hasCredentials) {
170
+ console.warn(
171
+ "[Upstash Redis] Redis client was initialized without url or token. Failed to execute command."
172
+ );
173
+ }
174
+ if (this.readYourWrites) {
175
+ const newHeader = this.upstashSyncToken;
176
+ this.headers["upstash-sync-token"] = newHeader;
177
+ }
108
178
  let res = null;
109
179
  let error = null;
110
180
  for (let i = 0; i <= this.retry.attempts; i++) {
111
181
  try {
112
- res = await fetch([this.baseUrl, ...req.path ?? []].join("/"), requestOptions);
182
+ res = await fetch(requestUrl, requestOptions);
113
183
  break;
114
- } catch (err) {
115
- error = err;
116
- await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
184
+ } catch (error_) {
185
+ if (requestOptions.signal?.aborted && isSignalFunction) {
186
+ throw error_;
187
+ } else if (requestOptions.signal?.aborted) {
188
+ const myBlob = new Blob([
189
+ JSON.stringify({ result: requestOptions.signal.reason ?? "Aborted" })
190
+ ]);
191
+ const myOptions = {
192
+ status: 200,
193
+ statusText: requestOptions.signal.reason ?? "Aborted"
194
+ };
195
+ res = new Response(myBlob, myOptions);
196
+ break;
197
+ }
198
+ error = error_;
199
+ if (i < this.retry.attempts) {
200
+ await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
201
+ }
117
202
  }
118
203
  }
119
204
  if (!res) {
120
205
  throw error ?? new Error("Exhausted all retries");
121
206
  }
122
- const body = await res.json();
123
207
  if (!res.ok) {
124
- throw new UpstashError(`${body.error}, command was: ${JSON.stringify(req.body)}`);
208
+ let body2;
209
+ const rawBody2 = await res.text();
210
+ try {
211
+ body2 = JSON.parse(rawBody2);
212
+ } catch (error2) {
213
+ throw new UpstashJSONParseError(rawBody2, { cause: error2 });
214
+ }
215
+ throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
216
+ }
217
+ if (this.readYourWrites) {
218
+ const headers = res.headers;
219
+ this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
220
+ }
221
+ if (isEventStream && req && req.onMessage && res.body) {
222
+ const reader = res.body.getReader();
223
+ const decoder = new TextDecoder();
224
+ (async () => {
225
+ try {
226
+ while (true) {
227
+ const { value, done } = await reader.read();
228
+ if (done) break;
229
+ const chunk = decoder.decode(value);
230
+ const lines = chunk.split("\n");
231
+ for (const line of lines) {
232
+ if (line.startsWith("data: ")) {
233
+ const data = line.slice(6);
234
+ req.onMessage?.(data);
235
+ }
236
+ }
237
+ }
238
+ } catch (error2) {
239
+ if (error2 instanceof Error && error2.name === "AbortError") {
240
+ } else {
241
+ console.error("Stream reading error:", error2);
242
+ }
243
+ } finally {
244
+ try {
245
+ await reader.cancel();
246
+ } catch {
247
+ }
248
+ }
249
+ })();
250
+ return { result: 1 };
251
+ }
252
+ let body;
253
+ const rawBody = await res.text();
254
+ try {
255
+ body = JSON.parse(rawBody);
256
+ } catch (error2) {
257
+ throw new UpstashJSONParseError(rawBody, { cause: error2 });
125
258
  }
126
- if (this.options?.responseEncoding === "base64") {
259
+ if (this.readYourWrites) {
260
+ const headers = res.headers;
261
+ this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
262
+ }
263
+ if (this.options.responseEncoding === "base64") {
127
264
  if (Array.isArray(body)) {
128
265
  return body.map(({ result: result2, error: error2 }) => ({
129
266
  result: decode(result2),
@@ -154,8 +291,9 @@ function base64decode(b64) {
154
291
  function decode(raw) {
155
292
  let result = void 0;
156
293
  switch (typeof raw) {
157
- case "undefined":
294
+ case "undefined": {
158
295
  return raw;
296
+ }
159
297
  case "number": {
160
298
  result = raw;
161
299
  break;
@@ -163,7 +301,7 @@ function decode(raw) {
163
301
  case "object": {
164
302
  if (Array.isArray(raw)) {
165
303
  result = raw.map(
166
- (v) => typeof v === "string" ? base64decode(v) : Array.isArray(v) ? v.map(decode) : v
304
+ (v) => typeof v === "string" ? base64decode(v) : Array.isArray(v) ? v.map((element) => decode(element)) : v
167
305
  );
168
306
  } else {
169
307
  result = null;
@@ -174,49 +312,140 @@ function decode(raw) {
174
312
  result = raw === "OK" ? "OK" : base64decode(raw);
175
313
  break;
176
314
  }
177
- default:
315
+ default: {
178
316
  break;
317
+ }
179
318
  }
180
319
  return result;
181
320
  }
182
-
183
- // pkg/util.ts
184
- function parseRecursive(obj) {
185
- const parsed = Array.isArray(obj) ? obj.map((o) => {
186
- try {
187
- return parseRecursive(o);
188
- } catch {
189
- return o;
190
- }
191
- }) : JSON.parse(obj);
192
- if (typeof parsed === "number" && parsed.toString() !== obj) {
321
+ function merge(obj, key, value) {
322
+ if (!value) {
193
323
  return obj;
194
324
  }
195
- return parsed;
325
+ obj[key] = obj[key] ? [obj[key], value].join(",") : value;
326
+ return obj;
196
327
  }
197
- function parseResponse(result) {
198
- try {
199
- return parseRecursive(result);
200
- } catch {
201
- return result;
202
- }
328
+
329
+ // pkg/auto-pipeline.ts
330
+ var EXCLUDE_COMMANDS = /* @__PURE__ */ new Set([
331
+ "scan",
332
+ "keys",
333
+ "flushdb",
334
+ "flushall",
335
+ "dbsize",
336
+ "hscan",
337
+ "hgetall",
338
+ "hkeys",
339
+ "lrange",
340
+ "sscan",
341
+ "smembers",
342
+ "xrange",
343
+ "xrevrange",
344
+ "zscan",
345
+ "zrange",
346
+ "exec"
347
+ ]);
348
+ function createAutoPipelineProxy(_redis, json) {
349
+ const redis = _redis;
350
+ if (!redis.autoPipelineExecutor) {
351
+ redis.autoPipelineExecutor = new AutoPipelineExecutor(redis);
352
+ }
353
+ return new Proxy(redis, {
354
+ get: (redis2, command) => {
355
+ if (command === "pipelineCounter") {
356
+ return redis2.autoPipelineExecutor.pipelineCounter;
357
+ }
358
+ if (command === "json") {
359
+ return createAutoPipelineProxy(redis2, true);
360
+ }
361
+ const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
362
+ const isCommandExcluded = EXCLUDE_COMMANDS.has(command);
363
+ if (commandInRedisButNotPipeline || isCommandExcluded) {
364
+ return redis2[command];
365
+ }
366
+ const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
367
+ if (isFunction) {
368
+ return (...args) => {
369
+ return redis2.autoPipelineExecutor.withAutoPipeline((pipeline) => {
370
+ if (json) {
371
+ pipeline.json[command](
372
+ ...args
373
+ );
374
+ } else {
375
+ pipeline[command](...args);
376
+ }
377
+ });
378
+ };
379
+ }
380
+ return redis2.autoPipelineExecutor.pipeline[command];
381
+ }
382
+ });
203
383
  }
384
+ var AutoPipelineExecutor = class {
385
+ pipelinePromises = /* @__PURE__ */ new WeakMap();
386
+ activePipeline = null;
387
+ indexInCurrentPipeline = 0;
388
+ redis;
389
+ pipeline;
390
+ // only to make sure that proxy can work
391
+ pipelineCounter = 0;
392
+ // to keep track of how many times a pipeline was executed
393
+ constructor(redis) {
394
+ this.redis = redis;
395
+ this.pipeline = redis.pipeline();
396
+ }
397
+ async withAutoPipeline(executeWithPipeline) {
398
+ const pipeline = this.activePipeline ?? this.redis.pipeline();
399
+ if (!this.activePipeline) {
400
+ this.activePipeline = pipeline;
401
+ this.indexInCurrentPipeline = 0;
402
+ }
403
+ const index = this.indexInCurrentPipeline++;
404
+ executeWithPipeline(pipeline);
405
+ const pipelineDone = this.deferExecution().then(() => {
406
+ if (!this.pipelinePromises.has(pipeline)) {
407
+ const pipelinePromise = pipeline.exec({ keepErrors: true });
408
+ this.pipelineCounter += 1;
409
+ this.pipelinePromises.set(pipeline, pipelinePromise);
410
+ this.activePipeline = null;
411
+ }
412
+ return this.pipelinePromises.get(pipeline);
413
+ });
414
+ const results = await pipelineDone;
415
+ const commandResult = results[index];
416
+ if (commandResult.error) {
417
+ throw new UpstashError(`Command failed: ${commandResult.error}`);
418
+ }
419
+ return commandResult.result;
420
+ }
421
+ async deferExecution() {
422
+ await Promise.resolve();
423
+ await Promise.resolve();
424
+ }
425
+ };
204
426
 
205
427
  // pkg/commands/command.ts
206
428
  var defaultSerializer = (c) => {
207
429
  switch (typeof c) {
208
430
  case "string":
209
431
  case "number":
210
- case "boolean":
432
+ case "boolean": {
211
433
  return c;
212
- default:
434
+ }
435
+ default: {
213
436
  return JSON.stringify(c);
437
+ }
214
438
  }
215
439
  };
216
440
  var Command = class {
217
441
  command;
218
442
  serialize;
219
443
  deserialize;
444
+ headers;
445
+ path;
446
+ onMessage;
447
+ isStreaming;
448
+ signal;
220
449
  /**
221
450
  * Create a new command instance.
222
451
  *
@@ -224,21 +453,45 @@ var Command = class {
224
453
  */
225
454
  constructor(command, opts) {
226
455
  this.serialize = defaultSerializer;
227
- this.deserialize = typeof opts?.automaticDeserialization === "undefined" || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
456
+ this.deserialize = opts?.automaticDeserialization === void 0 || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
228
457
  this.command = command.map((c) => this.serialize(c));
458
+ this.headers = opts?.headers;
459
+ this.path = opts?.path;
460
+ this.onMessage = opts?.streamOptions?.onMessage;
461
+ this.isStreaming = opts?.streamOptions?.isStreaming ?? false;
462
+ this.signal = opts?.streamOptions?.signal;
463
+ if (opts?.latencyLogging) {
464
+ const originalExec = this.exec.bind(this);
465
+ this.exec = async (client) => {
466
+ const start = performance.now();
467
+ const result = await originalExec(client);
468
+ const end = performance.now();
469
+ const loggerResult = (end - start).toFixed(2);
470
+ console.log(
471
+ `Latency for \x1B[38;2;19;185;39m${this.command[0].toString().toUpperCase()}\x1B[0m: \x1B[38;2;0;255;255m${loggerResult} ms\x1B[0m`
472
+ );
473
+ return result;
474
+ };
475
+ }
229
476
  }
230
477
  /**
231
478
  * Execute the command using a client.
232
479
  */
233
480
  async exec(client) {
234
481
  const { result, error } = await client.request({
235
- body: this.command
482
+ body: this.command,
483
+ path: this.path,
484
+ upstashSyncToken: client.upstashSyncToken,
485
+ headers: this.headers,
486
+ onMessage: this.onMessage,
487
+ isStreaming: this.isStreaming,
488
+ signal: this.signal
236
489
  });
237
490
  if (error) {
238
491
  throw new UpstashError(error);
239
492
  }
240
- if (typeof result === "undefined") {
241
- throw new Error("Request did not return a result");
493
+ if (result === void 0) {
494
+ throw new TypeError("Request did not return a result");
242
495
  }
243
496
  return this.deserialize(result);
244
497
  }
@@ -265,6 +518,37 @@ var BitCountCommand = class extends Command {
265
518
  }
266
519
  };
267
520
 
521
+ // pkg/commands/bitfield.ts
522
+ var BitFieldCommand = class {
523
+ constructor(args, client, opts, execOperation = (command) => command.exec(this.client)) {
524
+ this.client = client;
525
+ this.opts = opts;
526
+ this.execOperation = execOperation;
527
+ this.command = ["bitfield", ...args];
528
+ }
529
+ command;
530
+ chain(...args) {
531
+ this.command.push(...args);
532
+ return this;
533
+ }
534
+ get(...args) {
535
+ return this.chain("get", ...args);
536
+ }
537
+ set(...args) {
538
+ return this.chain("set", ...args);
539
+ }
540
+ incrby(...args) {
541
+ return this.chain("incrby", ...args);
542
+ }
543
+ overflow(overflow) {
544
+ return this.chain("overflow", overflow);
545
+ }
546
+ exec() {
547
+ const command = new Command(this.command, this.opts);
548
+ return this.execOperation(command);
549
+ }
550
+ };
551
+
268
552
  // pkg/commands/bitop.ts
269
553
  var BitOpCommand = class extends Command {
270
554
  constructor(cmd, opts) {
@@ -279,6 +563,21 @@ var BitPosCommand = class extends Command {
279
563
  }
280
564
  };
281
565
 
566
+ // pkg/commands/copy.ts
567
+ var CopyCommand = class extends Command {
568
+ constructor([key, destinationKey, opts], commandOptions) {
569
+ super(["COPY", key, destinationKey, ...opts?.replace ? ["REPLACE"] : []], {
570
+ ...commandOptions,
571
+ deserialize(result) {
572
+ if (result > 0) {
573
+ return "COPIED";
574
+ }
575
+ return "NOT_COPIED";
576
+ }
577
+ });
578
+ }
579
+ };
580
+
282
581
  // pkg/commands/dbsize.ts
283
582
  var DBSizeCommand = class extends Command {
284
583
  constructor(opts) {
@@ -314,6 +613,13 @@ var EchoCommand = class extends Command {
314
613
  }
315
614
  };
316
615
 
616
+ // pkg/commands/evalRo.ts
617
+ var EvalROCommand = class extends Command {
618
+ constructor([script, keys, args], opts) {
619
+ super(["eval_ro", script, keys.length, ...keys, ...args ?? []], opts);
620
+ }
621
+ };
622
+
317
623
  // pkg/commands/eval.ts
318
624
  var EvalCommand = class extends Command {
319
625
  constructor([script, keys, args], opts) {
@@ -321,6 +627,13 @@ var EvalCommand = class extends Command {
321
627
  }
322
628
  };
323
629
 
630
+ // pkg/commands/evalshaRo.ts
631
+ var EvalshaROCommand = class extends Command {
632
+ constructor([sha, keys, args], opts) {
633
+ super(["evalsha_ro", sha, keys.length, ...keys, ...args ?? []], opts);
634
+ }
635
+ };
636
+
324
637
  // pkg/commands/evalsha.ts
325
638
  var EvalshaCommand = class extends Command {
326
639
  constructor([sha, keys, args], opts) {
@@ -328,6 +641,14 @@ var EvalshaCommand = class extends Command {
328
641
  }
329
642
  };
330
643
 
644
+ // pkg/commands/exec.ts
645
+ var ExecCommand = class extends Command {
646
+ constructor(cmd, opts) {
647
+ const normalizedCmd = cmd.map((arg) => typeof arg === "string" ? arg : String(arg));
648
+ super(normalizedCmd, opts);
649
+ }
650
+ };
651
+
331
652
  // pkg/commands/exists.ts
332
653
  var ExistsCommand = class extends Command {
333
654
  constructor(cmd, opts) {
@@ -338,7 +659,7 @@ var ExistsCommand = class extends Command {
338
659
  // pkg/commands/expire.ts
339
660
  var ExpireCommand = class extends Command {
340
661
  constructor(cmd, opts) {
341
- super(["expire", ...cmd], opts);
662
+ super(["expire", ...cmd.filter(Boolean)], opts);
342
663
  }
343
664
  };
344
665
 
@@ -400,6 +721,129 @@ var GeoDistCommand = class extends Command {
400
721
  }
401
722
  };
402
723
 
724
+ // pkg/commands/geo_hash.ts
725
+ var GeoHashCommand = class extends Command {
726
+ constructor(cmd, opts) {
727
+ const [key] = cmd;
728
+ const members = Array.isArray(cmd[1]) ? cmd[1] : cmd.slice(1);
729
+ super(["GEOHASH", key, ...members], opts);
730
+ }
731
+ };
732
+
733
+ // pkg/commands/geo_pos.ts
734
+ var GeoPosCommand = class extends Command {
735
+ constructor(cmd, opts) {
736
+ const [key] = cmd;
737
+ const members = Array.isArray(cmd[1]) ? cmd[1] : cmd.slice(1);
738
+ super(["GEOPOS", key, ...members], {
739
+ deserialize: (result) => transform(result),
740
+ ...opts
741
+ });
742
+ }
743
+ };
744
+ function transform(result) {
745
+ const final = [];
746
+ for (const pos of result) {
747
+ if (!pos?.[0] || !pos?.[1]) {
748
+ continue;
749
+ }
750
+ final.push({ lng: Number.parseFloat(pos[0]), lat: Number.parseFloat(pos[1]) });
751
+ }
752
+ return final;
753
+ }
754
+
755
+ // pkg/commands/geo_search.ts
756
+ var GeoSearchCommand = class extends Command {
757
+ constructor([key, centerPoint, shape, order, opts], commandOptions) {
758
+ const command = ["GEOSEARCH", key];
759
+ if (centerPoint.type === "FROMMEMBER" || centerPoint.type === "frommember") {
760
+ command.push(centerPoint.type, centerPoint.member);
761
+ }
762
+ if (centerPoint.type === "FROMLONLAT" || centerPoint.type === "fromlonlat") {
763
+ command.push(centerPoint.type, centerPoint.coordinate.lon, centerPoint.coordinate.lat);
764
+ }
765
+ if (shape.type === "BYRADIUS" || shape.type === "byradius") {
766
+ command.push(shape.type, shape.radius, shape.radiusType);
767
+ }
768
+ if (shape.type === "BYBOX" || shape.type === "bybox") {
769
+ command.push(shape.type, shape.rect.width, shape.rect.height, shape.rectType);
770
+ }
771
+ command.push(order);
772
+ if (opts?.count) {
773
+ command.push("COUNT", opts.count.limit, ...opts.count.any ? ["ANY"] : []);
774
+ }
775
+ const transform2 = (result) => {
776
+ if (!opts?.withCoord && !opts?.withDist && !opts?.withHash) {
777
+ return result.map((member) => {
778
+ try {
779
+ return { member: JSON.parse(member) };
780
+ } catch {
781
+ return { member };
782
+ }
783
+ });
784
+ }
785
+ return result.map((members) => {
786
+ let counter = 1;
787
+ const obj = {};
788
+ try {
789
+ obj.member = JSON.parse(members[0]);
790
+ } catch {
791
+ obj.member = members[0];
792
+ }
793
+ if (opts.withDist) {
794
+ obj.dist = Number.parseFloat(members[counter++]);
795
+ }
796
+ if (opts.withHash) {
797
+ obj.hash = members[counter++].toString();
798
+ }
799
+ if (opts.withCoord) {
800
+ obj.coord = {
801
+ long: Number.parseFloat(members[counter][0]),
802
+ lat: Number.parseFloat(members[counter][1])
803
+ };
804
+ }
805
+ return obj;
806
+ });
807
+ };
808
+ super(
809
+ [
810
+ ...command,
811
+ ...opts?.withCoord ? ["WITHCOORD"] : [],
812
+ ...opts?.withDist ? ["WITHDIST"] : [],
813
+ ...opts?.withHash ? ["WITHHASH"] : []
814
+ ],
815
+ {
816
+ deserialize: transform2,
817
+ ...commandOptions
818
+ }
819
+ );
820
+ }
821
+ };
822
+
823
+ // pkg/commands/geo_search_store.ts
824
+ var GeoSearchStoreCommand = class extends Command {
825
+ constructor([destination, key, centerPoint, shape, order, opts], commandOptions) {
826
+ const command = ["GEOSEARCHSTORE", destination, key];
827
+ if (centerPoint.type === "FROMMEMBER" || centerPoint.type === "frommember") {
828
+ command.push(centerPoint.type, centerPoint.member);
829
+ }
830
+ if (centerPoint.type === "FROMLONLAT" || centerPoint.type === "fromlonlat") {
831
+ command.push(centerPoint.type, centerPoint.coordinate.lon, centerPoint.coordinate.lat);
832
+ }
833
+ if (shape.type === "BYRADIUS" || shape.type === "byradius") {
834
+ command.push(shape.type, shape.radius, shape.radiusType);
835
+ }
836
+ if (shape.type === "BYBOX" || shape.type === "bybox") {
837
+ command.push(shape.type, shape.rect.width, shape.rect.height, shape.rectType);
838
+ }
839
+ command.push(order);
840
+ if (opts?.count) {
841
+ command.push("COUNT", opts.count.limit, ...opts.count.any ? ["ANY"] : []);
842
+ }
843
+ super([...command, ...opts?.storeDist ? ["STOREDIST"] : []], commandOptions);
844
+ }
845
+ };
846
+
403
847
  // pkg/commands/get.ts
404
848
  var GetCommand = class extends Command {
405
849
  constructor(cmd, opts) {
@@ -421,6 +865,27 @@ var GetDelCommand = class extends Command {
421
865
  }
422
866
  };
423
867
 
868
+ // pkg/commands/getex.ts
869
+ var GetExCommand = class extends Command {
870
+ constructor([key, opts], cmdOpts) {
871
+ const command = ["getex", key];
872
+ if (opts) {
873
+ if ("ex" in opts && typeof opts.ex === "number") {
874
+ command.push("ex", opts.ex);
875
+ } else if ("px" in opts && typeof opts.px === "number") {
876
+ command.push("px", opts.px);
877
+ } else if ("exat" in opts && typeof opts.exat === "number") {
878
+ command.push("exat", opts.exat);
879
+ } else if ("pxat" in opts && typeof opts.pxat === "number") {
880
+ command.push("pxat", opts.pxat);
881
+ } else if ("persist" in opts && opts.persist) {
882
+ command.push("persist");
883
+ }
884
+ }
885
+ super(command, cmdOpts);
886
+ }
887
+ };
888
+
424
889
  // pkg/commands/getrange.ts
425
890
  var GetRangeCommand = class extends Command {
426
891
  constructor(cmd, opts) {
@@ -449,6 +914,122 @@ var HExistsCommand = class extends Command {
449
914
  }
450
915
  };
451
916
 
917
+ // pkg/commands/hexpire.ts
918
+ var HExpireCommand = class extends Command {
919
+ constructor(cmd, opts) {
920
+ const [key, fields, seconds, option] = cmd;
921
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
922
+ super(
923
+ [
924
+ "hexpire",
925
+ key,
926
+ seconds,
927
+ ...option ? [option] : [],
928
+ "FIELDS",
929
+ fieldArray.length,
930
+ ...fieldArray
931
+ ],
932
+ opts
933
+ );
934
+ }
935
+ };
936
+
937
+ // pkg/commands/hexpireat.ts
938
+ var HExpireAtCommand = class extends Command {
939
+ constructor(cmd, opts) {
940
+ const [key, fields, timestamp, option] = cmd;
941
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
942
+ super(
943
+ [
944
+ "hexpireat",
945
+ key,
946
+ timestamp,
947
+ ...option ? [option] : [],
948
+ "FIELDS",
949
+ fieldArray.length,
950
+ ...fieldArray
951
+ ],
952
+ opts
953
+ );
954
+ }
955
+ };
956
+
957
+ // pkg/commands/hexpiretime.ts
958
+ var HExpireTimeCommand = class extends Command {
959
+ constructor(cmd, opts) {
960
+ const [key, fields] = cmd;
961
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
962
+ super(["hexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
963
+ }
964
+ };
965
+
966
+ // pkg/commands/hpersist.ts
967
+ var HPersistCommand = class extends Command {
968
+ constructor(cmd, opts) {
969
+ const [key, fields] = cmd;
970
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
971
+ super(["hpersist", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
972
+ }
973
+ };
974
+
975
+ // pkg/commands/hpexpire.ts
976
+ var HPExpireCommand = class extends Command {
977
+ constructor(cmd, opts) {
978
+ const [key, fields, milliseconds, option] = cmd;
979
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
980
+ super(
981
+ [
982
+ "hpexpire",
983
+ key,
984
+ milliseconds,
985
+ ...option ? [option] : [],
986
+ "FIELDS",
987
+ fieldArray.length,
988
+ ...fieldArray
989
+ ],
990
+ opts
991
+ );
992
+ }
993
+ };
994
+
995
+ // pkg/commands/hpexpireat.ts
996
+ var HPExpireAtCommand = class extends Command {
997
+ constructor(cmd, opts) {
998
+ const [key, fields, timestamp, option] = cmd;
999
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1000
+ super(
1001
+ [
1002
+ "hpexpireat",
1003
+ key,
1004
+ timestamp,
1005
+ ...option ? [option] : [],
1006
+ "FIELDS",
1007
+ fieldArray.length,
1008
+ ...fieldArray
1009
+ ],
1010
+ opts
1011
+ );
1012
+ }
1013
+ };
1014
+
1015
+ // pkg/commands/hpexpiretime.ts
1016
+ var HPExpireTimeCommand = class extends Command {
1017
+ constructor(cmd, opts) {
1018
+ const [key, fields] = cmd;
1019
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1020
+ super(["hpexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1021
+ }
1022
+ };
1023
+
1024
+ // pkg/commands/hpttl.ts
1025
+ var HPTtlCommand = class extends Command {
1026
+ constructor(cmd, opts) {
1027
+ const [key, fields] = cmd;
1028
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1029
+ super(["hpttl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1030
+ }
1031
+ };
1032
+
452
1033
  // pkg/commands/hget.ts
453
1034
  var HGetCommand = class extends Command {
454
1035
  constructor(cmd, opts) {
@@ -462,16 +1043,12 @@ function deserialize(result) {
462
1043
  return null;
463
1044
  }
464
1045
  const obj = {};
465
- while (result.length >= 2) {
466
- const key = result.shift();
467
- const value = result.shift();
1046
+ for (let i = 0; i < result.length; i += 2) {
1047
+ const key = result[i];
1048
+ const value = result[i + 1];
468
1049
  try {
469
- const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(value);
470
- if (valueIsNumberAndNotSafeInteger) {
471
- obj[key] = value;
472
- } else {
473
- obj[key] = JSON.parse(value);
474
- }
1050
+ const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
1051
+ obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
475
1052
  } catch {
476
1053
  obj[key] = value;
477
1054
  }
@@ -517,15 +1094,15 @@ var HLenCommand = class extends Command {
517
1094
 
518
1095
  // pkg/commands/hmget.ts
519
1096
  function deserialize2(fields, result) {
520
- if (result.length === 0 || result.every((field) => field === null)) {
1097
+ if (result.every((field) => field === null)) {
521
1098
  return null;
522
1099
  }
523
1100
  const obj = {};
524
- for (let i = 0; i < fields.length; i++) {
1101
+ for (const [i, field] of fields.entries()) {
525
1102
  try {
526
- obj[fields[i]] = JSON.parse(result[i]);
1103
+ obj[field] = JSON.parse(result[i]);
527
1104
  } catch {
528
- obj[fields[i]] = result[i];
1105
+ obj[field] = result[i];
529
1106
  }
530
1107
  }
531
1108
  return obj;
@@ -552,9 +1129,9 @@ function deserialize3(result) {
552
1129
  return null;
553
1130
  }
554
1131
  const obj = {};
555
- while (result.length >= 2) {
556
- const key = result.shift();
557
- const value = result.shift();
1132
+ for (let i = 0; i < result.length; i += 2) {
1133
+ const key = result[i];
1134
+ const value = result[i + 1];
558
1135
  try {
559
1136
  obj[key] = JSON.parse(value);
560
1137
  } catch {
@@ -573,7 +1150,7 @@ var HRandFieldCommand = class extends Command {
573
1150
  command.push("WITHVALUES");
574
1151
  }
575
1152
  super(command, {
576
- // @ts-ignore TODO:
1153
+ // @ts-expect-error to silence compiler
577
1154
  deserialize: cmd[2] ? (result) => deserialize3(result) : opts?.deserialize,
578
1155
  ...opts
579
1156
  });
@@ -590,7 +1167,10 @@ var HScanCommand = class extends Command {
590
1167
  if (typeof cmdOpts?.count === "number") {
591
1168
  command.push("count", cmdOpts.count);
592
1169
  }
593
- super(command, opts);
1170
+ super(command, {
1171
+ deserialize: deserializeScanResponse,
1172
+ ...opts
1173
+ });
594
1174
  }
595
1175
  };
596
1176
 
@@ -615,6 +1195,15 @@ var HStrLenCommand = class extends Command {
615
1195
  }
616
1196
  };
617
1197
 
1198
+ // pkg/commands/httl.ts
1199
+ var HTtlCommand = class extends Command {
1200
+ constructor(cmd, opts) {
1201
+ const [key, fields] = cmd;
1202
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1203
+ super(["httl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1204
+ }
1205
+ };
1206
+
618
1207
  // pkg/commands/hvals.ts
619
1208
  var HValsCommand = class extends Command {
620
1209
  constructor(cmd, opts) {
@@ -734,6 +1323,14 @@ var JsonGetCommand = class extends Command {
734
1323
  }
735
1324
  };
736
1325
 
1326
+ // pkg/commands/json_merge.ts
1327
+ var JsonMergeCommand = class extends Command {
1328
+ constructor(cmd, opts) {
1329
+ const command = ["JSON.MERGE", ...cmd];
1330
+ super(command, opts);
1331
+ }
1332
+ };
1333
+
737
1334
  // pkg/commands/json_mget.ts
738
1335
  var JsonMGetCommand = class extends Command {
739
1336
  constructor(cmd, opts) {
@@ -741,6 +1338,17 @@ var JsonMGetCommand = class extends Command {
741
1338
  }
742
1339
  };
743
1340
 
1341
+ // pkg/commands/json_mset.ts
1342
+ var JsonMSetCommand = class extends Command {
1343
+ constructor(cmd, opts) {
1344
+ const command = ["JSON.MSET"];
1345
+ for (const c of cmd) {
1346
+ command.push(c.key, c.path, c.value);
1347
+ }
1348
+ super(command, opts);
1349
+ }
1350
+ };
1351
+
744
1352
  // pkg/commands/json_numincrby.ts
745
1353
  var JsonNumIncrByCommand = class extends Command {
746
1354
  constructor(cmd, opts) {
@@ -854,6 +1462,14 @@ var LMoveCommand = class extends Command {
854
1462
  }
855
1463
  };
856
1464
 
1465
+ // pkg/commands/lmpop.ts
1466
+ var LmPopCommand = class extends Command {
1467
+ constructor(cmd, opts) {
1468
+ const [numkeys, keys, direction, count] = cmd;
1469
+ super(["LMPOP", numkeys, ...keys, direction, ...count ? ["COUNT", count] : []], opts);
1470
+ }
1471
+ };
1472
+
857
1473
  // pkg/commands/lpop.ts
858
1474
  var LPopCommand = class extends Command {
859
1475
  constructor(cmd, opts) {
@@ -938,7 +1554,7 @@ var MSetCommand = class extends Command {
938
1554
  // pkg/commands/msetnx.ts
939
1555
  var MSetNXCommand = class extends Command {
940
1556
  constructor([kv], opts) {
941
- super(["msetnx", ...Object.entries(kv).flatMap((_) => _)], opts);
1557
+ super(["msetnx", ...Object.entries(kv).flat()], opts);
942
1558
  }
943
1559
  };
944
1560
 
@@ -963,11 +1579,32 @@ var PExpireAtCommand = class extends Command {
963
1579
  }
964
1580
  };
965
1581
 
1582
+ // pkg/commands/pfadd.ts
1583
+ var PfAddCommand = class extends Command {
1584
+ constructor(cmd, opts) {
1585
+ super(["pfadd", ...cmd], opts);
1586
+ }
1587
+ };
1588
+
1589
+ // pkg/commands/pfcount.ts
1590
+ var PfCountCommand = class extends Command {
1591
+ constructor(cmd, opts) {
1592
+ super(["pfcount", ...cmd], opts);
1593
+ }
1594
+ };
1595
+
1596
+ // pkg/commands/pfmerge.ts
1597
+ var PfMergeCommand = class extends Command {
1598
+ constructor(cmd, opts) {
1599
+ super(["pfmerge", ...cmd], opts);
1600
+ }
1601
+ };
1602
+
966
1603
  // pkg/commands/ping.ts
967
1604
  var PingCommand = class extends Command {
968
1605
  constructor(cmd, opts) {
969
1606
  const command = ["ping"];
970
- if (typeof cmd !== "undefined" && typeof cmd[0] !== "undefined") {
1607
+ if (cmd?.[0] !== void 0) {
971
1608
  command.push(cmd[0]);
972
1609
  }
973
1610
  super(command, opts);
@@ -1054,10 +1691,16 @@ var ScanCommand = class extends Command {
1054
1691
  if (typeof opts?.count === "number") {
1055
1692
  command.push("count", opts.count);
1056
1693
  }
1057
- if (opts?.type && opts.type.length > 0) {
1694
+ if (opts && "withType" in opts && opts.withType === true) {
1695
+ command.push("withtype");
1696
+ } else if (opts && "type" in opts && opts.type && opts.type.length > 0) {
1058
1697
  command.push("type", opts.type);
1059
1698
  }
1060
- super(command, cmdOpts);
1699
+ super(command, {
1700
+ // @ts-expect-error ignore types here
1701
+ deserialize: opts?.withType ? deserializeScanWithTypesResponse : deserializeScanResponse,
1702
+ ...cmdOpts
1703
+ });
1061
1704
  }
1062
1705
  };
1063
1706
 
@@ -1250,7 +1893,10 @@ var SScanCommand = class extends Command {
1250
1893
  if (typeof opts?.count === "number") {
1251
1894
  command.push("count", opts.count);
1252
1895
  }
1253
- super(command, cmdOpts);
1896
+ super(command, {
1897
+ deserialize: deserializeScanResponse,
1898
+ ...cmdOpts
1899
+ });
1254
1900
  }
1255
1901
  };
1256
1902
 
@@ -1310,6 +1956,14 @@ var UnlinkCommand = class extends Command {
1310
1956
  }
1311
1957
  };
1312
1958
 
1959
+ // pkg/commands/xack.ts
1960
+ var XAckCommand = class extends Command {
1961
+ constructor([key, group, id], opts) {
1962
+ const ids = Array.isArray(id) ? [...id] : [id];
1963
+ super(["XACK", key, group, ...ids], opts);
1964
+ }
1965
+ };
1966
+
1313
1967
  // pkg/commands/xadd.ts
1314
1968
  var XAddCommand = class extends Command {
1315
1969
  constructor([key, id, entries, opts], commandOptions) {
@@ -1320,7 +1974,7 @@ var XAddCommand = class extends Command {
1320
1974
  }
1321
1975
  if (opts.trim) {
1322
1976
  command.push(opts.trim.type, opts.trim.comparison, opts.trim.threshold);
1323
- if (typeof opts.trim.limit !== "undefined") {
1977
+ if (opts.trim.limit !== void 0) {
1324
1978
  command.push("LIMIT", opts.trim.limit);
1325
1979
  }
1326
1980
  }
@@ -1333,19 +1987,152 @@ var XAddCommand = class extends Command {
1333
1987
  }
1334
1988
  };
1335
1989
 
1990
+ // pkg/commands/xautoclaim.ts
1991
+ var XAutoClaim = class extends Command {
1992
+ constructor([key, group, consumer, minIdleTime, start, options], opts) {
1993
+ const commands = [];
1994
+ if (options?.count) {
1995
+ commands.push("COUNT", options.count);
1996
+ }
1997
+ if (options?.justId) {
1998
+ commands.push("JUSTID");
1999
+ }
2000
+ super(["XAUTOCLAIM", key, group, consumer, minIdleTime, start, ...commands], opts);
2001
+ }
2002
+ };
2003
+
2004
+ // pkg/commands/xclaim.ts
2005
+ var XClaimCommand = class extends Command {
2006
+ constructor([key, group, consumer, minIdleTime, id, options], opts) {
2007
+ const ids = Array.isArray(id) ? [...id] : [id];
2008
+ const commands = [];
2009
+ if (options?.idleMS) {
2010
+ commands.push("IDLE", options.idleMS);
2011
+ }
2012
+ if (options?.idleMS) {
2013
+ commands.push("TIME", options.timeMS);
2014
+ }
2015
+ if (options?.retryCount) {
2016
+ commands.push("RETRYCOUNT", options.retryCount);
2017
+ }
2018
+ if (options?.force) {
2019
+ commands.push("FORCE");
2020
+ }
2021
+ if (options?.justId) {
2022
+ commands.push("JUSTID");
2023
+ }
2024
+ if (options?.lastId) {
2025
+ commands.push("LASTID", options.lastId);
2026
+ }
2027
+ super(["XCLAIM", key, group, consumer, minIdleTime, ...ids, ...commands], opts);
2028
+ }
2029
+ };
2030
+
2031
+ // pkg/commands/xdel.ts
2032
+ var XDelCommand = class extends Command {
2033
+ constructor([key, ids], opts) {
2034
+ const cmds = Array.isArray(ids) ? [...ids] : [ids];
2035
+ super(["XDEL", key, ...cmds], opts);
2036
+ }
2037
+ };
2038
+
2039
+ // pkg/commands/xgroup.ts
2040
+ var XGroupCommand = class extends Command {
2041
+ constructor([key, opts], commandOptions) {
2042
+ const command = ["XGROUP"];
2043
+ switch (opts.type) {
2044
+ case "CREATE": {
2045
+ command.push("CREATE", key, opts.group, opts.id);
2046
+ if (opts.options) {
2047
+ if (opts.options.MKSTREAM) {
2048
+ command.push("MKSTREAM");
2049
+ }
2050
+ if (opts.options.ENTRIESREAD !== void 0) {
2051
+ command.push("ENTRIESREAD", opts.options.ENTRIESREAD.toString());
2052
+ }
2053
+ }
2054
+ break;
2055
+ }
2056
+ case "CREATECONSUMER": {
2057
+ command.push("CREATECONSUMER", key, opts.group, opts.consumer);
2058
+ break;
2059
+ }
2060
+ case "DELCONSUMER": {
2061
+ command.push("DELCONSUMER", key, opts.group, opts.consumer);
2062
+ break;
2063
+ }
2064
+ case "DESTROY": {
2065
+ command.push("DESTROY", key, opts.group);
2066
+ break;
2067
+ }
2068
+ case "SETID": {
2069
+ command.push("SETID", key, opts.group, opts.id);
2070
+ if (opts.options?.ENTRIESREAD !== void 0) {
2071
+ command.push("ENTRIESREAD", opts.options.ENTRIESREAD.toString());
2072
+ }
2073
+ break;
2074
+ }
2075
+ default: {
2076
+ throw new Error("Invalid XGROUP");
2077
+ }
2078
+ }
2079
+ super(command, commandOptions);
2080
+ }
2081
+ };
2082
+
2083
+ // pkg/commands/xinfo.ts
2084
+ var XInfoCommand = class extends Command {
2085
+ constructor([key, options], opts) {
2086
+ const cmds = [];
2087
+ if (options.type === "CONSUMERS") {
2088
+ cmds.push("CONSUMERS", key, options.group);
2089
+ } else {
2090
+ cmds.push("GROUPS", key);
2091
+ }
2092
+ super(["XINFO", ...cmds], opts);
2093
+ }
2094
+ };
2095
+
2096
+ // pkg/commands/xlen.ts
2097
+ var XLenCommand = class extends Command {
2098
+ constructor(cmd, opts) {
2099
+ super(["XLEN", ...cmd], opts);
2100
+ }
2101
+ };
2102
+
2103
+ // pkg/commands/xpending.ts
2104
+ var XPendingCommand = class extends Command {
2105
+ constructor([key, group, start, end, count, options], opts) {
2106
+ const consumers = options?.consumer === void 0 ? [] : Array.isArray(options.consumer) ? [...options.consumer] : [options.consumer];
2107
+ super(
2108
+ [
2109
+ "XPENDING",
2110
+ key,
2111
+ group,
2112
+ ...options?.idleTime ? ["IDLE", options.idleTime] : [],
2113
+ start,
2114
+ end,
2115
+ count,
2116
+ ...consumers
2117
+ ],
2118
+ opts
2119
+ );
2120
+ }
2121
+ };
2122
+
1336
2123
  // pkg/commands/xrange.ts
1337
2124
  function deserialize4(result) {
1338
2125
  const obj = {};
1339
2126
  for (const e of result) {
1340
- while (e.length >= 2) {
1341
- const streamId = e.shift();
1342
- const entries = e.shift();
2127
+ for (let i = 0; i < e.length; i += 2) {
2128
+ const streamId = e[i];
2129
+ const entries = e[i + 1];
1343
2130
  if (!(streamId in obj)) {
1344
2131
  obj[streamId] = {};
1345
2132
  }
1346
- while (entries.length >= 2) {
1347
- const field = entries.shift();
1348
- const value = entries.shift();
2133
+ for (let j = 0; j < entries.length; j += 2) {
2134
+ const field = entries[j];
2135
+ const value = entries[j + 1];
1349
2136
  try {
1350
2137
  obj[streamId][field] = JSON.parse(value);
1351
2138
  } catch {
@@ -1369,6 +2156,99 @@ var XRangeCommand = class extends Command {
1369
2156
  }
1370
2157
  };
1371
2158
 
2159
+ // pkg/commands/xread.ts
2160
+ var UNBALANCED_XREAD_ERR = "ERR Unbalanced XREAD list of streams: for each stream key an ID or '$' must be specified";
2161
+ var XReadCommand = class extends Command {
2162
+ constructor([key, id, options], opts) {
2163
+ if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
2164
+ throw new Error(UNBALANCED_XREAD_ERR);
2165
+ }
2166
+ const commands = [];
2167
+ if (typeof options?.count === "number") {
2168
+ commands.push("COUNT", options.count);
2169
+ }
2170
+ if (typeof options?.blockMS === "number") {
2171
+ commands.push("BLOCK", options.blockMS);
2172
+ }
2173
+ commands.push(
2174
+ "STREAMS",
2175
+ ...Array.isArray(key) ? [...key] : [key],
2176
+ ...Array.isArray(id) ? [...id] : [id]
2177
+ );
2178
+ super(["XREAD", ...commands], opts);
2179
+ }
2180
+ };
2181
+
2182
+ // pkg/commands/xreadgroup.ts
2183
+ var UNBALANCED_XREADGROUP_ERR = "ERR Unbalanced XREADGROUP list of streams: for each stream key an ID or '$' must be specified";
2184
+ var XReadGroupCommand = class extends Command {
2185
+ constructor([group, consumer, key, id, options], opts) {
2186
+ if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
2187
+ throw new Error(UNBALANCED_XREADGROUP_ERR);
2188
+ }
2189
+ const commands = [];
2190
+ if (typeof options?.count === "number") {
2191
+ commands.push("COUNT", options.count);
2192
+ }
2193
+ if (typeof options?.blockMS === "number") {
2194
+ commands.push("BLOCK", options.blockMS);
2195
+ }
2196
+ if (typeof options?.NOACK === "boolean" && options.NOACK) {
2197
+ commands.push("NOACK");
2198
+ }
2199
+ commands.push(
2200
+ "STREAMS",
2201
+ ...Array.isArray(key) ? [...key] : [key],
2202
+ ...Array.isArray(id) ? [...id] : [id]
2203
+ );
2204
+ super(["XREADGROUP", "GROUP", group, consumer, ...commands], opts);
2205
+ }
2206
+ };
2207
+
2208
+ // pkg/commands/xrevrange.ts
2209
+ var XRevRangeCommand = class extends Command {
2210
+ constructor([key, end, start, count], opts) {
2211
+ const command = ["XREVRANGE", key, end, start];
2212
+ if (typeof count === "number") {
2213
+ command.push("COUNT", count);
2214
+ }
2215
+ super(command, {
2216
+ deserialize: (result) => deserialize5(result),
2217
+ ...opts
2218
+ });
2219
+ }
2220
+ };
2221
+ function deserialize5(result) {
2222
+ const obj = {};
2223
+ for (const e of result) {
2224
+ for (let i = 0; i < e.length; i += 2) {
2225
+ const streamId = e[i];
2226
+ const entries = e[i + 1];
2227
+ if (!(streamId in obj)) {
2228
+ obj[streamId] = {};
2229
+ }
2230
+ for (let j = 0; j < entries.length; j += 2) {
2231
+ const field = entries[j];
2232
+ const value = entries[j + 1];
2233
+ try {
2234
+ obj[streamId][field] = JSON.parse(value);
2235
+ } catch {
2236
+ obj[streamId][field] = value;
2237
+ }
2238
+ }
2239
+ }
2240
+ }
2241
+ return obj;
2242
+ }
2243
+
2244
+ // pkg/commands/xtrim.ts
2245
+ var XTrimCommand = class extends Command {
2246
+ constructor([key, options], opts) {
2247
+ const { limit, strategy, threshold, exactness = "~" } = options;
2248
+ super(["XTRIM", key, strategy, exactness, threshold, ...limit ? ["LIMIT", limit] : []], opts);
2249
+ }
2250
+ };
2251
+
1372
2252
  // pkg/commands/zadd.ts
1373
2253
  var ZAddCommand = class extends Command {
1374
2254
  constructor([key, arg1, ...arg2], opts) {
@@ -1384,6 +2264,11 @@ var ZAddCommand = class extends Command {
1384
2264
  if ("incr" in arg1 && arg1.incr) {
1385
2265
  command.push("incr");
1386
2266
  }
2267
+ if ("lt" in arg1 && arg1.lt) {
2268
+ command.push("lt");
2269
+ } else if ("gt" in arg1 && arg1.gt) {
2270
+ command.push("gt");
2271
+ }
1387
2272
  if ("score" in arg1 && "member" in arg1) {
1388
2273
  command.push(arg1.score, arg1.member);
1389
2274
  }
@@ -1478,7 +2363,7 @@ var ZRangeCommand = class extends Command {
1478
2363
  if (opts?.rev) {
1479
2364
  command.push("rev");
1480
2365
  }
1481
- if (typeof opts?.count !== "undefined" && typeof opts?.offset !== "undefined") {
2366
+ if (opts?.count !== void 0 && opts.offset !== void 0) {
1482
2367
  command.push("limit", opts.offset, opts.count);
1483
2368
  }
1484
2369
  if (opts?.withScores) {
@@ -1540,7 +2425,10 @@ var ZScanCommand = class extends Command {
1540
2425
  if (typeof opts?.count === "number") {
1541
2426
  command.push("count", opts.count);
1542
2427
  }
1543
- super(command, cmdOpts);
2428
+ super(command, {
2429
+ deserialize: deserializeScanResponse,
2430
+ ...cmdOpts
2431
+ });
1544
2432
  }
1545
2433
  };
1546
2434
 
@@ -1569,7 +2457,7 @@ var ZUnionCommand = class extends Command {
1569
2457
  if ("aggregate" in opts) {
1570
2458
  command.push("aggregate", opts.aggregate);
1571
2459
  }
1572
- if (opts?.withScores) {
2460
+ if (opts.withScores) {
1573
2461
  command.push("withscores");
1574
2462
  }
1575
2463
  }
@@ -1600,6 +2488,192 @@ var ZUnionStoreCommand = class extends Command {
1600
2488
  }
1601
2489
  };
1602
2490
 
2491
+ // pkg/commands/psubscribe.ts
2492
+ var PSubscribeCommand = class extends Command {
2493
+ constructor(cmd, opts) {
2494
+ const sseHeaders = {
2495
+ Accept: "text/event-stream",
2496
+ "Cache-Control": "no-cache",
2497
+ Connection: "keep-alive"
2498
+ };
2499
+ super([], {
2500
+ ...opts,
2501
+ headers: sseHeaders,
2502
+ path: ["psubscribe", ...cmd],
2503
+ streamOptions: {
2504
+ isStreaming: true,
2505
+ onMessage: opts?.streamOptions?.onMessage,
2506
+ signal: opts?.streamOptions?.signal
2507
+ }
2508
+ });
2509
+ }
2510
+ };
2511
+
2512
+ // pkg/commands/subscribe.ts
2513
+ var Subscriber = class extends EventTarget {
2514
+ subscriptions;
2515
+ client;
2516
+ listeners;
2517
+ opts;
2518
+ constructor(client, channels, isPattern = false, opts) {
2519
+ super();
2520
+ this.client = client;
2521
+ this.subscriptions = /* @__PURE__ */ new Map();
2522
+ this.listeners = /* @__PURE__ */ new Map();
2523
+ this.opts = opts;
2524
+ for (const channel of channels) {
2525
+ if (isPattern) {
2526
+ this.subscribeToPattern(channel);
2527
+ } else {
2528
+ this.subscribeToChannel(channel);
2529
+ }
2530
+ }
2531
+ }
2532
+ subscribeToChannel(channel) {
2533
+ const controller = new AbortController();
2534
+ const command = new SubscribeCommand([channel], {
2535
+ streamOptions: {
2536
+ signal: controller.signal,
2537
+ onMessage: (data) => this.handleMessage(data, false)
2538
+ }
2539
+ });
2540
+ command.exec(this.client).catch((error) => {
2541
+ if (error.name !== "AbortError") {
2542
+ this.dispatchToListeners("error", error);
2543
+ }
2544
+ });
2545
+ this.subscriptions.set(channel, {
2546
+ command,
2547
+ controller,
2548
+ isPattern: false
2549
+ });
2550
+ }
2551
+ subscribeToPattern(pattern) {
2552
+ const controller = new AbortController();
2553
+ const command = new PSubscribeCommand([pattern], {
2554
+ streamOptions: {
2555
+ signal: controller.signal,
2556
+ onMessage: (data) => this.handleMessage(data, true)
2557
+ }
2558
+ });
2559
+ command.exec(this.client).catch((error) => {
2560
+ if (error.name !== "AbortError") {
2561
+ this.dispatchToListeners("error", error);
2562
+ }
2563
+ });
2564
+ this.subscriptions.set(pattern, {
2565
+ command,
2566
+ controller,
2567
+ isPattern: true
2568
+ });
2569
+ }
2570
+ handleMessage(data, isPattern) {
2571
+ const messageData = data.replace(/^data:\s*/, "");
2572
+ const firstCommaIndex = messageData.indexOf(",");
2573
+ const secondCommaIndex = messageData.indexOf(",", firstCommaIndex + 1);
2574
+ const thirdCommaIndex = isPattern ? messageData.indexOf(",", secondCommaIndex + 1) : -1;
2575
+ if (firstCommaIndex !== -1 && secondCommaIndex !== -1) {
2576
+ const type = messageData.slice(0, firstCommaIndex);
2577
+ if (isPattern && type === "pmessage" && thirdCommaIndex !== -1) {
2578
+ const pattern = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
2579
+ const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
2580
+ const messageStr = messageData.slice(thirdCommaIndex + 1);
2581
+ try {
2582
+ const message = this.opts?.automaticDeserialization === false ? messageStr : JSON.parse(messageStr);
2583
+ this.dispatchToListeners("pmessage", { pattern, channel, message });
2584
+ this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
2585
+ } catch (error) {
2586
+ this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
2587
+ }
2588
+ } else {
2589
+ const channel = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
2590
+ const messageStr = messageData.slice(secondCommaIndex + 1);
2591
+ try {
2592
+ if (type === "subscribe" || type === "psubscribe" || type === "unsubscribe" || type === "punsubscribe") {
2593
+ const count = Number.parseInt(messageStr);
2594
+ this.dispatchToListeners(type, count);
2595
+ } else {
2596
+ const message = this.opts?.automaticDeserialization === false ? messageStr : parseWithTryCatch(messageStr);
2597
+ this.dispatchToListeners(type, { channel, message });
2598
+ this.dispatchToListeners(`${type}:${channel}`, { channel, message });
2599
+ }
2600
+ } catch (error) {
2601
+ this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
2602
+ }
2603
+ }
2604
+ }
2605
+ }
2606
+ dispatchToListeners(type, data) {
2607
+ const listeners = this.listeners.get(type);
2608
+ if (listeners) {
2609
+ for (const listener of listeners) {
2610
+ listener(data);
2611
+ }
2612
+ }
2613
+ }
2614
+ on(type, listener) {
2615
+ if (!this.listeners.has(type)) {
2616
+ this.listeners.set(type, /* @__PURE__ */ new Set());
2617
+ }
2618
+ this.listeners.get(type)?.add(listener);
2619
+ }
2620
+ removeAllListeners() {
2621
+ this.listeners.clear();
2622
+ }
2623
+ async unsubscribe(channels) {
2624
+ if (channels) {
2625
+ for (const channel of channels) {
2626
+ const subscription = this.subscriptions.get(channel);
2627
+ if (subscription) {
2628
+ try {
2629
+ subscription.controller.abort();
2630
+ } catch {
2631
+ }
2632
+ this.subscriptions.delete(channel);
2633
+ }
2634
+ }
2635
+ } else {
2636
+ for (const subscription of this.subscriptions.values()) {
2637
+ try {
2638
+ subscription.controller.abort();
2639
+ } catch {
2640
+ }
2641
+ }
2642
+ this.subscriptions.clear();
2643
+ this.removeAllListeners();
2644
+ }
2645
+ }
2646
+ getSubscribedChannels() {
2647
+ return [...this.subscriptions.keys()];
2648
+ }
2649
+ };
2650
+ var SubscribeCommand = class extends Command {
2651
+ constructor(cmd, opts) {
2652
+ const sseHeaders = {
2653
+ Accept: "text/event-stream",
2654
+ "Cache-Control": "no-cache",
2655
+ Connection: "keep-alive"
2656
+ };
2657
+ super([], {
2658
+ ...opts,
2659
+ headers: sseHeaders,
2660
+ path: ["subscribe", ...cmd],
2661
+ streamOptions: {
2662
+ isStreaming: true,
2663
+ onMessage: opts?.streamOptions?.onMessage,
2664
+ signal: opts?.streamOptions?.signal
2665
+ }
2666
+ });
2667
+ }
2668
+ };
2669
+ var parseWithTryCatch = (str) => {
2670
+ try {
2671
+ return JSON.parse(str);
2672
+ } catch {
2673
+ return str;
2674
+ }
2675
+ };
2676
+
1603
2677
  // pkg/commands/zdiffstore.ts
1604
2678
  var ZDiffStoreCommand = class extends Command {
1605
2679
  constructor(cmd, opts) {
@@ -1626,20 +2700,21 @@ var Pipeline = class {
1626
2700
  this.commands = [];
1627
2701
  this.commandOptions = opts.commandOptions;
1628
2702
  this.multiExec = opts.multiExec ?? false;
2703
+ if (this.commandOptions?.latencyLogging) {
2704
+ const originalExec = this.exec.bind(this);
2705
+ this.exec = async (options) => {
2706
+ const start = performance.now();
2707
+ const result = await (options ? originalExec(options) : originalExec());
2708
+ const end = performance.now();
2709
+ const loggerResult = (end - start).toFixed(2);
2710
+ console.log(
2711
+ `Latency for \x1B[38;2;19;185;39m${this.multiExec ? ["MULTI-EXEC"] : ["PIPELINE"].toString().toUpperCase()}\x1B[0m: \x1B[38;2;0;255;255m${loggerResult} ms\x1B[0m`
2712
+ );
2713
+ return result;
2714
+ };
2715
+ }
1629
2716
  }
1630
- /**
1631
- * Send the pipeline request to upstash.
1632
- *
1633
- * Returns an array with the results of all pipelined commands.
1634
- *
1635
- * If all commands are statically chained from start to finish, types are inferred. You can still define a return type manually if necessary though:
1636
- * ```ts
1637
- * const p = redis.pipeline()
1638
- * p.get("key")
1639
- * const result = p.exec<[{ greeting: string }]>()
1640
- * ```
1641
- */
1642
- exec = async () => {
2717
+ exec = async (options) => {
1643
2718
  if (this.commands.length === 0) {
1644
2719
  throw new Error("Pipeline is empty");
1645
2720
  }
@@ -1648,7 +2723,12 @@ var Pipeline = class {
1648
2723
  path,
1649
2724
  body: Object.values(this.commands).map((c) => c.command)
1650
2725
  });
1651
- return res.map(({ error, result }, i) => {
2726
+ return options?.keepErrors ? res.map(({ error, result }, i) => {
2727
+ return {
2728
+ error,
2729
+ result: this.commands[i].deserialize(result)
2730
+ };
2731
+ }) : res.map(({ error, result }, i) => {
1652
2732
  if (error) {
1653
2733
  throw new UpstashError(
1654
2734
  `Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}`
@@ -1678,7 +2758,24 @@ var Pipeline = class {
1678
2758
  /**
1679
2759
  * @see https://redis.io/commands/bitcount
1680
2760
  */
1681
- bitcount = (...args) => this.chain(new BitCountCommand(args, this.commandOptions));
2761
+ bitcount = (...args) => this.chain(new BitCountCommand(args, this.commandOptions));
2762
+ /**
2763
+ * Returns an instance that can be used to execute `BITFIELD` commands on one key.
2764
+ *
2765
+ * @example
2766
+ * ```typescript
2767
+ * redis.set("mykey", 0);
2768
+ * const result = await redis.pipeline()
2769
+ * .bitfield("mykey")
2770
+ * .set("u4", 0, 16)
2771
+ * .incr("u4", "#1", 1)
2772
+ * .exec();
2773
+ * console.log(result); // [[0, 1]]
2774
+ * ```
2775
+ *
2776
+ * @see https://redis.io/commands/bitfield
2777
+ */
2778
+ bitfield = (...args) => new BitFieldCommand(args, this.client, this.commandOptions, this.chain.bind(this));
1682
2779
  /**
1683
2780
  * @see https://redis.io/commands/bitop
1684
2781
  */
@@ -1689,6 +2786,10 @@ var Pipeline = class {
1689
2786
  * @see https://redis.io/commands/bitpos
1690
2787
  */
1691
2788
  bitpos = (...args) => this.chain(new BitPosCommand(args, this.commandOptions));
2789
+ /**
2790
+ * @see https://redis.io/commands/copy
2791
+ */
2792
+ copy = (...args) => this.chain(new CopyCommand(args, this.commandOptions));
1692
2793
  /**
1693
2794
  * @see https://redis.io/commands/zdiffstore
1694
2795
  */
@@ -1713,10 +2814,18 @@ var Pipeline = class {
1713
2814
  * @see https://redis.io/commands/echo
1714
2815
  */
1715
2816
  echo = (...args) => this.chain(new EchoCommand(args, this.commandOptions));
2817
+ /**
2818
+ * @see https://redis.io/commands/eval_ro
2819
+ */
2820
+ evalRo = (...args) => this.chain(new EvalROCommand(args, this.commandOptions));
1716
2821
  /**
1717
2822
  * @see https://redis.io/commands/eval
1718
2823
  */
1719
2824
  eval = (...args) => this.chain(new EvalCommand(args, this.commandOptions));
2825
+ /**
2826
+ * @see https://redis.io/commands/evalsha_ro
2827
+ */
2828
+ evalshaRo = (...args) => this.chain(new EvalshaROCommand(args, this.commandOptions));
1720
2829
  /**
1721
2830
  * @see https://redis.io/commands/evalsha
1722
2831
  */
@@ -1741,6 +2850,30 @@ var Pipeline = class {
1741
2850
  * @see https://redis.io/commands/flushdb
1742
2851
  */
1743
2852
  flushdb = (...args) => this.chain(new FlushDBCommand(args, this.commandOptions));
2853
+ /**
2854
+ * @see https://redis.io/commands/geoadd
2855
+ */
2856
+ geoadd = (...args) => this.chain(new GeoAddCommand(args, this.commandOptions));
2857
+ /**
2858
+ * @see https://redis.io/commands/geodist
2859
+ */
2860
+ geodist = (...args) => this.chain(new GeoDistCommand(args, this.commandOptions));
2861
+ /**
2862
+ * @see https://redis.io/commands/geopos
2863
+ */
2864
+ geopos = (...args) => this.chain(new GeoPosCommand(args, this.commandOptions));
2865
+ /**
2866
+ * @see https://redis.io/commands/geohash
2867
+ */
2868
+ geohash = (...args) => this.chain(new GeoHashCommand(args, this.commandOptions));
2869
+ /**
2870
+ * @see https://redis.io/commands/geosearch
2871
+ */
2872
+ geosearch = (...args) => this.chain(new GeoSearchCommand(args, this.commandOptions));
2873
+ /**
2874
+ * @see https://redis.io/commands/geosearchstore
2875
+ */
2876
+ geosearchstore = (...args) => this.chain(new GeoSearchStoreCommand(args, this.commandOptions));
1744
2877
  /**
1745
2878
  * @see https://redis.io/commands/get
1746
2879
  */
@@ -1753,6 +2886,10 @@ var Pipeline = class {
1753
2886
  * @see https://redis.io/commands/getdel
1754
2887
  */
1755
2888
  getdel = (...args) => this.chain(new GetDelCommand(args, this.commandOptions));
2889
+ /**
2890
+ * @see https://redis.io/commands/getex
2891
+ */
2892
+ getex = (...args) => this.chain(new GetExCommand(args, this.commandOptions));
1756
2893
  /**
1757
2894
  * @see https://redis.io/commands/getrange
1758
2895
  */
@@ -1769,6 +2906,42 @@ var Pipeline = class {
1769
2906
  * @see https://redis.io/commands/hexists
1770
2907
  */
1771
2908
  hexists = (...args) => this.chain(new HExistsCommand(args, this.commandOptions));
2909
+ /**
2910
+ * @see https://redis.io/commands/hexpire
2911
+ */
2912
+ hexpire = (...args) => this.chain(new HExpireCommand(args, this.commandOptions));
2913
+ /**
2914
+ * @see https://redis.io/commands/hexpireat
2915
+ */
2916
+ hexpireat = (...args) => this.chain(new HExpireAtCommand(args, this.commandOptions));
2917
+ /**
2918
+ * @see https://redis.io/commands/hexpiretime
2919
+ */
2920
+ hexpiretime = (...args) => this.chain(new HExpireTimeCommand(args, this.commandOptions));
2921
+ /**
2922
+ * @see https://redis.io/commands/httl
2923
+ */
2924
+ httl = (...args) => this.chain(new HTtlCommand(args, this.commandOptions));
2925
+ /**
2926
+ * @see https://redis.io/commands/hpexpire
2927
+ */
2928
+ hpexpire = (...args) => this.chain(new HPExpireCommand(args, this.commandOptions));
2929
+ /**
2930
+ * @see https://redis.io/commands/hpexpireat
2931
+ */
2932
+ hpexpireat = (...args) => this.chain(new HPExpireAtCommand(args, this.commandOptions));
2933
+ /**
2934
+ * @see https://redis.io/commands/hpexpiretime
2935
+ */
2936
+ hpexpiretime = (...args) => this.chain(new HPExpireTimeCommand(args, this.commandOptions));
2937
+ /**
2938
+ * @see https://redis.io/commands/hpttl
2939
+ */
2940
+ hpttl = (...args) => this.chain(new HPTtlCommand(args, this.commandOptions));
2941
+ /**
2942
+ * @see https://redis.io/commands/hpersist
2943
+ */
2944
+ hpersist = (...args) => this.chain(new HPersistCommand(args, this.commandOptions));
1772
2945
  /**
1773
2946
  * @see https://redis.io/commands/hget
1774
2947
  */
@@ -1861,6 +3034,10 @@ var Pipeline = class {
1861
3034
  * @see https://redis.io/commands/lpop
1862
3035
  */
1863
3036
  lpop = (...args) => this.chain(new LPopCommand(args, this.commandOptions));
3037
+ /**
3038
+ * @see https://redis.io/commands/lmpop
3039
+ */
3040
+ lmpop = (...args) => this.chain(new LmPopCommand(args, this.commandOptions));
1864
3041
  /**
1865
3042
  * @see https://redis.io/commands/lpos
1866
3043
  */
@@ -1913,6 +3090,18 @@ var Pipeline = class {
1913
3090
  * @see https://redis.io/commands/pexpireat
1914
3091
  */
1915
3092
  pexpireat = (...args) => this.chain(new PExpireAtCommand(args, this.commandOptions));
3093
+ /**
3094
+ * @see https://redis.io/commands/pfadd
3095
+ */
3096
+ pfadd = (...args) => this.chain(new PfAddCommand(args, this.commandOptions));
3097
+ /**
3098
+ * @see https://redis.io/commands/pfcount
3099
+ */
3100
+ pfcount = (...args) => this.chain(new PfCountCommand(args, this.commandOptions));
3101
+ /**
3102
+ * @see https://redis.io/commands/pfmerge
3103
+ */
3104
+ pfmerge = (...args) => this.chain(new PfMergeCommand(args, this.commandOptions));
1916
3105
  /**
1917
3106
  * @see https://redis.io/commands/ping
1918
3107
  */
@@ -1956,7 +3145,7 @@ var Pipeline = class {
1956
3145
  /**
1957
3146
  * @see https://redis.io/commands/sadd
1958
3147
  */
1959
- sadd = (key, ...members) => this.chain(new SAddCommand([key, ...members], this.commandOptions));
3148
+ sadd = (key, member, ...members) => this.chain(new SAddCommand([key, member, ...members], this.commandOptions));
1960
3149
  /**
1961
3150
  * @see https://redis.io/commands/scan
1962
3151
  */
@@ -2083,10 +3272,7 @@ var Pipeline = class {
2083
3272
  zadd = (...args) => {
2084
3273
  if ("score" in args[1]) {
2085
3274
  return this.chain(
2086
- new ZAddCommand(
2087
- [args[0], args[1], ...args.slice(2)],
2088
- this.commandOptions
2089
- )
3275
+ new ZAddCommand([args[0], args[1], ...args.slice(2)], this.commandOptions)
2090
3276
  );
2091
3277
  }
2092
3278
  return this.chain(
@@ -2096,6 +3282,62 @@ var Pipeline = class {
2096
3282
  )
2097
3283
  );
2098
3284
  };
3285
+ /**
3286
+ * @see https://redis.io/commands/xadd
3287
+ */
3288
+ xadd = (...args) => this.chain(new XAddCommand(args, this.commandOptions));
3289
+ /**
3290
+ * @see https://redis.io/commands/xack
3291
+ */
3292
+ xack = (...args) => this.chain(new XAckCommand(args, this.commandOptions));
3293
+ /**
3294
+ * @see https://redis.io/commands/xdel
3295
+ */
3296
+ xdel = (...args) => this.chain(new XDelCommand(args, this.commandOptions));
3297
+ /**
3298
+ * @see https://redis.io/commands/xgroup
3299
+ */
3300
+ xgroup = (...args) => this.chain(new XGroupCommand(args, this.commandOptions));
3301
+ /**
3302
+ * @see https://redis.io/commands/xread
3303
+ */
3304
+ xread = (...args) => this.chain(new XReadCommand(args, this.commandOptions));
3305
+ /**
3306
+ * @see https://redis.io/commands/xreadgroup
3307
+ */
3308
+ xreadgroup = (...args) => this.chain(new XReadGroupCommand(args, this.commandOptions));
3309
+ /**
3310
+ * @see https://redis.io/commands/xinfo
3311
+ */
3312
+ xinfo = (...args) => this.chain(new XInfoCommand(args, this.commandOptions));
3313
+ /**
3314
+ * @see https://redis.io/commands/xlen
3315
+ */
3316
+ xlen = (...args) => this.chain(new XLenCommand(args, this.commandOptions));
3317
+ /**
3318
+ * @see https://redis.io/commands/xpending
3319
+ */
3320
+ xpending = (...args) => this.chain(new XPendingCommand(args, this.commandOptions));
3321
+ /**
3322
+ * @see https://redis.io/commands/xclaim
3323
+ */
3324
+ xclaim = (...args) => this.chain(new XClaimCommand(args, this.commandOptions));
3325
+ /**
3326
+ * @see https://redis.io/commands/xautoclaim
3327
+ */
3328
+ xautoclaim = (...args) => this.chain(new XAutoClaim(args, this.commandOptions));
3329
+ /**
3330
+ * @see https://redis.io/commands/xtrim
3331
+ */
3332
+ xtrim = (...args) => this.chain(new XTrimCommand(args, this.commandOptions));
3333
+ /**
3334
+ * @see https://redis.io/commands/xrange
3335
+ */
3336
+ xrange = (...args) => this.chain(new XRangeCommand(args, this.commandOptions));
3337
+ /**
3338
+ * @see https://redis.io/commands/xrevrange
3339
+ */
3340
+ xrevrange = (...args) => this.chain(new XRevRangeCommand(args, this.commandOptions));
2099
3341
  /**
2100
3342
  * @see https://redis.io/commands/zcard
2101
3343
  */
@@ -2213,22 +3455,22 @@ var Pipeline = class {
2213
3455
  * @see https://redis.io/commands/json.forget
2214
3456
  */
2215
3457
  forget: (...args) => this.chain(new JsonForgetCommand(args, this.commandOptions)),
2216
- /**
2217
- * @see https://redis.io/commands/geoadd
2218
- */
2219
- geoadd: (...args) => new GeoAddCommand(args, this.commandOptions).exec(this.client),
2220
- /**
2221
- * @see https://redis.io/commands/geodist
2222
- */
2223
- geodist: (...args) => new GeoDistCommand(args, this.commandOptions).exec(this.client),
2224
3458
  /**
2225
3459
  * @see https://redis.io/commands/json.get
2226
3460
  */
2227
3461
  get: (...args) => this.chain(new JsonGetCommand(args, this.commandOptions)),
3462
+ /**
3463
+ * @see https://redis.io/commands/json.merge
3464
+ */
3465
+ merge: (...args) => this.chain(new JsonMergeCommand(args, this.commandOptions)),
2228
3466
  /**
2229
3467
  * @see https://redis.io/commands/json.mget
2230
3468
  */
2231
3469
  mget: (...args) => this.chain(new JsonMGetCommand(args, this.commandOptions)),
3470
+ /**
3471
+ * @see https://redis.io/commands/json.mset
3472
+ */
3473
+ mset: (...args) => this.chain(new JsonMSetCommand(args, this.commandOptions)),
2232
3474
  /**
2233
3475
  * @see https://redis.io/commands/json.numincrby
2234
3476
  */
@@ -2274,27 +3516,43 @@ var Pipeline = class {
2274
3516
  };
2275
3517
 
2276
3518
  // pkg/script.ts
2277
- var import_enc_hex = __toESM(require("crypto-js/enc-hex"));
2278
- var import_sha1 = __toESM(require("crypto-js/sha1"));
3519
+ var import_uncrypto = require("uncrypto");
2279
3520
  var Script = class {
2280
3521
  script;
3522
+ /**
3523
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3524
+ * asynchronously. Do not use this property immidiately after the constructor.
3525
+ *
3526
+ * This property is only exposed for backwards compatibility and will be removed in the
3527
+ * future major release.
3528
+ */
2281
3529
  sha1;
2282
3530
  redis;
2283
3531
  constructor(redis, script) {
2284
3532
  this.redis = redis;
2285
- this.sha1 = this.digest(script);
2286
3533
  this.script = script;
3534
+ this.sha1 = "";
3535
+ void this.init(script);
3536
+ }
3537
+ /**
3538
+ * Initialize the script by computing its SHA-1 hash.
3539
+ */
3540
+ async init(script) {
3541
+ if (this.sha1) return;
3542
+ this.sha1 = await this.digest(script);
2287
3543
  }
2288
3544
  /**
2289
3545
  * Send an `EVAL` command to redis.
2290
3546
  */
2291
3547
  async eval(keys, args) {
3548
+ await this.init(this.script);
2292
3549
  return await this.redis.eval(this.script, keys, args);
2293
3550
  }
2294
3551
  /**
2295
3552
  * Calculates the sha1 hash of the script and then calls `EVALSHA`.
2296
3553
  */
2297
3554
  async evalsha(keys, args) {
3555
+ await this.init(this.script);
2298
3556
  return await this.redis.evalsha(this.sha1, keys, args);
2299
3557
  }
2300
3558
  /**
@@ -2304,19 +3562,87 @@ var Script = class {
2304
3562
  * Following calls will be able to use the cached script
2305
3563
  */
2306
3564
  async exec(keys, args) {
2307
- const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (err) => {
2308
- if (err instanceof Error && err.message.toLowerCase().includes("noscript")) {
3565
+ await this.init(this.script);
3566
+ const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
3567
+ if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
2309
3568
  return await this.redis.eval(this.script, keys, args);
2310
3569
  }
2311
- throw err;
3570
+ throw error;
3571
+ });
3572
+ return res;
3573
+ }
3574
+ /**
3575
+ * Compute the sha1 hash of the script and return its hex representation.
3576
+ */
3577
+ async digest(s) {
3578
+ const data = new TextEncoder().encode(s);
3579
+ const hashBuffer = await import_uncrypto.subtle.digest("SHA-1", data);
3580
+ const hashArray = [...new Uint8Array(hashBuffer)];
3581
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3582
+ }
3583
+ };
3584
+
3585
+ // pkg/scriptRo.ts
3586
+ var import_uncrypto2 = require("uncrypto");
3587
+ var ScriptRO = class {
3588
+ script;
3589
+ /**
3590
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3591
+ * asynchronously. Do not use this property immidiately after the constructor.
3592
+ *
3593
+ * This property is only exposed for backwards compatibility and will be removed in the
3594
+ * future major release.
3595
+ */
3596
+ sha1;
3597
+ redis;
3598
+ constructor(redis, script) {
3599
+ this.redis = redis;
3600
+ this.sha1 = "";
3601
+ this.script = script;
3602
+ void this.init(script);
3603
+ }
3604
+ async init(script) {
3605
+ if (this.sha1) return;
3606
+ this.sha1 = await this.digest(script);
3607
+ }
3608
+ /**
3609
+ * Send an `EVAL_RO` command to redis.
3610
+ */
3611
+ async evalRo(keys, args) {
3612
+ await this.init(this.script);
3613
+ return await this.redis.evalRo(this.script, keys, args);
3614
+ }
3615
+ /**
3616
+ * Calculates the sha1 hash of the script and then calls `EVALSHA_RO`.
3617
+ */
3618
+ async evalshaRo(keys, args) {
3619
+ await this.init(this.script);
3620
+ return await this.redis.evalshaRo(this.sha1, keys, args);
3621
+ }
3622
+ /**
3623
+ * Optimistically try to run `EVALSHA_RO` first.
3624
+ * If the script is not loaded in redis, it will fall back and try again with `EVAL_RO`.
3625
+ *
3626
+ * Following calls will be able to use the cached script
3627
+ */
3628
+ async exec(keys, args) {
3629
+ await this.init(this.script);
3630
+ const res = await this.redis.evalshaRo(this.sha1, keys, args).catch(async (error) => {
3631
+ if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
3632
+ return await this.redis.evalRo(this.script, keys, args);
3633
+ }
3634
+ throw error;
2312
3635
  });
2313
3636
  return res;
2314
3637
  }
2315
3638
  /**
2316
3639
  * Compute the sha1 hash of the script and return its hex representation.
2317
3640
  */
2318
- digest(s) {
2319
- return import_enc_hex.default.stringify((0, import_sha1.default)(s));
3641
+ async digest(s) {
3642
+ const data = new TextEncoder().encode(s);
3643
+ const hashBuffer = await import_uncrypto2.subtle.digest("SHA-1", data);
3644
+ const hashArray = [...new Uint8Array(hashBuffer)];
3645
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
2320
3646
  }
2321
3647
  };
2322
3648
 
@@ -2325,6 +3651,7 @@ var Redis = class {
2325
3651
  client;
2326
3652
  opts;
2327
3653
  enableTelemetry;
3654
+ enableAutoPipelining;
2328
3655
  /**
2329
3656
  * Create a new redis client
2330
3657
  *
@@ -2340,6 +3667,16 @@ var Redis = class {
2340
3667
  this.client = client;
2341
3668
  this.opts = opts;
2342
3669
  this.enableTelemetry = opts?.enableTelemetry ?? true;
3670
+ if (opts?.readYourWrites === false) {
3671
+ this.client.readYourWrites = false;
3672
+ }
3673
+ this.enableAutoPipelining = opts?.enableAutoPipelining ?? true;
3674
+ }
3675
+ get readYourWritesSyncToken() {
3676
+ return this.client.upstashSyncToken;
3677
+ }
3678
+ set readYourWritesSyncToken(session) {
3679
+ this.client.upstashSyncToken = session;
2343
3680
  }
2344
3681
  get json() {
2345
3682
  return {
@@ -2379,22 +3716,22 @@ var Redis = class {
2379
3716
  * @see https://redis.io/commands/json.forget
2380
3717
  */
2381
3718
  forget: (...args) => new JsonForgetCommand(args, this.opts).exec(this.client),
2382
- /**
2383
- * @see https://redis.io/commands/geoadd
2384
- */
2385
- geoadd: (...args) => new GeoAddCommand(args, this.opts).exec(this.client),
2386
- /**
2387
- * @see https://redis.io/commands/geodist
2388
- */
2389
- geodist: (...args) => new GeoDistCommand(args, this.opts).exec(this.client),
2390
3719
  /**
2391
3720
  * @see https://redis.io/commands/json.get
2392
3721
  */
2393
3722
  get: (...args) => new JsonGetCommand(args, this.opts).exec(this.client),
3723
+ /**
3724
+ * @see https://redis.io/commands/json.merge
3725
+ */
3726
+ merge: (...args) => new JsonMergeCommand(args, this.opts).exec(this.client),
2394
3727
  /**
2395
3728
  * @see https://redis.io/commands/json.mget
2396
3729
  */
2397
3730
  mget: (...args) => new JsonMGetCommand(args, this.opts).exec(this.client),
3731
+ /**
3732
+ * @see https://redis.io/commands/json.mset
3733
+ */
3734
+ mset: (...args) => new JsonMSetCommand(args, this.opts).exec(this.client),
2398
3735
  /**
2399
3736
  * @see https://redis.io/commands/json.numincrby
2400
3737
  */
@@ -2456,8 +3793,36 @@ var Redis = class {
2456
3793
  } catch {
2457
3794
  }
2458
3795
  };
2459
- createScript(script) {
2460
- return new Script(this, script);
3796
+ /**
3797
+ * Creates a new script.
3798
+ *
3799
+ * Scripts offer the ability to optimistically try to execute a script without having to send the
3800
+ * entire script to the server. If the script is loaded on the server, it tries again by sending
3801
+ * the entire script. Afterwards, the script is cached on the server.
3802
+ *
3803
+ * @param script - The script to create
3804
+ * @param opts - Optional options to pass to the script `{ readonly?: boolean }`
3805
+ * @returns A new script
3806
+ *
3807
+ * @example
3808
+ * ```ts
3809
+ * const redis = new Redis({...})
3810
+ *
3811
+ * const script = redis.createScript<string>("return ARGV[1];")
3812
+ * const arg1 = await script.eval([], ["Hello World"])
3813
+ * expect(arg1, "Hello World")
3814
+ * ```
3815
+ * @example
3816
+ * ```ts
3817
+ * const redis = new Redis({...})
3818
+ *
3819
+ * const script = redis.createScript<string>("return ARGV[1];", { readonly: true })
3820
+ * const arg1 = await script.evalRo([], ["Hello World"])
3821
+ * expect(arg1, "Hello World")
3822
+ * ```
3823
+ */
3824
+ createScript(script, opts) {
3825
+ return opts?.readonly ? new ScriptRO(this, script) : new Script(this, script);
2461
3826
  }
2462
3827
  /**
2463
3828
  * Create a new pipeline that allows you to send requests in bulk.
@@ -2469,6 +3834,9 @@ var Redis = class {
2469
3834
  commandOptions: this.opts,
2470
3835
  multiExec: false
2471
3836
  });
3837
+ autoPipeline = () => {
3838
+ return createAutoPipelineProxy(this);
3839
+ };
2472
3840
  /**
2473
3841
  * Create a new transaction to allow executing multiple steps atomically.
2474
3842
  *
@@ -2483,6 +3851,22 @@ var Redis = class {
2483
3851
  commandOptions: this.opts,
2484
3852
  multiExec: true
2485
3853
  });
3854
+ /**
3855
+ * Returns an instance that can be used to execute `BITFIELD` commands on one key.
3856
+ *
3857
+ * @example
3858
+ * ```typescript
3859
+ * redis.set("mykey", 0);
3860
+ * const result = await redis.bitfield("mykey")
3861
+ * .set("u4", 0, 16)
3862
+ * .incr("u4", "#1", 1)
3863
+ * .exec();
3864
+ * console.log(result); // [0, 1]
3865
+ * ```
3866
+ *
3867
+ * @see https://redis.io/commands/bitfield
3868
+ */
3869
+ bitfield = (...args) => new BitFieldCommand(args, this.client, this.opts);
2486
3870
  /**
2487
3871
  * @see https://redis.io/commands/append
2488
3872
  */
@@ -2501,6 +3885,10 @@ var Redis = class {
2501
3885
  * @see https://redis.io/commands/bitpos
2502
3886
  */
2503
3887
  bitpos = (...args) => new BitPosCommand(args, this.opts).exec(this.client);
3888
+ /**
3889
+ * @see https://redis.io/commands/copy
3890
+ */
3891
+ copy = (...args) => new CopyCommand(args, this.opts).exec(this.client);
2504
3892
  /**
2505
3893
  * @see https://redis.io/commands/dbsize
2506
3894
  */
@@ -2521,14 +3909,26 @@ var Redis = class {
2521
3909
  * @see https://redis.io/commands/echo
2522
3910
  */
2523
3911
  echo = (...args) => new EchoCommand(args, this.opts).exec(this.client);
3912
+ /**
3913
+ * @see https://redis.io/commands/eval_ro
3914
+ */
3915
+ evalRo = (...args) => new EvalROCommand(args, this.opts).exec(this.client);
2524
3916
  /**
2525
3917
  * @see https://redis.io/commands/eval
2526
3918
  */
2527
3919
  eval = (...args) => new EvalCommand(args, this.opts).exec(this.client);
3920
+ /**
3921
+ * @see https://redis.io/commands/evalsha_ro
3922
+ */
3923
+ evalshaRo = (...args) => new EvalshaROCommand(args, this.opts).exec(this.client);
2528
3924
  /**
2529
3925
  * @see https://redis.io/commands/evalsha
2530
3926
  */
2531
3927
  evalsha = (...args) => new EvalshaCommand(args, this.opts).exec(this.client);
3928
+ /**
3929
+ * Generic method to execute any Redis command.
3930
+ */
3931
+ exec = (args) => new ExecCommand(args, this.opts).exec(this.client);
2532
3932
  /**
2533
3933
  * @see https://redis.io/commands/exists
2534
3934
  */
@@ -2549,6 +3949,30 @@ var Redis = class {
2549
3949
  * @see https://redis.io/commands/flushdb
2550
3950
  */
2551
3951
  flushdb = (...args) => new FlushDBCommand(args, this.opts).exec(this.client);
3952
+ /**
3953
+ * @see https://redis.io/commands/geoadd
3954
+ */
3955
+ geoadd = (...args) => new GeoAddCommand(args, this.opts).exec(this.client);
3956
+ /**
3957
+ * @see https://redis.io/commands/geopos
3958
+ */
3959
+ geopos = (...args) => new GeoPosCommand(args, this.opts).exec(this.client);
3960
+ /**
3961
+ * @see https://redis.io/commands/geodist
3962
+ */
3963
+ geodist = (...args) => new GeoDistCommand(args, this.opts).exec(this.client);
3964
+ /**
3965
+ * @see https://redis.io/commands/geohash
3966
+ */
3967
+ geohash = (...args) => new GeoHashCommand(args, this.opts).exec(this.client);
3968
+ /**
3969
+ * @see https://redis.io/commands/geosearch
3970
+ */
3971
+ geosearch = (...args) => new GeoSearchCommand(args, this.opts).exec(this.client);
3972
+ /**
3973
+ * @see https://redis.io/commands/geosearchstore
3974
+ */
3975
+ geosearchstore = (...args) => new GeoSearchStoreCommand(args, this.opts).exec(this.client);
2552
3976
  /**
2553
3977
  * @see https://redis.io/commands/get
2554
3978
  */
@@ -2561,6 +3985,10 @@ var Redis = class {
2561
3985
  * @see https://redis.io/commands/getdel
2562
3986
  */
2563
3987
  getdel = (...args) => new GetDelCommand(args, this.opts).exec(this.client);
3988
+ /**
3989
+ * @see https://redis.io/commands/getex
3990
+ */
3991
+ getex = (...args) => new GetExCommand(args, this.opts).exec(this.client);
2564
3992
  /**
2565
3993
  * @see https://redis.io/commands/getrange
2566
3994
  */
@@ -2577,6 +4005,42 @@ var Redis = class {
2577
4005
  * @see https://redis.io/commands/hexists
2578
4006
  */
2579
4007
  hexists = (...args) => new HExistsCommand(args, this.opts).exec(this.client);
4008
+ /**
4009
+ * @see https://redis.io/commands/hexpire
4010
+ */
4011
+ hexpire = (...args) => new HExpireCommand(args, this.opts).exec(this.client);
4012
+ /**
4013
+ * @see https://redis.io/commands/hexpireat
4014
+ */
4015
+ hexpireat = (...args) => new HExpireAtCommand(args, this.opts).exec(this.client);
4016
+ /**
4017
+ * @see https://redis.io/commands/hexpiretime
4018
+ */
4019
+ hexpiretime = (...args) => new HExpireTimeCommand(args, this.opts).exec(this.client);
4020
+ /**
4021
+ * @see https://redis.io/commands/httl
4022
+ */
4023
+ httl = (...args) => new HTtlCommand(args, this.opts).exec(this.client);
4024
+ /**
4025
+ * @see https://redis.io/commands/hpexpire
4026
+ */
4027
+ hpexpire = (...args) => new HPExpireCommand(args, this.opts).exec(this.client);
4028
+ /**
4029
+ * @see https://redis.io/commands/hpexpireat
4030
+ */
4031
+ hpexpireat = (...args) => new HPExpireAtCommand(args, this.opts).exec(this.client);
4032
+ /**
4033
+ * @see https://redis.io/commands/hpexpiretime
4034
+ */
4035
+ hpexpiretime = (...args) => new HPExpireTimeCommand(args, this.opts).exec(this.client);
4036
+ /**
4037
+ * @see https://redis.io/commands/hpttl
4038
+ */
4039
+ hpttl = (...args) => new HPTtlCommand(args, this.opts).exec(this.client);
4040
+ /**
4041
+ * @see https://redis.io/commands/hpersist
4042
+ */
4043
+ hpersist = (...args) => new HPersistCommand(args, this.opts).exec(this.client);
2580
4044
  /**
2581
4045
  * @see https://redis.io/commands/hget
2582
4046
  */
@@ -2669,6 +4133,10 @@ var Redis = class {
2669
4133
  * @see https://redis.io/commands/lpop
2670
4134
  */
2671
4135
  lpop = (...args) => new LPopCommand(args, this.opts).exec(this.client);
4136
+ /**
4137
+ * @see https://redis.io/commands/lmpop
4138
+ */
4139
+ lmpop = (...args) => new LmPopCommand(args, this.opts).exec(this.client);
2672
4140
  /**
2673
4141
  * @see https://redis.io/commands/lpos
2674
4142
  */
@@ -2721,6 +4189,18 @@ var Redis = class {
2721
4189
  * @see https://redis.io/commands/pexpireat
2722
4190
  */
2723
4191
  pexpireat = (...args) => new PExpireAtCommand(args, this.opts).exec(this.client);
4192
+ /**
4193
+ * @see https://redis.io/commands/pfadd
4194
+ */
4195
+ pfadd = (...args) => new PfAddCommand(args, this.opts).exec(this.client);
4196
+ /**
4197
+ * @see https://redis.io/commands/pfcount
4198
+ */
4199
+ pfcount = (...args) => new PfCountCommand(args, this.opts).exec(this.client);
4200
+ /**
4201
+ * @see https://redis.io/commands/pfmerge
4202
+ */
4203
+ pfmerge = (...args) => new PfMergeCommand(args, this.opts).exec(this.client);
2724
4204
  /**
2725
4205
  * @see https://redis.io/commands/ping
2726
4206
  */
@@ -2729,6 +4209,13 @@ var Redis = class {
2729
4209
  * @see https://redis.io/commands/psetex
2730
4210
  */
2731
4211
  psetex = (key, ttl, value) => new PSetEXCommand([key, ttl, value], this.opts).exec(this.client);
4212
+ /**
4213
+ * @see https://redis.io/commands/psubscribe
4214
+ */
4215
+ psubscribe = (patterns) => {
4216
+ const patternArray = Array.isArray(patterns) ? patterns : [patterns];
4217
+ return new Subscriber(this.client, patternArray, true, this.opts);
4218
+ };
2732
4219
  /**
2733
4220
  * @see https://redis.io/commands/pttl
2734
4221
  */
@@ -2764,11 +4251,10 @@ var Redis = class {
2764
4251
  /**
2765
4252
  * @see https://redis.io/commands/sadd
2766
4253
  */
2767
- sadd = (key, ...members) => new SAddCommand([key, ...members], this.opts).exec(this.client);
2768
- /**
2769
- * @see https://redis.io/commands/scan
2770
- */
2771
- scan = (...args) => new ScanCommand(args, this.opts).exec(this.client);
4254
+ sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
4255
+ scan(cursor, opts) {
4256
+ return new ScanCommand([cursor, opts], this.opts).exec(this.client);
4257
+ }
2772
4258
  /**
2773
4259
  * @see https://redis.io/commands/scard
2774
4260
  */
@@ -2857,6 +4343,13 @@ var Redis = class {
2857
4343
  * @see https://redis.io/commands/strlen
2858
4344
  */
2859
4345
  strlen = (...args) => new StrLenCommand(args, this.opts).exec(this.client);
4346
+ /**
4347
+ * @see https://redis.io/commands/subscribe
4348
+ */
4349
+ subscribe = (channels) => {
4350
+ const channelArray = Array.isArray(channels) ? channels : [channels];
4351
+ return new Subscriber(this.client, channelArray, false, this.opts);
4352
+ };
2860
4353
  /**
2861
4354
  * @see https://redis.io/commands/sunion
2862
4355
  */
@@ -2889,19 +4382,66 @@ var Redis = class {
2889
4382
  * @see https://redis.io/commands/xadd
2890
4383
  */
2891
4384
  xadd = (...args) => new XAddCommand(args, this.opts).exec(this.client);
4385
+ /**
4386
+ * @see https://redis.io/commands/xack
4387
+ */
4388
+ xack = (...args) => new XAckCommand(args, this.opts).exec(this.client);
4389
+ /**
4390
+ * @see https://redis.io/commands/xdel
4391
+ */
4392
+ xdel = (...args) => new XDelCommand(args, this.opts).exec(this.client);
4393
+ /**
4394
+ * @see https://redis.io/commands/xgroup
4395
+ */
4396
+ xgroup = (...args) => new XGroupCommand(args, this.opts).exec(this.client);
4397
+ /**
4398
+ * @see https://redis.io/commands/xread
4399
+ */
4400
+ xread = (...args) => new XReadCommand(args, this.opts).exec(this.client);
4401
+ /**
4402
+ * @see https://redis.io/commands/xreadgroup
4403
+ */
4404
+ xreadgroup = (...args) => new XReadGroupCommand(args, this.opts).exec(this.client);
4405
+ /**
4406
+ * @see https://redis.io/commands/xinfo
4407
+ */
4408
+ xinfo = (...args) => new XInfoCommand(args, this.opts).exec(this.client);
4409
+ /**
4410
+ * @see https://redis.io/commands/xlen
4411
+ */
4412
+ xlen = (...args) => new XLenCommand(args, this.opts).exec(this.client);
4413
+ /**
4414
+ * @see https://redis.io/commands/xpending
4415
+ */
4416
+ xpending = (...args) => new XPendingCommand(args, this.opts).exec(this.client);
4417
+ /**
4418
+ * @see https://redis.io/commands/xclaim
4419
+ */
4420
+ xclaim = (...args) => new XClaimCommand(args, this.opts).exec(this.client);
4421
+ /**
4422
+ * @see https://redis.io/commands/xautoclaim
4423
+ */
4424
+ xautoclaim = (...args) => new XAutoClaim(args, this.opts).exec(this.client);
4425
+ /**
4426
+ * @see https://redis.io/commands/xtrim
4427
+ */
4428
+ xtrim = (...args) => new XTrimCommand(args, this.opts).exec(this.client);
2892
4429
  /**
2893
4430
  * @see https://redis.io/commands/xrange
2894
4431
  */
2895
4432
  xrange = (...args) => new XRangeCommand(args, this.opts).exec(this.client);
4433
+ /**
4434
+ * @see https://redis.io/commands/xrevrange
4435
+ */
4436
+ xrevrange = (...args) => new XRevRangeCommand(args, this.opts).exec(this.client);
2896
4437
  /**
2897
4438
  * @see https://redis.io/commands/zadd
2898
4439
  */
2899
4440
  zadd = (...args) => {
2900
4441
  if ("score" in args[1]) {
2901
- return new ZAddCommand(
2902
- [args[0], args[1], ...args.slice(2)],
2903
- this.opts
2904
- ).exec(this.client);
4442
+ return new ZAddCommand([args[0], args[1], ...args.slice(2)], this.opts).exec(
4443
+ this.client
4444
+ );
2905
4445
  }
2906
4446
  return new ZAddCommand(
2907
4447
  [args[0], args[1], ...args.slice(2)],
@@ -2991,25 +4531,52 @@ var Redis = class {
2991
4531
  };
2992
4532
 
2993
4533
  // version.ts
2994
- var VERSION = "v0.0.0-ci.9722909577fc3b6b939d0c937c6ba5f8e8287ee4";
4534
+ var VERSION = "v1.30.2";
2995
4535
 
2996
4536
  // platforms/nodejs.ts
2997
4537
  if (typeof atob === "undefined") {
2998
- global.atob = function(b64) {
2999
- return Buffer.from(b64, "base64").toString("utf-8");
3000
- };
4538
+ global.atob = (b64) => Buffer.from(b64, "base64").toString("utf8");
3001
4539
  }
3002
4540
  var Redis2 = class _Redis extends Redis {
4541
+ /**
4542
+ * Create a new redis client by providing a custom `Requester` implementation
4543
+ *
4544
+ * @example
4545
+ * ```ts
4546
+ *
4547
+ * import { UpstashRequest, Requester, UpstashResponse, Redis } from "@upstash/redis"
4548
+ *
4549
+ * const requester: Requester = {
4550
+ * request: <TResult>(req: UpstashRequest): Promise<UpstashResponse<TResult>> => {
4551
+ * // ...
4552
+ * }
4553
+ * }
4554
+ *
4555
+ * const redis = new Redis(requester)
4556
+ * ```
4557
+ */
3003
4558
  constructor(configOrRequester) {
3004
4559
  if ("request" in configOrRequester) {
3005
4560
  super(configOrRequester);
3006
4561
  return;
3007
4562
  }
3008
- if (configOrRequester.url.startsWith(" ") || configOrRequester.url.endsWith(" ") || /\r|\n/.test(configOrRequester.url)) {
3009
- console.warn("The redis url contains whitespace or newline, which can cause errors!");
4563
+ if (!configOrRequester.url) {
4564
+ console.warn(
4565
+ `[Upstash Redis] The 'url' property is missing or undefined in your Redis config.`
4566
+ );
4567
+ } else if (configOrRequester.url.startsWith(" ") || configOrRequester.url.endsWith(" ") || /\r|\n/.test(configOrRequester.url)) {
4568
+ console.warn(
4569
+ "[Upstash Redis] The redis url contains whitespace or newline, which can cause errors!"
4570
+ );
3010
4571
  }
3011
- if (configOrRequester.token.startsWith(" ") || configOrRequester.token.endsWith(" ") || /\r|\n/.test(configOrRequester.token)) {
3012
- console.warn("The redis token contains whitespace or newline, which can cause errors!");
4572
+ if (!configOrRequester.token) {
4573
+ console.warn(
4574
+ `[Upstash Redis] The 'token' property is missing or undefined in your Redis config.`
4575
+ );
4576
+ } else if (configOrRequester.token.startsWith(" ") || configOrRequester.token.endsWith(" ") || /\r|\n/.test(configOrRequester.token)) {
4577
+ console.warn(
4578
+ "[Upstash Redis] The redis token contains whitespace or newline, which can cause errors!"
4579
+ );
3013
4580
  }
3014
4581
  const client = new HttpClient({
3015
4582
  baseUrl: configOrRequester.url,
@@ -3017,18 +4584,30 @@ var Redis2 = class _Redis extends Redis {
3017
4584
  headers: { authorization: `Bearer ${configOrRequester.token}` },
3018
4585
  agent: configOrRequester.agent,
3019
4586
  responseEncoding: configOrRequester.responseEncoding,
3020
- cache: configOrRequester.cache || "no-store"
4587
+ cache: configOrRequester.cache ?? "no-store",
4588
+ signal: configOrRequester.signal,
4589
+ keepAlive: configOrRequester.keepAlive,
4590
+ readYourWrites: configOrRequester.readYourWrites
3021
4591
  });
4592
+ const safeEnv = typeof process === "object" && process && typeof process.env === "object" && process.env ? process.env : {};
3022
4593
  super(client, {
3023
4594
  automaticDeserialization: configOrRequester.automaticDeserialization,
3024
- enableTelemetry: !process.env.UPSTASH_DISABLE_TELEMETRY
4595
+ enableTelemetry: configOrRequester.enableTelemetry ?? !safeEnv.UPSTASH_DISABLE_TELEMETRY,
4596
+ latencyLogging: configOrRequester.latencyLogging,
4597
+ enableAutoPipelining: configOrRequester.enableAutoPipelining
3025
4598
  });
4599
+ const nodeVersion = typeof process === "object" && process ? process.version : void 0;
3026
4600
  this.addTelemetry({
3027
- // @ts-ignore
3028
- runtime: typeof EdgeRuntime === "string" ? "edge-light" : `node@${process.version}`,
3029
- platform: process.env.VERCEL ? "vercel" : process.env.AWS_REGION ? "aws" : "unknown",
4601
+ runtime: (
4602
+ // @ts-expect-error to silence compiler
4603
+ typeof EdgeRuntime === "string" ? "edge-light" : nodeVersion ? `node@${nodeVersion}` : "unknown"
4604
+ ),
4605
+ platform: safeEnv.UPSTASH_CONSOLE ? "console" : safeEnv.VERCEL ? "vercel" : safeEnv.AWS_REGION ? "aws" : "unknown",
3030
4606
  sdk: `@upstash/redis@${VERSION}`
3031
4607
  });
4608
+ if (this.enableAutoPipelining) {
4609
+ return this.autoPipeline();
4610
+ }
3032
4611
  }
3033
4612
  /**
3034
4613
  * Create a new Upstash Redis instance from environment variables.
@@ -3036,28 +4615,34 @@ var Redis2 = class _Redis extends Redis {
3036
4615
  * Use this to automatically load connection secrets from your environment
3037
4616
  * variables. For instance when using the Vercel integration.
3038
4617
  *
3039
- * This tries to load `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` from
3040
- * your environment using `process.env`.
4618
+ * This tries to load connection details from your environment using `process.env`:
4619
+ * - URL: `UPSTASH_REDIS_REST_URL` or fallback to `KV_REST_API_URL`
4620
+ * - Token: `UPSTASH_REDIS_REST_TOKEN` or fallback to `KV_REST_API_TOKEN`
4621
+ *
4622
+ * The fallback variables provide compatibility with Vercel KV and other platforms
4623
+ * that may use different naming conventions.
3041
4624
  */
3042
4625
  static fromEnv(config) {
3043
- if (typeof process?.env === "undefined") {
3044
- throw new Error(
3045
- 'Unable to get environment variables, `process.env` is undefined. If you are deploying to cloudflare, please import from "@upstash/redis/cloudflare" instead'
4626
+ if (typeof process !== "object" || !process || typeof process.env !== "object" || !process.env) {
4627
+ throw new TypeError(
4628
+ '[Upstash Redis] Unable to get environment variables, `process.env` is undefined. If you are deploying to cloudflare, please import from "@upstash/redis/cloudflare" instead'
3046
4629
  );
3047
4630
  }
3048
- const url = process?.env["UPSTASH_REDIS_REST_URL"];
4631
+ const url = process.env.UPSTASH_REDIS_REST_URL || process.env.KV_REST_API_URL;
3049
4632
  if (!url) {
3050
- throw new Error("Unable to find environment variable: `UPSTASH_REDIS_REST_URL`");
4633
+ console.warn("[Upstash Redis] Unable to find environment variable: `UPSTASH_REDIS_REST_URL`");
3051
4634
  }
3052
- const token = process?.env["UPSTASH_REDIS_REST_TOKEN"];
4635
+ const token = process.env.UPSTASH_REDIS_REST_TOKEN || process.env.KV_REST_API_TOKEN;
3053
4636
  if (!token) {
3054
- throw new Error("Unable to find environment variable: `UPSTASH_REDIS_REST_TOKEN`");
4637
+ console.warn(
4638
+ "[Upstash Redis] Unable to find environment variable: `UPSTASH_REDIS_REST_TOKEN`"
4639
+ );
3055
4640
  }
3056
4641
  return new _Redis({ ...config, url, token });
3057
4642
  }
3058
4643
  };
3059
4644
  // Annotate the CommonJS export names for ESM import in node:
3060
4645
  0 && (module.exports = {
3061
- Redis
4646
+ Redis,
4647
+ errors
3062
4648
  });
3063
- //# sourceMappingURL=nodejs.js.map