UNPKG

@net-vert/core

Version:

Dependency Inversion Network Library with Type-Safe Injection.

683 lines (682 loc) 15.9 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 || {}), g = /* @__PURE__ */ ((r) => (r.CACHE = "cache", r.RETRY = "retry", r.IDEMPOTENT = "idempotent", r.CONCURRENT = "concurrent", r.THROTTLE = "throttle", r))(g || {}); const k = "default", S = /* @__PURE__ */ new Map(), me = (r, e = k) => { S.set(e, r); }, q = (r = k) => { const e = S.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 }, F = Object.keys(v); function $(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 R(r, e) { const t = {}, n = e ?? []; return F.forEach( (s) => { t[s] = (...o) => { const i = v[s](...o); return $( i, n, r ); }; } ), t; } function b(r) { const { extensions: e, instanceKey: t } = r ?? {}, n = q(t); return R( n, e ); } const V = { retries: 3, delay: 0, retryCondition: () => !0 }, B = (r) => { const e = { ...V, ...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 h = typeof e.delay == "function" ? e.delay(c) : e.delay; h > 0 && await new Promise((I) => setTimeout(I, h)); } throw i; }, { __middlewareType: g.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() }; }, K = (r) => { const { config: e } = r, { method: t, url: n, data: s } = e; return [t, n, JSON.stringify(s)].join("|"); }, A = { key: K }, J = (r) => { const e = { ...A, ...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: g.IDEMPOTENT, promiseCache: t }); }; class z { 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 G = 0; const H = { parallelCount: 4, createId: () => G++ }, L = (r) => { const { parallelCount: e, createId: t } = { ...H, ...r }, n = new z(e); return Object.assign(({ config: o, next: i }) => { const a = t({ config: o }); return n.add(a, () => i()); }, { __middlewareType: g.CONCURRENT, pool: n }); }, T = /* @__PURE__ */ new Map(), w = (r, e) => { T.set(e, r); }; function U(r) { const e = T.get(r); if (!e) throw new Error(`Store实例 ${String(r)} 未注册`); return e; } class M { 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 X = (r) => !!r && (typeof r == "object" || typeof r == "function") && typeof r.then == "function", x = (r) => typeof window < "u" ? r() : { getItem() { return null; }, setItem() { }, removeItem() { }, clear() { }, key() { return null; }, get length() { return 0; } }, m = x(() => window.localStorage); class Z { constructor() { } getItem(e) { const t = String(e), n = m.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 { m.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); m.removeItem(t); } clear() { m.clear(); } length() { return m.length; } key(e) { return m.key(e); } keys() { const e = []; for (let t = 0; t < m.length; t++) { const n = m.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 y = x(() => window.sessionStorage); class Q { constructor() { } getItem(e) { const t = String(e), n = y.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 { y.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); y.removeItem(t); } clear() { y.clear(); } length() { return y.length; } key(e) { return y.key(e); } keys() { const e = []; for (let t = 0; t < y.length; t++) { const n = y.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, h = a.value; e(h, c, o), o++, a.continue(); } else n(); }, t.onerror = () => { s(t.error); }; }); } catch (t) { console.error("Failed to iterate storage", t); } } } const p = { memory: "memory", local: "local", session: "session", indexeddb: "indexeddb" }; function P(r, e) { Object.assign(r, e); } function W(r) { return P(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 ee(r) { return P(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 te(r) { const e = r.getItem(""); return X(e) ? W(r) : ee(r); } function C(r, ...e) { const t = U(r); let n; try { n = new t(...e); } catch { n = t(...e); } return te(n); } w(M, p.memory); w(Z, p.local); w(Q, p.session); w(Y, p.indexeddb); function N(r, e) { return { value: r, expireAt: Date.now() + e }; } function O(r, e = Date.now()) { return r.expireAt <= e; } function re(r, e = Date.now()) { return O(r, e) ? void 0 : r.value; } const ne = (r) => { const { config: e } = r, { method: t, url: n, data: s } = e; return [t, n, JSON.stringify(s)].join("|"); }, se = () => !0, E = 24 * 60 * 60 * 1e3, oe = { key: ne, duration: E, isValid: se, store: p.memory // 默认不持久化,使用内存存储 }; class ae { store; constructor(e) { return typeof e == "string" ? this.store = C(e) : (w(e.factory, e.key), this.store = C(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 = E) { const s = N(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 re(t); } /** * 检查是否有有效的缓存(未过期) * @param key 缓存 key * @returns true 表示有有效缓存,false 表示无缓存或已过期 */ async hasValidCache(e) { const t = await this.store.getItem(e); return t ? !O(t) : !1; } } const ie = ae, ce = (r) => { const e = { ...oe, ...r }, t = new ie(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 h = await i(), I = n({ key: a, config: o, cachedData: c, response: h }), u = N(h, I); return t.setItem(a, u), h; }, { __middlewareType: g.CACHE, storage: t }); }; class ue extends Error { constructor(e, t) { super(`请求在节流队列中等待超时:配置超时 ${e}ms,实际等待 ${t}ms`), this.name = "ThrottleTimeoutError"; } } function le(r, e) { const t = []; let n = 0, s = !1; const o = (u) => new Promise((l) => setTimeout(l, u)), i = () => { if (e === void 0 || t.length === 0) return !1; const u = Date.now(), l = t[0], d = u - l.timestamp; return d >= e ? (t.shift(), l.reject(new ue(e, d)), !0) : !1; }, a = async () => { if (!(s || t.length === 0)) { for (s = !0; t.length > 0; ) { if (e !== void 0 && i()) continue; if (t.length === 0) break; const l = Date.now() - n; if (n > 0 && l < r) { const D = r - l; await o(D); } const d = t.shift(); d && (n = Date.now(), d.task().then(d.resolve).catch(d.reject)); } s = !1; } }; return { add: (u) => new Promise((l, d) => { t.push({ task: u, resolve: l, reject: d, timestamp: Date.now() }), a(); }), getStatus: () => { const u = t.length > 0 ? n + r : null; return { queueLength: t.length, lastExecutionTime: n, isProcessing: s, nextExecutionTime: u }; }, clear: () => { t.length = 0; } }; } const he = { interval: 1e3 // timeout 默认 undefined,永不超时 }, ye = (r) => { const e = { ...he, ...r }, t = le(e.interval, e.timeout); return Object.assign(async ({ config: s, next: o }) => t.add(o), { __middlewareType: g.THROTTLE, throttler: t }); }; function ge(r) { const { instanceKey: e, key: t, duration: n, isValid: s, store: o, ...i } = r; return b({ instanceKey: e, extensions: [ J(i), ce({ 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 b({ instanceKey: e, extensions: [ L({ parallelCount: t, createId: n }), B({ retries: s, delay: o, retryCondition: i }) ] }); } export { ce as cache, L as concurrent, ge as createCachedIdempotentRequestor, fe as createConcurrentRetryRequestor, b as createRequestor, J as idempotent, me as inject, B as retry, ye as throttle, q as useRequestor };