UNPKG

@net-vert/core

Version:

Dependency Inversion Network Library with Type-Safe Injection.

694 lines (693 loc) 16.4 kB
import { TaskQueue as j } from "id-queue"; var f = /* @__PURE__ */ ((r) => (r.GET = "get", r.POST = "post", r.PUT = "put", r.DELETE = "delete", r))(f || {}), m = /* @__PURE__ */ ((r) => (r.CACHE = "cache", r.RETRY = "retry", r.IDEMPOTENT = "idempotent", r.CONCURRENT = "concurrent", r.SYNC = "sync", r))(m || {}); const S = "default", D = { retries: 3, delay: 0, retryCondition: () => !0 }, F = (r) => { const e = { ...D, ...r }; return Object.assign(async ({ config: n, next: s }) => { let o = 0, i; for (; o <= e.retries; ) try { return await s(); } catch (a) { if (i = a, o === e.retries) throw a; const c = { config: n, lastResponse: a, attempt: o }; if (!e.retryCondition(c)) throw a; o++; const u = typeof e.delay == "function" ? e.delay(c) : e.delay; u > 0 && await new Promise((l) => setTimeout(l, u)); } throw i; }, { __middlewareType: m.RETRY }); }, $ = () => { const r = /* @__PURE__ */ new Map(); return { getPromise: (o) => r.get(o), setPromise: (o, i) => { r.set(o, i), i.finally(() => r.delete(o)); }, delPromise: (o) => r.delete(o), clearCache: () => r.clear() }; }, E = (r) => { const { config: e } = r, { method: t, url: n, data: s } = e; return [t, n, JSON.stringify(s)].join("|"); }, T = { key: E }, q = (r) => { const e = { ...T, ...r }, t = $(); return Object.assign(({ config: s, next: o }) => { const i = e.key({ config: s }), a = t.getPromise(i); if (a) return a; const c = o(); return t.setPromise(i, c), c; }, { __middlewareType: m.IDEMPOTENT, promiseCache: t }); }; class R { parallelCount; tasks; runningCount; constructor(e = 4) { this.parallelCount = e, this.tasks = new j(), this.runningCount = 0; } // 加入 add(e, t) { return new Promise((n, s) => { this.tasks.enqueue(e, { task: t, resolve: n, reject: s }), this._run(); }); } // 删除 remove(e) { this.tasks.remove(e); } execute(e) { const { task: t, resolve: n, reject: s } = e; return t().then(n).catch(s).finally(() => { this.runningCount--, this._run(); }); } _run() { for (; this.runningCount < this.parallelCount && this.tasks.size > 0; ) { const e = this.tasks.dequeue(); this.runningCount++, this.execute(e); } } } let B = 0; const _ = { parallelCount: 4, createId: () => B++ }, K = (r) => { const { parallelCount: e, createId: t } = { ..._, ...r }, n = new R(e); return Object.assign(({ config: o, next: i }) => { const a = t({ config: o }); return n.add(a, () => i()); }, { __middlewareType: m.CONCURRENT, pool: n }); }, v = /* @__PURE__ */ new Map(), y = (r, e) => { v.set(e, r); }; function A(r) { const e = v.get(r); if (!e) throw new Error(`Store实例 ${String(r)} 未注册`); return e; } class J { store = /* @__PURE__ */ new Map(); getItem(e) { return this.store.get(e); } setItem(e, t) { return this.store.set(e, t), t; } removeItem(e) { this.store.delete(e); } clear() { this.store.clear(); } length() { return this.store.size; } key(e) { return Array.from(this.store.keys())[e]; } keys() { return Array.from(this.store.keys()); } iterate(e) { let t = 0; for (const [n, s] of this.store.entries()) e(s, n, t), t++; } } const z = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", b = (r) => typeof window < "u" ? r() : { getItem() { return null; }, setItem() { }, removeItem() { }, clear() { }, key() { return null; }, get length() { return 0; } }, h = b(() => window.localStorage); class G { constructor() { } getItem(e) { const t = String(e), n = h.getItem(t); if (n !== null) try { return JSON.parse(n); } catch (s) { console.error(`Failed to parse value for key: ${t}`, s); return; } } setItem(e, t) { const n = String(e); try { h.setItem(n, JSON.stringify(t)); } catch (s) { throw console.error(`Failed to set value for key: ${n}`, s), s; } return t; } removeItem(e) { const t = String(e); h.removeItem(t); } clear() { h.clear(); } length() { return h.length; } key(e) { return h.key(e); } keys() { const e = []; for (let t = 0; t < h.length; t++) { const n = h.key(t); n && e.push(n); } return e; } iterate(e) { this.keys().forEach((t, n) => { const s = this.getItem(t); s !== void 0 && e(s, t, n); }); } } const d = b(() => window.sessionStorage); class U { constructor() { } getItem(e) { const t = String(e), n = d.getItem(t); if (n !== null) try { return JSON.parse(n); } catch (s) { console.error(`Failed to parse value for key: ${t}`, s); return; } } setItem(e, t) { const n = String(e); try { d.setItem(n, JSON.stringify(t)); } catch (s) { throw console.error(`Failed to set value for key: ${n}`, s), s; } return t; } removeItem(e) { const t = String(e); d.removeItem(t); } clear() { d.clear(); } length() { return d.length; } key(e) { return d.key(e); } keys() { const e = []; for (let t = 0; t < d.length; t++) { const n = d.key(t); n && e.push(n); } return e; } iterate(e) { this.keys().forEach((t, n) => { const s = this.getItem(t); s !== void 0 && e(s, t, n); }); } } class Y { dbName; storeName; dbPromise = null; DB_VERSION = 1; constructor(e, t) { this.dbName = e, this.storeName = t, this.initDB(); } /** * 初始化数据库连接 */ initDB() { if (typeof window > "u" || !window.indexedDB) { console.warn("IndexedDB is not available"); return; } this.dbPromise = new Promise((e, t) => { const n = indexedDB.open(this.dbName, this.DB_VERSION); n.onerror = () => { t(new Error(`Failed to open database: ${this.dbName}`)); }, n.onsuccess = () => { e(n.result); }, n.onupgradeneeded = (s) => { const o = s.target.result; o.objectStoreNames.contains(this.storeName) || o.createObjectStore(this.storeName); }; }); } /** * 获取数据库实例 */ async getDB() { if (!this.dbPromise) throw new Error("IndexedDB is not initialized"); return this.dbPromise; } /** * 执行事务 */ async withStore(e, t) { const n = await this.getDB(); return new Promise((s, o) => { const i = n.transaction([this.storeName], e).objectStore(this.storeName), a = t(i); a.onsuccess = () => { s(a.result); }, a.onerror = () => { o(a.error); }; }); } async getItem(e) { try { const t = await this.withStore("readonly", (n) => n.get(String(e))); return t === void 0 ? void 0 : t; } catch (t) { console.error(`Failed to get value for key: ${String(e)}`, t); return; } } async setItem(e, t) { try { return await this.withStore("readwrite", (n) => n.put(t, String(e))), t; } catch (n) { throw console.error(`Failed to set value for key: ${String(e)}`, n), n; } } async removeItem(e) { try { await this.withStore("readwrite", (t) => t.delete(String(e))); } catch (t) { throw console.error(`Failed to remove value for key: ${String(e)}`, t), t; } } async clear() { try { await this.withStore("readwrite", (e) => e.clear()); } catch (e) { throw console.error("Failed to clear storage", e), e; } } async length() { try { return await this.withStore("readonly", (e) => e.count()); } catch (e) { return console.error("Failed to get storage length", e), 0; } } async key(e) { try { return (await this.withStore("readonly", (t) => t.getAllKeys()))[e]; } catch (t) { console.error("Failed to get key", t); return; } } async keys() { try { return await this.withStore("readonly", (e) => e.getAllKeys()); } catch (e) { return console.error("Failed to get all keys", e), []; } } async iterate(e) { try { const t = (await this.getDB()).transaction([this.storeName], "readonly").objectStore(this.storeName).openCursor(); return new Promise((n, s) => { let o = 0; t.onsuccess = (i) => { const a = i.target.result; if (a) { const c = a.key, u = a.value; e(u, c, o), o++, a.continue(); } else n(); }, t.onerror = () => { s(t.error); }; }); } catch (t) { console.error("Failed to iterate storage", t); } } } const g = { memory: "memory", local: "local", session: "session", indexeddb: "indexeddb" }; function N(r, e) { Object.assign(r, e); } function M(r) { return N(r, { async getItemOrDefault(e, t) { const n = await this.getItem(e); return n !== null ? n : t; }, async hasItem(e) { return await this.getItem(e) !== null; }, async removeItems(e) { await Promise.all(e.map((t) => this.removeItem(t))); }, async getItems(e) { return await Promise.all(e.map((t) => this.getItem(t))); } }), r; } function X(r) { return N(r, { getItemOrDefault(e, t) { const n = this.getItem(e); return n !== null ? n : t; }, hasItem(e) { return this.getItem(e) !== null; }, removeItems(e) { e.forEach((t) => this.removeItem(t)); }, getItems(e) { return e.map((t) => this.getItem(t)); } }), r; } function Z(r) { const e = r.getItem(""); return z(e) ? M(r) : X(r); } function w(r, ...e) { const t = A(r); let n; try { n = new t(...e); } catch { n = t(...e); } return Z(n); } y(J, g.memory); y(G, g.local); y(U, g.session); y(Y, g.indexeddb); function C(r, e) { return { value: r, expireAt: Date.now() + e }; } function I(r, e = Date.now()) { return r.expireAt <= e; } function x(r, e = Date.now()) { return I(r, e) ? void 0 : r.value; } const H = (r) => { const { config: e } = r, { method: t, url: n, data: s } = e; return [t, n, JSON.stringify(s)].join("|"); }, L = () => !0, k = 24 * 60 * 60 * 1e3, Q = { key: H, duration: k, isValid: L, store: g.memory // 默认不持久化,使用内存存储 }; let W = class { store; constructor(e) { return typeof e == "string" ? this.store = w(e) : (y(e.factory, e.key), this.store = w(e.key)), new Proxy(this, { get(t, n) { if (n in t) return t[n]; const s = t.store[n]; return typeof s == "function" ? s.bind(t.store) : s; } }); } /** * 设置缓存(自动包装成 ExpirableValue) * @param key 缓存 key * @param value 要缓存的值 * @param duration 过期时长(毫秒),默认 24 小时 */ setCache(e, t, n = k) { const s = C(t, n); this.store.setItem(e, s); } /** * 获取缓存值(检查过期,如果过期返回 undefined) * @param key 缓存 key * @returns 未过期返回值,已过期返回 undefined */ async getCache(e) { const t = await this.store.getItem(e); if (t) return x(t); } /** * 检查是否有有效的缓存(未过期) * @param key 缓存 key * @returns true 表示有有效缓存,false 表示无缓存或已过期 */ async hasValidCache(e) { const t = await this.store.getItem(e); return t ? !I(t) : !1; } }; const ee = W, te = (r) => { const e = { ...Q, ...r }, t = new ee(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration; return Object.assign(async ({ config: o, next: i }) => { const a = e.key({ config: o }), c = await t.getCache(a); if (c) { if (await e.isValid({ key: a, config: o, cachedData: c })) return c; t.removeItem(a); } const u = await i(), l = n({ key: a, config: o, cachedData: c, response: u }), p = C(u, l); return t.setItem(a, p), u; }, { __middlewareType: m.CACHE, storage: t }); }; class re { store; constructor(e) { return typeof e == "string" ? this.store = w(e) : (y(e.factory, e.key), this.store = w(e.key)), new Proxy(this, { get(t, n) { if (n in t) return t[n]; const s = t.store[n]; return typeof s == "function" ? s.bind(t.store) : s; } }); } /** * 设置缓存(自动包装成 ExpirableValue) * @param key 缓存 key * @param value 要缓存的值 * @param duration 过期时长(毫秒),默认 24 小时 */ setCache(e, t, n = k) { const s = C(t, n); this.store.setItem(e, s); } /** * 获取缓存值(检查过期,如果过期返回 undefined) * @param key 缓存 key * @returns 未过期返回值,已过期返回 undefined */ getCache(e) { const t = this.store.getItem(e); if (t) return x(t); } /** * 检查是否有有效的缓存(未过期) * @param key 缓存 key * @returns true 表示有有效缓存,false 表示无缓存或已过期 */ hasValidCache(e) { const t = this.store.getItem(e); return t ? !I(t) : !1; } } const ne = re, se = (r) => { const { config: e } = r, { method: t, url: n } = e; return [t, n].join("|"); }, oe = { suspense: !0, key: se, duration: 24 * 60 * 60 * 1e3, isValid: () => !0, store: g.memory }; function me(r) { const e = { ...oe, ...r }, t = new ne(e.store), n = (o) => typeof e.duration == "function" ? e.duration(o) : e.duration; return Object.assign(({ config: o, next: i }) => { const a = e.key({ config: o }), c = t.getCache(a); if (c) { if (e.isValid({ key: a, config: o, cachedData: c })) return c; t.removeItem(a); } if (e.suspense) throw (e.wrapSuspense ? e.wrapSuspense({ key: a, config: o, p: i() }) : i()).then((l) => { const p = n({ key: a, config: o, cachedData: c, response: l }); return t.setCache(a, l, p), l; }); return i().then((u) => { const l = n({ key: a, config: o, cachedData: c, response: u }); return t.setCache(a, u, l), u; }); }, { __middlewareType: m.SYNC }); } const P = /* @__PURE__ */ new Map(), ye = (r, e = S) => { P.set(e, r); }, ae = (r = S) => { const e = P.get(r); if (!e) throw new Error(`Requestor实例 ${String(r)} 未注册`); return e; }, V = { get: (r, e) => ({ url: r, method: f.GET, ...e, params: e?.params }), post: (r, e, t) => ({ url: r, method: f.POST, data: e, ...t }), delete: (r, e) => ({ url: r, method: f.DELETE, ...e }), put: (r, e, t) => ({ url: r, method: f.PUT, data: e, ...t }), request: (r) => r }, ie = Object.keys(V); function ce(r, e, t) { const n = {}, s = (o) => { if (o === e.length) return t(r); const i = e[o]; return i({ config: r, ctx: n, next: () => s(o + 1) }); }; return s(0); } function ue(r, e) { const t = {}, n = e ?? []; return ie.forEach( (s) => { t[s] = (...o) => { const i = V[s](...o); return ce( i, n, r ); }; } ), t; } function O(r) { const { extensions: e, instanceKey: t } = r ?? {}, n = ae(t); return ue( n, e ); } function ge(r) { const { instanceKey: e, key: t, duration: n, isValid: s, store: o, ...i } = r; return O({ instanceKey: e, extensions: [ q(i), te({ key: t, duration: n, isValid: s, store: o }) ] }); } function fe(r) { const { instanceKey: e, parallelCount: t, createId: n, retries: s, delay: o, retryCondition: i } = r; return O({ instanceKey: e, extensions: [ K({ parallelCount: t, createId: n }), F({ retries: s, delay: o, retryCondition: i }) ] }); } export { te as cache, K as concurrent, ge as createCachedIdempotentRequestor, fe as createConcurrentRetryRequestor, O as createRequestor, q as idempotent, ye as inject, F as retry, me as sync, ae as useRequestor };