@dee-wan/cache 1.0.1 → 2.0.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.
Files changed (57) hide show
  1. package/README.md +208 -3
  2. package/dist/chunk-A4WV6RY4.js +311 -0
  3. package/dist/chunk-A4WV6RY4.js.map +1 -0
  4. package/dist/chunk-AENVFT2S.js +6 -0
  5. package/dist/chunk-AENVFT2S.js.map +1 -0
  6. package/dist/chunk-E6OZZ5UX.js +133 -0
  7. package/dist/chunk-E6OZZ5UX.js.map +1 -0
  8. package/dist/chunk-JPK2AF7X.js +18 -0
  9. package/dist/chunk-JPK2AF7X.js.map +1 -0
  10. package/dist/chunk-LAXBP5DQ.js +330 -0
  11. package/dist/chunk-LAXBP5DQ.js.map +1 -0
  12. package/dist/chunk-LHOK33GI.js +12 -0
  13. package/dist/chunk-LHOK33GI.js.map +1 -0
  14. package/dist/chunk-M4UOCIDQ.js +557 -0
  15. package/dist/chunk-M4UOCIDQ.js.map +1 -0
  16. package/dist/chunk-NFBMWKY5.js +54 -0
  17. package/dist/chunk-NFBMWKY5.js.map +1 -0
  18. package/dist/chunk-O3KHMFHX.js +425 -0
  19. package/dist/chunk-O3KHMFHX.js.map +1 -0
  20. package/dist/chunk-WJNCFFF3.js +637 -0
  21. package/dist/chunk-WJNCFFF3.js.map +1 -0
  22. package/dist/chunk-WKZ7TKGM.js +82 -0
  23. package/dist/chunk-WKZ7TKGM.js.map +1 -0
  24. package/dist/chunk-ZBYAKDNZ.js +45 -0
  25. package/dist/chunk-ZBYAKDNZ.js.map +1 -0
  26. package/dist/chunk-ZCMZJKGN.js +78 -0
  27. package/dist/chunk-ZCMZJKGN.js.map +1 -0
  28. package/dist/client.d.ts +63 -0
  29. package/dist/client.js +260 -0
  30. package/dist/client.js.map +1 -0
  31. package/dist/cloudflare/index.d.ts +15 -2
  32. package/dist/cloudflare/index.js +413 -45
  33. package/dist/cloudflare/index.js.map +1 -1
  34. package/dist/d1/config.d.ts +41 -0
  35. package/dist/d1/config.js +102 -0
  36. package/dist/d1/config.js.map +1 -0
  37. package/dist/d1/index.d.ts +80 -0
  38. package/dist/d1/index.js +218 -0
  39. package/dist/d1/index.js.map +1 -0
  40. package/dist/d1/response-lease.d.ts +9 -0
  41. package/dist/d1/response-lease.js +44 -0
  42. package/dist/d1/response-lease.js.map +1 -0
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.js +3 -616
  45. package/dist/index.js.map +1 -1
  46. package/dist/profile--LBtbQI_.d.ts +30 -0
  47. package/dist/response-lease-DeeM-ofO.d.ts +19 -0
  48. package/dist/response-lease.d.ts +7 -0
  49. package/dist/response-lease.js +14 -0
  50. package/dist/response-lease.js.map +1 -0
  51. package/dist/response-warmup-BWQvnT1G.d.ts +38 -0
  52. package/dist/scoped-read.d.ts +12 -0
  53. package/dist/scoped-read.js +30 -0
  54. package/dist/scoped-read.js.map +1 -0
  55. package/dist/{types-DwtU0KpX.d.ts → types-CtErcz2a.d.ts} +25 -1
  56. package/docs/cache-contract.md +49 -1
  57. package/package.json +31 -2
