@upstash/redis 0.0.0-ci.9722909577fc3b6b939d0c937c6ba5f8e8287ee4 → 0.0.0-ci.9846a4b6d92b334b3956b0947a58e9bef9c92a42-20250303091249

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/fastly.js CHANGED
@@ -30,23 +30,77 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // platforms/fastly.ts
31
31
  var fastly_exports = {};
32
32
  __export(fastly_exports, {
33
- Redis: () => Redis2
33
+ Redis: () => Redis2,
34
+ errors: () => error_exports
34
35
  });
35
36
  module.exports = __toCommonJS(fastly_exports);
36
37
 
37
38
  // pkg/error.ts
39
+ var error_exports = {};
40
+ __export(error_exports, {
41
+ UpstashError: () => UpstashError,
42
+ UrlError: () => UrlError
43
+ });
38
44
  var UpstashError = class extends Error {
39
45
  constructor(message) {
40
46
  super(message);
41
47
  this.name = "UpstashError";
42
48
  }
43
49
  };
50
+ var UrlError = class extends Error {
51
+ constructor(url) {
52
+ super(
53
+ `Upstash Redis client was passed an invalid URL. You should pass a URL starting with https. Received: "${url}". `
54
+ );
55
+ this.name = "UrlError";
56
+ }
57
+ };
58
+
59
+ // pkg/util.ts
60
+ function parseRecursive(obj) {
61
+ const parsed = Array.isArray(obj) ? obj.map((o) => {
62
+ try {
63
+ return parseRecursive(o);
64
+ } catch {
65
+ return o;
66
+ }
67
+ }) : JSON.parse(obj);
68
+ if (typeof parsed === "number" && parsed.toString() !== obj) {
69
+ return obj;
70
+ }
71
+ return parsed;
72
+ }
73
+ function parseResponse(result) {
74
+ try {
75
+ return parseRecursive(result);
76
+ } catch {
77
+ return result;
78
+ }
79
+ }
80
+ function deserializeScanResponse(result) {
81
+ return [result[0], ...parseResponse(result.slice(1))];
82
+ }
83
+ function mergeHeaders(...headers) {
84
+ const merged = {};
85
+ for (const header of headers) {
86
+ if (!header) continue;
87
+ for (const [key, value] of Object.entries(header)) {
88
+ if (value !== void 0 && value !== null) {
89
+ merged[key] = value;
90
+ }
91
+ }
92
+ }
93
+ return merged;
94
+ }
44
95
 
45
96
  // pkg/http.ts
