Skip to content

Commit e3e536f

Browse files
Taz Singhclaude
andcommitted
Include dist/ in repo for git URL installs
Yarn 4 doesn't support git deps with build steps, so we include the pre-built dist folder for consumers using git URLs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 00377ec commit e3e536f

File tree

5 files changed

+417
-1
lines changed

5 files changed

+417
-1
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
node_modules
2-
dist
32
coverage

dist/workerSwr.cjs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
"use strict";
2+
var __defProp = Object.defineProperty;
3+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4+
var __getOwnPropNames = Object.getOwnPropertyNames;
5+
var __hasOwnProp = Object.prototype.hasOwnProperty;
6+
var __export = (target, all) => {
7+
for (var name in all)
8+
__defProp(target, name, { get: all[name], enumerable: true });
9+
};
10+
var __copyProps = (to, from, except, desc) => {
11+
if (from && typeof from === "object" || typeof from === "function") {
12+
for (let key of __getOwnPropNames(from))
13+
if (!__hasOwnProp.call(to, key) && key !== except)
14+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15+
}
16+
return to;
17+
};
18+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19+
20+
// src/workerSwr.ts
21+
var workerSwr_exports = {};
22+
__export(workerSwr_exports, {
23+
workerSwr: () => workerSwr
24+
});
25+
module.exports = __toCommonJS(workerSwr_exports);
26+
var workerSwr = ({
27+
fetcher,
28+
cacheName = "default",
29+
wait = false,
30+
cacheControl,
31+
vary,
32+
keyGenerator,
33+
swr = {}
34+
}) => {
35+
if (!globalThis.caches) {
36+
throw new Error("workerSwr requires globalThis.caches to be available");
37+
}
38+
const swrConfig = {
39+
staleAtHeaderName: "x-edge-cache-stale-at",
40+
staleErrorAtHeaderName: "x-edge-cache-stale-error-at",
41+
statusHeaderName: "x-edge-cache-status",
42+
defaultStaleSeconds: 60,
43+
...swr
44+
};
45+
const cacheControlDirectives = cacheControl?.split(",").map((d) => d.trim().toLowerCase());
46+
const varyDirectives = Array.isArray(vary) ? vary : vary?.split(",").map((d) => d.trim());
47+
if (varyDirectives?.includes("*")) {
48+
throw new Error(
49+
'workerSwr vary configuration cannot include "*", as it disallows effective caching.'
50+
);
51+
}
52+
const cache = globalThis.caches.open(cacheName);
53+
const processResponse = (response) => {
54+
const upstreamCacheControl = response.headers.get("cache-control");
55+
if (upstreamCacheControl) {
56+
const directives = upstreamCacheControl.split(",").map((d) => d.trim().toLowerCase());
57+
for (const directive of directives) {
58+
const [name, value] = directive.split("=", 2);
59+
if (name === "stale-while-revalidate" && value) {
60+
response.headers.set(
61+
swrConfig.staleAtHeaderName,
62+
(Date.now() + parseInt(value, 10) * 1e3).toString()
63+
);
64+
}
65+
if (name === "stale-if-error" && value) {
66+
response.headers.set(
67+
swrConfig.staleErrorAtHeaderName,
68+
(Date.now() + parseInt(value, 10) * 1e3).toString()
69+
);
70+
}
71+
}
72+
}
73+
if (cacheControlDirectives) {
74+
const existingDirectives = response.headers.get("cache-control")?.split(",").map((d) => d.trim().split("=", 1)[0]) ?? [];
75+
for (const directive of cacheControlDirectives) {
76+
const [name, value] = directive.trim().split("=", 2);
77+
if (!existingDirectives.includes(name)) {
78+
response.headers.append(
79+
"cache-control",
80+
`${name}${value ? `=${value}` : ""}`
81+
);
82+
}
83+
if (name === "stale-while-revalidate") {
84+
response.headers.set(
85+
swrConfig.staleAtHeaderName,
86+
(Date.now() + parseInt(value, 10) * 1e3).toString()
87+
);
88+
}
89+
if (name === "stale-if-error") {
90+
response.headers.set(
91+
swrConfig.staleErrorAtHeaderName,
92+
(Date.now() + parseInt(value, 10) * 1e3).toString()
93+
);
94+
}
95+
}
96+
}
97+
if (varyDirectives) {
98+
const existingVary = response.headers.get("vary")?.split(",").map((d) => d.trim()) ?? [];
99+
const vary2 = Array.from(
100+
new Set(
101+
[...existingVary, ...varyDirectives].map((d) => d.toLowerCase())
102+
)
103+
).sort();
104+
if (vary2.includes("*")) {
105+
response.headers.set("vary", "*");
106+
} else {
107+
response.headers.set("vary", vary2.join(", "));
108+
}
109+
}
110+
if (!response.headers.has(swrConfig.staleAtHeaderName)) {
111+
response.headers.set(
112+
swrConfig.staleAtHeaderName,
113+
(Date.now() + swrConfig.defaultStaleSeconds * 1e3).toString()
114+
);
115+
}
116+
if (!response.headers.has(swrConfig.staleErrorAtHeaderName) && swrConfig.defaultStaleErrorSeconds) {
117+
response.headers.set(
118+
swrConfig.staleErrorAtHeaderName,
119+
(Date.now() + swrConfig.defaultStaleErrorSeconds * 1e3).toString()
120+
);
121+
}
122+
};
123+
return async (request, env, ctx) => {
124+
if (request.method !== "GET") {
125+
return await fetcher(request);
126+
}
127+
const resolvedCache = await cache;
128+
const key = keyGenerator ? await keyGenerator(request) : request.url;
129+
const cachedResponse = await resolvedCache.match(key);
130+
if (cachedResponse) {
131+
const response2 = new Response(cachedResponse.body, cachedResponse);
132+
const staleAt = response2.headers.get(swrConfig.staleAtHeaderName);
133+
const isStale = !staleAt || Date.now() > parseInt(staleAt, 10);
134+
if (isStale) {
135+
response2.headers.set(swrConfig.statusHeaderName, "REVALIDATING");
136+
const revalidate = async () => {
137+
try {
138+
const revalidationRequest = new Request(request, {
139+
headers: new Headers(request.headers)
140+
});
141+
revalidationRequest.headers.delete("if-none-match");
142+
revalidationRequest.headers.delete("if-modified-since");
143+
let newResponse = await fetcher(revalidationRequest);
144+
newResponse = new Response(newResponse.body, newResponse);
145+
if (!newResponse.ok) {
146+
throw new Error(
147+
`Revalidation failed with status ${newResponse.status}`
148+
);
149+
}
150+
processResponse(newResponse);
151+
return await resolvedCache.put(key, newResponse.clone());
152+
} catch (error) {
153+
const staleErrorAt = response2.headers.get(
154+
swrConfig.staleErrorAtHeaderName
155+
);
156+
if (staleErrorAt && Date.now() < new Date(parseInt(staleErrorAt, 10)).getTime()) {
157+
return response2;
158+
}
159+
throw error;
160+
}
161+
};
162+
if (wait) {
163+
await revalidate();
164+
} else {
165+
ctx.waitUntil(revalidate());
166+
}
167+
return response2;
168+
}
169+
response2.headers.set(swrConfig.statusHeaderName, "HIT");
170+
return response2;
171+
}
172+
const fetchRequest = new Request(request, {
173+
headers: new Headers(request.headers)
174+
});
175+
fetchRequest.headers.delete("if-none-match");
176+
fetchRequest.headers.delete("if-modified-since");
177+
let response = await fetcher(fetchRequest);
178+
response = new Response(response.body, response);
179+
processResponse(response);
180+
response.headers.set(swrConfig.statusHeaderName, "MISS");
181+
if (!response.ok) {
182+
return response;
183+
}
184+
try {
185+
const responseToCache = response.clone();
186+
const cachePromise = resolvedCache.put(key, responseToCache);
187+
if (wait) {
188+
await cachePromise;
189+
} else {
190+
ctx.waitUntil(cachePromise);
191+
}
192+
} catch (error) {
193+
}
194+
return response;
195+
};
196+
};
197+
// Annotate the CommonJS export names for ESM import in node:
198+
0 && (module.exports = {
199+
workerSwr
200+
});

