lakutata
Version:
An IoC-based universal application framework.
653 lines (641 loc) • 19 kB
JavaScript
import { createClient as t, createCluster as e } from "@redis/client";
export { createClient, createCluster } from "@redis/client";
import { K as s } from "./Package.65.mjs";
import r from "cluster-key-slot";
import "buffer";
var i = class {
_eventListeners;
_maxListeners;
_logger;
constructor(t) {
this._eventListeners = new Map, this._maxListeners = 100, this._logger = t?.logger;
}
once(t, e) {
let s = (...r) => {
this.off(t, s), e(...r);
};
return this.on(t, s), this;
}
listenerCount(t) {
if (!t) return this.getAllListeners().length;
let e = this._eventListeners.get(t);
return e ? e.length : 0;
}
eventNames() {
return [ ...this._eventListeners.keys() ];
}
rawListeners(t) {
return t ? this._eventListeners.get(t) ?? [] : this.getAllListeners();
}
prependListener(t, e) {
let s = this._eventListeners.get(t) ?? [];
return s.unshift(e), this._eventListeners.set(t, s), this;
}
prependOnceListener(t, e) {
let s = (...r) => {
this.off(t, s), e(...r);
};
return this.prependListener(t, s), this;
}
maxListeners() {
return this._maxListeners;
}
addListener(t, e) {
return this.on(t, e), this;
}
on(t, e) {
this._eventListeners.has(t) || this._eventListeners.set(t, []);
let s = this._eventListeners.get(t);
return s && (s.length >= this._maxListeners && console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${s.length + 1} ${t} listeners added. Use setMaxListeners() to increase limit.`),
s.push(e)), this;
}
removeListener(t, e) {
return this.off(t, e), this;
}
off(t, e) {
let s = this._eventListeners.get(t) ?? [], r = s.indexOf(e);
return r !== -1 && s.splice(r, 1), s.length === 0 && this._eventListeners.delete(t),
this;
}
emit(t, ...e) {
let s = !1, r = this._eventListeners.get(t);
if (r && r.length > 0) for (let t of r) t(...e), s = !0;
return s;
}
listeners(t) {
return this._eventListeners.get(t) ?? [];
}
removeAllListeners(t) {
return t ? this._eventListeners.delete(t) : this._eventListeners.clear(), this;
}
setMaxListeners(t) {
this._maxListeners = t;
for (let e of this._eventListeners.values()) e.length > t && e.splice(t);
}
getAllListeners() {
let t = new Array;
for (let e of this._eventListeners.values()) t = [ ...t, ...e ];
return t;
}
};
var n = class extends i {
_hooks;
_throwHookErrors=!1;
constructor(t) {
super({
logger: t?.logger
}), this._hooks = new Map, t?.throwHookErrors !== void 0 && (this._throwHookErrors = t.throwHookErrors);
}
get hooks() {
return this._hooks;
}
get throwHookErrors() {
return this._throwHookErrors;
}
set throwHookErrors(t) {
this._throwHookErrors = t;
}
get logger() {
return this._logger;
}
set logger(t) {
this._logger = t;
}
onHook(t, e) {
let s = this._hooks.get(t);
s ? s.push(e) : this._hooks.set(t, [ e ]);
}
addHook(t, e) {
this.onHook(t, e);
}
onHooks(t) {
for (let e of t) this.onHook(e.event, e.handler);
}
prependHook(t, e) {
let s = this._hooks.get(t);
s ? s.unshift(e) : this._hooks.set(t, [ e ]);
}
prependOnceHook(t, e) {
let s = async (...r) => (this.removeHook(t, s), e(...r));
this.prependHook(t, s);
}
onceHook(t, e) {
let s = async (...r) => (this.removeHook(t, s), e(...r));
this.onHook(t, s);
}
removeHook(t, e) {
let s = this._hooks.get(t);
if (s) {
let t = s.indexOf(e);
t !== -1 && s.splice(t, 1);
}
}
removeHooks(t) {
for (let e of t) this.removeHook(e.event, e.handler);
}
async hook(t, ...e) {
let s = this._hooks.get(t);
if (s) for (let r of s) try {
await r(...e);
} catch (e) {
let s = `${t}: ${e.message}`;
if (this.emit("error", new Error(s)), this._logger && this._logger.error(s), this._throwHookErrors) throw new Error(s);
}
}
async callHook(t, ...e) {
await this.hook(t, ...e);
}
getHooks(t) {
return this._hooks.get(t);
}
clearHooks() {
this._hooks.clear();
}
};
var o = (t => {
t["RedisClientNotConnectedThrown"] = "Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true.";
return t;
})(o || {});
var a = t => {
const e = Math.min(2 ** t * 100, 2e3);
const s = (Math.random() - .5) * 100;
return e + s;
};
var c = class extends n {
_client=t();
_namespace;
_keyPrefixSeparator="::";
_clearBatchSize=1e3;
_useUnlink=true;
_noNamespaceAffectsAll=false;
_throwOnConnectError=true;
_throwErrors=false;
_connectionTimeout;
constructor(s, r) {
super();
const i = {
reconnectStrategy: a
};
if (s) {
if (typeof s === "string") {
this._client = t({
url: s,
socket: i
});
} else if (s.connect !== void 0) {
this._client = this.isClientCluster(s) ? s : s;
} else if (s instanceof Object) {
this._client = s.rootNodes === void 0 ? t(s) : e(s);
}
}
this.setOptions(r);
this.initClient();
}
get client() {
return this._client;
}
set client(t) {
this._client = t;
this.initClient();
}
get opts() {
let t = "redis://localhost:6379";
if (this._client.options) {
const e = this._client.options?.url;
if (e) {
t = e;
}
}
const e = {
namespace: this._namespace,
keyPrefixSeparator: this._keyPrefixSeparator,
clearBatchSize: this._clearBatchSize,
noNamespaceAffectsAll: this._noNamespaceAffectsAll,
useUnlink: this._useUnlink,
throwOnConnectError: this._throwOnConnectError,
throwErrors: this._throwErrors,
connectionTimeout: this._connectionTimeout,
dialect: "redis",
url: t
};
return e;
}
set opts(t) {
this.setOptions(t);
}
get namespace() {
return this._namespace;
}
set namespace(t) {
this._namespace = t;
}
get keyPrefixSeparator() {
return this._keyPrefixSeparator;
}
set keyPrefixSeparator(t) {
this._keyPrefixSeparator = t;
}
get clearBatchSize() {
return this._clearBatchSize;
}
set clearBatchSize(t) {
if (t > 0) {
this._clearBatchSize = t;
} else {
this.emit("error", "clearBatchSize must be greater than 0");
}
}
get useUnlink() {
return this._useUnlink;
}
set useUnlink(t) {
this._useUnlink = t;
}
get noNamespaceAffectsAll() {
return this._noNamespaceAffectsAll;
}
set noNamespaceAffectsAll(t) {
this._noNamespaceAffectsAll = t;
}
get throwOnConnectError() {
return this._throwOnConnectError;
}
set throwOnConnectError(t) {
this._throwOnConnectError = t;
}
get throwErrors() {
return this._throwErrors;
}
set throwErrors(t) {
this._throwErrors = t;
}
get connectionTimeout() {
return this._connectionTimeout;
}
set connectionTimeout(t) {
this._connectionTimeout = t;
}
async getClient() {
if (this._client.isOpen) {
return this._client;
}
try {
if (this._connectionTimeout === void 0) {
await this._client.connect();
} else {
await Promise.race([ this._client.connect(), this.createTimeoutPromise(this._connectionTimeout) ]);
}
} catch (t) {
this.emit("error", t);
if (this._throwOnConnectError) {
throw new Error("Redis client is not connected or has failed to connect. This is thrown because throwOnConnectError is set to true.");
}
await this.disconnect(true);
}
this.initClient();
return this._client;
}
async set(t, e, s) {
const r = await this.getClient();
try {
t = this.createKeyPrefix(t, this._namespace);
if (s) {
await r.set(t, e, {
PX: s
});
} else {
await r.set(t, e);
}
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
}
}
async setMany(t) {
const e = await this.getClient();
try {
const s = e.multi();
for (const {key: e, value: r, ttl: i} of t) {
const t = this.createKeyPrefix(e, this._namespace);
if (i) {
s.set(t, r, {
PX: i
});
} else {
s.set(t, r);
}
}
await s.exec();
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
}
}
async has(t) {
const e = await this.getClient();
try {
t = this.createKeyPrefix(t, this._namespace);
const s = await e.exists(t);
return s === 1;
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
return false;
}
}
async hasMany(t) {
const e = await this.getClient();
try {
const s = e.multi();
for (const e of t) {
const t = this.createKeyPrefix(e, this._namespace);
s.exists(t);
}
const r = await s.exec();
return r.map((t => t === 1));
} catch (e) {
this.emit("error", e);
if (this._throwErrors) {
throw e;
}
return Array.from({
length: t.length
}).fill(false);
}
}
async get(t) {
const e = await this.getClient();
try {
t = this.createKeyPrefix(t, this._namespace);
const s = await e.get(t);
if (s === null) {
return void 0;
}
return s;
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
return void 0;
}
}
async getMany(t) {
if (t.length === 0) {
return [];
}
t = t.map((t => this.createKeyPrefix(t, this._namespace)));
try {
const e = await this.mget(t);
return e;
} catch (e) {
this.emit("error", e);
if (this._throwErrors) {
throw e;
}
return Array.from({
length: t.length
}).fill(void 0);
}
}
async delete(t) {
const e = await this.getClient();
try {
t = this.createKeyPrefix(t, this._namespace);
let s = 0;
s = await (this._useUnlink ? e.unlink(t) : e.del(t));
return s > 0;
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
return false;
}
}
async deleteMany(t) {
let e = false;
const s = await this.getClient();
try {
const r = s.multi();
for (const e of t) {
const t = this.createKeyPrefix(e, this._namespace);
if (this._useUnlink) {
r.unlink(t);
} else {
r.del(t);
}
}
const i = await r.exec();
for (const t of i) {
if (typeof t === "number" && t > 0) {
e = true;
}
}
} catch (t) {
this.emit("error", t);
if (this._throwErrors) {
throw t;
}
}
return e;
}
async disconnect(t) {
if (this._client.isOpen) {
await (t ? this._client.disconnect() : this._client.quit());
}
}
createKeyPrefix(t, e) {
if (e) {
return `${e}${this._keyPrefixSeparator}${t}`;
}
return t;
}
getKeyWithoutPrefix(t, e) {
if (e) {
return t.replace(`${e}${this._keyPrefixSeparator}`, "");
}
return t;
}
isCluster() {
return this.isClientCluster(this._client);
}
async getMasterNodes() {
if (this.isCluster()) {
const t = await this.getClient();
return Promise.all(t.masters.map((async e => t.nodeClient(e))));
}
return [ await this.getClient() ];
}
async* iterator(t) {
const e = await this.getMasterNodes();
for (const s of e) {
const e = t ? `${t}${this._keyPrefixSeparator}*` : "*";
let r = "0";
do {
const i = await s.scan(Number.parseInt(r, 10), {
MATCH: e,
TYPE: "string"
});
r = i.cursor.toString();
let {keys: n} = i;
if (!t && !this._noNamespaceAffectsAll) {
n = n.filter((t => !t.includes(this._keyPrefixSeparator)));
}
if (n.length > 0) {
const e = await this.mget(n);
for (const s of n.keys()) {
const r = this.getKeyWithoutPrefix(n[s], t);
const i = e[s];
yield [ r, i ];
}
}
} while (r !== "0");
}
}
async clear() {
try {
const t = await this.getMasterNodes();
await Promise.all(t.map((async t => {
if (!this._namespace && this._noNamespaceAffectsAll) {
await t.flushDb();
return;
}
let e = "0";
const s = this._clearBatchSize;
const r = this._namespace ? `${this._namespace}${this._keyPrefixSeparator}*` : "*";
const i = [];
do {
const n = await t.scan(Number.parseInt(e, 10), {
MATCH: r,
COUNT: s,
TYPE: "string"
});
e = n.cursor.toString();
let {keys: o} = n;
if (o.length === 0) {
continue;
}
if (!this._namespace) {
o = o.filter((t => !t.includes(this._keyPrefixSeparator)));
}
i.push(this.clearWithClusterSupport(o));
} while (e !== "0");
await Promise.all(i);
})));
} catch (t) {
this.emit("error", t);
}
}
async mget(t) {
const e = this.getSlotMap(t);
const s = new Map;
await Promise.all(Array.from(e.entries(), (async ([t, e]) => {
const r = await this.getSlotMaster(t);
const i = await r.mGet(e);
for (const [t, r] of i.entries()) {
s.set(e[t], r ?? void 0);
}
})));
return t.map((t => s.get(t)));
}
async clearWithClusterSupport(t) {
if (t.length > 0) {
const e = this.getSlotMap(t);
await Promise.all(Array.from(e.entries(), (async ([t, e]) => {
const s = await this.getSlotMaster(t);
return this._useUnlink ? s.unlink(e) : s.del(e);
})));
}
}
async getSlotMaster(t) {
const e = await this.getClient();
if (this.isCluster()) {
const s = e;
const r = s.slots[t].master;
return s.nodeClient(r);
}
return e;
}
getSlotMap(t) {
const e = new Map;
if (this.isCluster()) {
for (const s of t) {
const t = r(s);
const i = e.get(t) ?? [];
i.push(s);
e.set(t, i);
}
} else {
e.set(0, t);
}
return e;
}
isClientCluster(t) {
if (t.options === void 0 && t.scan === void 0) {
return true;
}
return false;
}
setOptions(t) {
if (!t) {
return;
}
if (t.namespace) {
this._namespace = t.namespace;
}
if (t.keyPrefixSeparator !== void 0) {
this._keyPrefixSeparator = t.keyPrefixSeparator;
}
if (t.clearBatchSize !== void 0 && t.clearBatchSize > 0) {
this._clearBatchSize = t.clearBatchSize;
}
if (t.useUnlink !== void 0) {
this._useUnlink = t.useUnlink;
}
if (t.noNamespaceAffectsAll !== void 0) {
this._noNamespaceAffectsAll = t.noNamespaceAffectsAll;
}
if (t.throwOnConnectError !== void 0) {
this._throwOnConnectError = t.throwOnConnectError;
}
if (t.throwErrors !== void 0) {
this._throwErrors = t.throwErrors;
}
if (t.connectionTimeout !== void 0) {
this._connectionTimeout = t.connectionTimeout;
}
}
initClient() {
this._client.on("connect", (() => {
this.emit("connect", this._client);
}));
this._client.on("disconnect", (() => {
this.emit("disconnect", this._client);
}));
this._client.on("reconnecting", (t => {
this.emit("reconnecting", t);
}));
}
async createTimeoutPromise(t) {
return new Promise(((e, s) => setTimeout((() => {
s(new Error(`Redis timed out after ${t}ms`));
}), t)));
}
};
function h(t, e) {
t ??= "redis://localhost:6379";
const r = new c(t, e);
const i = new s(r, {
namespace: e?.namespace,
useKeyPrefix: false
});
return i;
}
export { s as Keyv, o as RedisErrorMessages, h as createKeyv, c as default, a as defaultReconnectStrategy };