memx 0.0.1 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/index.js +436 -94
- package/dist/index.js.map +2 -2
- package/dist/index.mjs +421 -76
- package/dist/index.mjs.map +2 -2
- package/index.d.ts +147 -68
- package/package.json +7 -7
- package/src/buffers.ts +9 -0
- package/src/client.ts +152 -78
- package/src/cluster.ts +24 -12
- package/src/connection.ts +1 -1
- package/src/encode.ts +1 -1
- package/src/fake.ts +222 -0
- package/src/index.ts +4 -0
- package/src/internals.ts +5 -0
- package/src/server.ts +28 -17
- package/src/types.ts +15 -9
- package/src/utils.ts +161 -0
package/dist/index.mjs
CHANGED
|
@@ -295,6 +295,9 @@ function typedArrayFlags(value) {
|
|
|
295
295
|
const flags = isUint8Array(value) ? 3402235920 /* UINT8ARRAY */ : isUint8ClampedArray(value) ? 3402235921 /* UINT8CLAMPEDARRAY */ : isUint16Array(value) ? 3402235922 /* UINT16ARRAY */ : isUint32Array(value) ? 3402235923 /* UINT32ARRAY */ : isInt8Array(value) ? 3402235924 /* INT8ARRAY */ : isInt16Array(value) ? 3402235925 /* INT16ARRAY */ : isInt32Array(value) ? 3402235926 /* INT32ARRAY */ : isBigUint64Array(value) ? 3402235927 /* BIGUINT64ARRAY */ : isBigInt64Array(value) ? 3402235928 /* BIGINT64ARRAY */ : isFloat32Array(value) ? 3402235929 /* FLOAT32ARRAY */ : isFloat64Array(value) ? 3402235930 /* FLOAT64ARRAY */ : assert2.fail("Unsupported kind of TypedArray");
|
|
296
296
|
return flags;
|
|
297
297
|
}
|
|
298
|
+
function logPromiseError(promise, message) {
|
|
299
|
+
return promise.catch((error) => console.log(message, error)).then(() => void 0);
|
|
300
|
+
}
|
|
298
301
|
|
|
299
302
|
// src/connection.ts
|
|
300
303
|
import assert3 from "assert";
|
|
@@ -438,6 +441,153 @@ var Connection = class {
|
|
|
438
441
|
}
|
|
439
442
|
};
|
|
440
443
|
|
|
444
|
+
// src/fake.ts
|
|
445
|
+
function toExp(ttl = 0) {
|
|
446
|
+
if (ttl === 0)
|
|
447
|
+
return Number.MAX_SAFE_INTEGER;
|
|
448
|
+
return Date.now() + ttl * 1e3;
|
|
449
|
+
}
|
|
450
|
+
var FakeAdapter = class {
|
|
451
|
+
#cache = /* @__PURE__ */ new Map();
|
|
452
|
+
#cas = 1n;
|
|
453
|
+
ttl = 0;
|
|
454
|
+
#get(key) {
|
|
455
|
+
if (key.length > 250)
|
|
456
|
+
throw new TypeError(`Key too long (len=${key.length})`);
|
|
457
|
+
const entry = this.#cache.get(key);
|
|
458
|
+
if (!entry)
|
|
459
|
+
return;
|
|
460
|
+
if (Date.now() > entry.exp) {
|
|
461
|
+
this.#cache.delete(key);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
return entry;
|
|
465
|
+
}
|
|
466
|
+
#set(key, value, flags, ttl) {
|
|
467
|
+
this.#cache.set(key, {
|
|
468
|
+
value,
|
|
469
|
+
flags: flags || 0,
|
|
470
|
+
cas: ++this.#cas,
|
|
471
|
+
exp: toExp(ttl)
|
|
472
|
+
});
|
|
473
|
+
return this.#cas;
|
|
474
|
+
}
|
|
475
|
+
async get(key) {
|
|
476
|
+
const entry = this.#get(key);
|
|
477
|
+
if (!entry)
|
|
478
|
+
return;
|
|
479
|
+
return {
|
|
480
|
+
value: entry.value,
|
|
481
|
+
flags: entry.flags,
|
|
482
|
+
cas: entry.cas,
|
|
483
|
+
recycle: () => void 0
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
async gat(key, ttl) {
|
|
487
|
+
const entry = this.#get(key);
|
|
488
|
+
if (!entry)
|
|
489
|
+
return;
|
|
490
|
+
entry.exp = toExp(ttl);
|
|
491
|
+
return {
|
|
492
|
+
value: entry.value,
|
|
493
|
+
flags: entry.flags,
|
|
494
|
+
cas: entry.cas,
|
|
495
|
+
recycle: () => void 0
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
async touch(key, ttl) {
|
|
499
|
+
const entry = this.#get(key);
|
|
500
|
+
if (entry)
|
|
501
|
+
entry.exp = toExp(ttl);
|
|
502
|
+
return !!entry;
|
|
503
|
+
}
|
|
504
|
+
async set(key, value, options = {}) {
|
|
505
|
+
const entry = this.#get(key);
|
|
506
|
+
if (entry && options.cas !== void 0 && entry.cas !== options.cas) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
return this.#set(key, value, options.flags, options.ttl);
|
|
510
|
+
}
|
|
511
|
+
async add(key, value, options = {}) {
|
|
512
|
+
if (this.#get(key))
|
|
513
|
+
return;
|
|
514
|
+
return this.#set(key, value, options.flags, options.ttl);
|
|
515
|
+
}
|
|
516
|
+
async replace(key, value, options = {}) {
|
|
517
|
+
if (!this.#get(key))
|
|
518
|
+
return;
|
|
519
|
+
return this.#set(key, value, options.flags, options.ttl);
|
|
520
|
+
}
|
|
521
|
+
async append(key, value, options = {}) {
|
|
522
|
+
const entry = this.#get(key);
|
|
523
|
+
if (!entry)
|
|
524
|
+
return false;
|
|
525
|
+
if (options.cas !== void 0 && options.cas !== entry.cas)
|
|
526
|
+
return false;
|
|
527
|
+
entry.value = Buffer.concat([entry.value, value]);
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
async prepend(key, value, options = {}) {
|
|
531
|
+
const entry = this.#get(key);
|
|
532
|
+
if (!entry)
|
|
533
|
+
return false;
|
|
534
|
+
if (options.cas !== void 0 && options.cas !== entry.cas)
|
|
535
|
+
return false;
|
|
536
|
+
entry.value = Buffer.concat([value, entry.value]);
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
async #counter(key, delta, options) {
|
|
540
|
+
const entry = this.#get(key);
|
|
541
|
+
if (!entry) {
|
|
542
|
+
if (options.initial !== void 0) {
|
|
543
|
+
const value = Buffer.from(options.initial.toString());
|
|
544
|
+
this.#set(key, value, void 0, options.ttl);
|
|
545
|
+
return { value: BigInt(options.initial), cas: this.#cas };
|
|
546
|
+
} else {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (options.cas !== void 0 && options.cas !== entry.cas)
|
|
551
|
+
return;
|
|
552
|
+
try {
|
|
553
|
+
const value = BigInt(entry.value.toString("utf-8")) + BigInt(delta);
|
|
554
|
+
this.#set(key, Buffer.from(value.toString()), void 0, options.ttl);
|
|
555
|
+
return { value, cas: this.#cas };
|
|
556
|
+
} catch (error) {
|
|
557
|
+
throw new TypeError(`${error.message} (status=NON_NUMERIC_VALUE, key=${key})`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
increment(key, delta = 1n, options = {}) {
|
|
561
|
+
return this.#counter(key, delta, options);
|
|
562
|
+
}
|
|
563
|
+
decrement(key, delta = 1n, options = {}) {
|
|
564
|
+
return this.#counter(key, -delta, options);
|
|
565
|
+
}
|
|
566
|
+
async delete(key, options = {}) {
|
|
567
|
+
const entry = this.#get(key);
|
|
568
|
+
if (entry && options.cas !== void 0 && entry.cas !== options.cas) {
|
|
569
|
+
return false;
|
|
570
|
+
}
|
|
571
|
+
return this.#cache.delete(key);
|
|
572
|
+
}
|
|
573
|
+
async flush(ttl) {
|
|
574
|
+
if (!ttl)
|
|
575
|
+
return this.#cache.clear();
|
|
576
|
+
const wait = toExp(ttl) - Date.now();
|
|
577
|
+
setTimeout(() => this.#cache.clear(), wait);
|
|
578
|
+
}
|
|
579
|
+
async noop() {
|
|
580
|
+
}
|
|
581
|
+
async quit() {
|
|
582
|
+
}
|
|
583
|
+
async version() {
|
|
584
|
+
return { fake: "0.0.0-fake" };
|
|
585
|
+
}
|
|
586
|
+
async stats() {
|
|
587
|
+
return { fake: { version: "0.0.0-fake" } };
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
441
591
|
// src/server.ts
|
|
442
592
|
var statsBigInt = [
|
|
443
593
|
"auth_cmds",
|
|
@@ -585,10 +735,9 @@ var ServerAdapter = class {
|
|
|
585
735
|
throw new Error(`Key too long (len=${keyLength})`);
|
|
586
736
|
return keyLength;
|
|
587
737
|
}
|
|
588
|
-
async get(key,
|
|
589
|
-
const { ttl } = options;
|
|
738
|
+
async #get(key, ttl) {
|
|
590
739
|
let keyOffset = 0;
|
|
591
|
-
if (ttl)
|
|
740
|
+
if (ttl !== void 0)
|
|
592
741
|
keyOffset = this.#buffer.writeUInt32BE(ttl);
|
|
593
742
|
const keyLength = this.#writeKey(key, keyOffset);
|
|
594
743
|
const [response] = await this.#connection.send({
|
|
@@ -614,9 +763,15 @@ var ServerAdapter = class {
|
|
|
614
763
|
fail(response, key);
|
|
615
764
|
}
|
|
616
765
|
}
|
|
617
|
-
async
|
|
618
|
-
|
|
619
|
-
|
|
766
|
+
async get(key) {
|
|
767
|
+
return this.#get(key);
|
|
768
|
+
}
|
|
769
|
+
async gat(key, ttl) {
|
|
770
|
+
return this.#get(key, ttl || 2592e3);
|
|
771
|
+
}
|
|
772
|
+
async touch(key, ttl) {
|
|
773
|
+
const timeToLive = ttl ?? this.#ttl;
|
|
774
|
+
const keyOffset = this.#buffer.writeUInt32BE(timeToLive);
|
|
620
775
|
const keyLength = this.#writeKey(key, keyOffset);
|
|
621
776
|
const [response] = await this.#connection.send({
|
|
622
777
|
opcode: 28 /* TOUCH */,
|
|
@@ -863,6 +1018,7 @@ var ServerAdapter = class {
|
|
|
863
1018
|
};
|
|
864
1019
|
|
|
865
1020
|
// src/cluster.ts
|
|
1021
|
+
import assert4 from "assert";
|
|
866
1022
|
function parseHosts(hosts) {
|
|
867
1023
|
const result = [];
|
|
868
1024
|
if (!hosts)
|
|
@@ -876,6 +1032,7 @@ function parseHosts(hosts) {
|
|
|
876
1032
|
}
|
|
877
1033
|
var ClusterAdapter = class {
|
|
878
1034
|
servers;
|
|
1035
|
+
ttl;
|
|
879
1036
|
constructor(serversOrOptions) {
|
|
880
1037
|
if (Array.isArray(serversOrOptions)) {
|
|
881
1038
|
this.servers = [...serversOrOptions];
|
|
@@ -903,6 +1060,10 @@ var ClusterAdapter = class {
|
|
|
903
1060
|
throw new Error("No hosts configured");
|
|
904
1061
|
if (this.servers.length === 1)
|
|
905
1062
|
this.server = () => this.servers[0];
|
|
1063
|
+
this.ttl = this.servers[0].ttl;
|
|
1064
|
+
this.servers.slice(1).forEach((server) => {
|
|
1065
|
+
assert4.equal(server.ttl, this.ttl, `TTL Mismatch (${server.ttl} != ${this.ttl})`);
|
|
1066
|
+
});
|
|
906
1067
|
Object.freeze(this.servers);
|
|
907
1068
|
}
|
|
908
1069
|
server(key) {
|
|
@@ -912,11 +1073,14 @@ var ClusterAdapter = class {
|
|
|
912
1073
|
hash = hash * 31 + key.charCodeAt(i);
|
|
913
1074
|
return this.servers[hash % this.servers.length];
|
|
914
1075
|
}
|
|
915
|
-
get(key
|
|
916
|
-
return this.server(key).get(key
|
|
1076
|
+
get(key) {
|
|
1077
|
+
return this.server(key).get(key);
|
|
917
1078
|
}
|
|
918
|
-
|
|
919
|
-
return this.server(key).
|
|
1079
|
+
gat(key, ttl) {
|
|
1080
|
+
return this.server(key).gat(key, ttl);
|
|
1081
|
+
}
|
|
1082
|
+
touch(key, ttl) {
|
|
1083
|
+
return this.server(key).touch(key, ttl);
|
|
920
1084
|
}
|
|
921
1085
|
set(key, value, options) {
|
|
922
1086
|
return this.server(key).set(key, value, options);
|
|
@@ -962,8 +1126,34 @@ var ClusterAdapter = class {
|
|
|
962
1126
|
};
|
|
963
1127
|
|
|
964
1128
|
// src/client.ts
|
|
965
|
-
import
|
|
1129
|
+
import assert5 from "assert";
|
|
966
1130
|
import { isTypedArray } from "util/types";
|
|
1131
|
+
function replacer(key, value) {
|
|
1132
|
+
if (typeof this[key] === "bigint")
|
|
1133
|
+
return ["\0__$BIGINT$__\0", this[key].toString()];
|
|
1134
|
+
if (this[key] instanceof Date)
|
|
1135
|
+
return ["\0__$DATE$__\0", this[key].toISOString()];
|
|
1136
|
+
if (this[key] instanceof Set)
|
|
1137
|
+
return ["\0__$SET$__\0", ...value];
|
|
1138
|
+
if (this[key] instanceof Map)
|
|
1139
|
+
return ["\0__$MAP$__\0", ...value.entries()];
|
|
1140
|
+
return value;
|
|
1141
|
+
}
|
|
1142
|
+
function reviver(key, value) {
|
|
1143
|
+
if (Array.isArray(value)) {
|
|
1144
|
+
switch (value[0]) {
|
|
1145
|
+
case "\0__$BIGINT$__\0":
|
|
1146
|
+
return BigInt(value[1]);
|
|
1147
|
+
case "\0__$DATE$__\0":
|
|
1148
|
+
return new Date(value[1]);
|
|
1149
|
+
case "\0__$SET$__\0":
|
|
1150
|
+
return new Set(value.slice(1));
|
|
1151
|
+
case "\0__$MAP$__\0":
|
|
1152
|
+
return new Map(value.slice(1));
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return value;
|
|
1156
|
+
}
|
|
967
1157
|
function toBuffer(value, options) {
|
|
968
1158
|
if (Buffer.isBuffer(value))
|
|
969
1159
|
return [value, __spreadProps(__spreadValues({}, options), { flags: 0 /* BUFFER */ })];
|
|
@@ -979,7 +1169,7 @@ function toBuffer(value, options) {
|
|
|
979
1169
|
case "object":
|
|
980
1170
|
break;
|
|
981
1171
|
default:
|
|
982
|
-
|
|
1172
|
+
assert5.fail(`Unable to store value of type "${typeof value}"`);
|
|
983
1173
|
}
|
|
984
1174
|
if (isTypedArray(value)) {
|
|
985
1175
|
const flags = typedArrayFlags(value);
|
|
@@ -988,15 +1178,63 @@ function toBuffer(value, options) {
|
|
|
988
1178
|
}
|
|
989
1179
|
if (value === null)
|
|
990
1180
|
return [EMPTY_BUFFER, __spreadProps(__spreadValues({}, options), { flags: 3402235918 /* NULL */ })];
|
|
991
|
-
|
|
1181
|
+
const json = JSON.stringify(value, replacer);
|
|
1182
|
+
return [Buffer.from(json, "utf-8"), __spreadProps(__spreadValues({}, options), { flags: 3402235919 /* JSON */ })];
|
|
1183
|
+
}
|
|
1184
|
+
function fromBuffer(result) {
|
|
1185
|
+
try {
|
|
1186
|
+
const { flags, value, cas } = result;
|
|
1187
|
+
switch (flags) {
|
|
1188
|
+
case 3402235904 /* BIGINT */:
|
|
1189
|
+
return { value: BigInt(value.toString("utf-8")), cas };
|
|
1190
|
+
case 3402235905 /* BOOLEAN */:
|
|
1191
|
+
return { value: !!value[0], cas };
|
|
1192
|
+
case 3402235906 /* NUMBER */:
|
|
1193
|
+
return { value: Number(value.toString("utf-8")), cas };
|
|
1194
|
+
case 3402235907 /* STRING */:
|
|
1195
|
+
return { value: value.toString("utf-8"), cas };
|
|
1196
|
+
case 3402235918 /* NULL */:
|
|
1197
|
+
return { value: null, cas };
|
|
1198
|
+
case 3402235919 /* JSON */:
|
|
1199
|
+
return { value: JSON.parse(value.toString("utf-8"), reviver), cas };
|
|
1200
|
+
case 3402235920 /* UINT8ARRAY */:
|
|
1201
|
+
return { value: makeTypedArray(Uint8Array, value), cas };
|
|
1202
|
+
case 3402235921 /* UINT8CLAMPEDARRAY */:
|
|
1203
|
+
return { value: makeTypedArray(Uint8ClampedArray, value), cas };
|
|
1204
|
+
case 3402235922 /* UINT16ARRAY */:
|
|
1205
|
+
return { value: makeTypedArray(Uint16Array, value), cas };
|
|
1206
|
+
case 3402235923 /* UINT32ARRAY */:
|
|
1207
|
+
return { value: makeTypedArray(Uint32Array, value), cas };
|
|
1208
|
+
case 3402235924 /* INT8ARRAY */:
|
|
1209
|
+
return { value: makeTypedArray(Int8Array, value), cas };
|
|
1210
|
+
case 3402235925 /* INT16ARRAY */:
|
|
1211
|
+
return { value: makeTypedArray(Int16Array, value), cas };
|
|
1212
|
+
case 3402235926 /* INT32ARRAY */:
|
|
1213
|
+
return { value: makeTypedArray(Int32Array, value), cas };
|
|
1214
|
+
case 3402235927 /* BIGUINT64ARRAY */:
|
|
1215
|
+
return { value: makeTypedArray(BigUint64Array, value), cas };
|
|
1216
|
+
case 3402235928 /* BIGINT64ARRAY */:
|
|
1217
|
+
return { value: makeTypedArray(BigInt64Array, value), cas };
|
|
1218
|
+
case 3402235929 /* FLOAT32ARRAY */:
|
|
1219
|
+
return { value: makeTypedArray(Float32Array, value), cas };
|
|
1220
|
+
case 3402235930 /* FLOAT64ARRAY */:
|
|
1221
|
+
return { value: makeTypedArray(Float64Array, value), cas };
|
|
1222
|
+
case 0 /* BUFFER */:
|
|
1223
|
+
default:
|
|
1224
|
+
return { value: Buffer.from(value), cas };
|
|
1225
|
+
}
|
|
1226
|
+
} finally {
|
|
1227
|
+
result.recycle();
|
|
1228
|
+
}
|
|
992
1229
|
}
|
|
993
|
-
function makeTypedArray(constructor, source
|
|
1230
|
+
function makeTypedArray(constructor, source) {
|
|
994
1231
|
const clone = Buffer.from(source);
|
|
995
1232
|
const { buffer, byteOffset, byteLength } = clone;
|
|
996
|
-
return new constructor(buffer, byteOffset, byteLength /
|
|
1233
|
+
return new constructor(buffer, byteOffset, byteLength / constructor.BYTES_PER_ELEMENT);
|
|
997
1234
|
}
|
|
998
1235
|
var Client = class {
|
|
999
1236
|
#adapter;
|
|
1237
|
+
#prefix;
|
|
1000
1238
|
constructor(adapterOrOptions) {
|
|
1001
1239
|
if (!adapterOrOptions) {
|
|
1002
1240
|
this.#adapter = new ClusterAdapter();
|
|
@@ -1005,96 +1243,73 @@ var Client = class {
|
|
|
1005
1243
|
} else if ("hosts" in adapterOrOptions) {
|
|
1006
1244
|
this.#adapter = new ClusterAdapter(adapterOrOptions);
|
|
1007
1245
|
}
|
|
1008
|
-
|
|
1246
|
+
this.#prefix = "";
|
|
1247
|
+
assert5(this.#adapter, "Invalid client constructor arguments");
|
|
1009
1248
|
}
|
|
1010
1249
|
get adapter() {
|
|
1011
1250
|
return this.#adapter;
|
|
1012
1251
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
return { value: makeTypedArray(Uint16Array, value, 2), cas };
|
|
1038
|
-
case 3402235923 /* UINT32ARRAY */:
|
|
1039
|
-
return { value: makeTypedArray(Uint32Array, value, 4), cas };
|
|
1040
|
-
case 3402235924 /* INT8ARRAY */:
|
|
1041
|
-
return { value: makeTypedArray(Int8Array, value, 1), cas };
|
|
1042
|
-
case 3402235925 /* INT16ARRAY */:
|
|
1043
|
-
return { value: makeTypedArray(Int16Array, value, 2), cas };
|
|
1044
|
-
case 3402235926 /* INT32ARRAY */:
|
|
1045
|
-
return { value: makeTypedArray(Int32Array, value, 4), cas };
|
|
1046
|
-
case 3402235927 /* BIGUINT64ARRAY */:
|
|
1047
|
-
return { value: makeTypedArray(BigUint64Array, value, 8), cas };
|
|
1048
|
-
case 3402235928 /* BIGINT64ARRAY */:
|
|
1049
|
-
return { value: makeTypedArray(BigInt64Array, value, 8), cas };
|
|
1050
|
-
case 3402235929 /* FLOAT32ARRAY */:
|
|
1051
|
-
return { value: makeTypedArray(Float32Array, value, 4), cas };
|
|
1052
|
-
case 3402235930 /* FLOAT64ARRAY */:
|
|
1053
|
-
return { value: makeTypedArray(Float64Array, value, 8), cas };
|
|
1054
|
-
case 0 /* BUFFER */:
|
|
1055
|
-
default:
|
|
1056
|
-
return { value: Buffer.from(value), cas };
|
|
1057
|
-
}
|
|
1058
|
-
} finally {
|
|
1059
|
-
result.recycle();
|
|
1060
|
-
}
|
|
1252
|
+
get prefix() {
|
|
1253
|
+
return this.#prefix;
|
|
1254
|
+
}
|
|
1255
|
+
withPrefix(prefix) {
|
|
1256
|
+
assert5(prefix, "Invalid prefix");
|
|
1257
|
+
const client = new Client(this.#adapter);
|
|
1258
|
+
client.#prefix = prefix;
|
|
1259
|
+
return client;
|
|
1260
|
+
}
|
|
1261
|
+
async get(key) {
|
|
1262
|
+
const result = await this.#adapter.get(this.#prefix + key);
|
|
1263
|
+
return result && fromBuffer(result).value;
|
|
1264
|
+
}
|
|
1265
|
+
async gat(key, ttl) {
|
|
1266
|
+
const result = await this.#adapter.gat(this.#prefix + key, ttl);
|
|
1267
|
+
return result && fromBuffer(result).value;
|
|
1268
|
+
}
|
|
1269
|
+
async getc(key) {
|
|
1270
|
+
const result = await this.#adapter.get(this.#prefix + key);
|
|
1271
|
+
return result && fromBuffer(result);
|
|
1272
|
+
}
|
|
1273
|
+
async gatc(key, ttl) {
|
|
1274
|
+
const result = await this.#adapter.gat(this.#prefix + key, ttl);
|
|
1275
|
+
return result && fromBuffer(result);
|
|
1061
1276
|
}
|
|
1062
1277
|
async set(key, value, options) {
|
|
1063
|
-
return this.#adapter.set(key, ...toBuffer(value, options));
|
|
1278
|
+
return this.#adapter.set(this.#prefix + key, ...toBuffer(value, options));
|
|
1064
1279
|
}
|
|
1065
1280
|
async add(key, value, options) {
|
|
1066
|
-
return this.#adapter.add(key, ...toBuffer(value, options));
|
|
1281
|
+
return this.#adapter.add(this.#prefix + key, ...toBuffer(value, options));
|
|
1067
1282
|
}
|
|
1068
1283
|
async replace(key, value, options) {
|
|
1069
|
-
return this.#adapter.replace(key, ...toBuffer(value, options));
|
|
1284
|
+
return this.#adapter.replace(this.#prefix + key, ...toBuffer(value, options));
|
|
1070
1285
|
}
|
|
1071
1286
|
append(key, value, options) {
|
|
1072
|
-
return this.#adapter.append(key, ...toBuffer(value, options));
|
|
1287
|
+
return this.#adapter.append(this.#prefix + key, ...toBuffer(value, options));
|
|
1073
1288
|
}
|
|
1074
1289
|
prepend(key, value, options) {
|
|
1075
|
-
return this.#adapter.prepend(key, ...toBuffer(value, options));
|
|
1290
|
+
return this.#adapter.prepend(this.#prefix + key, ...toBuffer(value, options));
|
|
1076
1291
|
}
|
|
1077
1292
|
async increment(key, delta, options) {
|
|
1078
|
-
const counter = await this.#adapter.increment(key, delta, options);
|
|
1079
|
-
if (
|
|
1293
|
+
const counter = await this.#adapter.increment(this.#prefix + key, delta, options);
|
|
1294
|
+
if ((options == null ? void 0 : options.initial) !== void 0 && (counter == null ? void 0 : counter.value) === BigInt(options.initial)) {
|
|
1080
1295
|
const cas = await this.replace(key, counter.value, { cas: counter.cas, ttl: options.ttl });
|
|
1081
1296
|
counter.cas = cas ?? counter.cas;
|
|
1082
1297
|
}
|
|
1083
1298
|
return counter;
|
|
1084
1299
|
}
|
|
1085
1300
|
async decrement(key, delta, options) {
|
|
1086
|
-
const counter = await this.#adapter.decrement(key, delta, options);
|
|
1087
|
-
if (
|
|
1301
|
+
const counter = await this.#adapter.decrement(this.#prefix + key, delta, options);
|
|
1302
|
+
if ((options == null ? void 0 : options.initial) !== void 0 && (counter == null ? void 0 : counter.value) === BigInt(options.initial)) {
|
|
1088
1303
|
const cas = await this.replace(key, counter.value, { cas: counter.cas, ttl: options.ttl });
|
|
1089
1304
|
counter.cas = cas ?? counter.cas;
|
|
1090
1305
|
}
|
|
1091
1306
|
return counter;
|
|
1092
1307
|
}
|
|
1093
|
-
touch(key,
|
|
1094
|
-
return this.#adapter.touch(key,
|
|
1308
|
+
touch(key, ttl) {
|
|
1309
|
+
return this.#adapter.touch(this.#prefix + key, ttl);
|
|
1095
1310
|
}
|
|
1096
1311
|
delete(key, options) {
|
|
1097
|
-
return this.#adapter.delete(key, options);
|
|
1312
|
+
return this.#adapter.delete(this.#prefix + key, options);
|
|
1098
1313
|
}
|
|
1099
1314
|
flush(ttl) {
|
|
1100
1315
|
return this.#adapter.flush(ttl);
|
|
@@ -1112,9 +1327,139 @@ var Client = class {
|
|
|
1112
1327
|
return this.#adapter.stats();
|
|
1113
1328
|
}
|
|
1114
1329
|
};
|
|
1330
|
+
|
|
1331
|
+
// src/utils.ts
|
|
1332
|
+
import assert6 from "assert";
|
|
1333
|
+
var Factory = class {
|
|
1334
|
+
#factory;
|
|
1335
|
+
#client;
|
|
1336
|
+
#ttl;
|
|
1337
|
+
constructor(client, factory, ttl) {
|
|
1338
|
+
assert6(typeof factory === "function", "Invalid or no factory specified");
|
|
1339
|
+
assert6(client, "No client specified");
|
|
1340
|
+
this.#factory = factory;
|
|
1341
|
+
this.#client = client;
|
|
1342
|
+
this.#ttl = ttl;
|
|
1343
|
+
}
|
|
1344
|
+
async get(key) {
|
|
1345
|
+
const cached = await this.#client.getc(key);
|
|
1346
|
+
if (cached) {
|
|
1347
|
+
void logPromiseError(this.#client.touch(key), `Factory error touching key "${this.#client.prefix}${key}"`);
|
|
1348
|
+
return cached.value;
|
|
1349
|
+
}
|
|
1350
|
+
const created = await this.#factory(key);
|
|
1351
|
+
if (created) {
|
|
1352
|
+
void logPromiseError(this.#client.set(key, created, { ttl: this.#ttl }), `Factory error setting key "${this.#client.prefix}${key}"`);
|
|
1353
|
+
}
|
|
1354
|
+
return created;
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
var Bundle = class {
|
|
1358
|
+
#client;
|
|
1359
|
+
#name;
|
|
1360
|
+
#ttl;
|
|
1361
|
+
constructor(client, name, ttl) {
|
|
1362
|
+
assert6(client, "No client specified");
|
|
1363
|
+
assert6(name, "No bundle name specified");
|
|
1364
|
+
this.#client = client;
|
|
1365
|
+
this.#name = name;
|
|
1366
|
+
this.#ttl = ttl || 0;
|
|
1367
|
+
}
|
|
1368
|
+
async #appendKey(key) {
|
|
1369
|
+
await logPromiseError((async () => {
|
|
1370
|
+
const added = await this.#client.add(this.#name, key, { ttl: this.#ttl });
|
|
1371
|
+
if (!added) {
|
|
1372
|
+
await this.#client.append(this.#name, `\0${key}`);
|
|
1373
|
+
await this.#client.touch(this.#name, this.#ttl);
|
|
1374
|
+
}
|
|
1375
|
+
})(), `Bundle "${this.#client.prefix}${this.#name}" error recording key "${key}"`);
|
|
1376
|
+
}
|
|
1377
|
+
async #removeKey(key) {
|
|
1378
|
+
await logPromiseError((async () => {
|
|
1379
|
+
const result = await this.#client.getc(this.#name);
|
|
1380
|
+
if (!result)
|
|
1381
|
+
return;
|
|
1382
|
+
const keys = result.value.split("\0").filter((k) => k !== key).join("\0");
|
|
1383
|
+
await this.#client.set(this.#name, keys, { cas: result.cas, ttl: this.#ttl });
|
|
1384
|
+
})(), `Bundle "${this.#client.prefix}${this.#name}" error clearing key "${key}"`);
|
|
1385
|
+
}
|
|
1386
|
+
async add(key, value) {
|
|
1387
|
+
await this.#client.set(`${this.#name}:${key}`, value, { ttl: this.#ttl });
|
|
1388
|
+
await this.#appendKey(key);
|
|
1389
|
+
}
|
|
1390
|
+
async get(key) {
|
|
1391
|
+
const result = await this.#client.getc(`${this.#name}:${key}`);
|
|
1392
|
+
if (result)
|
|
1393
|
+
return result.value;
|
|
1394
|
+
await this.#removeKey(key);
|
|
1395
|
+
}
|
|
1396
|
+
async delete(key) {
|
|
1397
|
+
await this.#client.delete(`${this.#name}:${key}`);
|
|
1398
|
+
await this.#removeKey(key);
|
|
1399
|
+
}
|
|
1400
|
+
async list() {
|
|
1401
|
+
const result = await this.#client.getc(this.#name);
|
|
1402
|
+
if (!result)
|
|
1403
|
+
return {};
|
|
1404
|
+
const results = {};
|
|
1405
|
+
const promises = [];
|
|
1406
|
+
for (const key of new Set(result.value.split("\0"))) {
|
|
1407
|
+
promises.push(this.#client.getc(`${this.#name}:${key}`).then((result2) => {
|
|
1408
|
+
if (result2)
|
|
1409
|
+
results[key] = result2.value;
|
|
1410
|
+
}));
|
|
1411
|
+
}
|
|
1412
|
+
await Promise.all(promises);
|
|
1413
|
+
await logPromiseError(this.#client.set(this.#name, Object.keys(results).join("\0"), { cas: result.cas, ttl: this.#ttl }), `Bundle "${this.#client.prefix}${this.#name}" error compacting keys`);
|
|
1414
|
+
return results;
|
|
1415
|
+
}
|
|
1416
|
+
};
|
|
1417
|
+
var PoorManLock = class {
|
|
1418
|
+
#client;
|
|
1419
|
+
#name;
|
|
1420
|
+
constructor(client, name) {
|
|
1421
|
+
assert6(client, "No client specified");
|
|
1422
|
+
assert6(name, "No lock name specified");
|
|
1423
|
+
this.#client = client;
|
|
1424
|
+
this.#name = name;
|
|
1425
|
+
}
|
|
1426
|
+
async execute(executor, options) {
|
|
1427
|
+
const { timeout = 5e3, owner = false } = options || {};
|
|
1428
|
+
const end = Date.now() + timeout;
|
|
1429
|
+
let cas;
|
|
1430
|
+
do {
|
|
1431
|
+
cas = await this.#client.add(this.#name, owner, { ttl: 2 });
|
|
1432
|
+
if (cas !== void 0)
|
|
1433
|
+
break;
|
|
1434
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1435
|
+
} while (Date.now() < end);
|
|
1436
|
+
if (cas === void 0) {
|
|
1437
|
+
const other = await this.#client.getc(this.#name);
|
|
1438
|
+
const owner2 = other && other.value ? `"${other.value}"` : "anonymous";
|
|
1439
|
+
throw new Error(`Lock "${this.#client.prefix}${this.#name}" timeout (owner=${owner2})`);
|
|
1440
|
+
}
|
|
1441
|
+
const interval = setInterval(() => {
|
|
1442
|
+
void logPromiseError((async () => {
|
|
1443
|
+
const replaced = await this.#client.replace(this.#name, owner, { ttl: 2, cas });
|
|
1444
|
+
assert6(replaced !== void 0, `Lock "${this.#client.prefix}${this.#name}" not replaced`);
|
|
1445
|
+
cas = replaced;
|
|
1446
|
+
})(), `Error extending lock "${this.#client.prefix}${this.#name}"`);
|
|
1447
|
+
}, 100);
|
|
1448
|
+
try {
|
|
1449
|
+
return await executor();
|
|
1450
|
+
} finally {
|
|
1451
|
+
clearInterval(interval);
|
|
1452
|
+
await logPromiseError(this.#client.delete(this.#name, { cas }), `Error deleting lock "${this.#client.prefix}${this.#name}"`);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1115
1456
|
export {
|
|
1457
|
+
Bundle,
|
|
1116
1458
|
Client,
|
|
1117
1459
|
ClusterAdapter,
|
|
1460
|
+
Factory,
|
|
1461
|
+
FakeAdapter,
|
|
1462
|
+
PoorManLock,
|
|
1118
1463
|
ServerAdapter,
|
|
1119
1464
|
connection_exports as connection,
|
|
1120
1465
|
constants_exports as constants,
|