dist/workerSwr.d.cts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { RequestInit, ExecutionContext } from '@cloudflare/workers-types';
2+
3+
type FetchFn = (request: Request, init?: RequestInit) => Promise<Response>;
4+
interface WorkerSwrOptions {
5+
fetcher: FetchFn;
6+
cacheName?: string;
7+
wait?: boolean;
8+
cacheControl?: string;
9+
vary?: string | string[];
10+
keyGenerator?: (request: Request) => Promise<string> | string;
11+
swr?: {
12+
staleAtHeaderName?: string;
13+
staleErrorAtHeaderName?: string;
14+
statusHeaderName?: string;
15+
defaultStaleSeconds?: number;
16+
defaultStaleErrorSeconds?: number;
17+
};
18+
}
19+
declare const workerSwr: ({ fetcher, cacheName, wait, cacheControl, vary, keyGenerator, swr, }: WorkerSwrOptions) => ((request: Request, env: any, ctx: ExecutionContext) => Promise<Response>);
20+
21+
export { workerSwr };

dist/workerSwr.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { RequestInit, ExecutionContext } from '@cloudflare/workers-types';
2+
3+
type FetchFn = (request: Request, init?: RequestInit) => Promise<Response>;
4+
interface WorkerSwrOptions {
5+
fetcher: FetchFn;
6+
cacheName?: string;
7+
wait?: boolean;
8+
cacheControl?: string;
9+
vary?: string | string[];
10+
keyGenerator?: (request: Request) => Promise<string> | string;
11+
swr?: {
12+
staleAtHeaderName?: string;
13+
staleErrorAtHeaderName?: string;
14+
statusHeaderName?: string;
15+
defaultStaleSeconds?: number;
16+
defaultStaleErrorSeconds?: number;
17+
};
18+
}
19+
declare const workerSwr: ({ fetcher, cacheName, wait, cacheControl, vary, keyGenerator, swr, }: WorkerSwrOptions) => ((request: Request, env: any, ctx: ExecutionContext) => Promise<Response>);
20+
21+
export { workerSwr };

0 commit comments

Comments
 (0)