UNPKG

wardens

Version:

A framework for resource management

155 lines (154 loc) 4.57 kB
var O = Object.defineProperty; var R = (r, e, t) => e in r ? O(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t; var f = (r, e, t) => (R(r, typeof e != "symbol" ? e + "" : e, t), t), S = (r, e, t) => { if (!e.has(r)) throw TypeError("Cannot " + t); }; var n = (r, e, t) => (S(r, e, "read from private field"), t ? t.call(r) : e.get(r)), l = (r, e, t) => { if (e.has(r)) throw TypeError("Cannot add the same private member more than once"); e instanceof WeakSet ? e.add(r) : e.set(r, t); }, h = (r, e, t, s) => (S(r, e, "write to private field"), s ? s.call(r, t) : e.set(r, t), t); function T(r) { const e = /* @__PURE__ */ new WeakMap(); return new Proxy(r, { get(t, s) { const o = Reflect.get(t, s, t); if (typeof o == "function") { if (e.has(o) === !1) { const a = o.bind(t); Object.defineProperties( a, Object.getOwnPropertyDescriptors(o) ), e.set(o, a); } return e.get(o); } return o; }, set(t, s, o) { return Reflect.set(t, s, o, t); } }); } const C = /* @__PURE__ */ new WeakMap(), j = /* @__PURE__ */ new WeakSet(); function B(r) { return Proxy.revocable(r, {}); } var g, w; class x { constructor(e) { l(this, g, Symbol("Context ID")); l(this, w, void 0); h(this, w, e); } static getId(e) { return n(e, g); } static getDefaultValue(e) { var t; return n(t = e, w).call(t); } } g = new WeakMap(), w = new WeakMap(); const U = (r) => new x(r); var y, u, p, i; class A { constructor(e, t, s) { l(this, y, /* @__PURE__ */ new WeakSet()); l(this, u, void 0); l(this, p, void 0); l(this, i, void 0); /** Provision an owned resource and make sure it doesn't outlive us. */ f(this, "create", async (e, ...t) => { if (n(this, p).enforced) throw new Error("Cannot create new resources after teardown."); const s = Object.create(n(this, i)), o = await k(s, e, ...t); return n(this, u).add(o), o; }); /** * Tear down a resource. Happens automatically when resource owners are * deallocated. */ f(this, "destroy", async (e) => { if (n(this, y).has(e)) throw new Error("Resource already destroyed."); if (!n(this, u).has(e)) throw new Error("You do not own this resource."); n(this, u).delete(e), n(this, y).add(e), await D(e); }); /** Store a value in context. Anything down the chain can read it. */ f(this, "setContext", (e, t) => { n(this, i)[x.getId(e)] = t; }); /** Retrieve a value from context, or a default if it is unset. */ f(this, "getContext", (e) => { const t = x.getId(e); return t in n(this, i) ? n(this, i)[t] : x.getDefaultValue(e); }); h(this, i, e), h(this, u, t), h(this, p, s); } } y = new WeakMap(), u = new WeakMap(), p = new WeakMap(), i = new WeakMap(); const k = async (r, e, ...t) => { const s = { enforced: !1 }, o = /* @__PURE__ */ new Set(), a = new A(r, o, s); let c; try { c = await e(a, ...t); } catch (b) { const I = Array.from(o).reverse(), v = (await Promise.allSettled( I.map((d) => a.destroy(d)) )).filter( (d) => d.status === "rejected" ); throw v.length ? E( v.map((d) => d.reason), { cause: b } ) : b; } const P = c.value, { proxy: m, revoke: W } = B(P); return j.add(m), C.set(m, { curfew: s, resource: c, children: o, revoke: W }), m; }, D = async (r) => { if (!j.has(r)) throw new Error("Cannot destroy object. It is not a resource."); const e = C.get(r); if (e) { C.delete(r), e.revoke(); let t = { status: "fulfilled", value: void 0 }; if (e.resource.destroy) try { await e.resource.destroy(); } catch (c) { t = { status: "rejected", reason: c }; } e.curfew.enforced = !0; const s = Array.from(e.children).reverse().map(D), o = await Promise.allSettled(s), a = [t].concat(o).filter( (c) => c.status === "rejected" ); if (a.length) throw E(a.map((c) => c.reason)); } }, E = (r, e) => r.length === 1 ? r[0] : new M(r, e); class M extends Error { constructor(e, t) { super( "Some resources could not be destroyed. See the `failures` property for details.", t ), this.failures = e; } } const Y = async (r, ...e) => k(/* @__PURE__ */ Object.create(null), r, ...e); export { T as bindContext, Y as create, U as createContext, D as destroy };