@upstash/redis 0.0.0-ci.9846a4b6d92b334b3956b0947a58e9bef9c92a42-20250303091249 → 0.0.0-ci.9a0f7fcd9dc38c0a4ce2b192f3f9c3542ccc791c-20251125190254

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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) {
@@ -113,6 +129,8 @@ var HttpClient = class {
113
129
  const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
114
130
  const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
115
131
  const isEventStream = requestHeaders.Accept === "text/event-stream";
132
+ const signal = req.signal ?? this.options.signal;
133
+ const isSignalFunction = typeof signal === "function";
116
134
  const requestOptions = {
117
135
  //@ts-expect-error this should throw due to bun regression
118
136
  cache: this.options.cache,
@@ -121,7 +139,7 @@ var HttpClient = class {
121
139
  body: JSON.stringify(req.body),
122
140
  keepalive: this.options.keepAlive,
123
141
  agent: this.options.agent,
124
- signal: req.signal ?? this.options.signal,
142
+ signal: isSignalFunction ? signal() : signal,
125
143
  /**
126
144
  * Fastly specific
127
145
  */
@@ -143,13 +161,15 @@ var HttpClient = class {
143
161
  res = await fetch(requestUrl, requestOptions);
144
162
  break;
145
163
  } catch (error_) {
146
- if (this.options.signal?.aborted) {
164
+ if (requestOptions.signal?.aborted && isSignalFunction) {
165
+ throw error_;
166
+ } else if (requestOptions.signal?.aborted) {
147
167
  const myBlob = new Blob([
148
- JSON.stringify({ result: this.options.signal.reason ?? "Aborted" })
168
+ JSON.stringify({ result: requestOptions.signal.reason ?? "Aborted" })
149
169
  ]);
150
170
  const myOptions = {
151
171
  status: 200,
152
- statusText: this.options.signal.reason ?? "Aborted"
172
+ statusText: requestOptions.signal.reason ?? "Aborted"
153
173
  };
154
174
  res = new Response(myBlob, myOptions);
155
175
  break;
@@ -164,7 +184,13 @@ var HttpClient = class {
164
184
  throw error ?? new Error("Exhausted all retries");
165
185
  }
166
186
  if (!res.ok) {
167
- const body2 = await res.json();
187
+ let body2;
188
+ const rawBody2 = await res.text();
189
+ try {
190
+ body2 = JSON.parse(rawBody2);
191
+ } catch (error2) {
192
+ throw new UpstashJSONParseError(rawBody2, { cause: error2 });
193
+ }
168
194
  throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
169
195
  }
170
196
  if (this.readYourWrites) {
@@ -202,7 +228,13 @@ var HttpClient = class {
202
228
  })();
203
229
  return { result: 1 };
204
230
  }
205
- const body = await res.json();
231
+ let body;
232
+ const rawBody = await res.text();
233
+ try {
234
+ body = JSON.parse(rawBody);
235
+ } catch (error2) {
236
+ throw new UpstashJSONParseError(rawBody, { cause: error2 });
237
+ }
206
238
  if (this.readYourWrites) {
207
239
  const headers = res.headers;
208
240
  this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
@@ -352,9 +384,9 @@ function deserialize(result) {
352
384
  return null;
353
385
  }
354
386
  const obj = {};
355
- while (result.length >= 2) {
356
- const key = result.shift();
357
- const value = result.shift();
387
+ for (let i = 0; i < result.length; i += 2) {
388
+ const key = result[i];
389
+ const value = result[i + 1];
358
390
  try {
359
391
  obj[key] = JSON.parse(value);
360
392
  } catch {
@@ -496,6 +528,13 @@ var EchoCommand = class extends Command {
496
528
  }
497
529
  };
498
530
 
531
+ // pkg/commands/evalRo.ts
532
+ var EvalROCommand = class extends Command {
533
+ constructor([script, keys, args], opts) {
534
+ super(["eval_ro", script, keys.length, ...keys, ...args ?? []], opts);
535
+ }
536
+ };
537
+
499
538
  // pkg/commands/eval.ts
500
539
  var EvalCommand = class extends Command {
501
540
  constructor([script, keys, args], opts) {
@@ -503,6 +542,13 @@ var EvalCommand = class extends Command {
503
542
  }
504
543
  };
505
544
 
545
+ // pkg/commands/evalshaRo.ts
546
+ var EvalshaROCommand = class extends Command {
547
+ constructor([sha, keys, args], opts) {
548
+ super(["evalsha_ro", sha, keys.length, ...keys, ...args ?? []], opts);
549
+ }
550
+ };
551
+
506
552
  // pkg/commands/evalsha.ts
507
553
  var EvalshaCommand = class extends Command {
508
554
  constructor([sha, keys, args], opts) {
@@ -783,6 +829,122 @@ var HExistsCommand = class extends Command {
783
829
  }
784
830
  };
785
831
 
832
+ // pkg/commands/hexpire.ts
833
+ var HExpireCommand = class extends Command {
834
+ constructor(cmd, opts) {
835
+ const [key, fields, seconds, option] = cmd;
836
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
837
+ super(
838
+ [
839
+ "hexpire",
840
+ key,
841
+ seconds,
842
+ ...option ? [option] : [],
843
+ "FIELDS",
844
+ fieldArray.length,
845
+ ...fieldArray
846
+ ],
847
+ opts
848
+ );
849
+ }
850
+ };
851
+
852
+ // pkg/commands/hexpireat.ts
853
+ var HExpireAtCommand = class extends Command {
854
+ constructor(cmd, opts) {
855
+ const [key, fields, timestamp, option] = cmd;
856
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
857
+ super(
858
+ [
859
+ "hexpireat",
860
+ key,
861
+ timestamp,
862
+ ...option ? [option] : [],
863
+ "FIELDS",
864
+ fieldArray.length,
865
+ ...fieldArray
866
+ ],
867
+ opts
868
+ );
869
+ }
870
+ };
871
+
872
+ // pkg/commands/hexpiretime.ts
873
+ var HExpireTimeCommand = class extends Command {
874
+ constructor(cmd, opts) {
875
+ const [key, fields] = cmd;
876
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
877
+ super(["hexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
878
+ }
879
+ };
880
+
881
+ // pkg/commands/hpersist.ts
882
+ var HPersistCommand = class extends Command {
883
+ constructor(cmd, opts) {
884
+ const [key, fields] = cmd;
885
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
886
+ super(["hpersist", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
887
+ }
888
+ };
889
+
890
+ // pkg/commands/hpexpire.ts
891
+ var HPExpireCommand = class extends Command {
892
+ constructor(cmd, opts) {
893
+ const [key, fields, milliseconds, option] = cmd;
894
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
895
+ super(
896
+ [
897
+ "hpexpire",
898
+ key,
899
+ milliseconds,
900
+ ...option ? [option] : [],
901
+ "FIELDS",
902
+ fieldArray.length,
903
+ ...fieldArray
904
+ ],
905
+ opts
906
+ );
907
+ }
908
+ };
909
+
910
+ // pkg/commands/hpexpireat.ts
911
+ var HPExpireAtCommand = class extends Command {
912
+ constructor(cmd, opts) {
913
+ const [key, fields, timestamp, option] = cmd;
914
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
915
+ super(
916
+ [
917
+ "hpexpireat",
918
+ key,
919
+ timestamp,
920
+ ...option ? [option] : [],
921
+ "FIELDS",
922
+ fieldArray.length,
923
+ ...fieldArray
924
+ ],
925
+ opts
926
+ );
927
+ }
928
+ };
929
+
930
+ // pkg/commands/hpexpiretime.ts
931
+ var HPExpireTimeCommand = class extends Command {
932
+ constructor(cmd, opts) {
933
+ const [key, fields] = cmd;
934
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
935
+ super(["hpexpiretime", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
936
+ }
937
+ };
938
+
939
+ // pkg/commands/hpttl.ts
940
+ var HPTtlCommand = class extends Command {
941
+ constructor(cmd, opts) {
942
+ const [key, fields] = cmd;
943
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
944
+ super(["hpttl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
945
+ }
946
+ };
947
+
786
948
  // pkg/commands/hget.ts
787
949
  var HGetCommand = class extends Command {
788
950
  constructor(cmd, opts) {
@@ -796,9 +958,9 @@ function deserialize2(result) {
796
958
  return null;
797
959
  }
798
960
  const obj = {};
799
- while (result.length >= 2) {
800
- const key = result.shift();
801
- const value = result.shift();
961
+ for (let i = 0; i < result.length; i += 2) {
962
+ const key = result[i];
963
+ const value = result[i + 1];
802
964
  try {
803
965
  const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
804
966
  obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
@@ -914,6 +1076,15 @@ var HStrLenCommand = class extends Command {
914
1076
  }
915
1077
  };
916
1078
 
1079
+ // pkg/commands/httl.ts
1080
+ var HTtlCommand = class extends Command {
1081
+ constructor(cmd, opts) {
1082
+ const [key, fields] = cmd;
1083
+ const fieldArray = Array.isArray(fields) ? fields : [fields];
1084
+ super(["httl", key, "FIELDS", fieldArray.length, ...fieldArray], opts);
1085
+ }
1086
+ };
1087
+
917
1088
  // pkg/commands/hvals.ts
918
1089
  var HValsCommand = class extends Command {
919
1090
  constructor(cmd, opts) {
@@ -1033,6 +1204,14 @@ var JsonGetCommand = class extends Command {
1033
1204
  }
1034
1205
  };
1035
1206
 
1207
+ // pkg/commands/json_merge.ts
1208
+ var JsonMergeCommand = class extends Command {
1209
+ constructor(cmd, opts) {
1210
+ const command = ["JSON.MERGE", ...cmd];
1211
+ super(command, opts);
1212
+ }
1213
+ };
1214
+
1036
1215
  // pkg/commands/json_mget.ts
1037
1216
  var JsonMGetCommand = class extends Command {
1038
1217
  constructor(cmd, opts) {
@@ -1393,11 +1572,14 @@ var ScanCommand = class extends Command {
1393
1572
  if (typeof opts?.count === "number") {
1394
1573
  command.push("count", opts.count);
1395
1574
  }
1396
- if (opts?.type && opts.type.length > 0) {
1575
+ if (opts && "withType" in opts && opts.withType === true) {
1576
+ command.push("withtype");
1577
+ } else if (opts && "type" in opts && opts.type && opts.type.length > 0) {
1397
1578
  command.push("type", opts.type);
1398
1579
  }
1399
1580
  super(command, {
1400
- deserialize: deserializeScanResponse,
1581
+ // @ts-expect-error ignore types here
1582
+ deserialize: opts?.withType ? deserializeScanWithTypesResponse : deserializeScanResponse,
1401
1583
  ...cmdOpts
1402
1584
  });
1403
1585
  }
@@ -1823,15 +2005,15 @@ var XPendingCommand = class extends Command {
1823
2005
  function deserialize4(result) {
1824
2006
  const obj = {};
1825
2007
  for (const e of result) {
1826
- while (e.length >= 2) {
1827
- const streamId = e.shift();
1828
- const entries = e.shift();
2008
+ for (let i = 0; i < e.length; i += 2) {
2009
+ const streamId = e[i];
2010
+ const entries = e[i + 1];
1829
2011
  if (!(streamId in obj)) {
1830
2012
  obj[streamId] = {};
1831
2013
  }
1832
- while (entries.length >= 2) {
1833
- const field = entries.shift();
1834
- const value = entries.shift();
2014
+ for (let j = 0; j < entries.length; j += 2) {
2015
+ const field = entries[j];
2016
+ const value = entries[j + 1];
1835
2017
  try {
1836
2018
  obj[streamId][field] = JSON.parse(value);
1837
2019
  } catch {
@@ -1920,15 +2102,15 @@ var XRevRangeCommand = class extends Command {
1920
2102
  function deserialize5(result) {
1921
2103
  const obj = {};
1922
2104
  for (const e of result) {
1923
- while (e.length >= 2) {
1924
- const streamId = e.shift();
1925
- const entries = e.shift();
2105
+ for (let i = 0; i < e.length; i += 2) {
2106
+ const streamId = e[i];
2107
+ const entries = e[i + 1];
1926
2108
  if (!(streamId in obj)) {
1927
2109
  obj[streamId] = {};
1928
2110
  }
1929
- while (entries.length >= 2) {
1930
- const field = entries.shift();
1931
- const value = entries.shift();
2111
+ for (let j = 0; j < entries.length; j += 2) {
2112
+ const field = entries[j];
2113
+ const value = entries[j + 1];
1932
2114
  try {
1933
2115
  obj[streamId][field] = JSON.parse(value);
1934
2116
  } catch {
@@ -2327,10 +2509,18 @@ var Pipeline = class {
2327
2509
  * @see https://redis.io/commands/echo
2328
2510
  */
2329
2511
  echo = (...args) => this.chain(new EchoCommand(args, this.commandOptions));
2512
+ /**
2513
+ * @see https://redis.io/commands/eval_ro
2514
+ */
2515
+ evalRo = (...args) => this.chain(new EvalROCommand(args, this.commandOptions));
2330
2516
  /**
2331
2517
  * @see https://redis.io/commands/eval
2332
2518
  */
2333
2519
  eval = (...args) => this.chain(new EvalCommand(args, this.commandOptions));
2520
+ /**
2521
+ * @see https://redis.io/commands/evalsha_ro
2522
+ */
2523
+ evalshaRo = (...args) => this.chain(new EvalshaROCommand(args, this.commandOptions));
2334
2524
  /**
2335
2525
  * @see https://redis.io/commands/evalsha
2336
2526
  */
@@ -2411,6 +2601,42 @@ var Pipeline = class {
2411
2601
  * @see https://redis.io/commands/hexists
2412
2602
  */
2413
2603
  hexists = (...args) => this.chain(new HExistsCommand(args, this.commandOptions));
2604
+ /**
2605
+ * @see https://redis.io/commands/hexpire
2606
+ */
2607
+ hexpire = (...args) => this.chain(new HExpireCommand(args, this.commandOptions));
2608
+ /**
2609
+ * @see https://redis.io/commands/hexpireat
2610
+ */
2611
+ hexpireat = (...args) => this.chain(new HExpireAtCommand(args, this.commandOptions));
2612
+ /**
2613
+ * @see https://redis.io/commands/hexpiretime
2614
+ */
2615
+ hexpiretime = (...args) => this.chain(new HExpireTimeCommand(args, this.commandOptions));
2616
+ /**
2617
+ * @see https://redis.io/commands/httl
2618
+ */
2619
+ httl = (...args) => this.chain(new HTtlCommand(args, this.commandOptions));
2620
+ /**
2621
+ * @see https://redis.io/commands/hpexpire
2622
+ */
2623
+ hpexpire = (...args) => this.chain(new HPExpireCommand(args, this.commandOptions));
2624
+ /**
2625
+ * @see https://redis.io/commands/hpexpireat
2626
+ */
2627
+ hpexpireat = (...args) => this.chain(new HPExpireAtCommand(args, this.commandOptions));
2628
+ /**
2629
+ * @see https://redis.io/commands/hpexpiretime
2630
+ */
2631
+ hpexpiretime = (...args) => this.chain(new HPExpireTimeCommand(args, this.commandOptions));
2632
+ /**
2633
+ * @see https://redis.io/commands/hpttl
2634
+ */
2635
+ hpttl = (...args) => this.chain(new HPTtlCommand(args, this.commandOptions));
2636
+ /**
2637
+ * @see https://redis.io/commands/hpersist
2638
+ */
2639
+ hpersist = (...args) => this.chain(new HPersistCommand(args, this.commandOptions));
2414
2640
  /**
2415
2641
  * @see https://redis.io/commands/hget
2416
2642
  */
@@ -2928,6 +3154,10 @@ var Pipeline = class {
2928
3154
  * @see https://redis.io/commands/json.get
2929
3155
  */
2930
3156
  get: (...args) => this.chain(new JsonGetCommand(args, this.commandOptions)),
3157
+ /**
3158
+ * @see https://redis.io/commands/json.merge
3159
+ */
3160
+ merge: (...args) => this.chain(new JsonMergeCommand(args, this.commandOptions)),
2931
3161
  /**
2932
3162
  * @see https://redis.io/commands/json.mget
2933
3163
  */
@@ -2981,6 +3211,24 @@ var Pipeline = class {
2981
3211
  };
2982
3212
 
2983
3213
  // pkg/auto-pipeline.ts
3214
+ var EXCLUDE_COMMANDS = /* @__PURE__ */ new Set([
3215
+ "scan",
3216
+ "keys",
3217
+ "flushdb",
3218
+ "flushall",
3219
+ "dbsize",
3220
+ "hscan",
3221
+ "hgetall",
3222
+ "hkeys",
3223
+ "lrange",
3224
+ "sscan",
3225
+ "smembers",
3226
+ "xrange",
3227
+ "xrevrange",
3228
+ "zscan",
3229
+ "zrange",
3230
+ "exec"
3231
+ ]);
2984
3232
  function createAutoPipelineProxy(_redis, json) {
2985
3233
  const redis = _redis;
2986
3234
  if (!redis.autoPipelineExecutor) {
@@ -2995,7 +3243,8 @@ function createAutoPipelineProxy(_redis, json) {
2995
3243
  return createAutoPipelineProxy(redis2, true);
2996
3244
  }
2997
3245
  const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
2998
- if (commandInRedisButNotPipeline) {
3246
+ const isCommandExcluded = EXCLUDE_COMMANDS.has(command);
3247
+ if (commandInRedisButNotPipeline || isCommandExcluded) {
2999
3248
  return redis2[command];
3000
3249
  }
3001
3250
  const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
@@ -3085,11 +3334,13 @@ var Subscriber = class extends EventTarget {
3085
3334
  subscriptions;
3086
3335
  client;
3087
3336
  listeners;
3088
- constructor(client, channels, isPattern = false) {
3337
+ opts;
3338
+ constructor(client, channels, isPattern = false, opts) {
3089
3339
  super();
3090
3340
  this.client = client;
3091
3341
  this.subscriptions = /* @__PURE__ */ new Map();
3092
3342
  this.listeners = /* @__PURE__ */ new Map();
3343
+ this.opts = opts;
3093
3344
  for (const channel of channels) {
3094
3345
  if (isPattern) {
3095
3346
  this.subscribeToPattern(channel);
@@ -3148,7 +3399,7 @@ var Subscriber = class extends EventTarget {
3148
3399
  const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
3149
3400
  const messageStr = messageData.slice(thirdCommaIndex + 1);
3150
3401
  try {
3151
- const message = JSON.parse(messageStr);
3402
+ const message = this.opts?.automaticDeserialization === false ? messageStr : JSON.parse(messageStr);
3152
3403
  this.dispatchToListeners("pmessage", { pattern, channel, message });
3153
3404
  this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
3154
3405
  } catch (error) {
@@ -3162,7 +3413,7 @@ var Subscriber = class extends EventTarget {
3162
3413
  const count = Number.parseInt(messageStr);
3163
3414
  this.dispatchToListeners(type, count);
3164
3415
  } else {
3165
- const message = JSON.parse(messageStr);
3416
+ const message = this.opts?.automaticDeserialization === false ? messageStr : parseWithTryCatch(messageStr);
3166
3417
  this.dispatchToListeners(type, { channel, message });
3167
3418
  this.dispatchToListeners(`${type}:${channel}`, { channel, message });
3168
3419
  }
@@ -3235,29 +3486,52 @@ var SubscribeCommand = class extends Command {
3235
3486
  });
3236
3487
  }
3237
3488
  };
3489
+ var parseWithTryCatch = (str) => {
3490
+ try {
3491
+ return JSON.parse(str);
3492
+ } catch {
3493
+ return str;
3494
+ }
3495
+ };
3238
3496
 
3239
3497
  // pkg/script.ts
3240
- import Hex from "crypto-js/enc-hex.js";
3241
- import sha1 from "crypto-js/sha1.js";
3498
+ import { subtle } from "uncrypto";
3242
3499
  var Script = class {
3243
3500
  script;
3501
+ /**
3502
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3503
+ * asynchronously. Do not use this property immidiately after the constructor.
3504
+ *
3505
+ * This property is only exposed for backwards compatibility and will be removed in the
3506
+ * future major release.
3507
+ */
3244
3508
  sha1;
3245
3509
  redis;
3246
3510
  constructor(redis, script) {
3247
3511
  this.redis = redis;
3248
- this.sha1 = this.digest(script);
3249
3512
  this.script = script;
3513
+ this.sha1 = "";
3514
+ void this.init(script);
3515
+ }
3516
+ /**
3517
+ * Initialize the script by computing its SHA-1 hash.
3518
+ */
3519
+ async init(script) {
3520
+ if (this.sha1) return;
3521
+ this.sha1 = await this.digest(script);
3250
3522
  }
3251
3523
  /**
3252
3524
  * Send an `EVAL` command to redis.
3253
3525
  */
3254
3526
  async eval(keys, args) {
3527
+ await this.init(this.script);
3255
3528
  return await this.redis.eval(this.script, keys, args);
3256
3529
  }
3257
3530
  /**
3258
3531
  * Calculates the sha1 hash of the script and then calls `EVALSHA`.
3259
3532
  */
3260
3533
  async evalsha(keys, args) {
3534
+ await this.init(this.script);
3261
3535
  return await this.redis.evalsha(this.sha1, keys, args);
3262
3536
  }
3263
3537
  /**
@@ -3267,6 +3541,7 @@ var Script = class {
3267
3541
  * Following calls will be able to use the cached script
3268
3542
  */
3269
3543
  async exec(keys, args) {
3544
+ await this.init(this.script);
3270
3545
  const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
3271
3546
  if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
3272
3547
  return await this.redis.eval(this.script, keys, args);
@@ -3278,8 +3553,75 @@ var Script = class {
3278
3553
  /**
3279
3554
  * Compute the sha1 hash of the script and return its hex representation.
3280
3555
  */
3281
- digest(s) {
3282
- return Hex.stringify(sha1(s));
3556
+ async digest(s) {
3557
+ const data = new TextEncoder().encode(s);
3558
+ const hashBuffer = await subtle.digest("SHA-1", data);
3559
+ const hashArray = [...new Uint8Array(hashBuffer)];
3560
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3561
+ }
3562
+ };
3563
+
3564
+ // pkg/scriptRo.ts
3565
+ import { subtle as subtle2 } from "uncrypto";
3566
+ var ScriptRO = class {
3567
+ script;
3568
+ /**
3569
+ * @deprecated This property is initialized to an empty string and will be set in the init method
3570
+ * asynchronously. Do not use this property immidiately after the constructor.
3571
+ *
3572
+ * This property is only exposed for backwards compatibility and will be removed in the
3573
+ * future major release.
3574
+ */
3575
+ sha1;
3576
+ redis;
3577
+ constructor(redis, script) {
3578
+ this.redis = redis;
3579
+ this.sha1 = "";
3580
+ this.script = script;
3581
+ void this.init(script);
3582
+ }
3583
+ async init(script) {
3584
+ if (this.sha1) return;
3585
+ this.sha1 = await this.digest(script);
3586
+ }
3587
+ /**
3588
+ * Send an `EVAL_RO` command to redis.
3589
+ */
3590
+ async evalRo(keys, args) {
3591
+ await this.init(this.script);
3592
+ return await this.redis.evalRo(this.script, keys, args);
3593
+ }
3594
+ /**
3595
+ * Calculates the sha1 hash of the script and then calls `EVALSHA_RO`.
3596
+ */
3597
+ async evalshaRo(keys, args) {
3598
+ await this.init(this.script);
3599
+ return await this.redis.evalshaRo(this.sha1, keys, args);
3600
+ }
3601
+ /**
3602
+ * Optimistically try to run `EVALSHA_RO` first.
3603
+ * If the script is not loaded in redis, it will fall back and try again with `EVAL_RO`.
3604
+ *
3605
+ * Following calls will be able to use the cached script
3606
+ */
3607
+ async exec(keys, args) {
3608
+ await this.init(this.script);
3609
+ const res = await this.redis.evalshaRo(this.sha1, keys, args).catch(async (error) => {
3610
+ if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
3611
+ return await this.redis.evalRo(this.script, keys, args);
3612
+ }
3613
+ throw error;
3614
+ });
3615
+ return res;
3616
+ }
3617
+ /**
3618
+ * Compute the sha1 hash of the script and return its hex representation.
3619
+ */
3620
+ async digest(s) {
3621
+ const data = new TextEncoder().encode(s);
3622
+ const hashBuffer = await subtle2.digest("SHA-1", data);
3623
+ const hashArray = [...new Uint8Array(hashBuffer)];
3624
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
3283
3625
  }
3284
3626
  };
3285
3627
 
@@ -3357,6 +3699,10 @@ var Redis = class {
3357
3699
  * @see https://redis.io/commands/json.get
3358
3700
  */
3359
3701
  get: (...args) => new JsonGetCommand(args, this.opts).exec(this.client),
3702
+ /**
3703
+ * @see https://redis.io/commands/json.merge
3704
+ */
3705
+ merge: (...args) => new JsonMergeCommand(args, this.opts).exec(this.client),
3360
3706
  /**
3361
3707
  * @see https://redis.io/commands/json.mget
3362
3708
  */
@@ -3426,8 +3772,36 @@ var Redis = class {
3426
3772
  } catch {
3427
3773
  }
3428
3774
  };
3429
- createScript(script) {
3430
- return new Script(this, script);
3775
+ /**
3776
+ * Creates a new script.
3777
+ *
3778
+ * Scripts offer the ability to optimistically try to execute a script without having to send the
3779
+ * entire script to the server. If the script is loaded on the server, it tries again by sending
3780
+ * the entire script. Afterwards, the script is cached on the server.
3781
+ *
3782
+ * @param script - The script to create
3783
+ * @param opts - Optional options to pass to the script `{ readonly?: boolean }`
3784
+ * @returns A new script
3785
+ *
3786
+ * @example
3787
+ * ```ts
3788
+ * const redis = new Redis({...})
3789
+ *
3790
+ * const script = redis.createScript<string>("return ARGV[1];")
3791
+ * const arg1 = await script.eval([], ["Hello World"])
3792
+ * expect(arg1, "Hello World")
3793
+ * ```
3794
+ * @example
3795
+ * ```ts
3796
+ * const redis = new Redis({...})
3797
+ *
3798
+ * const script = redis.createScript<string>("return ARGV[1];", { readonly: true })
3799
+ * const arg1 = await script.evalRo([], ["Hello World"])
3800
+ * expect(arg1, "Hello World")
3801
+ * ```
3802
+ */
3803
+ createScript(script, opts) {
3804
+ return opts?.readonly ? new ScriptRO(this, script) : new Script(this, script);
3431
3805
  }
3432
3806
  /**
3433
3807
  * Create a new pipeline that allows you to send requests in bulk.
@@ -3514,10 +3888,18 @@ var Redis = class {
3514
3888
  * @see https://redis.io/commands/echo
3515
3889
  */
3516
3890
  echo = (...args) => new EchoCommand(args, this.opts).exec(this.client);
3891
+ /**
3892
+ * @see https://redis.io/commands/eval_ro
3893
+ */
3894
+ evalRo = (...args) => new EvalROCommand(args, this.opts).exec(this.client);
3517
3895
  /**
3518
3896
  * @see https://redis.io/commands/eval
3519
3897
  */
3520
3898
  eval = (...args) => new EvalCommand(args, this.opts).exec(this.client);
3899
+ /**
3900
+ * @see https://redis.io/commands/evalsha_ro
3901
+ */
3902
+ evalshaRo = (...args) => new EvalshaROCommand(args, this.opts).exec(this.client);
3521
3903
  /**
3522
3904
  * @see https://redis.io/commands/evalsha
3523
3905
  */
@@ -3602,6 +3984,42 @@ var Redis = class {
3602
3984
  * @see https://redis.io/commands/hexists
3603
3985
  */
3604
3986
  hexists = (...args) => new HExistsCommand(args, this.opts).exec(this.client);
3987
+ /**
3988
+ * @see https://redis.io/commands/hexpire
3989
+ */
3990
+ hexpire = (...args) => new HExpireCommand(args, this.opts).exec(this.client);
3991
+ /**
3992
+ * @see https://redis.io/commands/hexpireat
3993
+ */
3994
+ hexpireat = (...args) => new HExpireAtCommand(args, this.opts).exec(this.client);
3995
+ /**
3996
+ * @see https://redis.io/commands/hexpiretime
3997
+ */
3998
+ hexpiretime = (...args) => new HExpireTimeCommand(args, this.opts).exec(this.client);
3999
+ /**
4000
+ * @see https://redis.io/commands/httl
4001
+ */
4002
+ httl = (...args) => new HTtlCommand(args, this.opts).exec(this.client);
4003
+ /**
4004
+ * @see https://redis.io/commands/hpexpire
4005
+ */
4006
+ hpexpire = (...args) => new HPExpireCommand(args, this.opts).exec(this.client);
4007
+ /**
4008
+ * @see https://redis.io/commands/hpexpireat
4009
+ */
4010
+ hpexpireat = (...args) => new HPExpireAtCommand(args, this.opts).exec(this.client);
4011
+ /**
4012
+ * @see https://redis.io/commands/hpexpiretime
4013
+ */
4014
+ hpexpiretime = (...args) => new HPExpireTimeCommand(args, this.opts).exec(this.client);
4015
+ /**
4016
+ * @see https://redis.io/commands/hpttl
4017
+ */
4018
+ hpttl = (...args) => new HPTtlCommand(args, this.opts).exec(this.client);
4019
+ /**
4020
+ * @see https://redis.io/commands/hpersist
4021
+ */
4022
+ hpersist = (...args) => new HPersistCommand(args, this.opts).exec(this.client);
3605
4023
  /**
3606
4024
  * @see https://redis.io/commands/hget
3607
4025
  */
@@ -3775,7 +4193,7 @@ var Redis = class {
3775
4193
  */
3776
4194
  psubscribe = (patterns) => {
3777
4195
  const patternArray = Array.isArray(patterns) ? patterns : [patterns];
3778
- return new Subscriber(this.client, patternArray, true);
4196
+ return new Subscriber(this.client, patternArray, true, this.opts);
3779
4197
  };
3780
4198
  /**
3781
4199
  * @see https://redis.io/commands/pttl
@@ -3813,10 +4231,9 @@ var Redis = class {
3813
4231
  * @see https://redis.io/commands/sadd
3814
4232
  */
3815
4233
  sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
3816
- /**
3817
- * @see https://redis.io/commands/scan
3818
- */
3819
- scan = (...args) => new ScanCommand(args, this.opts).exec(this.client);
4234
+ scan(cursor, opts) {
4235
+ return new ScanCommand([cursor, opts], this.opts).exec(this.client);
4236
+ }
3820
4237
  /**
3821
4238
  * @see https://redis.io/commands/scard
3822
4239
  */
@@ -3910,7 +4327,7 @@ var Redis = class {
3910
4327
  */
3911
4328
  subscribe = (channels) => {
3912
4329
  const channelArray = Array.isArray(channels) ? channels : [channels];
3913
- return new Subscriber(this.client, channelArray);
4330
+ return new Subscriber(this.client, channelArray, false, this.opts);
3914
4331
  };
3915
4332
  /**
3916
4333
  * @see https://redis.io/commands/sunion