@upstash/redis 0.0.0-ci.d3170677a5859e31d40407781286bdf17d64ca72-20250220114636 → 0.0.0-ci.d3985e1d3f7f296ee10dff2746b51fa88dddc9a9-20251222113217

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.
@@ -8,11 +8,12 @@ var __export = (target, all) => {
8
8
  var error_exports = {};
9
9
  __export(error_exports, {
10
10
  UpstashError: () => UpstashError,
11
+ UpstashJSONParseError: () => UpstashJSONParseError,
11
12
  UrlError: () => UrlError
12
13
  });
13
14
  var UpstashError = class extends Error {
14
- constructor(message) {
15
- super(message);
15
+ constructor(message, options) {
16
+ super(message, options);
16
17
  this.name = "UpstashError";
17
18
  }
18
19
  };
@@ -24,6 +25,13 @@ var UrlError = class extends Error {
24
25
  this.name = "UrlError";
25
26
  }
26
27
  };
28
+ var UpstashJSONParseError = class extends UpstashError {
29
+ constructor(body, options) {
30
+ const truncatedBody = body.length > 200 ? body.slice(0, 200) + "..." : body;
31
+ super(`Unable to parse response body: ${truncatedBody}`, options);
32
+ this.name = "UpstashJSONParseError";
33
+ }
34
+ };
27
35
 
28
36
  // pkg/util.ts
29
37
  function parseRecursive(obj) {
@@ -49,6 +57,14 @@ function parseResponse(result) {
49
57
  function deserializeScanResponse(result) {
50
58
  return [result[0], ...parseResponse(result.slice(1))];
51
59
  }
60
+ function deserializeScanWithTypesResponse(result) {
61
+ const [cursor, keys] = result;
62
+ const parsedKeys = [];
63
+ for (let i = 0; i < keys.length; i += 2) {
64
+ parsedKeys.push({ key: keys[i], type: keys[i + 1] });
65
+ }
66
+ return [cursor, parsedKeys];
67
+ }
52
68
  function mergeHeaders(...headers) {
53
69
  const merged = {};
54
70
  for (const header of headers) {
@@ -61,6 +77,15 @@ function mergeHeaders(...headers) {
61
77
  }
62
78
  return merged;
63
79
  }
80
+ function kvArrayToObject(v) {
81
+ if (typeof v === "object" && v !== null && !Array.isArray(v)) return v;
82
+ if (!Array.isArray(v)) return {};
83
+ const obj = {};
84
+ for (let i = 0; i < v.length; i += 2) {
85
+ if (typeof v[i] === "string") obj[v[i]] = v[i + 1];
86
+ }
87
+ return obj;
88
+ }
64
89
 
65
90
  // pkg/http.ts
66
91
  var HttpClient = class {
@@ -113,6 +138,8 @@ var HttpClient = class {
113
138
  const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
114
139
  const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
115
140
  const isEventStream = requestHeaders.Accept === "text/event-stream";
141
+ const signal = req.signal ?? this.options.signal;
142
+ const isSignalFunction = typeof signal === "function";
116
143
  const requestOptions = {
117
144
  //@ts-expect-error this should throw due to bun regression
118
145
  cache: this.options.cache,
@@ -121,7 +148,7 @@ var HttpClient = class {
121
148
  body: JSON.stringify(req.body),
122
149
  keepalive: this.options.keepAlive,
123
150
  agent: this.options.agent,
124
- signal: req.signal ?? this.options.signal,
151
+ signal: isSignalFunction ? signal() : signal,
125
152
  /**
126
153
  * Fastly specific
127
154
  */
@@ -143,13 +170,15 @@ var HttpClient = class {
143
170
  res = await fetch(requestUrl, requestOptions);
144
171
  break;
145
172
  } catch (error_) {
146
- if (this.options.signal?.aborted) {
173
+ if (requestOptions.signal?.aborted && isSignalFunction) {
174
+ throw error_;
175
+ } else if (requestOptions.signal?.aborted) {
147
176
  const myBlob = new Blob([
148
- JSON.stringify({ result: this.options.signal.reason ?? "Aborted" })
177
+ JSON.stringify({ result: requestOptions.signal.reason ?? "Aborted" })
149
178
  ]);
150
179
  const myOptions = {
151
180
  status: 200,
152
- statusText: this.options.signal.reason ?? "Aborted"
181
+ statusText: requestOptions.signal.reason ?? "Aborted"
153
182
  };
154
183
  res = new Response(myBlob, myOptions);
155
184
  break;
@@ -164,7 +193,13 @@ var HttpClient = class {
164
193
  throw error ?? new Error("Exhausted all retries");
165
194
  }
166
195
  if (!res.ok) {
167
- const body2 = await res.json();
196
+ let body2;
197
+ const rawBody2 = await res.text();
198
+ try {
199
+ body2 = JSON.parse(rawBody2);
200
+ } catch (error2) {
201
+ throw new UpstashJSONParseError(rawBody2, { cause: error2 });
202
+ }
168
203
  throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
169
204
  }
170
205
  if (this.readYourWrites) {
@@ -202,7 +237,13 @@ var HttpClient = class {
202
237
  })();
203
238
  return { result: 1 };
204
239
  }
205
- const body = await res.json();
240
+ let body;
241
+ const rawBody = await res.text();
242
+ try {
243
+ body = JSON.parse(rawBody);
244
+ } catch (error2) {
245
+ throw new UpstashJSONParseError(rawBody, { cause: error2 });
246
+ }
206
247
  if (this.readYourWrites) {
207
248
  const headers = res.headers;
208
249
  this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
@@ -352,9 +393,9 @@ function deserialize(result) {
352
393
  return null;
353
394
  }
354
395
  const obj = {};
355
- while (result.length >= 2) {
356
- const key = result.shift();
357
- const value = result.shift();
396
+ for (let i = 0; i < result.length; i += 2) {
397
+ const key = result[i];
398
+ const value = result[i + 1];
358
399
  try {
359
400
  obj[key] = JSON.parse(value);
360
401
  } catch {
@@ -496,6 +537,13 @@ var EchoCommand = class extends Command {
496
537
  }
497
538
  };
498
539
 
540
+ // pkg/commands/evalRo.ts
541
+ var EvalROCommand = class extends Command {
542
+ constructor([script, keys, args], opts) {
543
+ super(["eval_ro", script, keys.length, ...keys, ...args ?? []], opts);
544
+ }
545
+ };
546
+
499
547
  // pkg/commands/eval.ts
500
548
  var EvalCommand = class extends Command {
501
549
  constructor([script, keys, args], opts) {
@@ -503,6 +551,13 @@ var EvalCommand = class extends Command {
503
551
  }
504
552
  };
505
553
 
554
+ // pkg/commands/evalshaRo.ts
555
+ var EvalshaROCommand = class extends Command {
556
+ constructor([sha, keys, args], opts) {
557
+ super(["evalsha_ro", sha, keys.length, ...keys, ...args ?? []], opts);
558
+ }
559
+ };
560
+
506
561
  // pkg/commands/evalsha.ts
507
562
  var EvalshaCommand = class extends Command {
508
563
  constructor([sha, keys, args], opts) {
@@ -539,6 +594,20 @@ var ExpireAtCommand = class extends Command {
539
594
  }
540
595
  };
541
596
 
597
+ // pkg/commands/fcall.ts
598
+ var FCallCommand = class extends Command {
599
+ constructor([fn, keys, args], opts) {
600
+ super(["fcall", fn, ...keys ? [keys.length, ...keys] : [0], ...args ?? []], opts);
601
+ }
602
+ };
603
+
604
+ // pkg/commands/fcall_ro.ts
605
+ var FCallRoCommand = class extends Command {
606
+ constructor([fn, keys, args], opts) {
607
+ super(["fcall_ro", fn, ...keys ? [keys.length, ...keys] : [], ...args ?? []], opts);
608
+ }
609
+ };
610
+
542
611
  // pkg/commands/flushall.ts
543
612
  var FlushAllCommand = class extends Command {
544
613
  constructor(args, opts) {
@@ -561,6 +630,85 @@ var FlushDBCommand = class extends Command {
561
630
  }
562
631
  };
563
632
 
633
+ // pkg/commands/function_delete.ts
634
+ var FunctionDeleteCommand = class extends Command {
635
+ constructor([libraryName], opts) {
636
+ super(["function", "delete", libraryName], opts);
637
+ }
638
+ };
639
+
640
+ // pkg/commands/function_flush.ts
641
+ var FunctionFlushCommand = class extends Command {
642
+ constructor(opts) {
643
+ super(["function", "flush"], opts);
644
+ }
645
+ };
646
+
647
+ // pkg/commands/function_list.ts
648
+ var FunctionListCommand = class extends Command {
649
+ constructor([args], opts) {
650
+ const command = ["function", "list"];
651
+ if (args?.libraryName) {
652
+ command.push("libraryname", args.libraryName);
653
+ }
654
+ if (args?.withCode) {
655
+ command.push("withcode");
656
+ }
657
+ super(command, { deserialize: deserialize2, ...opts });
658
+ }
659
+ };
660
+ function deserialize2(result) {
661
+ if (!Array.isArray(result)) return [];
662
+ return result.map((libRaw) => {
663
+ const lib = kvArrayToObject(libRaw);
664
+ const functionsParsed = lib.functions.map(
665
+ (fnRaw) => kvArrayToObject(fnRaw)
666
+ );
667
+ return {
668
+ libraryName: lib.library_name,
669
+ engine: lib.engine,
670
+ functions: functionsParsed.map((fn) => ({
671
+ name: fn.name,
672
+ description: fn.description ?? void 0,
673
+ flags: fn.flags
674
+ })),
675
+ libraryCode: lib.library_code
676
+ };
677
+ });
678
+ }
679
+
680
+ // pkg/commands/function_load.ts
681
+ var FunctionLoadCommand = class extends Command {
682
+ constructor([args], opts) {
683
+ super(["function", "load", ...args.replace ? ["replace"] : [], args.code], opts);
684
+ }
685
+ };
686
+
687
+ // pkg/commands/function_stats.ts
688
+ var FunctionStatsCommand = class extends Command {
689
+ constructor(opts) {
690
+ super(["function", "stats"], { deserialize: deserialize3, ...opts });
691
+ }
692
+ };
693
+ function deserialize3(result) {
694
+ const rawEngines = kvArrayToObject(kvArrayToObject(result).engines);
695
+ const parsedEngines = Object.fromEntries(
696
+ Object.entries(rawEngines).map(([key, value]) => [key, kvArrayToObject(value)])
697
+ );
698
+ const final = {
699
+ engines: Object.fromEntries(
700
+ Object.entries(parsedEngines).map(([key, value]) => [
701
+ key,
702
+ {
703
+ librariesCount: value.libraries_count,
704
+ functionsCount: value.functions_count
705
+ }
706
+ ])
707
+ )
708
+ };
709
+ return final;
710
+ }
711
+
564
712
  // pkg/commands/geo_add.ts
565
713
  var GeoAddCommand = class extends Command {
566
714
  constructor([key, arg1, ...arg2], opts) {
@@ -783,6 +931,122 @@ var HExistsCommand = class extends Command {
783
931
  }
784
932
  };
785
933
 
934
+ // pkg/commands/hexpire.ts
935
+ var HExpireCommand = class extends Command {
936
+ constructor(cmd, opts) {
937
+ const [key, fields, seconds, option] = cmd;
938
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
939
+ super(
940
+ [
941
+ "hexpire",
942
+ key,
943
+ seconds,
944
+ ...option ? [option] : [],
945
+ "FIELDS",
946
+ fieldArray.length,
947
+ ...fieldArray
948
+ ],
949
+ opts
950
+ );
951
+ }
952
+ };
953
+
954
+ // pkg/commands/hexpireat.ts
955
+ var HExpireAtCommand = class extends Command {
956
+ constructor(cmd, opts) {
957
+ const [key, fields, timestamp, option] = cmd;
958
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
959
+ super(
960
+ [
961
+ "hexpireat",
962
+ key,
963
+ timestamp,
964
+ ...option ? [option] : [],
965
+ "FIELDS",
966
+ fieldArray.length,
967
+ ...fieldArray
968
+ ],
969
+ opts
970
+ );
971
+ }
972
+ };
973
+
974
+ // pkg/commands/hexpiretime.ts
975
+ var HExpireTimeCommand = class extends Command {
976
+ constructor(cmd, opts) {
977
+ const [key, fields] = cmd;
978
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
979
+ super(["hexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
980
+ }
981
+ };
982
+
983
+ // pkg/commands/hpersist.ts
984
+ var HPersistCommand = class extends Command {
985
+ constructor(cmd, opts) {
986
+ const [key, fields] = cmd;
987
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
988
+ super(["hpersist", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
989
+ }
990
+ };
991
+
992
+ // pkg/commands/hpexpire.ts
993
+ var HPExpireCommand = class extends Command {
994
+ constructor(cmd, opts) {
995
+ const [key, fields, milliseconds, option] = cmd;
996
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
997
+ super(
998
+ [
999
+ "hpexpire",
1000
+ key,
1001
+ milliseconds,
1002
+ ...option ? [option] : [],
1003
+ "FIELDS",
1004
+ fieldArray.length,
1005
+ ...fieldArray
1006
+ ],
1007
+ opts
1008
+ );
1009
+ }
1010
+ };
1011
+
1012
+ // pkg/commands/hpexpireat.ts
1013
+ var HPExpireAtCommand = class extends Command {
1014
+ constructor(cmd, opts) {
1015
+ const [key, fields, timestamp, option] = cmd;
1016
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1017
+ super(
1018
+ [
1019
+ "hpexpireat",
1020
+ key,
1021
+ timestamp,
1022
+ ...option ? [option] : [],
1023
+ "FIELDS",
1024
+ fieldArray.length,
1025
+ ...fieldArray
1026
+ ],
1027
+ opts
1028
+ );
1029
+ }
1030
+ };
1031
+
1032
+ // pkg/commands/hpexpiretime.ts
1033
+ var HPExpireTimeCommand = class extends Command {
1034
+ constructor(cmd, opts) {
1035
+ const [key, fields] = cmd;
1036
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1037
+ super(["hpexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1038
+ }
1039
+ };
1040
+
1041
+ // pkg/commands/hpttl.ts
1042
+ var HPTtlCommand = class extends Command {
1043
+ constructor(cmd, opts) {
1044
+ const [key, fields] = cmd;
1045
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1046
+ super(["hpttl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1047
+ }
1048
+ };
1049
+
786
1050
  // pkg/commands/hget.ts
787
1051
  var HGetCommand = class extends Command {
788
1052
  constructor(cmd, opts) {
@@ -791,14 +1055,14 @@ var HGetCommand = class extends Command {
791
1055
  };
792
1056
 
793
1057
  // pkg/commands/hgetall.ts
794
- function deserialize2(result) {
1058
+ function deserialize4(result) {
795
1059
  if (result.length === 0) {
796
1060
  return null;
797
1061
  }
798
1062
  const obj = {};
799
- while (result.length >= 2) {
800
- const key = result.shift();
801
- const value = result.shift();
1063
+ for (let i = 0; i < result.length; i += 2) {
1064
+ const key = result[i];
1065
+ const value = result[i + 1];
802
1066
  try {
803
1067
  const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
804
1068
  obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
@@ -811,7 +1075,7 @@ function deserialize2(result) {
811
1075
  var HGetAllCommand = class extends Command {
812
1076
  constructor(cmd, opts) {
813
1077
  super(["hgetall", ...cmd], {
814
- deserialize: (result) => deserialize2(result),
1078
+ deserialize: (result) => deserialize4(result),
815
1079
  ...opts
816
1080
  });
817
1081
  }
@@ -846,7 +1110,7 @@ var HLenCommand = class extends Command {
846
1110
  };
847
1111
 
848
1112
  // pkg/commands/hmget.ts
849
- function deserialize3(fields, result) {
1113
+ function deserialize5(fields, result) {
850
1114
  if (result.every((field) => field === null)) {
851
1115
  return null;
852
1116
  }
@@ -863,7 +1127,7 @@ function deserialize3(fields, result) {
863
1127
  var HMGetCommand = class extends Command {
864
1128
  constructor([key, ...fields], opts) {
865
1129
  super(["hmget", key, ...fields], {
866
- deserialize: (result) => deserialize3(fields, result),
1130
+ deserialize: (result) => deserialize5(fields, result),
867
1131
  ...opts
868
1132
  });
869
1133
  }
@@ -914,6 +1178,15 @@ var HStrLenCommand = class extends Command {
914
1178
  }
915
1179
  };
916
1180
 
1181
+ // pkg/commands/httl.ts
1182
+ var HTtlCommand = class extends Command {
1183
+ constructor(cmd, opts) {
1184
+ const [key, fields] = cmd;
1185
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1186
+ super(["httl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1187
+ }
1188
+ };
1189
+
917
1190
  // pkg/commands/hvals.ts
918
1191
  var HValsCommand = class extends Command {
919
1192
  constructor(cmd, opts) {
@@ -1033,6 +1306,14 @@ var JsonGetCommand = class extends Command {
1033
1306
  }
1034
1307
  };
1035
1308
 
1309
+ // pkg/commands/json_merge.ts
1310
+ var JsonMergeCommand = class extends Command {
1311
+ constructor(cmd, opts) {
1312
+ const command = ["JSON.MERGE", ...cmd];
1313
+ super(command, opts);
1314
+ }
1315
+ };
1316
+
1036
1317
  // pkg/commands/json_mget.ts
1037
1318
  var JsonMGetCommand = class extends Command {
1038
1319
  constructor(cmd, opts) {
@@ -1393,11 +1674,14 @@ var ScanCommand = class extends Command {
1393
1674
  if (typeof opts?.count === "number") {
1394
1675
  command.push("count", opts.count);
1395
1676
  }
1396
- if (opts?.type && opts.type.length > 0) {
1677
+ if (opts && "withType" in opts && opts.withType === true) {
1678
+ command.push("withtype");
1679
+ } else if (opts && "type" in opts && opts.type && opts.type.length > 0) {
1397
1680
  command.push("type", opts.type);
1398
1681
  }
1399
1682
  super(command, {
1400
- deserialize: deserializeScanResponse,
1683
+ // @ts-expect-error ignore types here
1684
+ deserialize: opts?.withType ? deserializeScanWithTypesResponse : deserializeScanResponse,
1401
1685
  ...cmdOpts
1402
1686
  });
1403
1687
  }
@@ -1820,18 +2104,18 @@ var XPendingCommand = class extends Command {
1820
2104
  };
1821
2105
 
1822
2106
  // pkg/commands/xrange.ts
1823
- function deserialize4(result) {
2107
+ function deserialize6(result) {
1824
2108
  const obj = {};
1825
2109
  for (const e of result) {
1826
- while (e.length >= 2) {
1827
- const streamId = e.shift();
1828
- const entries = e.shift();
2110
+ for (let i = 0; i < e.length; i += 2) {
2111
+ const streamId = e[i];
2112
+ const entries = e[i + 1];
1829
2113
  if (!(streamId in obj)) {
1830
2114
  obj[streamId] = {};
1831
2115
  }
1832
- while (entries.length >= 2) {
1833
- const field = entries.shift();
1834
- const value = entries.shift();
2116
+ for (let j = 0; j < entries.length; j += 2) {
2117
+ const field = entries[j];
2118
+ const value = entries[j + 1];
1835
2119
  try {
1836
2120
  obj[streamId][field] = JSON.parse(value);
1837
2121
  } catch {
@@ -1849,7 +2133,7 @@ var XRangeCommand = class extends Command {
1849
2133
  command.push("COUNT", count);
1850
2134
  }
1851
2135
  super(command, {
1852
- deserialize: (result) => deserialize4(result),
2136
+ deserialize: (result) => deserialize6(result),
1853
2137
  ...opts
1854
2138
  });
1855
2139
  }
@@ -1912,23 +2196,23 @@ var XRevRangeCommand = class extends Command {
1912
2196
  command.push("COUNT", count);
1913
2197
  }
1914
2198
  super(command, {
1915
- deserialize: (result) => deserialize5(result),
2199
+ deserialize: (result) => deserialize7(result),
1916
2200
  ...opts
1917
2201
  });
1918
2202
  }
1919
2203
  };
1920
- function deserialize5(result) {
2204
+ function deserialize7(result) {
1921
2205
  const obj = {};
1922
2206
  for (const e of result) {
1923
- while (e.length >= 2) {
1924
- const streamId = e.shift();
1925
- const entries = e.shift();
2207
+ for (let i = 0; i < e.length; i += 2) {
2208
+ const streamId = e[i];
2209
+ const entries = e[i + 1];
1926
2210
  if (!(streamId in obj)) {
1927
2211
  obj[streamId] = {};
1928
2212
  }
1929
- while (entries.length >= 2) {
1930
- const field = entries.shift();
1931
- const value = entries.shift();
2213
+ for (let j = 0; j < entries.length; j += 2) {
2214
+ const field = entries[j];
2215
+ const value = entries[j + 1];
1932
2216
  try {
1933
2217
  obj[streamId][field] = JSON.parse(value);
1934
2218
  } catch {
@@ -2327,10 +2611,18 @@ var Pipeline = class {
2327
2611
  * @see https://redis.io/commands/echo
2328
2612
  */
2329
2613
  echo = (...args) => this.chain(new EchoCommand(args, this.commandOptions));
2614
+ /**
2615
+ * @see https://redis.io/commands/eval_ro
2616
+ */
2617
+ evalRo = (...args) => this.chain(new EvalROCommand(args, this.commandOptions));
2330
2618
  /**
2331
2619
  * @see https://redis.io/commands/eval
2332
2620
  */
2333
2621
  eval = (...args) => this.chain(new EvalCommand(args, this.commandOptions));
2622
+ /**
2623
+ * @see https://redis.io/commands/evalsha_ro
2624
+ */
2625
+ evalshaRo = (...args) => this.chain(new EvalshaROCommand(args, this.commandOptions));
2334
2626
  /**
2335
2627
  * @see https://redis.io/commands/evalsha
2336
2628
  */
@@ -2411,6 +2703,42 @@ var Pipeline = class {
2411
2703
  * @see https://redis.io/commands/hexists
2412
2704
  */
2413
2705
  hexists = (...args) => this.chain(new HExistsCommand(args, this.commandOptions));
2706
+ /**
2707
+ * @see https://redis.io/commands/hexpire
2708
+ */
2709
+ hexpire = (...args) => this.chain(new HExpireCommand(args, this.commandOptions));
2710
+ /**
2711
+ * @see https://redis.io/commands/hexpireat
2712
+ */
2713
+ hexpireat = (...args) => this.chain(new HExpireAtCommand(args, this.commandOptions));
2714
+ /**
2715
+ * @see https://redis.io/commands/hexpiretime
2716
+ */
2717
+ hexpiretime = (...args) => this.chain(new HExpireTimeCommand(args, this.commandOptions));
2718
+ /**
2719
+ * @see https://redis.io/commands/httl
2720
+ */
2721
+ httl = (...args) => this.chain(new HTtlCommand(args, this.commandOptions));
2722
+ /**
2723
+ * @see https://redis.io/commands/hpexpire
2724
+ */
2725
+ hpexpire = (...args) => this.chain(new HPExpireCommand(args, this.commandOptions));
2726
+ /**
2727
+ * @see https://redis.io/commands/hpexpireat
2728
+ */
2729
+ hpexpireat = (...args) => this.chain(new HPExpireAtCommand(args, this.commandOptions));
2730
+ /**
2731
+ * @see https://redis.io/commands/hpexpiretime
2732
+ */
2733
+ hpexpiretime = (...args) => this.chain(new HPExpireTimeCommand(args, this.commandOptions));
2734
+ /**
2735
+ * @see https://redis.io/commands/hpttl
2736
+ */
2737
+ hpttl = (...args) => this.chain(new HPTtlCommand(args, this.commandOptions));
2738
+ /**
2739
+ * @see https://redis.io/commands/hpersist
2740
+ */
2741
+ hpersist = (...args) => this.chain(new HPersistCommand(args, this.commandOptions));
2414
2742
  /**
2415
2743
  * @see https://redis.io/commands/hget
2416
2744
  */
@@ -2928,6 +3256,10 @@ var Pipeline = class {
2928
3256
  * @see https://redis.io/commands/json.get
2929
3257
  */
2930
3258
  get: (...args) => this.chain(new JsonGetCommand(args, this.commandOptions)),
3259
+ /**
3260
+ * @see https://redis.io/commands/json.merge
3261
+ */
3262
+ merge: (...args) => this.chain(new JsonMergeCommand(args, this.commandOptions)),
2931
3263
  /**
2932
3264
  * @see https://redis.io/commands/json.mget
2933
3265
  */
@@ -2978,10 +3310,60 @@ var Pipeline = class {
2978
3310
  type: (...args) => this.chain(new JsonTypeCommand(args, this.commandOptions))
2979
3311
  };
2980
3312
  }
3313
+ get functions() {
3314
+ return {
3315
+ /**
3316
+ * @see https://redis.io/docs/latest/commands/function-load/
3317
+ */
3318
+ load: (...args) => this.chain(new FunctionLoadCommand(args, this.commandOptions)),
3319
+ /**
3320
+ * @see https://redis.io/docs/latest/commands/function-list/
3321
+ */
3322
+ list: (...args) => this.chain(new FunctionListCommand(args, this.commandOptions)),
3323
+ /**
3324
+ * @see https://redis.io/docs/latest/commands/function-delete/
3325
+ */
3326
+ delete: (...args) => this.chain(new FunctionDeleteCommand(args, this.commandOptions)),
3327
+ /**
3328
+ * @see https://redis.io/docs/latest/commands/function-flush/
3329
+ */
3330
+ flush: () => this.chain(new FunctionFlushCommand(this.commandOptions)),
3331
+ /**
3332
+ * @see https://redis.io/docs/latest/commands/function-stats/
3333
+ */
3334
+ stats: () => this.chain(new FunctionStatsCommand(this.commandOptions)),
3335
+ /**
3336
+ * @see https://redis.io/docs/latest/commands/fcall/
3337
+ */
3338
+ call: (...args) => this.chain(new FCallCommand(args, this.commandOptions)),
3339
+ /**
3340
+ * @see https://redis.io/docs/latest/commands/fcall_ro/
3341
+ */
3342
+ callRo: (...args) => this.chain(new FCallRoCommand(args, this.commandOptions))
3343
+ };
3344
+ }
2981
3345
  };
2982
3346
 
2983
3347
  // pkg/auto-pipeline.ts
2984
- function createAutoPipelineProxy(_redis, json) {
3348
+ var EXCLUDE_COMMANDS = /* @__PURE__ */ new Set([
3349
+ "scan",
3350
+ "keys",
3351
+ "flushdb",
3352
+ "flushall",
3353
+ "dbsize",
3354
+ "hscan",
3355
+ "hgetall",
3356
+ "hkeys",
3357
+ "lrange",
3358
+ "sscan",
3359
+ "smembers",
3360
+ "xrange",
3361
+ "xrevrange",
3362
+ "zscan",
3363
+ "zrange",
3364
+ "exec"
3365
+ ]);
3366
+ function createAutoPipelineProxy(_redis, namespace = "root") {
2985
3367
  const redis = _redis;
2986
3368
  if (!redis.autoPipelineExecutor) {
2987
3369
  redis.autoPipelineExecutor = new AutoPipelineExecutor(redis);
@@ -2991,28 +3373,31 @@ function createAutoPipelineProxy(_redis, json) {
2991
3373
  if (command === "pipelineCounter") {
2992
3374
  return redis2.autoPipelineExecutor.pipelineCounter;
2993
3375
  }
2994
- if (command === "json") {
2995
- return createAutoPipelineProxy(redis2, true);
3376
+ if (namespace === "root" && command === "json") {
3377
+ return createAutoPipelineProxy(redis2, "json");
3378
+ }
3379
+ if (namespace === "root" && command === "functions") {
3380
+ return createAutoPipelineProxy(redis2, "functions");
2996
3381
  }
2997
- const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
2998
- if (commandInRedisButNotPipeline) {
2999
- return redis2[command];
3382
+ if (namespace === "root") {
3383
+ const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
3384
+ const isCommandExcluded = EXCLUDE_COMMANDS.has(command);
3385
+ if (commandInRedisButNotPipeline || isCommandExcluded) {
3386
+ return redis2[command];
3387
+ }
3000
3388
  }
3001
- const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
3389
+ const pipeline = redis2.autoPipelineExecutor.pipeline;
3390
+ const targetFunction = namespace === "json" ? pipeline.json[command] : namespace === "functions" ? pipeline.functions[command] : pipeline[command];
3391
+ const isFunction = typeof targetFunction === "function";
3002
3392
  if (isFunction) {
3003
3393
  return (...args) => {
3004
- return redis2.autoPipelineExecutor.withAutoPipeline((pipeline) => {
3005
- if (json) {
3006
- pipeline.json[command](
3007
- ...args
3008
- );
3009
- } else {
3010
- pipeline[command](...args);
3011
- }
3394
+ return redis2.autoPipelineExecutor.withAutoPipeline((pipeline2) => {
3395
+ const targetFunction2 = namespace === "json" ? pipeline2.json[command] : namespace === "functions" ? pipeline2.functions[command] : pipeline2[command];
3396
+ targetFunction2(...args);
3012
3397
  });
3013
3398
  };
3014
3399
  }
3015
- return redis2.autoPipelineExecutor.pipeline[command];
3400
+ return targetFunction;
3016
3401
  }
3017
3402
  });
3018
3403
  }
@@ -3085,11 +3470,13 @@ var Subscriber = class extends EventTarget {
3085
3470
  subscriptions;
3086
3471
  client;
3087
3472
  listeners;
3088
- constructor(client, channels, isPattern = false) {
3473
+ opts;
3474
+ constructor(client, channels, isPattern = false, opts) {
3089
3475
  super();
3090
3476
  this.client = client;
3091
3477
  this.subscriptions = /* @__PURE__ */ new Map();
3092
3478
  this.listeners = /* @__PURE__ */ new Map();
3479
+ this.opts = opts;
3093
3480
  for (const channel of channels) {
3094
3481
  if (isPattern) {
3095
3482
  this.subscribeToPattern(channel);
@@ -3148,10 +3535,9 @@ var Subscriber = class extends EventTarget {
3148
3535
  const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
3149
3536
  const messageStr = messageData.slice(thirdCommaIndex + 1);
3150
3537
  try {
3151
- const message = JSON.parse(messageStr);
3152
- this.dispatchToListeners("pmessage", message);
3153
- this.dispatchToListeners(`pmessageBuffer`, { pattern, channel, message });
3154
- this.dispatchToListeners(`pmessage:${pattern}`, { channel, message });
3538
+ const message = this.opts?.automaticDeserialization === false ? messageStr : JSON.parse(messageStr);
3539
+ this.dispatchToListeners("pmessage", { pattern, channel, message });
3540
+ this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
3155
3541
  } catch (error) {
3156
3542
  this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
3157
3543
  }
@@ -3159,10 +3545,14 @@ var Subscriber = class extends EventTarget {
3159
3545
  const channel = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
3160
3546
  const messageStr = messageData.slice(secondCommaIndex + 1);
3161
3547
  try {
3162
- const message = type === "subscribe" || type === "psubscribe" ? Number.parseInt(messageStr) : JSON.parse(messageStr);
3163
- this.dispatchToListeners(type, message);
3164
- this.dispatchToListeners(`${type}Buffer`, { channel, message });
3165
- this.dispatchToListeners(`${type}:${channel}`, message);
3548
+ if (type === "subscribe" || type === "psubscribe" || type === "unsubscribe" || type === "punsubscribe") {
3549
+ const count = Number.parseInt(messageStr);
3550
+ this.dispatchToListeners(type, count);
3551
+ } else {
3552
+ const message = this.opts?.automaticDeserialization === false ? messageStr : parseWithTryCatch(messageStr);
3553
+ this.dispatchToListeners(type, { channel, message });
3554
+ this.dispatchToListeners(`${type}:${channel}`, { channel, message });
3555
+ }
3166
3556
  } catch (error) {
3167
3557
  this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
3168
3558
  }
@@ -3232,29 +3622,52 @@ var SubscribeCommand = class extends Command {
3232
3622
  });
3233
3623
  }
3234
3624
  };
3625
+ var parseWithTryCatch = (str) => {
3626
+ try {
3627
+ return JSON.parse(str);
3628
+ } catch {
3629
+ return str;
3630
+ }
3631
+ };
3235
3632
 
3236
3633
  // pkg/script.ts
3237
- import Hex from "crypto-js/enc-hex.js";
3238
- import sha1 from "crypto-js/sha1.js";
3634
+ import { subtle } from "uncrypto";
3239
3635
  var Script = class {
3240
3636
  script;
3637
+ /**
3638
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3639
+ * asynchronously. Do not use this property immidiately after the constructor.
3640
+ *
3641
+ * This property is only exposed for backwards compatibility and will be removed in the
3642
+ * future major release.
3643
+ */
3241
3644
  sha1;
3242
3645
  redis;
3243
3646
  constructor(redis, script) {
3244
3647
  this.redis = redis;
3245
- this.sha1 = this.digest(script);
3246
3648
  this.script = script;
3649
+ this.sha1 = "";
3650
+ void this.init(script);
3651
+ }
3652
+ /**
3653
+ * Initialize the script by computing its SHA-1 hash.
3654
+ */
3655
+ async init(script) {
3656
+ if (this.sha1) return;
3657
+ this.sha1 = await this.digest(script);
3247
3658
  }
3248
3659
  /**
3249
3660
  * Send an `EVAL` command to redis.
3250
3661
  */
3251
3662
  async eval(keys, args) {
3663
+ await this.init(this.script);
3252
3664
  return await this.redis.eval(this.script, keys, args);
3253
3665
  }
3254
3666
  /**
3255
3667
  * Calculates the sha1 hash of the script and then calls `EVALSHA`.
3256
3668
  */
3257
3669
  async evalsha(keys, args) {
3670
+ await this.init(this.script);
3258
3671
  return await this.redis.evalsha(this.sha1, keys, args);
3259
3672
  }
3260
3673
  /**
@@ -3264,6 +3677,7 @@ var Script = class {
3264
3677
  * Following calls will be able to use the cached script
3265
3678
  */
3266
3679
  async exec(keys, args) {
3680
+ await this.init(this.script);
3267
3681
  const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
3268
3682
  if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
3269
3683
  return await this.redis.eval(this.script, keys, args);
@@ -3275,8 +3689,75 @@ var Script = class {
3275
3689
  /**
3276
3690
  * Compute the sha1 hash of the script and return its hex representation.
3277
3691
  */
3278
- digest(s) {
3279
- return Hex.stringify(sha1(s));
3692
+ async digest(s) {
3693
+ const data = new TextEncoder().encode(s);
3694
+ const hashBuffer = await subtle.digest("SHA-1", data);
3695
+ const hashArray = [...new Uint8Array(hashBuffer)];
3696
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3697
+ }
3698
+ };
3699
+
3700
+ // pkg/scriptRo.ts
3701
+ import { subtle as subtle2 } from "uncrypto";
3702
+ var ScriptRO = class {
3703
+ script;
3704
+ /**
3705
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3706
+ * asynchronously. Do not use this property immidiately after the constructor.
3707
+ *
3708
+ * This property is only exposed for backwards compatibility and will be removed in the
3709
+ * future major release.
3710
+ */
3711
+ sha1;
3712
+ redis;
3713
+ constructor(redis, script) {
3714
+ this.redis = redis;
3715
+ this.sha1 = "";
3716
+ this.script = script;
3717
+ void this.init(script);
3718
+ }
3719
+ async init(script) {
3720
+ if (this.sha1) return;
3721
+ this.sha1 = await this.digest(script);
3722
+ }
3723
+ /**
3724
+ * Send an `EVAL_RO` command to redis.
3725
+ */
3726
+ async evalRo(keys, args) {
3727
+ await this.init(this.script);
3728
+ return await this.redis.evalRo(this.script, keys, args);
3729
+ }
3730
+ /**
3731
+ * Calculates the sha1 hash of the script and then calls `EVALSHA_RO`.
3732
+ */
3733
+ async evalshaRo(keys, args) {
3734
+ await this.init(this.script);
3735
+ return await this.redis.evalshaRo(this.sha1, keys, args);
3736
+ }
3737
+ /**
3738
+ * Optimistically try to run `EVALSHA_RO` first.
3739
+ * If the script is not loaded in redis, it will fall back and try again with `EVAL_RO`.
3740
+ *
3741
+ * Following calls will be able to use the cached script
3742
+ */
3743
+ async exec(keys, args) {
3744
+ await this.init(this.script);
3745
+ const res = await this.redis.evalshaRo(this.sha1, keys, args).catch(async (error) => {
3746
+ if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
3747
+ return await this.redis.evalRo(this.script, keys, args);
3748
+ }
3749
+ throw error;
3750
+ });
3751
+ return res;
3752
+ }
3753
+ /**
3754
+ * Compute the sha1 hash of the script and return its hex representation.
3755
+ */
3756
+ async digest(s) {
3757
+ const data = new TextEncoder().encode(s);
3758
+ const hashBuffer = await subtle2.digest("SHA-1", data);
3759
+ const hashArray = [...new Uint8Array(hashBuffer)];
3760
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3280
3761
  }
3281
3762
  };
3282
3763
 
@@ -3354,6 +3835,10 @@ var Redis = class {
3354
3835
  * @see https://redis.io/commands/json.get
3355
3836
  */
3356
3837
  get: (...args) => new JsonGetCommand(args, this.opts).exec(this.client),
3838
+ /**
3839
+ * @see https://redis.io/commands/json.merge
3840
+ */
3841
+ merge: (...args) => new JsonMergeCommand(args, this.opts).exec(this.client),
3357
3842
  /**
3358
3843
  * @see https://redis.io/commands/json.mget
3359
3844
  */
@@ -3404,6 +3889,40 @@ var Redis = class {
3404
3889
  type: (...args) => new JsonTypeCommand(args, this.opts).exec(this.client)
3405
3890
  };
3406
3891
  }
3892
+ get functions() {
3893
+ return {
3894
+ /**
3895
+ * @see https://redis.io/docs/latest/commands/function-load/
3896
+ */
3897
+ load: (...args) => new FunctionLoadCommand(args, this.opts).exec(this.client),
3898
+ /**
3899
+ * @see https://redis.io/docs/latest/commands/function-list/
3900
+ */
3901
+ list: (...args) => new FunctionListCommand(args, this.opts).exec(this.client),
3902
+ /**
3903
+ * @see https://redis.io/docs/latest/commands/function-delete/
3904
+ */
3905
+ delete: (...args) => new FunctionDeleteCommand(args, this.opts).exec(this.client),
3906
+ /**
3907
+ * @see https://redis.io/docs/latest/commands/function-flush/
3908
+ */
3909
+ flush: () => new FunctionFlushCommand(this.opts).exec(this.client),
3910
+ /**
3911
+ * @see https://redis.io/docs/latest/commands/function-stats/
3912
+ *
3913
+ * Note: `running_script` field is not supported and therefore not included in the type.
3914
+ */
3915
+ stats: () => new FunctionStatsCommand(this.opts).exec(this.client),
3916
+ /**
3917
+ * @see https://redis.io/docs/latest/commands/fcall/
3918
+ */
3919
+ call: (...args) => new FCallCommand(args, this.opts).exec(this.client),
3920
+ /**
3921
+ * @see https://redis.io/docs/latest/commands/fcall_ro/
3922
+ */
3923
+ callRo: (...args) => new FCallRoCommand(args, this.opts).exec(this.client)
3924
+ };
3925
+ }
3407
3926
  /**
3408
3927
  * Wrap a new middleware around the HTTP client.
3409
3928
  */
@@ -3423,8 +3942,36 @@ var Redis = class {
3423
3942
  } catch {
3424
3943
  }
3425
3944
  };
3426
- createScript(script) {
3427
- return new Script(this, script);
3945
+ /**
3946
+ * Creates a new script.
3947
+ *
3948
+ * Scripts offer the ability to optimistically try to execute a script without having to send the
3949
+ * entire script to the server. If the script is loaded on the server, it tries again by sending
3950
+ * the entire script. Afterwards, the script is cached on the server.
3951
+ *
3952
+ * @param script - The script to create
3953
+ * @param opts - Optional options to pass to the script `{ readonly?: boolean }`
3954
+ * @returns A new script
3955
+ *
3956
+ * @example
3957
+ * ```ts
3958
+ * const redis = new Redis({...})
3959
+ *
3960
+ * const script = redis.createScript<string>("return ARGV[1];")
3961
+ * const arg1 = await script.eval([], ["Hello World"])
3962
+ * expect(arg1, "Hello World")
3963
+ * ```
3964
+ * @example
3965
+ * ```ts
3966
+ * const redis = new Redis({...})
3967
+ *
3968
+ * const script = redis.createScript<string>("return ARGV[1];", { readonly: true })
3969
+ * const arg1 = await script.evalRo([], ["Hello World"])
3970
+ * expect(arg1, "Hello World")
3971
+ * ```
3972
+ */
3973
+ createScript(script, opts) {
3974
+ return opts?.readonly ? new ScriptRO(this, script) : new Script(this, script);
3428
3975
  }
3429
3976
  /**
3430
3977
  * Create a new pipeline that allows you to send requests in bulk.
@@ -3511,10 +4058,18 @@ var Redis = class {
3511
4058
  * @see https://redis.io/commands/echo
3512
4059
  */
3513
4060
  echo = (...args) => new EchoCommand(args, this.opts).exec(this.client);
4061
+ /**
4062
+ * @see https://redis.io/commands/eval_ro
4063
+ */
4064
+ evalRo = (...args) => new EvalROCommand(args, this.opts).exec(this.client);
3514
4065
  /**
3515
4066
  * @see https://redis.io/commands/eval
3516
4067
  */
3517
4068
  eval = (...args) => new EvalCommand(args, this.opts).exec(this.client);
4069
+ /**
4070
+ * @see https://redis.io/commands/evalsha_ro
4071
+ */
4072
+ evalshaRo = (...args) => new EvalshaROCommand(args, this.opts).exec(this.client);
3518
4073
  /**
3519
4074
  * @see https://redis.io/commands/evalsha
3520
4075
  */
@@ -3599,6 +4154,42 @@ var Redis = class {
3599
4154
  * @see https://redis.io/commands/hexists
3600
4155
  */
3601
4156
  hexists = (...args) => new HExistsCommand(args, this.opts).exec(this.client);
4157
+ /**
4158
+ * @see https://redis.io/commands/hexpire
4159
+ */
4160
+ hexpire = (...args) => new HExpireCommand(args, this.opts).exec(this.client);
4161
+ /**
4162
+ * @see https://redis.io/commands/hexpireat
4163
+ */
4164
+ hexpireat = (...args) => new HExpireAtCommand(args, this.opts).exec(this.client);
4165
+ /**
4166
+ * @see https://redis.io/commands/hexpiretime
4167
+ */
4168
+ hexpiretime = (...args) => new HExpireTimeCommand(args, this.opts).exec(this.client);
4169
+ /**
4170
+ * @see https://redis.io/commands/httl
4171
+ */
4172
+ httl = (...args) => new HTtlCommand(args, this.opts).exec(this.client);
4173
+ /**
4174
+ * @see https://redis.io/commands/hpexpire
4175
+ */
4176
+ hpexpire = (...args) => new HPExpireCommand(args, this.opts).exec(this.client);
4177
+ /**
4178
+ * @see https://redis.io/commands/hpexpireat
4179
+ */
4180
+ hpexpireat = (...args) => new HPExpireAtCommand(args, this.opts).exec(this.client);
4181
+ /**
4182
+ * @see https://redis.io/commands/hpexpiretime
4183
+ */
4184
+ hpexpiretime = (...args) => new HPExpireTimeCommand(args, this.opts).exec(this.client);
4185
+ /**
4186
+ * @see https://redis.io/commands/hpttl
4187
+ */
4188
+ hpttl = (...args) => new HPTtlCommand(args, this.opts).exec(this.client);
4189
+ /**
4190
+ * @see https://redis.io/commands/hpersist
4191
+ */
4192
+ hpersist = (...args) => new HPersistCommand(args, this.opts).exec(this.client);
3602
4193
  /**
3603
4194
  * @see https://redis.io/commands/hget
3604
4195
  */
@@ -3767,9 +4358,12 @@ var Redis = class {
3767
4358
  * @see https://redis.io/commands/psetex
3768
4359
  */
3769
4360
  psetex = (key, ttl, value) => new PSetEXCommand([key, ttl, value], this.opts).exec(this.client);
4361
+ /**
4362
+ * @see https://redis.io/commands/psubscribe
4363
+ */
3770
4364
  psubscribe = (patterns) => {
3771
4365
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
3772
- return new Subscriber(this.client, patternArray, true);
4366
+ return new Subscriber(this.client, patternArray, true, this.opts);
3773
4367
  };
3774
4368
  /**
3775
4369
  * @see https://redis.io/commands/pttl
@@ -3807,10 +4401,9 @@ var Redis = class {
3807
4401
  * @see https://redis.io/commands/sadd
3808
4402
  */
3809
4403
  sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
3810
- /**
3811
- * @see https://redis.io/commands/scan
3812
- */
3813
- scan = (...args) => new ScanCommand(args, this.opts).exec(this.client);
4404
+ scan(cursor, opts) {
4405
+ return new ScanCommand([cursor, opts], this.opts).exec(this.client);
4406
+ }
3814
4407
  /**
3815
4408
  * @see https://redis.io/commands/scard
3816
4409
  */
@@ -3904,7 +4497,7 @@ var Redis = class {
3904
4497
  */
3905
4498
  subscribe = (channels) => {
3906
4499
  const channelArray = Array.isArray(channels) ? channels : [channels];
3907
- return new Subscriber(this.client, channelArray);
4500
+ return new Subscriber(this.client, channelArray, false, this.opts);
3908
4501
  };
3909
4502
  /**
3910
4503
  * @see https://redis.io/commands/sunion