46
97
  var HttpClient = class {
47
98
  baseUrl;
48
99
  headers;
49
100
  options;
101
+ readYourWrites;
102
+ upstashSyncToken = "";
103
+ hasCredentials;
50
104
  retry;
51
105
  constructor(config) {
52
106
  this.options = {
@@ -54,76 +108,137 @@ var HttpClient = class {
54
108
  agent: config.agent,
55
109
  responseEncoding: config.responseEncoding ?? "base64",
56
110
  // default to base64
57
- cache: config.cache
111
+ cache: config.cache,
112
+ signal: config.signal,
113
+ keepAlive: config.keepAlive ?? true
58
114
  };
59
- this.baseUrl = config.baseUrl.replace(/\/$/, "");
115
+ this.upstashSyncToken = "";
116
+ this.readYourWrites = config.readYourWrites ?? true;
117
+ this.baseUrl = (config.baseUrl || "").replace(/\/$/, "");
118
+ const urlRegex = /^https?:\/\/[^\s#$./?].\S*$/;
119
+ if (this.baseUrl && !urlRegex.test(this.baseUrl)) {
120
+ throw new UrlError(this.baseUrl);
121
+ }
60
122
  this.headers = {
61
123
  "Content-Type": "application/json",
62
124
  ...config.headers
63
125
  };
126
+ this.hasCredentials = Boolean(this.baseUrl && this.headers.authorization.split(" ")[1]);
64
127
  if (this.options.responseEncoding === "base64") {
65
128
  this.headers["Upstash-Encoding"] = "base64";
66
129
  }
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
- }
130
+ this.retry = typeof config.retry === "boolean" && !config.retry ? {
131
+ attempts: 1,
132
+ backoff: () => 0
133
+ } : {
134
+ attempts: config.retry?.retries ?? 5,
135
+ backoff: config.retry?.backoff ?? ((retryCount) => Math.exp(retryCount) * 50)
136
+ };
78
137
  }
79
138
  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
139
  this.headers = merge(this.headers, "Upstash-Telemetry-Runtime", telemetry.runtime);
92
140
  this.headers = merge(this.headers, "Upstash-Telemetry-Platform", telemetry.platform);
93
141
  this.headers = merge(this.headers, "Upstash-Telemetry-Sdk", telemetry.sdk);
94
142
  }
95
143
  async request(req) {
144
+ const requestHeaders = mergeHeaders(this.headers, req.headers ?? {});
145
+ const requestUrl = [this.baseUrl, ...req.path ?? []].join("/");
146
+ const isEventStream = requestHeaders.Accept === "text/event-stream";
96
147
  const requestOptions = {
148
+ //@ts-expect-error this should throw due to bun regression
97
149
  cache: this.options.cache,
98
150
  method: "POST",
99
- headers: this.headers,
151
+ headers: requestHeaders,
100
152
  body: JSON.stringify(req.body),
101
- keepalive: true,
102
- agent: this.options?.agent,
153
+ keepalive: this.options.keepAlive,
154
+ agent: this.options.agent,
155
+ signal: req.signal ?? this.options.signal,
103
156
  /**
104
157
  * Fastly specific
105
158
  */
106
- backend: this.options?.backend
159
+ backend: this.options.backend
107
160
  };
161
+ if (!this.hasCredentials) {
162
+ console.warn(
163
+ "[Upstash Redis] Redis client was initialized without url or token. Failed to execute command."
164
+ );
165
+ }
166
+ if (this.readYourWrites) {
167
+ const newHeader = this.upstashSyncToken;
168
+ this.headers["upstash-sync-token"] = newHeader;
169
+ }
108
170
  let res = null;
109
171
  let error = null;
110
172
  for (let i = 0; i <= this.retry.attempts; i++) {
111
173
  try {
112
- res = await fetch([this.baseUrl, ...req.path ?? []].join("/"), requestOptions);
174
+ res = await fetch(requestUrl, requestOptions);
113
175
  break;
114
- } catch (err) {
115
- error = err;
116
- await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
176
+ } catch (error_) {
177
+ if (this.options.signal?.aborted) {
178
+ const myBlob = new Blob([
179
+ JSON.stringify({ result: this.options.signal.reason ?? "Aborted" })
180
+ ]);
181
+ const myOptions = {
182
+ status: 200,
183
+ statusText: this.options.signal.reason ?? "Aborted"
184
+ };
185
+ res = new Response(myBlob, myOptions);
186
+ break;
187
+ }
188
+ error = error_;
189
+ if (i < this.retry.attempts) {
190
+ await new Promise((r) => setTimeout(r, this.retry.backoff(i)));
191
+ }
117
192
  }
118
193
  }
119
194
  if (!res) {
120
195
  throw error ?? new Error("Exhausted all retries");
121
196
  }
122
- const body = await res.json();
123
197
  if (!res.ok) {
124
- throw new UpstashError(`${body.error}, command was: ${JSON.stringify(req.body)}`);
198
+ const body2 = await res.json();
199
+ throw new UpstashError(`${body2.error}, command was: ${JSON.stringify(req.body)}`);
200
+ }
201
+ if (this.readYourWrites) {
202
+ const headers = res.headers;
203
+ this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
125
204
  }
126
- if (this.options?.responseEncoding === "base64") {
205
+ if (isEventStream && req && req.onMessage && res.body) {
206
+ const reader = res.body.getReader();
207
+ const decoder = new TextDecoder();
208
+ (async () => {
209
+ try {
210
+ while (true) {
211
+ const { value, done } = await reader.read();
212
+ if (done) break;
213
+ const chunk = decoder.decode(value);
214
+ const lines = chunk.split("\n");
215
+ for (const line of lines) {
216
+ if (line.startsWith("data: ")) {
217
+ const data = line.slice(6);
218
+ req.onMessage?.(data);
219
+ }
220
+ }
221
+ }
222
+ } catch (error2) {
223
+ if (error2 instanceof Error && error2.name === "AbortError") {
224
+ } else {
225
+ console.error("Stream reading error:", error2);
226
+ }
227
+ } finally {
228
+ try {
229
+ await reader.cancel();
230
+ } catch {
231
+ }
232
+ }
233
+ })();
234
+ return { result: 1 };
235
+ }
236
+ const body = await res.json();
237
+ if (this.readYourWrites) {
238
+ const headers = res.headers;
239
+ this.upstashSyncToken = headers.get("upstash-sync-token") ?? "";
240
+ }
241
+ if (this.options.responseEncoding === "base64") {
127
242
  if (Array.isArray(body)) {
128
243
  return body.map(({ result: result2, error: error2 }) => ({
129
244
  result: decode(result2),
@@ -154,8 +269,9 @@ function base64decode(b64) {
154
269
  function decode(raw) {
155
270
  let result = void 0;
156
271
  switch (typeof raw) {
157
- case "undefined":
272
+ case "undefined": {
158
273
  return raw;
274
+ }
159
275
  case "number": {
160
276
  result = raw;
161
277
  break;
@@ -163,7 +279,7 @@ function decode(raw) {
163
279
  case "object": {
164
280
  if (Array.isArray(raw)) {
165
281
  result = raw.map(
166
- (v) => typeof v === "string" ? base64decode(v) : Array.isArray(v) ? v.map(decode) : v
282
+ (v) => typeof v === "string" ? base64decode(v) : Array.isArray(v) ? v.map((element) => decode(element)) : v
167
283
  );
168
284
  } else {
169
285
  result = null;
@@ -174,49 +290,121 @@ function decode(raw) {
174
290
  result = raw === "OK" ? "OK" : base64decode(raw);
175
291
  break;
176
292
  }
177
- default:
293
+ default: {
178
294
  break;
295
+ }
179
296
  }
180
297
  return result;
181
298
  }
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) {
299
+ function merge(obj, key, value) {
300
+ if (!value) {
193
301
  return obj;
194
302
  }
195
- return parsed;
303
+ obj[key] = obj[key] ? [obj[key], value].join(",") : value;
304
+ return obj;
196
305
  }
197
- function parseResponse(result) {
198
- try {
199
- return parseRecursive(result);
200
- } catch {
201
- return result;
306
+
307
+ // pkg/auto-pipeline.ts
308
+ function createAutoPipelineProxy(_redis, json) {
309
+ const redis = _redis;
310
+ if (!redis.autoPipelineExecutor) {
311
+ redis.autoPipelineExecutor = new AutoPipelineExecutor(redis);
202
312
  }
313
+ return new Proxy(redis, {
314
+ get: (redis2, command) => {
315
+ if (command === "pipelineCounter") {
316
+ return redis2.autoPipelineExecutor.pipelineCounter;
317
+ }
318
+ if (command === "json") {
319
+ return createAutoPipelineProxy(redis2, true);
320
+ }
321
+ const commandInRedisButNotPipeline = command in redis2 && !(command in redis2.autoPipelineExecutor.pipeline);
322
+ if (commandInRedisButNotPipeline) {
323
+ return redis2[command];
324
+ }
325
+ const isFunction = json ? typeof redis2.autoPipelineExecutor.pipeline.json[command] === "function" : typeof redis2.autoPipelineExecutor.pipeline[command] === "function";
326
+ if (isFunction) {
327
+ return (...args) => {
328
+ return redis2.autoPipelineExecutor.withAutoPipeline((pipeline) => {
329
+ if (json) {
330
+ pipeline.json[command](
331
+ ...args
332
+ );
333
+ } else {
334
+ pipeline[command](...args);
335
+ }
336
+ });
337
+ };
338
+ }
339
+ return redis2.autoPipelineExecutor.pipeline[command];
340
+ }
341
+ });
203
342
  }
343
+ var AutoPipelineExecutor = class {
344
+ pipelinePromises = /* @__PURE__ */ new WeakMap();
345
+ activePipeline = null;
346
+ indexInCurrentPipeline = 0;
347
+ redis;
348
+ pipeline;
349
+ // only to make sure that proxy can work
350
+ pipelineCounter = 0;
351
+ // to keep track of how many times a pipeline was executed
352
+ constructor(redis) {
353
+ this.redis = redis;
354
+ this.pipeline = redis.pipeline();
355
+ }
356
+ async withAutoPipeline(executeWithPipeline) {
357
+ const pipeline = this.activePipeline ?? this.redis.pipeline();
358
+ if (!this.activePipeline) {
359
+ this.activePipeline = pipeline;
360
+ this.indexInCurrentPipeline = 0;
361
+ }
362
+ const index = this.indexInCurrentPipeline++;
363
+ executeWithPipeline(pipeline);
364
+ const pipelineDone = this.deferExecution().then(() => {
365
+ if (!this.pipelinePromises.has(pipeline)) {
366
+ const pipelinePromise = pipeline.exec({ keepErrors: true });
367
+ this.pipelineCounter += 1;
368
+ this.pipelinePromises.set(pipeline, pipelinePromise);
369
+ this.activePipeline = null;
370
+ }
371
+ return this.pipelinePromises.get(pipeline);
372
+ });
373
+ const results = await pipelineDone;
374
+ const commandResult = results[index];
375
+ if (commandResult.error) {
376
+ throw new UpstashError(`Command failed: ${commandResult.error}`);
377
+ }
378
+ return commandResult.result;
379
+ }
380
+ async deferExecution() {
381
+ await Promise.resolve();
382
+ await Promise.resolve();
383
+ }
384
+ };
204
385
 
205
386
  // pkg/commands/command.ts
206
387
  var defaultSerializer = (c) => {
207
388
  switch (typeof c) {
208
389
  case "string":
209
390
  case "number":
210
- case "boolean":
391
+ case "boolean": {
211
392
  return c;
212
- default:
393
+ }
394
+ default: {
213
395
  return JSON.stringify(c);
396
+ }
214
397
  }
215
398
  };
216
399
  var Command = class {
217
400
  command;
218
401
  serialize;
219
402
  deserialize;
403
+ headers;
404
+ path;
405
+ onMessage;
406
+ isStreaming;
407
+ signal;
220
408
  /**
221
409
  * Create a new command instance.
222
410
  *
@@ -224,21 +412,45 @@ var Command = class {
224
412
  */
225
413
  constructor(command, opts) {
226
414
  this.serialize = defaultSerializer;
227
- this.deserialize = typeof opts?.automaticDeserialization === "undefined" || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
415
+ this.deserialize = opts?.automaticDeserialization === void 0 || opts.automaticDeserialization ? opts?.deserialize ?? parseResponse : (x) => x;
228
416
  this.command = command.map((c) => this.serialize(c));
417
+ this.headers = opts?.headers;
418
+ this.path = opts?.path;
419
+ this.onMessage = opts?.streamOptions?.onMessage;
420
+ this.isStreaming = opts?.streamOptions?.isStreaming ?? false;
421
+ this.signal = opts?.streamOptions?.signal;
422
+ if (opts?.latencyLogging) {
423
+ const originalExec = this.exec.bind(this);
424
+ this.exec = async (client) => {
425
+ const start = performance.now();
426
+ const result = await originalExec(client);
427
+ const end = performance.now();
428
+ const loggerResult = (end - start).toFixed(2);
429
+ console.log(
430
+ `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`
431
+ );
432
+ return result;
433
+ };
434
+ }
229
435
  }
230
436
  /**
231
437
  * Execute the command using a client.
232
438
  */
233
439
  async exec(client) {
234
440
  const { result, error } = await client.request({
235
- body: this.command
441
+ body: this.command,
442
+ path: this.path,
443
+ upstashSyncToken: client.upstashSyncToken,
444
+ headers: this.headers,
445
+ onMessage: this.onMessage,
446
+ isStreaming: this.isStreaming,
447
+ signal: this.signal
236
448
  });
237
449
  if (error) {
238
450
  throw new UpstashError(error);
239
451
  }
240
- if (typeof result === "undefined") {
241
- throw new Error("Request did not return a result");
452
+ if (result === void 0) {
453
+ throw new TypeError("Request did not return a result");
242
454
  }
243
455
  return this.deserialize(result);
244
456
  }
@@ -265,6 +477,37 @@ var BitCountCommand = class extends Command {
265
477
  }
266
478
  };
267
479
 
480
+ // pkg/commands/bitfield.ts
481
+ var BitFieldCommand = class {
482
+ constructor(args, client, opts, execOperation = (command) => command.exec(this.client)) {
483
+ this.client = client;
484
+ this.opts = opts;
485
+ this.execOperation = execOperation;
486
+ this.command = ["bitfield", ...args];
487
+ }
488
+ command;
489
+ chain(...args) {
490
+ this.command.push(...args);
491
+ return this;
492
+ }
493
+ get(...args) {
494
+ return this.chain("get", ...args);
495
+ }
496
+ set(...args) {
497
+ return this.chain("set", ...args);
498
+ }
499
+ incrby(...args) {
500
+ return this.chain("incrby", ...args);
501
+ }
502
+ overflow(overflow) {
503
+ return this.chain("overflow", overflow);
504
+ }
505
+ exec() {
506
+ const command = new Command(this.command, this.opts);
507
+ return this.execOperation(command);
508
+ }
509
+ };
510
+
268
511
  // pkg/commands/bitop.ts
269
512
  var BitOpCommand = class extends Command {
270
513
  constructor(cmd, opts) {
@@ -279,6 +522,21 @@ var BitPosCommand = class extends Command {
279
522
  }
280
523
  };
281
524
 
525
+ // pkg/commands/copy.ts
526
+ var CopyCommand = class extends Command {
527
+ constructor([key, destinationKey, opts], commandOptions) {
528
+ super(["COPY", key, destinationKey, ...opts?.replace ? ["REPLACE"] : []], {
529
+ ...commandOptions,
530
+ deserialize(result) {
531
+ if (result > 0) {
532
+ return "COPIED";
533
+ }
534
+ return "NOT_COPIED";
535
+ }
536
+ });
537
+ }
538
+ };
539
+
282
540
  // pkg/commands/dbsize.ts
283
541
  var DBSizeCommand = class extends Command {
284
542
  constructor(opts) {
@@ -328,6 +586,14 @@ var EvalshaCommand = class extends Command {
328
586
  }
329
587
  };
330
588
 
589
+ // pkg/commands/exec.ts
590
+ var ExecCommand = class extends Command {
591
+ constructor(cmd, opts) {
592
+ const normalizedCmd = cmd.map((arg) => typeof arg === "string" ? arg : String(arg));
593
+ super(normalizedCmd, opts);
594
+ }
595
+ };
596
+
331
597
  // pkg/commands/exists.ts
332
598
  var ExistsCommand = class extends Command {
333
599
  constructor(cmd, opts) {
@@ -338,7 +604,7 @@ var ExistsCommand = class extends Command {
338
604
  // pkg/commands/expire.ts
339
605
  var ExpireCommand = class extends Command {
340
606
  constructor(cmd, opts) {
341
- super(["expire", ...cmd], opts);
607
+ super(["expire", ...cmd.filter(Boolean)], opts);
342
608
  }
343
609
  };
344
610
 
@@ -400,6 +666,129 @@ var GeoDistCommand = class extends Command {
400
666
  }
401
667
  };
402
668
 
669
+ // pkg/commands/geo_hash.ts
670
+ var GeoHashCommand = class extends Command {
671
+ constructor(cmd, opts) {
672
+ const [key] = cmd;
673
+ const members = Array.isArray(cmd[1]) ? cmd[1] : cmd.slice(1);
674
+ super(["GEOHASH", key, ...members], opts);
675
+ }
676
+ };
677
+
678
+ // pkg/commands/geo_pos.ts
679
+ var GeoPosCommand = class extends Command {
680
+ constructor(cmd, opts) {
681
+ const [key] = cmd;
682
+ const members = Array.isArray(cmd[1]) ? cmd[1] : cmd.slice(1);
683
+ super(["GEOPOS", key, ...members], {
684
+ deserialize: (result) => transform(result),
685
+ ...opts
686
+ });
687
+ }
688
+ };
689
+ function transform(result) {
690
+ const final = [];
691
+ for (const pos of result) {
692
+ if (!pos?.[0] || !pos?.[1]) {
693
+ continue;
694
+ }
695
+ final.push({ lng: Number.parseFloat(pos[0]), lat: Number.parseFloat(pos[1]) });
696
+ }
697
+ return final;
698
+ }
699
+
700
+ // pkg/commands/geo_search.ts
701
+ var GeoSearchCommand = class extends Command {
702
+ constructor([key, centerPoint, shape, order, opts], commandOptions) {
703
+ const command = ["GEOSEARCH", key];
704
+ if (centerPoint.type === "FROMMEMBER" || centerPoint.type === "frommember") {
705
+ command.push(centerPoint.type, centerPoint.member);
706
+ }
707
+ if (centerPoint.type === "FROMLONLAT" || centerPoint.type === "fromlonlat") {
708
+ command.push(centerPoint.type, centerPoint.coordinate.lon, centerPoint.coordinate.lat);
709
+ }
710
+ if (shape.type === "BYRADIUS" || shape.type === "byradius") {
711
+ command.push(shape.type, shape.radius, shape.radiusType);
712
+ }
713
+ if (shape.type === "BYBOX" || shape.type === "bybox") {
714
+ command.push(shape.type, shape.rect.width, shape.rect.height, shape.rectType);
715
+ }
716
+ command.push(order);
717
+ if (opts?.count) {
718
+ command.push("COUNT", opts.count.limit, ...opts.count.any ? ["ANY"] : []);
719
+ }
720
+ const transform2 = (result) => {
721
+ if (!opts?.withCoord && !opts?.withDist && !opts?.withHash) {
722
+ return result.map((member) => {
723
+ try {
724
+ return { member: JSON.parse(member) };
725
+ } catch {
726
+ return { member };
727
+ }
728
+ });
729
+ }
730
+ return result.map((members) => {
731
+ let counter = 1;
732
+ const obj = {};
733
+ try {
734
+ obj.member = JSON.parse(members[0]);
735
+ } catch {
736
+ obj.member = members[0];
737
+ }
738
+ if (opts.withDist) {
739
+ obj.dist = Number.parseFloat(members[counter++]);
740
+ }
741
+ if (opts.withHash) {
742
+ obj.hash = members[counter++].toString();
743
+ }
744
+ if (opts.withCoord) {
745
+ obj.coord = {
746
+ long: Number.parseFloat(members[counter][0]),
747
+ lat: Number.parseFloat(members[counter][1])
748
+ };
749
+ }
750
+ return obj;
751
+ });
752
+ };
753
+ super(
754
+ [
755
+ ...command,
756
+ ...opts?.withCoord ? ["WITHCOORD"] : [],
757
+ ...opts?.withDist ? ["WITHDIST"] : [],
758
+ ...opts?.withHash ? ["WITHHASH"] : []
759
+ ],
760
+ {
761
+ deserialize: transform2,
762
+ ...commandOptions
763
+ }
764
+ );
765
+ }
766
+ };
767
+
768
+ // pkg/commands/geo_search_store.ts
769
+ var GeoSearchStoreCommand = class extends Command {
770
+ constructor([destination, key, centerPoint, shape, order, opts], commandOptions) {
771
+ const command = ["GEOSEARCHSTORE", destination, key];
772
+ if (centerPoint.type === "FROMMEMBER" || centerPoint.type === "frommember") {
773
+ command.push(centerPoint.type, centerPoint.member);
774
+ }
775
+ if (centerPoint.type === "FROMLONLAT" || centerPoint.type === "fromlonlat") {
776
+ command.push(centerPoint.type, centerPoint.coordinate.lon, centerPoint.coordinate.lat);
777
+ }
778
+ if (shape.type === "BYRADIUS" || shape.type === "byradius") {
779
+ command.push(shape.type, shape.radius, shape.radiusType);
780
+ }
781
+ if (shape.type === "BYBOX" || shape.type === "bybox") {
782
+ command.push(shape.type, shape.rect.width, shape.rect.height, shape.rectType);
783
+ }
784
+ command.push(order);
785
+ if (opts?.count) {
786
+ command.push("COUNT", opts.count.limit, ...opts.count.any ? ["ANY"] : []);
787
+ }
788
+ super([...command, ...opts?.storeDist ? ["STOREDIST"] : []], commandOptions);
789
+ }
790
+ };
791
+
403
792
  // pkg/commands/get.ts
404
793
  var GetCommand = class extends Command {
405
794
  constructor(cmd, opts) {
@@ -421,6 +810,27 @@ var GetDelCommand = class extends Command {
421
810
  }
422
811
  };
423
812
 
813
+ // pkg/commands/getex.ts
814
+ var GetExCommand = class extends Command {
815
+ constructor([key, opts], cmdOpts) {
816
+ const command = ["getex", key];
817
+ if (opts) {
818
+ if ("ex" in opts && typeof opts.ex === "number") {
819
+ command.push("ex", opts.ex);
820
+ } else if ("px" in opts && typeof opts.px === "number") {
821
+ command.push("px", opts.px);
822
+ } else if ("exat" in opts && typeof opts.exat === "number") {
823
+ command.push("exat", opts.exat);
824
+ } else if ("pxat" in opts && typeof opts.pxat === "number") {
825
+ command.push("pxat", opts.pxat);
826
+ } else if ("persist" in opts && opts.persist) {
827
+ command.push("persist");
828
+ }
829
+ }
830
+ super(command, cmdOpts);
831
+ }
832
+ };
833
+
424
834
  // pkg/commands/getrange.ts
425
835
  var GetRangeCommand = class extends Command {
426
836
  constructor(cmd, opts) {
@@ -466,12 +876,8 @@ function deserialize(result) {
466
876
  const key = result.shift();
467
877
  const value = result.shift();
468
878
  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
- }
879
+ const valueIsNumberAndNotSafeInteger = !Number.isNaN(Number(value)) && !Number.isSafeInteger(Number(value));
880
+ obj[key] = valueIsNumberAndNotSafeInteger ? value : JSON.parse(value);
475
881
  } catch {
476
882
  obj[key] = value;
477
883
  }
@@ -517,15 +923,15 @@ var HLenCommand = class extends Command {
517
923
 
518
924
  // pkg/commands/hmget.ts
519
925
  function deserialize2(fields, result) {
520
- if (result.length === 0 || result.every((field) => field === null)) {
926
+ if (result.every((field) => field === null)) {
521
927
  return null;
522
928
  }
523
929
  const obj = {};
524
- for (let i = 0; i < fields.length; i++) {
930
+ for (const [i, field] of fields.entries()) {
525
931
  try {
526
- obj[fields[i]] = JSON.parse(result[i]);
932
+ obj[field] = JSON.parse(result[i]);
527
933
  } catch {
528
- obj[fields[i]] = result[i];
934
+ obj[field] = result[i];
529
935
  }
530
936
  }
531
937
  return obj;
@@ -573,7 +979,7 @@ var HRandFieldCommand = class extends Command {
573
979
  command.push("WITHVALUES");
574
980
  }
575
981
  super(command, {
576
- // @ts-ignore TODO:
982
+ // @ts-expect-error to silence compiler
577
983
  deserialize: cmd[2] ? (result) => deserialize3(result) : opts?.deserialize,
578
984
  ...opts
579
985
  });
@@ -590,7 +996,10 @@ var HScanCommand = class extends Command {
590
996
  if (typeof cmdOpts?.count === "number") {
591
997
  command.push("count", cmdOpts.count);
592
998
  }
593
- super(command, opts);
999
+ super(command, {
1000
+ deserialize: deserializeScanResponse,
1001
+ ...opts
1002
+ });
594
1003
  }
595
1004
  };
596
1005
 
@@ -741,6 +1150,17 @@ var JsonMGetCommand = class extends Command {
741
1150
  }
742
1151
  };
743
1152
 
1153
+ // pkg/commands/json_mset.ts
1154
+ var JsonMSetCommand = class extends Command {
1155
+ constructor(cmd, opts) {
1156
+ const command = ["JSON.MSET"];
1157
+ for (const c of cmd) {
1158
+ command.push(c.key, c.path, c.value);
1159
+ }
1160
+ super(command, opts);
1161
+ }
1162
+ };
1163
+
744
1164
  // pkg/commands/json_numincrby.ts
745
1165
  var JsonNumIncrByCommand = class extends Command {
746
1166
  constructor(cmd, opts) {
@@ -854,6 +1274,14 @@ var LMoveCommand = class extends Command {
854
1274
  }
855
1275
  };
856
1276
 
1277
+ // pkg/commands/lmpop.ts
1278
+ var LmPopCommand = class extends Command {
1279
+ constructor(cmd, opts) {
1280
+ const [numkeys, keys, direction, count] = cmd;
1281
+ super(["LMPOP", numkeys, ...keys, direction, ...count ? ["COUNT", count] : []], opts);
1282
+ }
1283
+ };
1284
+
857
1285
  // pkg/commands/lpop.ts
858
1286
  var LPopCommand = class extends Command {
859
1287
  constructor(cmd, opts) {
@@ -938,7 +1366,7 @@ var MSetCommand = class extends Command {
938
1366
  // pkg/commands/msetnx.ts
939
1367
  var MSetNXCommand = class extends Command {
940
1368
  constructor([kv], opts) {
941
- super(["msetnx", ...Object.entries(kv).flatMap((_) => _)], opts);
1369
+ super(["msetnx", ...Object.entries(kv).flat()], opts);
942
1370
  }
943
1371
  };
944
1372
 
@@ -963,11 +1391,32 @@ var PExpireAtCommand = class extends Command {
963
1391
  }
964
1392
  };
965
1393
 
1394
+ // pkg/commands/pfadd.ts
1395
+ var PfAddCommand = class extends Command {
1396
+ constructor(cmd, opts) {
1397
+ super(["pfadd", ...cmd], opts);
1398
+ }
1399
+ };
1400
+
1401
+ // pkg/commands/pfcount.ts
1402
+ var PfCountCommand = class extends Command {
1403
+ constructor(cmd, opts) {
1404
+ super(["pfcount", ...cmd], opts);
1405
+ }
1406
+ };
1407
+
1408
+ // pkg/commands/pfmerge.ts
1409
+ var PfMergeCommand = class extends Command {
1410
+ constructor(cmd, opts) {
1411
+ super(["pfmerge", ...cmd], opts);
1412
+ }
1413
+ };
1414
+
966
1415
  // pkg/commands/ping.ts
967
1416
  var PingCommand = class extends Command {
968
1417
  constructor(cmd, opts) {
969
1418
  const command = ["ping"];
970
- if (typeof cmd !== "undefined" && typeof cmd[0] !== "undefined") {
1419
+ if (cmd?.[0] !== void 0) {
971
1420
  command.push(cmd[0]);
972
1421
  }
973
1422
  super(command, opts);
@@ -1057,7 +1506,10 @@ var ScanCommand = class extends Command {
1057
1506
  if (opts?.type && opts.type.length > 0) {
1058
1507
  command.push("type", opts.type);
1059
1508
  }
1060
- super(command, cmdOpts);
1509
+ super(command, {
1510
+ deserialize: deserializeScanResponse,
1511
+ ...cmdOpts
1512
+ });
1061
1513
  }
1062
1514
  };
1063
1515
 
@@ -1250,7 +1702,10 @@ var SScanCommand = class extends Command {
1250
1702
  if (typeof opts?.count === "number") {
1251
1703
  command.push("count", opts.count);
1252
1704
  }
1253
- super(command, cmdOpts);
1705
+ super(command, {
1706
+ deserialize: deserializeScanResponse,
1707
+ ...cmdOpts
1708
+ });
1254
1709
  }
1255
1710
  };
1256
1711
 
@@ -1310,31 +1765,269 @@ var UnlinkCommand = class extends Command {
1310
1765
  }
1311
1766
  };
1312
1767
 
1313
- // pkg/commands/xadd.ts
1314
- var XAddCommand = class extends Command {
1315
- constructor([key, id, entries, opts], commandOptions) {
1316
- const command = ["XADD", key];
1317
- if (opts) {
1318
- if (opts.nomkStream) {
1319
- command.push("NOMKSTREAM");
1320
- }
1321
- if (opts.trim) {
1322
- command.push(opts.trim.type, opts.trim.comparison, opts.trim.threshold);
1323
- if (typeof opts.trim.limit !== "undefined") {
1324
- command.push("LIMIT", opts.trim.limit);
1325
- }
1326
- }
1768
+ // pkg/commands/xack.ts
1769
+ var XAckCommand = class extends Command {
1770
+ constructor([key, group, id], opts) {
1771
+ const ids = Array.isArray(id) ? [...id] : [id];
1772
+ super(["XACK", key, group, ...ids], opts);
1773
+ }
1774
+ };
1775
+
1776
+ // pkg/commands/xadd.ts
1777
+ var XAddCommand = class extends Command {
1778
+ constructor([key, id, entries, opts], commandOptions) {
1779
+ const command = ["XADD", key];
1780
+ if (opts) {
1781
+ if (opts.nomkStream) {
1782
+ command.push("NOMKSTREAM");
1783
+ }
1784
+ if (opts.trim) {
1785
+ command.push(opts.trim.type, opts.trim.comparison, opts.trim.threshold);
1786
+ if (opts.trim.limit !== void 0) {
1787
+ command.push("LIMIT", opts.trim.limit);
1788
+ }
1789
+ }
1790
+ }
1791
+ command.push(id);
1792
+ for (const [k, v] of Object.entries(entries)) {
1793
+ command.push(k, v);
1794
+ }
1795
+ super(command, commandOptions);
1796
+ }
1797
+ };
1798
+
1799
+ // pkg/commands/xautoclaim.ts
1800
+ var XAutoClaim = class extends Command {
1801
+ constructor([key, group, consumer, minIdleTime, start, options], opts) {
1802
+ const commands = [];
1803
+ if (options?.count) {
1804
+ commands.push("COUNT", options.count);
1805
+ }
1806
+ if (options?.justId) {
1807
+ commands.push("JUSTID");
1808
+ }
1809
+ super(["XAUTOCLAIM", key, group, consumer, minIdleTime, start, ...commands], opts);
1810
+ }
1811
+ };
1812
+
1813
+ // pkg/commands/xclaim.ts
1814
+ var XClaimCommand = class extends Command {
1815
+ constructor([key, group, consumer, minIdleTime, id, options], opts) {
1816
+ const ids = Array.isArray(id) ? [...id] : [id];
1817
+ const commands = [];
1818
+ if (options?.idleMS) {
1819
+ commands.push("IDLE", options.idleMS);
1820
+ }
1821
+ if (options?.idleMS) {
1822
+ commands.push("TIME", options.timeMS);
1823
+ }
1824
+ if (options?.retryCount) {
1825
+ commands.push("RETRYCOUNT", options.retryCount);
1826
+ }
1827
+ if (options?.force) {
1828
+ commands.push("FORCE");
1829
+ }
1830
+ if (options?.justId) {
1831
+ commands.push("JUSTID");
1832
+ }
1833
+ if (options?.lastId) {
1834
+ commands.push("LASTID", options.lastId);
1835
+ }
1836
+ super(["XCLAIM", key, group, consumer, minIdleTime, ...ids, ...commands], opts);
1837
+ }
1838
+ };
1839
+
1840
+ // pkg/commands/xdel.ts
1841
+ var XDelCommand = class extends Command {
1842
+ constructor([key, ids], opts) {
1843
+ const cmds = Array.isArray(ids) ? [...ids] : [ids];
1844
+ super(["XDEL", key, ...cmds], opts);
1845
+ }
1846
+ };
1847
+
1848
+ // pkg/commands/xgroup.ts
1849
+ var XGroupCommand = class extends Command {
1850
+ constructor([key, opts], commandOptions) {
1851
+ const command = ["XGROUP"];
1852
+ switch (opts.type) {
1853
+ case "CREATE": {
1854
+ command.push("CREATE", key, opts.group, opts.id);
1855
+ if (opts.options) {
1856
+ if (opts.options.MKSTREAM) {
1857
+ command.push("MKSTREAM");
1858
+ }
1859
+ if (opts.options.ENTRIESREAD !== void 0) {
1860
+ command.push("ENTRIESREAD", opts.options.ENTRIESREAD.toString());
1861
+ }
1862
+ }
1863
+ break;
1864
+ }
1865
+ case "CREATECONSUMER": {
1866
+ command.push("CREATECONSUMER", key, opts.group, opts.consumer);
1867
+ break;
1868
+ }
1869
+ case "DELCONSUMER": {
1870
+ command.push("DELCONSUMER", key, opts.group, opts.consumer);
1871
+ break;
1872
+ }
1873
+ case "DESTROY": {
1874
+ command.push("DESTROY", key, opts.group);
1875
+ break;
1876
+ }
1877
+ case "SETID": {
1878
+ command.push("SETID", key, opts.group, opts.id);
1879
+ if (opts.options?.ENTRIESREAD !== void 0) {
1880
+ command.push("ENTRIESREAD", opts.options.ENTRIESREAD.toString());
1881
+ }
1882
+ break;
1883
+ }
1884
+ default: {
1885
+ throw new Error("Invalid XGROUP");
1886
+ }
1887
+ }
1888
+ super(command, commandOptions);
1889
+ }
1890
+ };
1891
+
1892
+ // pkg/commands/xinfo.ts
1893
+ var XInfoCommand = class extends Command {
1894
+ constructor([key, options], opts) {
1895
+ const cmds = [];
1896
+ if (options.type === "CONSUMERS") {
1897
+ cmds.push("CONSUMERS", key, options.group);
1898
+ } else {
1899
+ cmds.push("GROUPS", key);
1900
+ }
1901
+ super(["XINFO", ...cmds], opts);
1902
+ }
1903
+ };
1904
+
1905
+ // pkg/commands/xlen.ts
1906
+ var XLenCommand = class extends Command {
1907
+ constructor(cmd, opts) {
1908
+ super(["XLEN", ...cmd], opts);
1909
+ }
1910
+ };
1911
+
1912
+ // pkg/commands/xpending.ts
1913
+ var XPendingCommand = class extends Command {
1914
+ constructor([key, group, start, end, count, options], opts) {
1915
+ const consumers = options?.consumer === void 0 ? [] : Array.isArray(options.consumer) ? [...options.consumer] : [options.consumer];
1916
+ super(
1917
+ [
1918
+ "XPENDING",
1919
+ key,
1920
+ group,
1921
+ ...options?.idleTime ? ["IDLE", options.idleTime] : [],
1922
+ start,
1923
+ end,
1924
+ count,
1925
+ ...consumers
1926
+ ],
1927
+ opts
1928
+ );
1929
+ }
1930
+ };
1931
+
1932
+ // pkg/commands/xrange.ts
1933
+ function deserialize4(result) {
1934
+ const obj = {};
1935
+ for (const e of result) {
1936
+ while (e.length >= 2) {
1937
+ const streamId = e.shift();
1938
+ const entries = e.shift();
1939
+ if (!(streamId in obj)) {
1940
+ obj[streamId] = {};
1941
+ }
1942
+ while (entries.length >= 2) {
1943
+ const field = entries.shift();
1944
+ const value = entries.shift();
1945
+ try {
1946
+ obj[streamId][field] = JSON.parse(value);
1947
+ } catch {
1948
+ obj[streamId][field] = value;
1949
+ }
1950
+ }
1951
+ }
1952
+ }
1953
+ return obj;
1954
+ }
1955
+ var XRangeCommand = class extends Command {
1956
+ constructor([key, start, end, count], opts) {
1957
+ const command = ["XRANGE", key, start, end];
1958
+ if (typeof count === "number") {
1959
+ command.push("COUNT", count);
1960
+ }
1961
+ super(command, {
1962
+ deserialize: (result) => deserialize4(result),
1963
+ ...opts
1964
+ });
1965
+ }
1966
+ };
1967
+
1968
+ // pkg/commands/xread.ts
1969
+ var UNBALANCED_XREAD_ERR = "ERR Unbalanced XREAD list of streams: for each stream key an ID or '$' must be specified";
1970
+ var XReadCommand = class extends Command {
1971
+ constructor([key, id, options], opts) {
1972
+ if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
1973
+ throw new Error(UNBALANCED_XREAD_ERR);
1974
+ }
1975
+ const commands = [];
1976
+ if (typeof options?.count === "number") {
1977
+ commands.push("COUNT", options.count);
1978
+ }
1979
+ if (typeof options?.blockMS === "number") {
1980
+ commands.push("BLOCK", options.blockMS);
1981
+ }
1982
+ commands.push(
1983
+ "STREAMS",
1984
+ ...Array.isArray(key) ? [...key] : [key],
1985
+ ...Array.isArray(id) ? [...id] : [id]
1986
+ );
1987
+ super(["XREAD", ...commands], opts);
1988
+ }
1989
+ };
1990
+
1991
+ // pkg/commands/xreadgroup.ts
1992
+ var UNBALANCED_XREADGROUP_ERR = "ERR Unbalanced XREADGROUP list of streams: for each stream key an ID or '$' must be specified";
1993
+ var XReadGroupCommand = class extends Command {
1994
+ constructor([group, consumer, key, id, options], opts) {
1995
+ if (Array.isArray(key) && Array.isArray(id) && key.length !== id.length) {
1996
+ throw new Error(UNBALANCED_XREADGROUP_ERR);
1327
1997
  }
1328
- command.push(id);
1329
- for (const [k, v] of Object.entries(entries)) {
1330
- command.push(k, v);
1998
+ const commands = [];
1999
+ if (typeof options?.count === "number") {
2000
+ commands.push("COUNT", options.count);
1331
2001
  }
1332
- super(command, commandOptions);
2002
+ if (typeof options?.blockMS === "number") {
2003
+ commands.push("BLOCK", options.blockMS);
2004
+ }
2005
+ if (typeof options?.NOACK === "boolean" && options.NOACK) {
2006
+ commands.push("NOACK");
2007
+ }
2008
+ commands.push(
2009
+ "STREAMS",
2010
+ ...Array.isArray(key) ? [...key] : [key],
2011
+ ...Array.isArray(id) ? [...id] : [id]
2012
+ );
2013
+ super(["XREADGROUP", "GROUP", group, consumer, ...commands], opts);
1333
2014
  }
1334
2015
  };
1335
2016
 
1336
- // pkg/commands/xrange.ts
1337
- function deserialize4(result) {
2017
+ // pkg/commands/xrevrange.ts
2018
+ var XRevRangeCommand = class extends Command {
2019
+ constructor([key, end, start, count], opts) {
2020
+ const command = ["XREVRANGE", key, end, start];
2021
+ if (typeof count === "number") {
2022
+ command.push("COUNT", count);
2023
+ }
2024
+ super(command, {
2025
+ deserialize: (result) => deserialize5(result),
2026
+ ...opts
2027
+ });
2028
+ }
2029
+ };
2030
+ function deserialize5(result) {
1338
2031
  const obj = {};
1339
2032
  for (const e of result) {
1340
2033
  while (e.length >= 2) {
@@ -1356,16 +2049,12 @@ function deserialize4(result) {
1356
2049
  }
1357
2050
  return obj;
1358
2051
  }
1359
- var XRangeCommand = class extends Command {
1360
- constructor([key, start, end, count], opts) {
1361
- const command = ["XRANGE", key, start, end];
1362
- if (typeof count === "number") {
1363
- command.push("COUNT", count);
1364
- }
1365
- super(command, {
1366
- deserialize: (result) => deserialize4(result),
1367
- ...opts
1368
- });
2052
+
2053
+ // pkg/commands/xtrim.ts
2054
+ var XTrimCommand = class extends Command {
2055
+ constructor([key, options], opts) {
2056
+ const { limit, strategy, threshold, exactness = "~" } = options;
2057
+ super(["XTRIM", key, strategy, exactness, threshold, ...limit ? ["LIMIT", limit] : []], opts);
1369
2058
  }
1370
2059
  };
1371
2060
 
@@ -1384,6 +2073,11 @@ var ZAddCommand = class extends Command {
1384
2073
  if ("incr" in arg1 && arg1.incr) {
1385
2074
  command.push("incr");
1386
2075
  }
2076
+ if ("lt" in arg1 && arg1.lt) {
2077
+ command.push("lt");
2078
+ } else if ("gt" in arg1 && arg1.gt) {
2079
+ command.push("gt");
2080
+ }
1387
2081
  if ("score" in arg1 && "member" in arg1) {
1388
2082
  command.push(arg1.score, arg1.member);
1389
2083
  }
@@ -1478,7 +2172,7 @@ var ZRangeCommand = class extends Command {
1478
2172
  if (opts?.rev) {
1479
2173
  command.push("rev");
1480
2174
  }
1481
- if (typeof opts?.count !== "undefined" && typeof opts?.offset !== "undefined") {
2175
+ if (opts?.count !== void 0 && opts.offset !== void 0) {
1482
2176
  command.push("limit", opts.offset, opts.count);
1483
2177
  }
1484
2178
  if (opts?.withScores) {
@@ -1540,7 +2234,10 @@ var ZScanCommand = class extends Command {
1540
2234
  if (typeof opts?.count === "number") {
1541
2235
  command.push("count", opts.count);
1542
2236
  }
1543
- super(command, cmdOpts);
2237
+ super(command, {
2238
+ deserialize: deserializeScanResponse,
2239
+ ...cmdOpts
2240
+ });
1544
2241
  }
1545
2242
  };
1546
2243
 
@@ -1569,7 +2266,7 @@ var ZUnionCommand = class extends Command {
1569
2266
  if ("aggregate" in opts) {
1570
2267
  command.push("aggregate", opts.aggregate);
1571
2268
  }
1572
- if (opts?.withScores) {
2269
+ if (opts.withScores) {
1573
2270
  command.push("withscores");
1574
2271
  }
1575
2272
  }
@@ -1600,6 +2297,183 @@ var ZUnionStoreCommand = class extends Command {
1600
2297
  }
1601
2298
  };
1602
2299
 
2300
+ // pkg/commands/psubscribe.ts
2301
+ var PSubscribeCommand = class extends Command {
2302
+ constructor(cmd, opts) {
2303
+ const sseHeaders = {
2304
+ Accept: "text/event-stream",
2305
+ "Cache-Control": "no-cache",
2306
+ Connection: "keep-alive"
2307
+ };
2308
+ super([], {
2309
+ ...opts,
2310
+ headers: sseHeaders,
2311
+ path: ["psubscribe", ...cmd],
2312
+ streamOptions: {
2313
+ isStreaming: true,
2314
+ onMessage: opts?.streamOptions?.onMessage,
2315
+ signal: opts?.streamOptions?.signal
2316
+ }
2317
+ });
2318
+ }
2319
+ };
2320
+
2321
+ // pkg/commands/subscribe.ts
2322
+ var Subscriber = class extends EventTarget {
2323
+ subscriptions;
2324
+ client;
2325
+ listeners;
2326
+ constructor(client, channels, isPattern = false) {
2327
+ super();
2328
+ this.client = client;
2329
+ this.subscriptions = /* @__PURE__ */ new Map();
2330
+ this.listeners = /* @__PURE__ */ new Map();
2331
+ for (const channel of channels) {
2332
+ if (isPattern) {
2333
+ this.subscribeToPattern(channel);
2334
+ } else {
2335
+ this.subscribeToChannel(channel);
2336
+ }
2337
+ }
2338
+ }
2339
+ subscribeToChannel(channel) {
2340
+ const controller = new AbortController();
2341
+ const command = new SubscribeCommand([channel], {
2342
+ streamOptions: {
2343
+ signal: controller.signal,
2344
+ onMessage: (data) => this.handleMessage(data, false)
2345
+ }
2346
+ });
2347
+ command.exec(this.client).catch((error) => {
2348
+ if (error.name !== "AbortError") {
2349
+ this.dispatchToListeners("error", error);
2350
+ }
2351
+ });
2352
+ this.subscriptions.set(channel, {
2353
+ command,
2354
+ controller,
2355
+ isPattern: false
2356
+ });
2357
+ }
2358
+ subscribeToPattern(pattern) {
2359
+ const controller = new AbortController();
2360
+ const command = new PSubscribeCommand([pattern], {
2361
+ streamOptions: {
2362
+ signal: controller.signal,
2363
+ onMessage: (data) => this.handleMessage(data, true)
2364
+ }
2365
+ });
2366
+ command.exec(this.client).catch((error) => {
2367
+ if (error.name !== "AbortError") {
2368
+ this.dispatchToListeners("error", error);
2369
+ }
2370
+ });
2371
+ this.subscriptions.set(pattern, {
2372
+ command,
2373
+ controller,
2374
+ isPattern: true
2375
+ });
2376
+ }
2377
+ handleMessage(data, isPattern) {
2378
+ const messageData = data.replace(/^data:\s*/, "");
2379
+ const firstCommaIndex = messageData.indexOf(",");
2380
+ const secondCommaIndex = messageData.indexOf(",", firstCommaIndex + 1);
2381
+ const thirdCommaIndex = isPattern ? messageData.indexOf(",", secondCommaIndex + 1) : -1;
2382
+ if (firstCommaIndex !== -1 && secondCommaIndex !== -1) {
2383
+ const type = messageData.slice(0, firstCommaIndex);
2384
+ if (isPattern && type === "pmessage" && thirdCommaIndex !== -1) {
2385
+ const pattern = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
2386
+ const channel = messageData.slice(secondCommaIndex + 1, thirdCommaIndex);
2387
+ const messageStr = messageData.slice(thirdCommaIndex + 1);
2388
+ try {
2389
+ const message = JSON.parse(messageStr);
2390
+ this.dispatchToListeners("pmessage", { pattern, channel, message });
2391
+ this.dispatchToListeners(`pmessage:${pattern}`, { pattern, channel, message });
2392
+ } catch (error) {
2393
+ this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
2394
+ }
2395
+ } else {
2396
+ const channel = messageData.slice(firstCommaIndex + 1, secondCommaIndex);
2397
+ const messageStr = messageData.slice(secondCommaIndex + 1);
2398
+ try {
2399
+ if (type === "subscribe" || type === "psubscribe" || type === "unsubscribe" || type === "punsubscribe") {
2400
+ const count = Number.parseInt(messageStr);
2401
+ this.dispatchToListeners(type, count);
2402
+ } else {
2403
+ const message = JSON.parse(messageStr);
2404
+ this.dispatchToListeners(type, { channel, message });
2405
+ this.dispatchToListeners(`${type}:${channel}`, { channel, message });
2406
+ }
2407
+ } catch (error) {
2408
+ this.dispatchToListeners("error", new Error(`Failed to parse message: ${error}`));
2409
+ }
2410
+ }
2411
+ }
2412
+ }
2413
+ dispatchToListeners(type, data) {
2414
+ const listeners = this.listeners.get(type);
2415
+ if (listeners) {
2416
+ for (const listener of listeners) {
2417
+ listener(data);
2418
+ }
2419
+ }
2420
+ }
2421
+ on(type, listener) {
2422
+ if (!this.listeners.has(type)) {
2423
+ this.listeners.set(type, /* @__PURE__ */ new Set());
2424
+ }
2425
+ this.listeners.get(type)?.add(listener);
2426
+ }
2427
+ removeAllListeners() {
2428
+ this.listeners.clear();
2429
+ }
2430
+ async unsubscribe(channels) {
2431
+ if (channels) {
2432
+ for (const channel of channels) {
2433
+ const subscription = this.subscriptions.get(channel);
2434
+ if (subscription) {
2435
+ try {
2436
+ subscription.controller.abort();
2437
+ } catch {
2438
+ }
2439
+ this.subscriptions.delete(channel);
2440
+ }
2441
+ }
2442
+ } else {
2443
+ for (const subscription of this.subscriptions.values()) {
2444
+ try {
2445
+ subscription.controller.abort();
2446
+ } catch {
2447
+ }
2448
+ }
2449
+ this.subscriptions.clear();
2450
+ this.removeAllListeners();
2451
+ }
2452
+ }
2453
+ getSubscribedChannels() {
2454
+ return [...this.subscriptions.keys()];
2455
+ }
2456
+ };
2457
+ var SubscribeCommand = class extends Command {
2458
+ constructor(cmd, opts) {
2459
+ const sseHeaders = {
2460
+ Accept: "text/event-stream",
2461
+ "Cache-Control": "no-cache",
2462
+ Connection: "keep-alive"
2463
+ };
2464
+ super([], {
2465
+ ...opts,
2466
+ headers: sseHeaders,
2467
+ path: ["subscribe", ...cmd],
2468
+ streamOptions: {
2469
+ isStreaming: true,
2470
+ onMessage: opts?.streamOptions?.onMessage,
2471
+ signal: opts?.streamOptions?.signal
2472
+ }
2473
+ });
2474
+ }
2475
+ };
2476
+
1603
2477
  // pkg/commands/zdiffstore.ts
1604
2478
  var ZDiffStoreCommand = class extends Command {
1605
2479
  constructor(cmd, opts) {
@@ -1626,20 +2500,21 @@ var Pipeline = class {
1626
2500
  this.commands = [];
1627
2501
  this.commandOptions = opts.commandOptions;
1628
2502
  this.multiExec = opts.multiExec ?? false;
2503
+ if (this.commandOptions?.latencyLogging) {
2504
+ const originalExec = this.exec.bind(this);
2505
+ this.exec = async (options) => {
2506
+ const start = performance.now();
2507
+ const result = await (options ? originalExec(options) : originalExec());
2508
+ const end = performance.now();
2509
+ const loggerResult = (end - start).toFixed(2);
2510
+ console.log(
2511
+ `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`
2512
+ );
2513
+ return result;
2514
+ };
2515
+ }
1629
2516
  }
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 () => {
2517
+ exec = async (options) => {
1643
2518
  if (this.commands.length === 0) {
1644
2519
  throw new Error("Pipeline is empty");
1645
2520
  }
@@ -1648,7 +2523,12 @@ var Pipeline = class {
1648
2523
  path,
1649
2524
  body: Object.values(this.commands).map((c) => c.command)
1650
2525
  });
1651
- return res.map(({ error, result }, i) => {
2526
+ return options?.keepErrors ? res.map(({ error, result }, i) => {
2527
+ return {
2528
+ error,
2529
+ result: this.commands[i].deserialize(result)
2530
+ };
2531
+ }) : res.map(({ error, result }, i) => {
1652
2532
  if (error) {
1653
2533
  throw new UpstashError(
1654
2534
  `Command ${i + 1} [ ${this.commands[i].command[0]} ] failed: ${error}`
@@ -1679,6 +2559,23 @@ var Pipeline = class {
1679
2559
  * @see https://redis.io/commands/bitcount
1680
2560
  */
1681
2561
  bitcount = (...args) => this.chain(new BitCountCommand(args, this.commandOptions));
2562
+ /**
2563
+ * Returns an instance that can be used to execute `BITFIELD` commands on one key.
2564
+ *
2565
+ * @example
2566
+ * ```typescript
2567
+ * redis.set("mykey", 0);
2568
+ * const result = await redis.pipeline()
2569
+ * .bitfield("mykey")
2570
+ * .set("u4", 0, 16)
2571
+ * .incr("u4", "#1", 1)
2572
+ * .exec();
2573
+ * console.log(result); // [[0, 1]]
2574
+ * ```
2575
+ *
2576
+ * @see https://redis.io/commands/bitfield
2577
+ */
2578
+ bitfield = (...args) => new BitFieldCommand(args, this.client, this.commandOptions, this.chain.bind(this));
1682
2579
  /**
1683
2580
  * @see https://redis.io/commands/bitop
1684
2581
  */
@@ -1689,6 +2586,10 @@ var Pipeline = class {
1689
2586
  * @see https://redis.io/commands/bitpos
1690
2587
  */
1691
2588
  bitpos = (...args) => this.chain(new BitPosCommand(args, this.commandOptions));
2589
+ /**
2590
+ * @see https://redis.io/commands/copy
2591
+ */
2592
+ copy = (...args) => this.chain(new CopyCommand(args, this.commandOptions));
1692
2593
  /**
1693
2594
  * @see https://redis.io/commands/zdiffstore
1694
2595
  */
@@ -1741,6 +2642,30 @@ var Pipeline = class {
1741
2642
  * @see https://redis.io/commands/flushdb
1742
2643
  */
1743
2644
  flushdb = (...args) => this.chain(new FlushDBCommand(args, this.commandOptions));
2645
+ /**
2646
+ * @see https://redis.io/commands/geoadd
2647
+ */
2648
+ geoadd = (...args) => this.chain(new GeoAddCommand(args, this.commandOptions));
2649
+ /**
2650
+ * @see https://redis.io/commands/geodist
2651
+ */
2652
+ geodist = (...args) => this.chain(new GeoDistCommand(args, this.commandOptions));
2653
+ /**
2654
+ * @see https://redis.io/commands/geopos
2655
+ */
2656
+ geopos = (...args) => this.chain(new GeoPosCommand(args, this.commandOptions));
2657
+ /**
2658
+ * @see https://redis.io/commands/geohash
2659
+ */
2660
+ geohash = (...args) => this.chain(new GeoHashCommand(args, this.commandOptions));
2661
+ /**
2662
+ * @see https://redis.io/commands/geosearch
2663
+ */
2664
+ geosearch = (...args) => this.chain(new GeoSearchCommand(args, this.commandOptions));
2665
+ /**
2666
+ * @see https://redis.io/commands/geosearchstore
2667
+ */
2668
+ geosearchstore = (...args) => this.chain(new GeoSearchStoreCommand(args, this.commandOptions));
1744
2669
  /**
1745
2670
  * @see https://redis.io/commands/get
1746
2671
  */
@@ -1753,6 +2678,10 @@ var Pipeline = class {
1753
2678
  * @see https://redis.io/commands/getdel
1754
2679
  */
1755
2680
  getdel = (...args) => this.chain(new GetDelCommand(args, this.commandOptions));
2681
+ /**
2682
+ * @see https://redis.io/commands/getex
2683
+ */
2684
+ getex = (...args) => this.chain(new GetExCommand(args, this.commandOptions));
1756
2685
  /**
1757
2686
  * @see https://redis.io/commands/getrange
1758
2687
  */
@@ -1861,6 +2790,10 @@ var Pipeline = class {
1861
2790
  * @see https://redis.io/commands/lpop
1862
2791
  */
1863
2792
  lpop = (...args) => this.chain(new LPopCommand(args, this.commandOptions));
2793
+ /**
2794
+ * @see https://redis.io/commands/lmpop
2795
+ */
2796
+ lmpop = (...args) => this.chain(new LmPopCommand(args, this.commandOptions));
1864
2797
  /**
1865
2798
  * @see https://redis.io/commands/lpos
1866
2799
  */
@@ -1913,6 +2846,18 @@ var Pipeline = class {
1913
2846
  * @see https://redis.io/commands/pexpireat
1914
2847
  */
1915
2848
  pexpireat = (...args) => this.chain(new PExpireAtCommand(args, this.commandOptions));
2849
+ /**
2850
+ * @see https://redis.io/commands/pfadd
2851
+ */
2852
+ pfadd = (...args) => this.chain(new PfAddCommand(args, this.commandOptions));
2853
+ /**
2854
+ * @see https://redis.io/commands/pfcount
2855
+ */
2856
+ pfcount = (...args) => this.chain(new PfCountCommand(args, this.commandOptions));
2857
+ /**
2858
+ * @see https://redis.io/commands/pfmerge
2859
+ */
2860
+ pfmerge = (...args) => this.chain(new PfMergeCommand(args, this.commandOptions));
1916
2861
  /**
1917
2862
  * @see https://redis.io/commands/ping
1918
2863
  */
@@ -1956,7 +2901,7 @@ var Pipeline = class {
1956
2901
  /**
1957
2902
  * @see https://redis.io/commands/sadd
1958
2903
  */
1959
- sadd = (key, ...members) => this.chain(new SAddCommand([key, ...members], this.commandOptions));
2904
+ sadd = (key, member, ...members) => this.chain(new SAddCommand([key, member, ...members], this.commandOptions));
1960
2905
  /**
1961
2906
  * @see https://redis.io/commands/scan
1962
2907
  */
@@ -2083,10 +3028,7 @@ var Pipeline = class {
2083
3028
  zadd = (...args) => {
2084
3029
  if ("score" in args[1]) {
2085
3030
  return this.chain(
2086
- new ZAddCommand(
2087
- [args[0], args[1], ...args.slice(2)],
2088
- this.commandOptions
2089
- )
3031
+ new ZAddCommand([args[0], args[1], ...args.slice(2)], this.commandOptions)
2090
3032
  );
2091
3033
  }
2092
3034
  return this.chain(
@@ -2096,6 +3038,62 @@ var Pipeline = class {
2096
3038
  )
2097
3039
  );
2098
3040
  };
3041
+ /**
3042
+ * @see https://redis.io/commands/xadd
3043
+ */
3044
+ xadd = (...args) => this.chain(new XAddCommand(args, this.commandOptions));
3045
+ /**
3046
+ * @see https://redis.io/commands/xack
3047
+ */
3048
+ xack = (...args) => this.chain(new XAckCommand(args, this.commandOptions));
3049
+ /**
3050
+ * @see https://redis.io/commands/xdel
3051
+ */
3052
+ xdel = (...args) => this.chain(new XDelCommand(args, this.commandOptions));
3053
+ /**
3054
+ * @see https://redis.io/commands/xgroup
3055
+ */
3056
+ xgroup = (...args) => this.chain(new XGroupCommand(args, this.commandOptions));
3057
+ /**
3058
+ * @see https://redis.io/commands/xread
3059
+ */
3060
+ xread = (...args) => this.chain(new XReadCommand(args, this.commandOptions));
3061
+ /**
3062
+ * @see https://redis.io/commands/xreadgroup
3063
+ */
3064
+ xreadgroup = (...args) => this.chain(new XReadGroupCommand(args, this.commandOptions));
3065
+ /**
3066
+ * @see https://redis.io/commands/xinfo
3067
+ */
3068
+ xinfo = (...args) => this.chain(new XInfoCommand(args, this.commandOptions));
3069
+ /**
3070
+ * @see https://redis.io/commands/xlen
3071
+ */
3072
+ xlen = (...args) => this.chain(new XLenCommand(args, this.commandOptions));
3073
+ /**
3074
+ * @see https://redis.io/commands/xpending
3075
+ */
3076
+ xpending = (...args) => this.chain(new XPendingCommand(args, this.commandOptions));
3077
+ /**
3078
+ * @see https://redis.io/commands/xclaim
3079
+ */
3080
+ xclaim = (...args) => this.chain(new XClaimCommand(args, this.commandOptions));
3081
+ /**
3082
+ * @see https://redis.io/commands/xautoclaim
3083
+ */
3084
+ xautoclaim = (...args) => this.chain(new XAutoClaim(args, this.commandOptions));
3085
+ /**
3086
+ * @see https://redis.io/commands/xtrim
3087
+ */
3088
+ xtrim = (...args) => this.chain(new XTrimCommand(args, this.commandOptions));
3089
+ /**
3090
+ * @see https://redis.io/commands/xrange
3091
+ */
3092
+ xrange = (...args) => this.chain(new XRangeCommand(args, this.commandOptions));
3093
+ /**
3094
+ * @see https://redis.io/commands/xrevrange
3095
+ */
3096
+ xrevrange = (...args) => this.chain(new XRevRangeCommand(args, this.commandOptions));
2099
3097
  /**
2100
3098
  * @see https://redis.io/commands/zcard
2101
3099
  */
@@ -2213,14 +3211,6 @@ var Pipeline = class {
2213
3211
  * @see https://redis.io/commands/json.forget
2214
3212
  */
2215
3213
  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
3214
  /**
2225
3215
  * @see https://redis.io/commands/json.get
2226
3216
  */
@@ -2229,6 +3219,10 @@ var Pipeline = class {
2229
3219
  * @see https://redis.io/commands/json.mget
2230
3220
  */
2231
3221
  mget: (...args) => this.chain(new JsonMGetCommand(args, this.commandOptions)),
3222
+ /**
3223
+ * @see https://redis.io/commands/json.mset
3224
+ */
3225
+ mset: (...args) => this.chain(new JsonMSetCommand(args, this.commandOptions)),
2232
3226
  /**
2233
3227
  * @see https://redis.io/commands/json.numincrby
2234
3228
  */
@@ -2274,8 +3268,8 @@ var Pipeline = class {
2274
3268
  };
2275
3269
 
2276
3270
  // pkg/script.ts
2277
- var import_enc_hex = __toESM(require("crypto-js/enc-hex"));
2278
- var import_sha1 = __toESM(require("crypto-js/sha1"));
3271
+ var import_enc_hex = __toESM(require("crypto-js/enc-hex.js"));
3272
+ var import_sha1 = __toESM(require("crypto-js/sha1.js"));
2279
3273
  var Script = class {
2280
3274
  script;
2281
3275
  sha1;
@@ -2304,11 +3298,11 @@ var Script = class {
2304
3298
  * Following calls will be able to use the cached script
2305
3299
  */
2306
3300
  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")) {
3301
+ const res = await this.redis.evalsha(this.sha1, keys, args).catch(async (error) => {
3302
+ if (error instanceof Error && error.message.toLowerCase().includes("noscript")) {
2309
3303
  return await this.redis.eval(this.script, keys, args);
2310
3304
  }
2311
- throw err;
3305
+ throw error;
2312
3306
  });
2313
3307
  return res;
2314
3308
  }
@@ -2325,6 +3319,7 @@ var Redis = class {
2325
3319
  client;
2326
3320
  opts;
2327
3321
  enableTelemetry;
3322
+ enableAutoPipelining;
2328
3323
  /**
2329
3324
  * Create a new redis client
2330
3325
  *
@@ -2340,6 +3335,16 @@ var Redis = class {
2340
3335
  this.client = client;
2341
3336
  this.opts = opts;
2342
3337
  this.enableTelemetry = opts?.enableTelemetry ?? true;
3338
+ if (opts?.readYourWrites === false) {
3339
+ this.client.readYourWrites = false;
3340
+ }
3341
+ this.enableAutoPipelining = opts?.enableAutoPipelining ?? true;
3342
+ }
3343
+ get readYourWritesSyncToken() {
3344
+ return this.client.upstashSyncToken;
3345
+ }
3346
+ set readYourWritesSyncToken(session) {
3347
+ this.client.upstashSyncToken = session;
2343
3348
  }
2344
3349
  get json() {
2345
3350
  return {
@@ -2379,14 +3384,6 @@ var Redis = class {
2379
3384
  * @see https://redis.io/commands/json.forget
2380
3385
  */
2381
3386
  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
3387
  /**
2391
3388
  * @see https://redis.io/commands/json.get
2392
3389
  */
@@ -2395,6 +3392,10 @@ var Redis = class {
2395
3392
  * @see https://redis.io/commands/json.mget
2396
3393
  */
2397
3394
  mget: (...args) => new JsonMGetCommand(args, this.opts).exec(this.client),
3395
+ /**
3396
+ * @see https://redis.io/commands/json.mset
3397
+ */
3398
+ mset: (...args) => new JsonMSetCommand(args, this.opts).exec(this.client),
2398
3399
  /**
2399
3400
  * @see https://redis.io/commands/json.numincrby
2400
3401
  */
@@ -2469,6 +3470,9 @@ var Redis = class {
2469
3470
  commandOptions: this.opts,
2470
3471
  multiExec: false
2471
3472
  });
3473
+ autoPipeline = () => {
3474
+ return createAutoPipelineProxy(this);
3475
+ };
2472
3476
  /**
2473
3477
  * Create a new transaction to allow executing multiple steps atomically.
2474
3478
  *
@@ -2483,6 +3487,22 @@ var Redis = class {
2483
3487
  commandOptions: this.opts,
2484
3488
  multiExec: true
2485
3489
  });
3490
+ /**
3491
+ * Returns an instance that can be used to execute `BITFIELD` commands on one key.
3492
+ *
3493
+ * @example
3494
+ * ```typescript
3495
+ * redis.set("mykey", 0);
3496
+ * const result = await redis.bitfield("mykey")
3497
+ * .set("u4", 0, 16)
3498
+ * .incr("u4", "#1", 1)
3499
+ * .exec();
3500
+ * console.log(result); // [0, 1]
3501
+ * ```
3502
+ *
3503
+ * @see https://redis.io/commands/bitfield
3504
+ */
3505
+ bitfield = (...args) => new BitFieldCommand(args, this.client, this.opts);
2486
3506
  /**
2487
3507
  * @see https://redis.io/commands/append
2488
3508
  */
@@ -2501,6 +3521,10 @@ var Redis = class {
2501
3521
  * @see https://redis.io/commands/bitpos
2502
3522
  */
2503
3523
  bitpos = (...args) => new BitPosCommand(args, this.opts).exec(this.client);
3524
+ /**
3525
+ * @see https://redis.io/commands/copy
3526
+ */
3527
+ copy = (...args) => new CopyCommand(args, this.opts).exec(this.client);
2504
3528
  /**
2505
3529
  * @see https://redis.io/commands/dbsize
2506
3530
  */
@@ -2529,6 +3553,10 @@ var Redis = class {
2529
3553
  * @see https://redis.io/commands/evalsha
2530
3554
  */
2531
3555
  evalsha = (...args) => new EvalshaCommand(args, this.opts).exec(this.client);
3556
+ /**
3557
+ * Generic method to execute any Redis command.
3558
+ */
3559
+ exec = (args) => new ExecCommand(args, this.opts).exec(this.client);
2532
3560
  /**
2533
3561
  * @see https://redis.io/commands/exists
2534
3562
  */
@@ -2549,6 +3577,30 @@ var Redis = class {
2549
3577
  * @see https://redis.io/commands/flushdb
2550
3578
  */
2551
3579
  flushdb = (...args) => new FlushDBCommand(args, this.opts).exec(this.client);
3580
+ /**
3581
+ * @see https://redis.io/commands/geoadd
3582
+ */
3583
+ geoadd = (...args) => new GeoAddCommand(args, this.opts).exec(this.client);
3584
+ /**
3585
+ * @see https://redis.io/commands/geopos
3586
+ */
3587
+ geopos = (...args) => new GeoPosCommand(args, this.opts).exec(this.client);
3588
+ /**
3589
+ * @see https://redis.io/commands/geodist
3590
+ */
3591
+ geodist = (...args) => new GeoDistCommand(args, this.opts).exec(this.client);
3592
+ /**
3593
+ * @see https://redis.io/commands/geohash
3594
+ */
3595
+ geohash = (...args) => new GeoHashCommand(args, this.opts).exec(this.client);
3596
+ /**
3597
+ * @see https://redis.io/commands/geosearch
3598
+ */
3599
+ geosearch = (...args) => new GeoSearchCommand(args, this.opts).exec(this.client);
3600
+ /**
3601
+ * @see https://redis.io/commands/geosearchstore
3602
+ */
3603
+ geosearchstore = (...args) => new GeoSearchStoreCommand(args, this.opts).exec(this.client);
2552
3604
  /**
2553
3605
  * @see https://redis.io/commands/get
2554
3606
  */
@@ -2561,6 +3613,10 @@ var Redis = class {
2561
3613
  * @see https://redis.io/commands/getdel
2562
3614
  */
2563
3615
  getdel = (...args) => new GetDelCommand(args, this.opts).exec(this.client);
3616
+ /**
3617
+ * @see https://redis.io/commands/getex
3618
+ */
3619
+ getex = (...args) => new GetExCommand(args, this.opts).exec(this.client);
2564
3620
  /**
2565
3621
  * @see https://redis.io/commands/getrange
2566
3622
  */
@@ -2669,6 +3725,10 @@ var Redis = class {
2669
3725
  * @see https://redis.io/commands/lpop
2670
3726
  */
2671
3727
  lpop = (...args) => new LPopCommand(args, this.opts).exec(this.client);
3728
+ /**
3729
+ * @see https://redis.io/commands/lmpop
3730
+ */
3731
+ lmpop = (...args) => new LmPopCommand(args, this.opts).exec(this.client);
2672
3732
  /**
2673
3733
  * @see https://redis.io/commands/lpos
2674
3734
  */
@@ -2721,6 +3781,18 @@ var Redis = class {
2721
3781
  * @see https://redis.io/commands/pexpireat
2722
3782
  */
2723
3783
  pexpireat = (...args) => new PExpireAtCommand(args, this.opts).exec(this.client);
3784
+ /**
3785
+ * @see https://redis.io/commands/pfadd
3786
+ */
3787
+ pfadd = (...args) => new PfAddCommand(args, this.opts).exec(this.client);
3788
+ /**
3789
+ * @see https://redis.io/commands/pfcount
3790
+ */
3791
+ pfcount = (...args) => new PfCountCommand(args, this.opts).exec(this.client);
3792
+ /**
3793
+ * @see https://redis.io/commands/pfmerge
3794
+ */
3795
+ pfmerge = (...args) => new PfMergeCommand(args, this.opts).exec(this.client);
2724
3796
  /**
2725
3797
  * @see https://redis.io/commands/ping
2726
3798
  */
@@ -2729,6 +3801,13 @@ var Redis = class {
2729
3801
  * @see https://redis.io/commands/psetex
2730
3802
  */
2731
3803
  psetex = (key, ttl, value) => new PSetEXCommand([key, ttl, value], this.opts).exec(this.client);
3804
+ /**
3805
+ * @see https://redis.io/commands/psubscribe
3806
+ */
3807
+ psubscribe = (patterns) => {
3808
+ const patternArray = Array.isArray(patterns) ? patterns : [patterns];
3809
+ return new Subscriber(this.client, patternArray, true);
3810
+ };
2732
3811
  /**
2733
3812
  * @see https://redis.io/commands/pttl
2734
3813
  */
@@ -2764,7 +3843,7 @@ var Redis = class {
2764
3843
  /**
2765
3844
  * @see https://redis.io/commands/sadd
2766
3845
  */
2767
- sadd = (key, ...members) => new SAddCommand([key, ...members], this.opts).exec(this.client);
3846
+ sadd = (key, member, ...members) => new SAddCommand([key, member, ...members], this.opts).exec(this.client);
2768
3847
  /**
2769
3848
  * @see https://redis.io/commands/scan
2770
3849
  */
@@ -2857,6 +3936,13 @@ var Redis = class {
2857
3936
  * @see https://redis.io/commands/strlen
2858
3937
  */
2859
3938
  strlen = (...args) => new StrLenCommand(args, this.opts).exec(this.client);
3939
+ /**
3940
+ * @see https://redis.io/commands/subscribe
3941
+ */
3942
+ subscribe = (channels) => {
3943
+ const channelArray = Array.isArray(channels) ? channels : [channels];
3944
+ return new Subscriber(this.client, channelArray);
3945
+ };
2860
3946
  /**
2861
3947
  * @see https://redis.io/commands/sunion
2862
3948
  */
@@ -2889,19 +3975,66 @@ var Redis = class {
2889
3975
  * @see https://redis.io/commands/xadd
2890
3976
  */
2891
3977
  xadd = (...args) => new XAddCommand(args, this.opts).exec(this.client);
3978
+ /**
3979
+ * @see https://redis.io/commands/xack
3980
+ */
3981
+ xack = (...args) => new XAckCommand(args, this.opts).exec(this.client);
3982
+ /**
3983
+ * @see https://redis.io/commands/xdel
3984
+ */
3985
+ xdel = (...args) => new XDelCommand(args, this.opts).exec(this.client);
3986
+ /**
3987
+ * @see https://redis.io/commands/xgroup
3988
+ */
3989
+ xgroup = (...args) => new XGroupCommand(args, this.opts).exec(this.client);
3990
+ /**
3991
+ * @see https://redis.io/commands/xread
3992
+ */
3993
+ xread = (...args) => new XReadCommand(args, this.opts).exec(this.client);
3994
+ /**
3995
+ * @see https://redis.io/commands/xreadgroup
3996
+ */
3997
+ xreadgroup = (...args) => new XReadGroupCommand(args, this.opts).exec(this.client);
3998
+ /**
3999
+ * @see https://redis.io/commands/xinfo
4000
+ */
4001
+ xinfo = (...args) => new XInfoCommand(args, this.opts).exec(this.client);
4002
+ /**
4003
+ * @see https://redis.io/commands/xlen
4004
+ */
4005
+ xlen = (...args) => new XLenCommand(args, this.opts).exec(this.client);
4006
+ /**
4007
+ * @see https://redis.io/commands/xpending
4008
+ */
4009
+ xpending = (...args) => new XPendingCommand(args, this.opts).exec(this.client);
4010
+ /**
4011
+ * @see https://redis.io/commands/xclaim
4012
+ */
4013
+ xclaim = (...args) => new XClaimCommand(args, this.opts).exec(this.client);
4014
+ /**
4015
+ * @see https://redis.io/commands/xautoclaim
4016
+ */
4017
+ xautoclaim = (...args) => new XAutoClaim(args, this.opts).exec(this.client);
4018
+ /**
4019
+ * @see https://redis.io/commands/xtrim
4020
+ */
4021
+ xtrim = (...args) => new XTrimCommand(args, this.opts).exec(this.client);
2892
4022
  /**
2893
4023
  * @see https://redis.io/commands/xrange
2894
4024
  */
2895
4025
  xrange = (...args) => new XRangeCommand(args, this.opts).exec(this.client);
4026
+ /**
4027
+ * @see https://redis.io/commands/xrevrange
4028
+ */
4029
+ xrevrange = (...args) => new XRevRangeCommand(args, this.opts).exec(this.client);
2896
4030
  /**
2897
4031
  * @see https://redis.io/commands/zadd
2898
4032
  */
2899
4033
  zadd = (...args) => {
2900
4034
  if ("score" in args[1]) {
2901
- return new ZAddCommand(
2902
- [args[0], args[1], ...args.slice(2)],
2903
- this.opts
2904
- ).exec(this.client);
4035
+ return new ZAddCommand([args[0], args[1], ...args.slice(2)], this.opts).exec(
4036
+ this.client
4037
+ );
2905
4038
  }
2906
4039
  return new ZAddCommand(
2907
4040
  [args[0], args[1], ...args.slice(2)],
@@ -2991,7 +4124,7 @@ var Redis = class {
2991
4124
  };
2992
4125
 
2993
4126
  // version.ts
2994
- var VERSION = "v0.0.0-ci.9722909577fc3b6b939d0c937c6ba5f8e8287ee4";
4127
+ var VERSION = "v1.30.2";
2995
4128
 
2996
4129
  // platforms/fastly.ts
2997
4130
  var Redis2 = class extends Redis {
@@ -3008,30 +4141,48 @@ var Redis2 = class extends Redis {
3008
4141
  * ```
3009
4142
  */
3010
4143
  constructor(config) {
3011
- if (config.url.startsWith(" ") || config.url.endsWith(" ") || /\r|\n/.test(config.url)) {
3012
- console.warn("The redis url contains whitespace or newline, which can cause errors!");
4144
+ if (!config.url) {
4145
+ console.warn(
4146
+ `[Upstash Redis] The 'url' property is missing or undefined in your Redis config.`
4147
+ );
4148
+ } else if (config.url.startsWith(" ") || config.url.endsWith(" ") || /\r|\n/.test(config.url)) {
4149
+ console.warn(
4150
+ "[Upstash Redis] The redis url contains whitespace or newline, which can cause errors!"
4151
+ );
3013
4152
  }
3014
- if (config.token.startsWith(" ") || config.token.endsWith(" ") || /\r|\n/.test(config.token)) {
3015
- console.warn("The redis token contains whitespace or newline, which can cause errors!");
4153
+ if (!config.token) {
4154
+ console.warn(
4155
+ `[Upstash Redis] The 'token' property is missing or undefined in your Redis config.`
4156
+ );
4157
+ } else if (config.token.startsWith(" ") || config.token.endsWith(" ") || /\r|\n/.test(config.token)) {
4158
+ console.warn(
4159
+ "[Upstash Redis] The redis token contains whitespace or newline, which can cause errors!"
4160
+ );
3016
4161
  }
3017
4162
  const client = new HttpClient({
3018
4163
  baseUrl: config.url,
3019
4164
  retry: config.retry,
3020
4165
  headers: { authorization: `Bearer ${config.token}` },
3021
4166
  options: { backend: config.backend },
3022
- responseEncoding: config.responseEncoding
4167
+ responseEncoding: config.responseEncoding,
4168
+ keepAlive: config.keepAlive,
4169
+ readYourWrites: config.readYourWrites
3023
4170
  });
3024
4171
  super(client, {
3025
- automaticDeserialization: config.automaticDeserialization
4172
+ automaticDeserialization: config.automaticDeserialization,
4173
+ enableAutoPipelining: config.enableAutoPipelining
3026
4174
  });
3027
4175
  this.addTelemetry({
3028
4176
  sdk: `@upstash/redis@${VERSION}`,
3029
4177
  platform: "fastly"
3030
4178
  });
4179
+ if (this.enableAutoPipelining) {
4180
+ return this.autoPipeline();
4181
+ }
3031
4182
  }
3032
4183
  };
3033
4184
  // Annotate the CommonJS export names for ESM import in node:
3034
4185
  0 && (module.exports = {
3035
- Redis
4186
+ Redis,
4187
+ errors
3036
4188
  });
3037
- //# sourceMappingURL=fastly.js.map