@floegence/floe-webapp-core 0.68.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resource-cache.d.ts +2 -0
- package/dist/resource-cache.js +132 -123
- package/package.json +1 -1
package/dist/resource-cache.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export interface CachedResourceDefinition<T> {
|
|
|
38
38
|
}
|
|
39
39
|
export interface ResourceCache {
|
|
40
40
|
resource<T>(definition: CachedResourceDefinition<T>): CachedResource<T>;
|
|
41
|
+
/** Abort pending refreshes without retiring snapshots, storage, hydration or subscribers. */
|
|
42
|
+
cancelRefreshes(scope: string): void;
|
|
41
43
|
clearScope(scope: string): Promise<void>;
|
|
42
44
|
flush(): Promise<void>;
|
|
43
45
|
dispose(): void;
|
package/dist/resource-cache.js
CHANGED
|
@@ -1,177 +1,186 @@
|
|
|
1
|
-
async function
|
|
2
|
-
const
|
|
3
|
-
let
|
|
4
|
-
const
|
|
5
|
-
for (const
|
|
6
|
-
if (
|
|
7
|
-
await
|
|
1
|
+
async function J(y, l) {
|
|
2
|
+
const m = [...await y.list()].sort((r, s) => r.lastAccessedAt - s.lastAccessedAt);
|
|
3
|
+
let i = m.reduce((r, s) => r + s.bytes, 0);
|
|
4
|
+
const a = [];
|
|
5
|
+
for (const r of m) {
|
|
6
|
+
if (i <= Math.max(0, l)) break;
|
|
7
|
+
await y.remove(r.key), a.push(r.key), i -= r.bytes;
|
|
8
8
|
}
|
|
9
|
-
return
|
|
9
|
+
return a;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
const
|
|
13
|
-
let
|
|
14
|
-
const d = (
|
|
15
|
-
}),
|
|
16
|
-
const
|
|
17
|
-
list: async () => (await
|
|
18
|
-
remove: (
|
|
19
|
-
},
|
|
20
|
-
for (const
|
|
21
|
-
},
|
|
22
|
-
clearTimeout(
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
for (const [
|
|
26
|
-
if (
|
|
11
|
+
function z(y) {
|
|
12
|
+
const l = y.storage, m = Math.max(0, y.maxBytes ?? 32 * 1024 * 1024), i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map();
|
|
13
|
+
let r, s = Promise.resolve(), n = !1;
|
|
14
|
+
const d = (t) => (s = s.then(t).catch(() => {
|
|
15
|
+
}), s), f = async () => {
|
|
16
|
+
const t = await J({
|
|
17
|
+
list: async () => (await l.list()).map((e) => ({ ...e, lastAccessedAt: Math.max(e.lastAccessedAt, i.get(e.key)?.accessedAt ?? 0) })),
|
|
18
|
+
remove: (e) => l.remove(e)
|
|
19
|
+
}, m);
|
|
20
|
+
for (const e of t) i.get(e)?.evicted();
|
|
21
|
+
}, p = async () => {
|
|
22
|
+
clearTimeout(r), r = void 0;
|
|
23
|
+
const t = [...a];
|
|
24
|
+
a.clear(), t.length && d(async () => {
|
|
25
|
+
for (const [e, v] of t)
|
|
26
|
+
if (v.valid())
|
|
27
27
|
try {
|
|
28
|
-
await
|
|
28
|
+
await l.set(e, v.value), v.stored();
|
|
29
29
|
} catch {
|
|
30
30
|
}
|
|
31
|
-
await
|
|
32
|
-
}), await
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
31
|
+
await f();
|
|
32
|
+
}), await s;
|
|
33
|
+
}, x = (t, e, v, o) => {
|
|
34
|
+
a.set(t, { value: e, valid: v, stored: o }), r === void 0 && (r = setTimeout(() => {
|
|
35
|
+
p();
|
|
36
|
+
}, y.writeDelayMs ?? 100));
|
|
37
37
|
};
|
|
38
38
|
return {
|
|
39
|
-
resource: (
|
|
40
|
-
if (
|
|
41
|
-
if (!
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
45
|
-
let
|
|
46
|
-
const
|
|
47
|
-
let
|
|
48
|
-
const
|
|
49
|
-
for (const c of
|
|
50
|
-
},
|
|
51
|
-
++
|
|
39
|
+
resource: (t) => {
|
|
40
|
+
if (n) throw new Error("Resource cache is disposed");
|
|
41
|
+
if (!t.scope || !t.key || !Number.isSafeInteger(t.version)) throw new Error("Invalid resource identity");
|
|
42
|
+
const e = JSON.stringify([t.scope, t.key, t.version]), v = i.get(e);
|
|
43
|
+
if (v)
|
|
44
|
+
return v.accessedAt = Date.now(), v.handle;
|
|
45
|
+
let o = { data: void 0, restoring: !0, refreshing: !1, stale: !0, error: void 0 };
|
|
46
|
+
const S = /* @__PURE__ */ new Set();
|
|
47
|
+
let D = 0, w = 0, E, R, g, h, M;
|
|
48
|
+
const b = () => {
|
|
49
|
+
for (const c of S) c();
|
|
50
|
+
}, P = (c) => {
|
|
51
|
+
++D, o = { data: c, restoring: !1, refreshing: o.refreshing, stale: !1, error: void 0 };
|
|
52
52
|
try {
|
|
53
|
-
const u = JSON.stringify({ version:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}) :
|
|
53
|
+
const u = JSON.stringify({ version: t.version, data: t.persist ? t.persist(c) : c });
|
|
54
|
+
E = u, u !== R ? x(e, u, () => E === u, () => {
|
|
55
|
+
R = u;
|
|
56
|
+
}) : a.delete(e);
|
|
57
57
|
} catch {
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
if (!(
|
|
59
|
+
b();
|
|
60
|
+
}, C = D, O = l.get(e).then((c) => {
|
|
61
|
+
if (!(n || D !== C || c === null))
|
|
62
62
|
try {
|
|
63
63
|
const u = JSON.parse(c);
|
|
64
|
-
if (u.version !==
|
|
65
|
-
const A =
|
|
66
|
-
|
|
64
|
+
if (u.version !== t.version) throw new Error("Unsupported snapshot");
|
|
65
|
+
const A = t.decode(u.data);
|
|
66
|
+
o = { ...o, data: A, stale: !0 }, E = c, R = c;
|
|
67
67
|
} catch {
|
|
68
|
-
d(() =>
|
|
68
|
+
d(() => l.remove(e));
|
|
69
69
|
}
|
|
70
70
|
}).catch(() => {
|
|
71
71
|
}).finally(() => {
|
|
72
|
-
|
|
73
|
-
}),
|
|
74
|
-
snapshot: () =>
|
|
75
|
-
subscribe: (c) => (
|
|
76
|
-
|
|
72
|
+
n || !o.restoring || (o = { ...o, restoring: !1 }, b());
|
|
73
|
+
}), q = {
|
|
74
|
+
snapshot: () => o,
|
|
75
|
+
subscribe: (c) => (S.add(c), () => {
|
|
76
|
+
S.delete(c);
|
|
77
77
|
}),
|
|
78
|
-
hydrate: () =>
|
|
78
|
+
hydrate: () => O,
|
|
79
79
|
refresh: (c) => {
|
|
80
|
-
if (
|
|
81
|
-
const u = ++
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
if (h) return h;
|
|
81
|
+
const u = ++w, A = new AbortController();
|
|
82
|
+
g = A, o = { ...o, refreshing: !0, error: void 0 }, b();
|
|
83
|
+
const B = new Promise((k, I) => {
|
|
84
|
+
M = () => I(new DOMException("Resource refresh cancelled", "AbortError"));
|
|
85
|
+
}), N = Promise.resolve().then(() => c(A.signal)).then((k) => (!n && u === w && !A.signal.aborted && P(k), k), (k) => {
|
|
86
|
+
throw !n && u === w && !A.signal.aborted && (o = { ...o, stale: !0, error: k }, b()), k;
|
|
87
|
+
});
|
|
88
|
+
return h = Promise.race([N, B]).finally(() => {
|
|
89
|
+
u === w && (h = void 0, g = void 0, M = void 0, o = { ...o, refreshing: !1 }, b());
|
|
90
|
+
}), h;
|
|
87
91
|
},
|
|
88
92
|
set: (c) => {
|
|
89
|
-
++
|
|
93
|
+
++w, g?.abort(), h = void 0, o = { ...o, refreshing: !1 }, P(c);
|
|
90
94
|
},
|
|
91
95
|
invalidate: (c = !1) => {
|
|
92
|
-
++
|
|
96
|
+
++D, ++w, g?.abort(), g = void 0, h = void 0, E = void 0, R = void 0, a.delete(e), o = { data: c ? void 0 : o.data, restoring: !1, refreshing: !1, stale: !0, error: void 0 }, b(), d(() => l.remove(e));
|
|
93
97
|
}
|
|
94
98
|
};
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
}, handle:
|
|
98
|
-
++
|
|
99
|
-
}
|
|
99
|
+
return i.set(e, { scope: t.scope, accessedAt: Date.now(), evicted: () => {
|
|
100
|
+
R = void 0;
|
|
101
|
+
}, handle: q, cancelRefresh: () => {
|
|
102
|
+
h && (++w, M?.(), M = void 0, g?.abort(), g = void 0, h = void 0, o = { ...o, refreshing: !1, stale: !0 }, b());
|
|
103
|
+
}, stop: () => {
|
|
104
|
+
++w, g?.abort(), S.clear();
|
|
105
|
+
} }), q;
|
|
100
106
|
},
|
|
101
|
-
flush:
|
|
102
|
-
|
|
103
|
-
for (const
|
|
107
|
+
flush: p,
|
|
108
|
+
cancelRefreshes: (t) => {
|
|
109
|
+
for (const e of i.values()) e.scope === t && e.cancelRefresh();
|
|
110
|
+
},
|
|
111
|
+
clearScope: async (t) => {
|
|
112
|
+
for (const e of i.values()) e.scope === t && e.handle.invalidate(!0);
|
|
104
113
|
await d(async () => {
|
|
105
|
-
for (const
|
|
114
|
+
for (const e of await l.list())
|
|
106
115
|
try {
|
|
107
|
-
JSON.parse(
|
|
116
|
+
JSON.parse(e.key)[0] === t && await l.remove(e.key);
|
|
108
117
|
} catch {
|
|
109
118
|
}
|
|
110
119
|
});
|
|
111
120
|
},
|
|
112
121
|
dispose: () => {
|
|
113
|
-
if (!
|
|
114
|
-
|
|
115
|
-
for (const
|
|
116
|
-
|
|
122
|
+
if (!n) {
|
|
123
|
+
n = !0;
|
|
124
|
+
for (const t of i.values()) t.stop();
|
|
125
|
+
p(), i.clear();
|
|
117
126
|
}
|
|
118
127
|
}
|
|
119
128
|
};
|
|
120
129
|
}
|
|
121
|
-
function
|
|
122
|
-
let
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}, n
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
},
|
|
133
|
-
|
|
130
|
+
function L(y = "floe-resource-cache") {
|
|
131
|
+
let l;
|
|
132
|
+
const m = () => l ??= new Promise((a, r) => {
|
|
133
|
+
const s = indexedDB.open(y, 1);
|
|
134
|
+
s.onupgradeneeded = () => s.result.createObjectStore("snapshots", { keyPath: "key" }), s.onsuccess = () => {
|
|
135
|
+
const n = s.result;
|
|
136
|
+
n.onversionchange = () => {
|
|
137
|
+
n.close(), l = void 0;
|
|
138
|
+
}, a(n);
|
|
139
|
+
}, s.onerror = () => {
|
|
140
|
+
l = void 0, r(s.error);
|
|
141
|
+
}, s.onblocked = () => {
|
|
142
|
+
l = void 0, r(new Error("Resource cache database is blocked"));
|
|
134
143
|
};
|
|
135
|
-
}),
|
|
136
|
-
const
|
|
137
|
-
return new Promise((
|
|
138
|
-
const
|
|
139
|
-
let
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
}), i = async (a, r) => {
|
|
145
|
+
const s = await m();
|
|
146
|
+
return new Promise((n, d) => {
|
|
147
|
+
const f = s.transaction("snapshots", a);
|
|
148
|
+
let p;
|
|
149
|
+
f.oncomplete = () => n(p), f.onerror = () => d(f.error), f.onabort = () => d(f.error ?? new Error("Resource cache transaction aborted")), r(f.objectStore("snapshots"), (x) => {
|
|
150
|
+
p = x;
|
|
142
151
|
});
|
|
143
152
|
});
|
|
144
153
|
};
|
|
145
154
|
return {
|
|
146
|
-
get: (
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
const d =
|
|
150
|
-
d &&
|
|
155
|
+
get: (a) => i("readwrite", (r, s) => {
|
|
156
|
+
const n = r.get(a);
|
|
157
|
+
n.onsuccess = () => {
|
|
158
|
+
const d = n.result;
|
|
159
|
+
d && r.put({ ...d, lastAccessedAt: Date.now() }), s(d?.value ?? null);
|
|
151
160
|
};
|
|
152
161
|
}),
|
|
153
|
-
set: (
|
|
154
|
-
|
|
162
|
+
set: (a, r) => i("readwrite", (s, n) => {
|
|
163
|
+
s.put({ key: a, value: r, bytes: new TextEncoder().encode(r).byteLength, lastAccessedAt: Date.now() }), n(void 0);
|
|
155
164
|
}),
|
|
156
|
-
remove: (
|
|
157
|
-
|
|
165
|
+
remove: (a) => i("readwrite", (r, s) => {
|
|
166
|
+
r.delete(a), s(void 0);
|
|
158
167
|
}),
|
|
159
|
-
list: () =>
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
const d =
|
|
168
|
+
list: () => i("readonly", (a, r) => {
|
|
169
|
+
const s = [], n = a.openCursor();
|
|
170
|
+
n.onsuccess = () => {
|
|
171
|
+
const d = n.result;
|
|
163
172
|
if (!d) {
|
|
164
|
-
|
|
173
|
+
r(s);
|
|
165
174
|
return;
|
|
166
175
|
}
|
|
167
|
-
const { key:
|
|
168
|
-
|
|
176
|
+
const { key: f, bytes: p, lastAccessedAt: x } = d.value;
|
|
177
|
+
s.push({ key: f, bytes: p, lastAccessedAt: x }), d.continue();
|
|
169
178
|
};
|
|
170
179
|
})
|
|
171
180
|
};
|
|
172
181
|
}
|
|
173
182
|
export {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
183
|
+
L as createIndexedDBResourceCacheStorage,
|
|
184
|
+
z as createResourceCache,
|
|
185
|
+
J as enforceResourceCacheBudget
|
|
177
186
|
};
|