package/dist/client.js ADDED
@@ -0,0 +1,260 @@
1
+ import { needsFreshness } from './chunk-JPK2AF7X.js';
2
+ import { mergeD1Bookmarks, parseD1Bookmarks, D1_BOOKMARK_HEADER, serializeD1Bookmarks } from './chunk-ZBYAKDNZ.js';
3
+ export { D1_BOOKMARK_HEADER, parseD1Bookmarks, serializeD1Bookmarks } from './chunk-ZBYAKDNZ.js';
4
+
5
+ // src/client.ts
6
+ function createSingleFlight() {
7
+ const pending = /* @__PURE__ */ new Map();
8
+ return {
9
+ run(key, load) {
10
+ const existing = pending.get(key);
11
+ if (existing) return existing;
12
+ const promise = Promise.resolve().then(load);
13
+ pending.set(key, promise);
14
+ void promise.then(() => {
15
+ if (pending.get(key) === promise) pending.delete(key);
16
+ }, () => {
17
+ if (pending.get(key) === promise) pending.delete(key);
18
+ });
19
+ return promise;
20
+ },
21
+ forget(key) {
22
+ pending.delete(key);
23
+ }
24
+ };
25
+ }
26
+ function createIntentWarmup(cooldownMs = 6e4, now = monotonicNow) {
27
+ const duration = Number.isFinite(cooldownMs) && cooldownMs > 0 ? cooldownMs : 6e4;
28
+ const warmed = /* @__PURE__ */ new Map();
29
+ let scope = "";
30
+ let generation = 0;
31
+ let running = false;
32
+ let queued;
33
+ const drain = () => {
34
+ if (running || !queued) return;
35
+ const task = queued;
36
+ queued = void 0;
37
+ if ((warmed.get(task.key) ?? 0) > now()) return;
38
+ running = true;
39
+ const isCurrent = () => task.generation === generation && scope !== "";
40
+ void Promise.resolve().then(() => isCurrent() ? task.load(isCurrent) : false).then((ok) => {
41
+ if (ok && task.generation === generation) warmed.set(task.key, now() + duration);
42
+ }, () => {
43
+ }).finally(() => {
44
+ running = false;
45
+ drain();
46
+ });
47
+ };
48
+ return {
49
+ setScope(next) {
50
+ if (scope === next) return;
51
+ scope = next;
52
+ generation++;
53
+ queued = void 0;
54
+ warmed.clear();
55
+ },
56
+ invalidate() {
57
+ generation++;
58
+ queued = void 0;
59
+ warmed.clear();
60
+ },
61
+ warm(key, load) {
62
+ if (!scope || !key || (warmed.get(key) ?? 0) > now()) return;
63
+ queued = { key, load, generation };
64
+ drain();
65
+ }
66
+ };
67
+ }
68
+ function usesGenerationCookie(policy, url, transport) {
69
+ if (policy.freshnessCookieMode !== "generation" || !policy.credentialHeaders?.some((name) => name.toLowerCase() === "cookie") || transport?.withCredentials !== true || !transport.origin || transport.baseUrl === void 0) return false;
70
+ try {
71
+ const origin = new URL(transport.origin).origin;
72
+ const base = new URL(transport.baseUrl, origin);
73
+ return origin !== "null" && new URL(url, base).origin === origin;
74
+ } catch {
75
+ return false;
76
+ }
77
+ }
78
+ function createReadFreshness(policy, now = Date.now) {
79
+ const until = /* @__PURE__ */ new Map();
80
+ const prune = (time) => {
81
+ for (const [scope, deadline] of until) if (deadline <= time) until.delete(scope);
82
+ };
83
+ return {
84
+ headers(scope, method) {
85
+ const time = now();
86
+ prune(time);
87
+ if (method.toUpperCase() !== "GET" || !until.has(scope)) return {};
88
+ return { "Cache-Control": "no-cache", ...policy.freshnessHeader ? { [policy.freshnessHeader]: "1" } : {} };
89
+ },
90
+ observe(scope, method, url, transport) {
91
+ const time = now();
92
+ prune(time);
93
+ let pathname;
94
+ try {
95
+ pathname = new URL(url, "https://cache.invalid").pathname;
96
+ } catch {
97
+ pathname = "";
98
+ }
99
+ if (needsFreshness(method, pathname, policy.freshnessCookieExcludedPaths) && !usesGenerationCookie(policy, url, transport)) until.set(scope, time + (Number.isInteger(policy.maxSeconds) && policy.maxSeconds !== void 0 && policy.maxSeconds >= 1 && policy.maxSeconds <= 300 ? policy.maxSeconds : 5) * 1e3);
100
+ }
101
+ };
102
+ }
103
+ function monotonicNow() {
104
+ const clock = Reflect.get(globalThis, "performance");
105
+ if (clock && typeof clock === "object") {
106
+ const read = Reflect.get(clock, "now");
107
+ if (typeof read === "function") {
108
+ const value = Reflect.apply(read, clock, []);
109
+ if (typeof value === "number" && Number.isFinite(value)) return value;
110
+ }
111
+ }
112
+ return Date.now();
113
+ }
114
+ function createRevalidationWindow(windowMs, now = monotonicNow) {
115
+ const duration = Number.isFinite(windowMs) && windowMs > 0 ? windowMs : 3e5;
116
+ const scopes = /* @__PURE__ */ new Map();
117
+ return {
118
+ remaining(scope) {
119
+ const time = now();
120
+ let deadline = scopes.get(scope);
121
+ if (deadline === void 0) {
122
+ deadline = time + duration;
123
+ scopes.set(scope, deadline);
124
+ }
125
+ return Math.max(0, deadline - time);
126
+ },
127
+ take(scope) {
128
+ const time = now();
129
+ const deadline = scopes.get(scope);
130
+ if (deadline !== void 0 && time < deadline) return false;
131
+ scopes.set(scope, time + duration);
132
+ return true;
133
+ }
134
+ };
135
+ }
136
+ var mutationChannelName = "dee-wan-cache-invalidation-v1";
137
+ var validScope = (scope) => /^[A-Za-z0-9:_-]{1,256}$/.test(scope);
138
+ var validMethod = (method) => /^[!#$%&'*+.^_`|~0-9A-Z-]{1,32}$/.test(method);
139
+ var validPathname = (pathname) => pathname.startsWith("/") && pathname.length <= 2048 && ![...pathname].some((character) => character === "?" || character === "#" || character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127);
140
+ function invalidationChannel(value) {
141
+ return !!value && typeof value === "object" && Reflect.get(value, "name") === mutationChannelName && ["postMessage", "addEventListener", "removeEventListener", "close"].every((name) => typeof Reflect.get(value, name) === "function");
142
+ }
143
+ function browserInvalidationChannel() {
144
+ const document = Reflect.get(globalThis, "document");
145
+ if (!document || typeof document !== "object") return void 0;
146
+ const constructor = Reflect.get(globalThis, "BroadcastChannel");
147
+ if (typeof constructor !== "function") return void 0;
148
+ try {
149
+ const channel = Reflect.construct(constructor, [mutationChannelName]);
150
+ return invalidationChannel(channel) ? channel : void 0;
151
+ } catch {
152
+ return void 0;
153
+ }
154
+ }
155
+ function createMutationInvalidation(policy, options = {}) {
156
+ const supplied = options.channel === void 0 ? browserInvalidationChannel() : options.channel;
157
+ const channel = invalidationChannel(supplied) ? supplied : void 0;
158
+ const listeners = /* @__PURE__ */ new Map();
159
+ let disposed = false;
160
+ const notify = (event) => {
161
+ for (const listener of listeners.get(event.scope) ?? []) {
162
+ try {
163
+ listener({ ...event });
164
+ } catch {
165
+ }
166
+ }
167
+ };
168
+ const receive = ({ data }) => {
169
+ try {
170
+ if (disposed || !data || typeof data !== "object" || Object.keys(data).sort().join(",") !== "method,pathname,scope") return;
171
+ const scope = Reflect.get(data, "scope");
172
+ const method = Reflect.get(data, "method");
173
+ const pathname = Reflect.get(data, "pathname");
174
+ if (typeof scope !== "string" || !validScope(scope) || typeof method !== "string" || !validMethod(method) || typeof pathname !== "string" || !validPathname(pathname) || !needsFreshness(method, pathname, policy.freshnessCookieExcludedPaths)) return;
175
+ notify({ scope, method, pathname });
176
+ } catch {
177
+ }
178
+ };
179
+ channel?.addEventListener("message", receive);
180
+ return {
181
+ publish(scope, method, url) {
182
+ if (disposed || !validScope(scope)) return;
183
+ const normalized = method.toUpperCase();
184
+ if (!validMethod(normalized)) return;
185
+ let pathname;
186
+ try {
187
+ pathname = new URL(url, "https://cache.invalid").pathname;
188
+ } catch {
189
+ return;
190
+ }
191
+ if (!validPathname(pathname) || !needsFreshness(normalized, pathname, policy.freshnessCookieExcludedPaths)) return;
192
+ const event = { scope, method: normalized, pathname };
193
+ notify(event);
194
+ try {
195
+ channel?.postMessage({ scope, method: normalized, pathname });
196
+ } catch {
197
+ }
198
+ },
199
+ subscribe(scope, listener) {
200
+ if (disposed || !validScope(scope)) return () => {
201
+ };
202
+ let group = listeners.get(scope);
203
+ if (!group) {
204
+ group = /* @__PURE__ */ new Set();
205
+ listeners.set(scope, group);
206
+ }
207
+ group.add(listener);
208
+ const subscribed = group;
209
+ return () => {
210
+ subscribed.delete(listener);
211
+ if (subscribed.size === 0 && listeners.get(scope) === subscribed) listeners.delete(scope);
212
+ };
213
+ },
214
+ dispose() {
215
+ if (disposed) return;
216
+ disposed = true;
217
+ listeners.clear();
218
+ channel?.removeEventListener("message", receive);
219
+ channel?.close();
220
+ }
221
+ };
222
+ }
223
+ function createD1BookmarkFetch(fetcher = fetch, options = {}) {
224
+ const origins = /* @__PURE__ */ new Map();
225
+ return async (input, init) => {
226
+ const request = new Request(input, init);
227
+ const origin = new URL(request.url).origin;
228
+ const bookmarks = origins.get(origin) ?? {};
229
+ if (!origins.has(origin)) origins.set(origin, bookmarks);
230
+ const key = `dee-wan:d1-bookmarks:${origin}`;
231
+ const mergeStored = () => {
232
+ try {
233
+ const saved = parseD1Bookmarks(options.storage?.getItem(key) ?? null);
234
+ const combined = { ...bookmarks };
235
+ if (mergeD1Bookmarks(combined, saved)) Object.assign(bookmarks, combined);
236
+ } catch {
237
+ }
238
+ };
239
+ mergeStored();
240
+ const headers = new Headers(request.headers);
241
+ const outgoing = { ...bookmarks };
242
+ if (!mergeD1Bookmarks(outgoing, parseD1Bookmarks(headers.get(D1_BOOKMARK_HEADER)))) throw new RangeError("D1 bookmark capacity exceeded");
243
+ const encoded = serializeD1Bookmarks(outgoing);
244
+ if (encoded && encoded !== "{}") headers.set(D1_BOOKMARK_HEADER, encoded);
245
+ else headers.delete(D1_BOOKMARK_HEADER);
246
+ const response = await fetcher(new Request(request, { headers }));
247
+ mergeStored();
248
+ if (!mergeD1Bookmarks(bookmarks, parseD1Bookmarks(response.headers.get(D1_BOOKMARK_HEADER)))) throw new RangeError("D1 bookmark capacity exceeded");
249
+ try {
250
+ const value = serializeD1Bookmarks(bookmarks);
251
+ if (value && value !== "{}") options.storage?.setItem(key, value);
252
+ } catch {
253
+ }
254
+ return response;
255
+ };
256
+ }
257
+
258
+ export { createD1BookmarkFetch, createIntentWarmup, createMutationInvalidation, createReadFreshness, createRevalidationWindow, createSingleFlight };
259
+ //# sourceMappingURL=client.js.map
260
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["import type { D1CacheProfile } from './d1/profile';\nimport { needsFreshness } from './d1/read-freshness-policy';\n\nexport function createSingleFlight<Key, Value>() {\n const pending = new Map<Key, Promise<Value>>();\n return {\n run(key: Key, load: () => Promise<Value>): Promise<Value> {\n const existing = pending.get(key);\n if (existing) return existing;\n const promise = Promise.resolve().then(load);\n pending.set(key, promise);\n void promise.then(() => { if (pending.get(key) === promise) pending.delete(key); }, () => { if (pending.get(key) === promise) pending.delete(key); });\n return promise;\n },\n forget(key: Key): void { pending.delete(key); },\n };\n}\n\nexport function createIntentWarmup(cooldownMs = 60_000, now: () => number = monotonicNow) {\n const duration = Number.isFinite(cooldownMs) && cooldownMs > 0 ? cooldownMs : 60_000;\n const warmed = new Map<string, number>();\n let scope = '';\n let generation = 0;\n let running = false;\n let queued: { key: string; load: (isCurrent: () => boolean) => Promise<boolean>; generation: number } | undefined;\n const drain = () => {\n if (running || !queued) return;\n const task = queued;\n queued = undefined;\n if ((warmed.get(task.key) ?? 0) > now()) return;\n running = true;\n const isCurrent = () => task.generation === generation && scope !== '';\n void Promise.resolve().then(() => isCurrent() ? task.load(isCurrent) : false).then((ok) => {\n if (ok && task.generation === generation) warmed.set(task.key, now() + duration);\n }, () => {}).finally(() => { running = false; drain(); });\n };\n return {\n setScope(next: string): void {\n if (scope === next) return;\n scope = next;\n generation++;\n queued = undefined;\n warmed.clear();\n },\n invalidate(): void { generation++; queued = undefined; warmed.clear(); },\n warm(key: string, load: (isCurrent: () => boolean) => Promise<boolean>): void {\n if (!scope || !key || (warmed.get(key) ?? 0) > now()) return;\n queued = { key, load, generation };\n drain();\n },\n };\n}\n\ntype ReadLeasePolicy = Pick<NonNullable<D1CacheProfile['readResponseLease']>, 'freshnessHeader' | 'freshnessCookieExcludedPaths' | 'maxSeconds' | 'freshnessCookieMode'> & Partial<Pick<NonNullable<D1CacheProfile['readResponseLease']>, 'credentialHeaders'>>;\n\nexport interface FreshnessTransport { origin?: string; baseUrl?: string; withCredentials?: boolean }\n\nfunction usesGenerationCookie(policy: ReadLeasePolicy, url: string, transport?: FreshnessTransport): boolean {\n if (policy.freshnessCookieMode !== 'generation' || !policy.credentialHeaders?.some((name) => name.toLowerCase() === 'cookie') || transport?.withCredentials !== true || !transport.origin || transport.baseUrl === undefined) return false;\n try {\n const origin = new URL(transport.origin).origin;\n const base = new URL(transport.baseUrl, origin);\n return origin !== 'null' && new URL(url, base).origin === origin;\n } catch { return false; }\n}\n\nexport function createReadFreshness(policy: ReadLeasePolicy, now: () => number = Date.now) {\n const until = new Map<string, number>();\n const prune = (time: number) => { for (const [scope, deadline] of until) if (deadline <= time) until.delete(scope); };\n return {\n headers(scope: string, method: string): Record<string, string> {\n const time = now();\n prune(time);\n if (method.toUpperCase() !== 'GET' || !until.has(scope)) return {};\n return { 'Cache-Control':'no-cache', ...(policy.freshnessHeader ? { [policy.freshnessHeader]:'1' } : {}) };\n },\n observe(scope: string, method: string, url: string, transport?: FreshnessTransport): void {\n const time = now();\n prune(time);\n let pathname: string;\n try { pathname = new URL(url, 'https://cache.invalid').pathname; } catch { pathname = ''; }\n if (needsFreshness(method, pathname, policy.freshnessCookieExcludedPaths) && !usesGenerationCookie(policy, url, transport)) until.set(scope, time + (Number.isInteger(policy.maxSeconds) && policy.maxSeconds !== undefined && policy.maxSeconds >= 1 && policy.maxSeconds <= 300 ? policy.maxSeconds : 5) * 1000);\n },\n };\n}\n\nfunction monotonicNow(): number {\n const clock: unknown = Reflect.get(globalThis, 'performance');\n if (clock && typeof clock === 'object') {\n const read: unknown = Reflect.get(clock, 'now');\n if (typeof read === 'function') {\n const value: unknown = Reflect.apply(read, clock, []);\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n }\n }\n return Date.now();\n}\n\nexport function createRevalidationWindow(windowMs: number, now: () => number = monotonicNow) {\n const duration = Number.isFinite(windowMs) && windowMs > 0 ? windowMs : 300_000;\n const scopes = new Map<string, number>();\n return {\n remaining(scope: string): number {\n const time = now();\n let deadline = scopes.get(scope);\n if (deadline === undefined) { deadline = time + duration; scopes.set(scope, deadline); }\n return Math.max(0, deadline - time);\n },\n take(scope: string): boolean {\n const time = now();\n const deadline = scopes.get(scope);\n if (deadline !== undefined && time < deadline) return false;\n scopes.set(scope, time + duration);\n return true;\n },\n };\n}\n\nexport interface MutationInvalidationEvent {\n scope: string;\n method: string;\n pathname: string;\n}\n\nexport interface MutationInvalidationChannel {\n readonly name: string;\n postMessage(value: MutationInvalidationEvent): void;\n addEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n removeEventListener(type: 'message', listener: (event: { data: unknown }) => void): void;\n close(): void;\n}\n\nconst mutationChannelName = 'dee-wan-cache-invalidation-v1';\nconst validScope = (scope: string): boolean => /^[A-Za-z0-9:_-]{1,256}$/.test(scope);\nconst validMethod = (method: string): boolean => /^[!#$%&'*+.^_`|~0-9A-Z-]{1,32}$/.test(method);\nconst validPathname = (pathname: string): boolean => pathname.startsWith('/') && pathname.length <= 2048 && ![...pathname].some((character) => character === '?' || character === '#' || character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127);\n\nfunction invalidationChannel(value: unknown): value is MutationInvalidationChannel {\n return !!value && typeof value === 'object' && Reflect.get(value, 'name') === mutationChannelName && ['postMessage', 'addEventListener', 'removeEventListener', 'close'].every((name) => typeof Reflect.get(value, name) === 'function');\n}\n\nfunction browserInvalidationChannel(): MutationInvalidationChannel | undefined {\n const document: unknown = Reflect.get(globalThis, 'document');\n if (!document || typeof document !== 'object') return undefined;\n const constructor: unknown = Reflect.get(globalThis, 'BroadcastChannel');\n if (typeof constructor !== 'function') return undefined;\n try { const channel: unknown = Reflect.construct(constructor, [mutationChannelName]); return invalidationChannel(channel) ? channel : undefined; } catch { return undefined; }\n}\n\nexport function createMutationInvalidation(policy: Pick<NonNullable<D1CacheProfile['readResponseLease']>, 'freshnessCookieExcludedPaths'>, options: { channel?: MutationInvalidationChannel | null } = {}) {\n const supplied = options.channel === undefined ? browserInvalidationChannel() : options.channel;\n const channel = invalidationChannel(supplied) ? supplied : undefined;\n const listeners = new Map<string, Set<(event: MutationInvalidationEvent) => void>>();\n let disposed = false;\n const notify = (event: MutationInvalidationEvent) => {\n for (const listener of listeners.get(event.scope) ?? []) {\n try { listener({ ...event }); } catch { /* Subscribers are independent. */ }\n }\n };\n const receive = ({ data }: { data: unknown }) => {\n try {\n if (disposed || !data || typeof data !== 'object' || Object.keys(data).sort().join(',') !== 'method,pathname,scope') return;\n const scope: unknown = Reflect.get(data, 'scope');\n const method: unknown = Reflect.get(data, 'method');\n const pathname: unknown = Reflect.get(data, 'pathname');\n if (typeof scope !== 'string' || !validScope(scope) || typeof method !== 'string' || !validMethod(method) || typeof pathname !== 'string' || !validPathname(pathname) || !needsFreshness(method, pathname, policy.freshnessCookieExcludedPaths)) return;\n notify({ scope, method, pathname });\n } catch { /* Ignore malformed messages. */ }\n };\n channel?.addEventListener('message', receive);\n return {\n publish(scope: string, method: string, url: string): void {\n if (disposed || !validScope(scope)) return;\n const normalized = method.toUpperCase();\n if (!validMethod(normalized)) return;\n let pathname: string;\n try { pathname = new URL(url, 'https://cache.invalid').pathname; } catch { return; }\n if (!validPathname(pathname) || !needsFreshness(normalized, pathname, policy.freshnessCookieExcludedPaths)) return;\n const event = { scope, method:normalized, pathname };\n notify(event);\n try { channel?.postMessage({ scope, method:normalized, pathname }); } catch { /* Local notification remains available. */ }\n },\n subscribe(scope: string, listener: (event: MutationInvalidationEvent) => void): () => void {\n if (disposed || !validScope(scope)) return () => {};\n let group = listeners.get(scope);\n if (!group) { group = new Set(); listeners.set(scope, group); }\n group.add(listener);\n const subscribed = group;\n return () => { subscribed.delete(listener); if (subscribed.size === 0 && listeners.get(scope) === subscribed) listeners.delete(scope); };\n },\n dispose(): void {\n if (disposed) return;\n disposed = true;\n listeners.clear();\n channel?.removeEventListener('message', receive);\n channel?.close();\n },\n };\n}\n\nexport { D1_BOOKMARK_HEADER, parseD1Bookmarks, serializeD1Bookmarks } from './d1/bookmarks';\n\nimport { D1_BOOKMARK_HEADER, mergeD1Bookmarks, parseD1Bookmarks, serializeD1Bookmarks } from './d1/bookmarks';\n\nexport interface D1BookmarkStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n}\n\nexport function createD1BookmarkFetch(fetcher: typeof fetch = fetch, options: { storage?: D1BookmarkStorage } = {}): typeof fetch {\n const origins = new Map<string, Record<string, string>>();\n return async (input, init) => {\n const request = new Request(input, init);\n const origin = new URL(request.url).origin;\n const bookmarks = origins.get(origin) ?? {};\n if (!origins.has(origin)) origins.set(origin, bookmarks);\n const key = `dee-wan:d1-bookmarks:${origin}`;\n const mergeStored = () => {\n try {\n const saved = parseD1Bookmarks(options.storage?.getItem(key) ?? null);\n const combined = { ...bookmarks };\n if (mergeD1Bookmarks(combined, saved)) Object.assign(bookmarks, combined);\n } catch { /* Storage is optional. */ }\n };\n mergeStored();\n const headers = new Headers(request.headers);\n const outgoing = { ...bookmarks };\n if (!mergeD1Bookmarks(outgoing, parseD1Bookmarks(headers.get(D1_BOOKMARK_HEADER)))) throw new RangeError('D1 bookmark capacity exceeded');\n const encoded = serializeD1Bookmarks(outgoing);\n if (encoded && encoded !== '{}') headers.set(D1_BOOKMARK_HEADER, encoded);\n else headers.delete(D1_BOOKMARK_HEADER);\n const response = await fetcher(new Request(request, { headers }));\n mergeStored();\n if (!mergeD1Bookmarks(bookmarks, parseD1Bookmarks(response.headers.get(D1_BOOKMARK_HEADER)))) throw new RangeError('D1 bookmark capacity exceeded');\n try {\n const value = serializeD1Bookmarks(bookmarks);\n if (value && value !== '{}') options.storage?.setItem(key, value);\n } catch { /* Storage is optional. */ }\n return response;\n };\n}\n"]}
@@ -1,9 +1,11 @@
1
1
  import { DurableObject } from 'cloudflare:workers';
