lakutata
Version:
An IoC-based universal application framework.
711 lines (697 loc) • 19.6 kB
JavaScript
import { Buffer as e } from "buffer";
var t = s => {
if (s === void 0 || s === null) {
return "null";
}
if (typeof s === "string") {
return JSON.stringify(s.startsWith(":") ? ":" + s : s);
}
if (e.isBuffer(s)) {
return JSON.stringify(":base64:" + s.toString("base64"));
}
if (s?.toJSON) {
s = s.toJSON();
}
if (typeof s === "object") {
let e = "";
const i = Array.isArray(s);
e = i ? "[" : "{";
let r = true;
for (const o in s) {
const a = typeof s[o] === "function" || !i && s[o] === void 0;
if (!Object.hasOwn(s, o) || a) {
continue;
}
if (!r) {
e += ",";
}
r = false;
if (i) {
e += t(s[o]);
} else if (s[o] !== void 0) {
e += t(o) + ":" + t(s[o]);
}
}
e += i ? "]" : "}";
return e;
}
return JSON.stringify(s);
};
var s = t => JSON.parse(t, ((t, s) => {
if (typeof s === "string") {
if (s.startsWith(":base64:")) {
return e.from(s.slice(8), "base64");
}
return s.startsWith(":") ? s.slice(1) : s;
}
return s;
}));
var i = class {
_eventListeners;
_maxListeners;
constructor() {
this._eventListeners = new Map;
this._maxListeners = 100;
}
maxListeners() {
return this._maxListeners;
}
addListener(e, t) {
this.on(e, t);
}
on(e, t) {
if (!this._eventListeners.has(e)) {
this._eventListeners.set(e, []);
}
const s = this._eventListeners.get(e);
if (s) {
if (s.length >= this._maxListeners) {
console.warn(`MaxListenersExceededWarning: Possible event memory leak detected. ${s.length + 1} ${e} listeners added. Use setMaxListeners() to increase limit.`);
}
s.push(t);
}
return this;
}
removeListener(e, t) {
this.off(e, t);
}
off(e, t) {
const s = this._eventListeners.get(e) ?? [];
const i = s.indexOf(t);
if (i !== -1) {
s.splice(i, 1);
}
if (s.length === 0) {
this._eventListeners.delete(e);
}
}
once(e, t) {
const s = (...i) => {
t(...i);
this.off(e, s);
};
this.on(e, s);
}
emit(e, ...t) {
const s = this._eventListeners.get(e);
if (s && s.length > 0) {
for (const e of s) {
e(...t);
}
}
}
listeners(e) {
return this._eventListeners.get(e) ?? [];
}
removeAllListeners(e) {
if (e) {
this._eventListeners.delete(e);
} else {
this._eventListeners.clear();
}
}
setMaxListeners(e) {
this._maxListeners = e;
}
};
var r = i;
var o = class extends r {
_hookHandlers;
constructor() {
super();
this._hookHandlers = new Map;
}
addHandler(e, t) {
const s = this._hookHandlers.get(e);
if (s) {
s.push(t);
} else {
this._hookHandlers.set(e, [ t ]);
}
}
removeHandler(e, t) {
const s = this._hookHandlers.get(e);
if (s) {
const e = s.indexOf(t);
if (e !== -1) {
s.splice(e, 1);
}
}
}
trigger(e, t) {
const s = this._hookHandlers.get(e);
if (s) {
for (const i of s) {
try {
i(t);
} catch (t) {
this.emit("error", new Error(`Error in hook handler for event "${e}": ${t.message}`));
}
}
}
}
get handlers() {
return new Map(this._hookHandlers);
}
};
var a = o;
var n = class extends r {
enabled=true;
hits=0;
misses=0;
sets=0;
deletes=0;
errors=0;
constructor(e) {
super();
if (e !== void 0) {
this.enabled = e;
}
this.reset();
}
hit() {
if (this.enabled) {
this.hits++;
}
}
miss() {
if (this.enabled) {
this.misses++;
}
}
set() {
if (this.enabled) {
this.sets++;
}
}
delete() {
if (this.enabled) {
this.deletes++;
}
}
reset() {
this.hits = 0;
this.misses = 0;
this.sets = 0;
this.deletes = 0;
this.errors = 0;
}
};
var h = n;
var l = (e => {
e["PRE_SET"] = "preSet";
e["POST_SET"] = "postSet";
e["PRE_GET"] = "preGet";
e["POST_GET"] = "postGet";
e["PRE_GET_MANY"] = "preGetMany";
e["POST_GET_MANY"] = "postGetMany";
e["PRE_DELETE"] = "preDelete";
e["POST_DELETE"] = "postDelete";
return e;
})(l || {});
var c = [ "sqlite", "postgres", "mysql", "mongo", "redis", "valkey", "etcd" ];
var f = class extends r {
opts;
iterator;
hooks=new a;
stats=new h(false);
_ttl;
_namespace;
_store=new Map;
_serialize=t;
_deserialize=s;
_compression;
_useKeyPrefix=true;
constructor(e, i) {
super();
i ??= {};
e ??= {};
this.opts = {
namespace: "keyv",
serialize: t,
deserialize: s,
emitErrors: true,
store: new Map,
...i
};
if (e && e.get) {
this.opts.store = e;
} else {
this.opts = {
...this.opts,
...e
};
}
this._store = this.opts.store ?? new Map;
this._compression = this.opts.compression;
this._serialize = this.opts.serialize;
this._deserialize = this.opts.deserialize;
if (this.opts.namespace) {
this._namespace = this.opts.namespace;
}
if (this._store) {
if (!this._isValidStorageAdapter(this._store)) {
throw new Error("Invalid storage adapter");
}
if (typeof this._store.on === "function") {
this._store.on("error", (e => this.emit("error", e)));
}
this._store.namespace = this._namespace;
if (typeof this._store[Symbol.iterator] === "function" && this._store instanceof Map) {
this.iterator = this.generateIterator(this._store);
} else if ("iterator" in this._store && this._store.opts && this._checkIterableAdapter()) {
this.iterator = this.generateIterator(this._store.iterator.bind(this._store));
}
}
if (this.opts.stats) {
this.stats.enabled = this.opts.stats;
}
if (this.opts.ttl) {
this._ttl = this.opts.ttl;
}
if (this.opts.useKeyPrefix !== void 0) {
this._useKeyPrefix = this.opts.useKeyPrefix;
}
}
get store() {
return this._store;
}
set store(e) {
if (this._isValidStorageAdapter(e)) {
this._store = e;
this.opts.store = e;
if (typeof e.on === "function") {
e.on("error", (e => this.emit("error", e)));
}
if (this._namespace) {
this._store.namespace = this._namespace;
}
if (typeof e[Symbol.iterator] === "function" && e instanceof Map) {
this.iterator = this.generateIterator(e);
} else if ("iterator" in e && e.opts && this._checkIterableAdapter()) {
this.iterator = this.generateIterator(e.iterator.bind(e));
}
} else {
throw new Error("Invalid storage adapter");
}
}
get compression() {
return this._compression;
}
set compression(e) {
this._compression = e;
}
get namespace() {
return this._namespace;
}
set namespace(e) {
this._namespace = e;
this.opts.namespace = e;
this._store.namespace = e;
if (this.opts.store) {
this.opts.store.namespace = e;
}
}
get ttl() {
return this._ttl;
}
set ttl(e) {
this.opts.ttl = e;
this._ttl = e;
}
get serialize() {
return this._serialize;
}
set serialize(e) {
this.opts.serialize = e;
this._serialize = e;
}
get deserialize() {
return this._deserialize;
}
set deserialize(e) {
this.opts.deserialize = e;
this._deserialize = e;
}
get useKeyPrefix() {
return this._useKeyPrefix;
}
set useKeyPrefix(e) {
this._useKeyPrefix = e;
this.opts.useKeyPrefix = e;
}
generateIterator(e) {
const t = async function*() {
for await (const [t, s] of typeof e === "function" ? e(this._store.namespace) : e) {
const e = await this.deserializeData(s);
if (this._useKeyPrefix && this._store.namespace && !t.includes(this._store.namespace)) {
continue;
}
if (typeof e.expires === "number" && Date.now() > e.expires) {
this.delete(t);
continue;
}
yield [ this._getKeyUnprefix(t), e.value ];
}
};
return t.bind(this);
}
_checkIterableAdapter() {
return c.includes(this._store.opts.dialect) || c.some((e => this._store.opts.url.includes(e)));
}
_getKeyPrefix(e) {
if (!this._useKeyPrefix) {
return e;
}
if (!this._namespace) {
return e;
}
return `${this._namespace}:${e}`;
}
_getKeyPrefixArray(e) {
if (!this._useKeyPrefix) {
return e;
}
if (!this._namespace) {
return e;
}
return e.map((e => `${this._namespace}:${e}`));
}
_getKeyUnprefix(e) {
if (!this._useKeyPrefix) {
return e;
}
return e.split(":").splice(1).join(":");
}
_isValidStorageAdapter(e) {
return e instanceof Map || typeof e.get === "function" && typeof e.set === "function" && typeof e.delete === "function" && typeof e.clear === "function";
}
async get(e, t) {
const {store: s} = this.opts;
const i = Array.isArray(e);
const r = i ? this._getKeyPrefixArray(e) : this._getKeyPrefix(e);
const o = e => typeof e.expires === "number" && Date.now() > e.expires;
if (i) {
if (t?.raw === true) {
return this.getMany(e, {
raw: true
});
}
return this.getMany(e, {
raw: false
});
}
this.hooks.trigger("preGet", {
key: r
});
const a = await s.get(r);
const n = typeof a === "string" || this.opts.compression ? await this.deserializeData(a) : a;
if (n === void 0 || n === null) {
this.stats.miss();
return void 0;
}
if (o(n)) {
await this.delete(e);
this.stats.miss();
return void 0;
}
this.hooks.trigger("postGet", {
key: r,
value: n
});
this.stats.hit();
return t?.raw ? n : n.value;
}
async getMany(e, t) {
const {store: s} = this.opts;
const i = this._getKeyPrefixArray(e);
const r = e => typeof e.expires === "number" && Date.now() > e.expires;
this.hooks.trigger("preGetMany", {
keys: i
});
if (s.getMany === void 0) {
const e = i.map((async e => {
const i = await s.get(e);
const o = typeof i === "string" || this.opts.compression ? await this.deserializeData(i) : i;
if (o === void 0 || o === null) {
return void 0;
}
if (r(o)) {
await this.delete(e);
return void 0;
}
return t?.raw ? o : o.value;
}));
const o = await Promise.allSettled(e);
const a = o.map((e => e.value));
this.hooks.trigger("postGetMany", a);
if (a.length > 0) {
this.stats.hit();
}
return a;
}
const o = await s.getMany(i);
const a = [];
for (const s in o) {
let i = o[s];
if (typeof i === "string") {
i = await this.deserializeData(i);
}
if (i === void 0 || i === null) {
a.push(void 0);
continue;
}
if (r(i)) {
await this.delete(e[s]);
a.push(void 0);
continue;
}
const n = t?.raw ? i : i.value;
a.push(n);
}
this.hooks.trigger("postGetMany", a);
if (a.length > 0) {
this.stats.hit();
}
return a;
}
async set(e, t, s) {
const i = {
key: e,
value: t,
ttl: s
};
this.hooks.trigger("preSet", i);
const r = this._getKeyPrefix(i.key);
i.ttl ??= this._ttl;
if (i.ttl === 0) {
i.ttl = void 0;
}
const {store: o} = this.opts;
const a = typeof i.ttl === "number" ? Date.now() + i.ttl : void 0;
if (typeof i.value === "symbol") {
this.emit("error", "symbol cannot be serialized");
throw new Error("symbol cannot be serialized");
}
const n = {
value: i.value,
expires: a
};
const h = await this.serializeData(n);
let l = true;
try {
const e = await o.set(r, h, i.ttl);
if (typeof e === "boolean") {
l = e;
}
} catch (e) {
l = false;
this.emit("error", e);
}
this.hooks.trigger("postSet", {
key: r,
value: h,
ttl: s
});
this.stats.set();
return l;
}
async setMany(e) {
let t = [];
try {
if (this._store.setMany !== void 0) {
const s = await Promise.all(e.map((async ({key: e, value: t, ttl: s}) => {
s ??= this._ttl;
if (s === 0) {
s = void 0;
}
const i = typeof s === "number" ? Date.now() + s : void 0;
if (typeof t === "symbol") {
this.emit("error", "symbol cannot be serialized");
throw new Error("symbol cannot be serialized");
}
const r = {
value: t,
expires: i
};
const o = await this.serializeData(r);
return {
key: e,
value: o,
ttl: s
};
})));
t = await this._store.setMany(s);
}
const s = [];
for (const t of e) {
s.push(this.set(t.key, t.value, t.ttl));
}
const i = await Promise.allSettled(s);
t = i.map((e => e.value));
} catch (s) {
this.emit("error", s);
t = e.map((() => false));
}
return t;
}
async delete(e) {
const {store: t} = this.opts;
if (Array.isArray(e)) {
return this.deleteMany(e);
}
const s = this._getKeyPrefix(e);
this.hooks.trigger("preDelete", {
key: s
});
let i = true;
try {
const e = await t.delete(s);
if (typeof e === "boolean") {
i = e;
}
} catch (e) {
i = false;
this.emit("error", e);
}
this.hooks.trigger("postDelete", {
key: s,
value: i
});
this.stats.delete();
return i;
}
async deleteMany(e) {
try {
const {store: t} = this.opts;
const s = this._getKeyPrefixArray(e);
this.hooks.trigger("preDelete", {
key: s
});
if (t.deleteMany !== void 0) {
return await t.deleteMany(s);
}
const i = s.map((async e => t.delete(e)));
const r = await Promise.allSettled(i);
const o = r.every((e => e.value === true));
this.hooks.trigger("postDelete", {
key: s,
value: o
});
return o;
} catch (e) {
this.emit("error", e);
return false;
}
}
async clear() {
this.emit("clear");
const {store: e} = this.opts;
try {
await e.clear();
} catch (e) {
this.emit("error", e);
}
}
async has(e) {
if (Array.isArray(e)) {
return this.hasMany(e);
}
const t = this._getKeyPrefix(e);
const {store: s} = this.opts;
if (s.has !== void 0 && !(s instanceof Map)) {
return s.has(t);
}
let i;
try {
i = await s.get(t);
} catch (e) {
this.emit("error", e);
}
if (i) {
const e = await this.deserializeData(i);
if (e) {
if (e.expires === void 0 || e.expires === null) {
return true;
}
return e.expires > Date.now();
}
}
return false;
}
async hasMany(e) {
const t = this._getKeyPrefixArray(e);
const {store: s} = this.opts;
if (s.hasMany !== void 0) {
return s.hasMany(t);
}
const i = [];
for (const e of t) {
i.push(await this.has(e));
}
return i;
}
async disconnect() {
const {store: e} = this.opts;
this.emit("disconnect");
if (typeof e.disconnect === "function") {
return e.disconnect();
}
}
emit(e, ...t) {
if (e === "error" && !this.opts.emitErrors) {
return;
}
super.emit(e, ...t);
}
async serializeData(e) {
if (!this._serialize) {
return e;
}
if (this._compression?.compress) {
return this._serialize({
value: await this._compression.compress(e.value),
expires: e.expires
});
}
return this._serialize(e);
}
async deserializeData(e) {
if (!this._deserialize) {
return e;
}
if (this._compression?.decompress && typeof e === "string") {
const t = await this._deserialize(e);
return {
value: await this._compression.decompress(t?.value),
expires: t?.expires
};
}
if (typeof e === "string") {
return this._deserialize(e);
}
return void 0;
}
};
var p = f;
export { f as K, s as d, p as i };