2
- import { R as ReadRequest, a as ReadResponse, W as WriteRequest, b as WriteResult, c as ReleaseRequest, B as BeginWriteRequest, E as EndWriteRequest, C as CacheStore } from '../types-DwtU0KpX.js';
2
+ import { I as InspectFencesRequest, a as InspectFencesResponse, R as ReadRequest, b as ReadResponse, W as WriteRequest, c as WriteResult, d as ReleaseRequest, B as BeginWriteRequest, E as EndWriteRequest, C as CacheStore } from '../types-CtErcz2a.js';
3
+ export { a as ReadResponseWarmupContext, R as ReadResponseWarmupOptions, b as ReadResponseWarmupTarget, c as createResponseWarmup } from '../response-warmup-BWQvnT1G.js';
3
4
 
4
5
  declare class CacheCoordinator<Env = unknown> extends DurableObject<Env> {
5
6
  private readonly core;
6
7
  constructor(ctx: DurableObjectState, env: Env);
8
+ inspectFences(request: InspectFencesRequest): InspectFencesResponse;
7
9
  read(request: ReadRequest): ReadResponse;
8
10
  write(request: WriteRequest): WriteResult;
9
11
  release(request: ReleaseRequest): void;
@@ -23,4 +25,15 @@ interface DurableObjectStoreOptions {
23
25
 
24
26
  declare function createDurableObjectStore<Env>(namespace: DurableObjectNamespace<CacheCoordinator<Env>>, options: DurableObjectStoreOptions): CacheStore;
25
27
 
26
- export { CacheCoordinator, type CoordinatorLocationHint, type DurableObjectStoreOptions, createDurableObjectStore };
28
+ interface RegionalStoreOptions {
29
+ namespace: string;
30
+ generation: string;
31
+ ttlMs: number;
32
+ enabled?: boolean;
33
+ cache?: () => Pick<Cache, "match" | "put">;
34
+ now?: () => number;
35
+ waitUntil?: (promise: Promise<unknown>) => void;
36
+ }
37
+ declare function createRegionalStore(store: CacheStore, options: RegionalStoreOptions): CacheStore;
38
+
39
+ export { CacheCoordinator, type CoordinatorLocationHint, type DurableObjectStoreOptions, type RegionalStoreOptions, createDurableObjectStore, createRegionalStore };