Skip to content

Commit 63a58f6

Browse files
authored
Proxy To Docs On Netlify (#491)
* Proxy To Docs On Netlify * Update GRAPHGEN_URL fallback to new URL * update project list * handle relative locations in proxy for netlify * dedup proxy routes: derive pattern from prefix proxyRoute now auto-generates the route pattern from the prefix (`/${prefix}(.*)`) when no explicit pattern is provided, so callers just pass the proxy config object directly. * try/catch * always copy headers * with retries and backoff
1 parent d35df35 commit 63a58f6

4 files changed

Lines changed: 113 additions & 93 deletions

File tree

.github/workflows/deploy.yaml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747

4848
- name: Download Staticalize
4949
run: |
50-
wget https://github.com/thefrontside/staticalize/releases/download/v0.2.6/staticalize-linux.tar.gz \
50+
wget https://github.com/thefrontside/staticalize/releases/download/v0.2.7/staticalize-linux.tar.gz \
5151
-O /tmp/staticalize-linux.tar.gz
5252
tar -xzf /tmp/staticalize-linux.tar.gz -C /usr/local/bin
5353
chmod +x /usr/local/bin/staticalize-linux
@@ -57,7 +57,9 @@ jobs:
5757
staticalize-linux \
5858
--site=http://127.0.0.1:8005 \
5959
--output=built \
60-
--base=https://frontside.com
60+
--base=https://frontside.com \
61+
--concurrency=25 \
62+
--retries=5
6163
6264
- name: Deploy Preview to Netlify
6365
id: netlify
@@ -130,7 +132,7 @@ jobs:
130132

131133
- name: Download Staticalize
132134
run: |
133-
wget https://github.com/thefrontside/staticalize/releases/download/v0.2.6/staticalize-linux.tar.gz \
135+
wget https://github.com/thefrontside/staticalize/releases/download/v0.2.7/staticalize-linux.tar.gz \
134136
-O /tmp/staticalize-linux.tar.gz
135137
tar -xzf /tmp/staticalize-linux.tar.gz -C /usr/local/bin
136138
chmod +x /usr/local/bin/staticalize-linux
@@ -140,7 +142,9 @@ jobs:
140142
staticalize-linux \
141143
--site=http://127.0.0.1:8005 \
142144
--output=built \
143-
--base=https://frontside.com
145+
--base=https://frontside.com \
146+
--concurrency=25 \
147+
--retries=5
144148
145149
- name: Deploy to Production
146150
run: |

components/project-select.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,33 +78,34 @@ const projects = [
7878
{
7979
title: "Interactors",
8080
description: "Page Objects for components libraries",
81-
url: "https://frontside.com/interactors",
81+
url: "/interactors",
8282
version: "v1",
8383
img:
8484
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmEgewogICAgICAgIGZpbGw6ICNmZmY7CiAgICAgIH0KCiAgICAgIC5hLCAuYiwgLmMgewogICAgICAgIHN0cm9rZTogIzE0MzA1YzsKICAgICAgICBzdHJva2UtbWl0ZXJsaW1pdDogMTA7CiAgICAgICAgc3Ryb2tlLXdpZHRoOiAycHg7CiAgICAgIH0KCiAgICAgIC5iIHsKICAgICAgICBmaWxsOiAjMjZhYmU4OwogICAgICB9CgogICAgICAuYyB7CiAgICAgICAgZmlsbDogI2Y3NGQ3YjsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPGc+CiAgICA8ZWxsaXBzZSBjbGFzcz0iYSIgY3g9IjI4LjQ1IiBjeT0iNi45MSIgcng9IjQiIHJ5PSIzLjg5Ii8+CiAgICA8cGF0aCBjbGFzcz0iYiIgZD0iTTI4LjQ1LDEwLjhhMy45NCwzLjk0LDAsMCwxLTQtMy44OSw0LDQsMCwwLDEsLjI1LTEuMzQsNi40NSw2LjQ1LDAsMCwwLTEuMzMtLjE0QTYuMyw2LjMsMCwwLDAsMTcsMTEuNjRhNi4zOCw2LjM4LDAsMCwwLDEyLjc1LDAsNi45MSw2LjkxLDAsMCwwLS4xLTFBNC4zLDQuMywwLDAsMSwyOC40NSwxMC44WiIvPgogICAgPHBhdGggY2xhc3M9ImMiIGQ9Ik0xNywxMS42NGE2LjI2LDYuMjYsMCwwLDEsLjEtMSwxMS4xMSwxMS4xMSwwLDAsMC00LjY5LTEsMTAuODIsMTAuODIsMCwwLDAtMTEsMTAuNjhBMTAuODIsMTAuODIsMCwwLDAsMTIuNDEsMzFhMTAuODMsMTAuODMsMCwwLDAsMTEtMTAuNjgsMTAuNjYsMTAuNjYsMCwwLDAtLjMxLTIuNDhBNi4yNyw2LjI3LDAsMCwxLDE3LDExLjY0WiIvPgogIDwvZz4KPC9zdmc+Cg==",
8585
},
8686
{
8787
title: "Effection",
8888
description: "Structured Concurrency for JavaScript",
89-
url: "https://frontside.com/effection",
90-
version: "v3",
89+
url: "/effection",
90+
version: "v4",
9191
img:
9292
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmEgewogICAgICAgIGZpbGw6ICMxYzMwNWE7CiAgICAgIH0KCiAgICAgIC5iIHsKICAgICAgICBmaWxsOiAjMjZhYmU4OwogICAgICB9CgogICAgICAuYyB7CiAgICAgICAgZmlsbDogI2ZmZjsKICAgICAgfQoKICAgICAgLmQgewogICAgICAgIGZpbGw6ICNmNzRkN2I7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnPgogICAgPHJlY3QgY2xhc3M9ImEiIHg9IjEzLjU4IiB5PSI2Ljg5IiB3aWR0aD0iMTcuMTgiIGhlaWdodD0iMTcuMTgiIHJ4PSIxLjk2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNC40NiAyMC4yMSkgcm90YXRlKC00NSkiLz4KICAgIDxyZWN0IGNsYXNzPSJhIiB4PSI4LjM5IiB5PSIxMi4wOCIgd2lkdGg9IjE3LjE4IiBoZWlnaHQ9IjE3LjE4IiByeD0iMS45NiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTkuNjQgMTguMDYpIHJvdGF0ZSgtNDUpIi8+CiAgICA8cmVjdCBjbGFzcz0iYSIgeD0iMy4yNCIgeT0iNi45NyIgd2lkdGg9IjE3LjE4IiBoZWlnaHQ9IjE3LjE4IiByeD0iMS45NiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTcuNTMgMTIuOTIpIHJvdGF0ZSgtNDUpIi8+CiAgICA8cmVjdCBjbGFzcz0iYiIgeD0iMTYuMjgiIHk9IjkuNjEiIHdpZHRoPSIxMS43OCIgaGVpZ2h0PSIxMS43OCIgcng9IjIuMjYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC00LjQ3IDIwLjIxKSByb3RhdGUoLTQ1KSIvPgogICAgPHJlY3QgY2xhc3M9ImMiIHg9IjExLjA3IiB5PSIxNC44MSIgd2lkdGg9IjExLjc4IiBoZWlnaHQ9IjExLjc4IiByeD0iMi4yNiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTkuNjcgMTguMDYpIHJvdGF0ZSgtNDUpIi8+CiAgICA8cmVjdCBjbGFzcz0iZCIgeD0iNS45NyIgeT0iOS43MSIgd2lkdGg9IjExLjc4IiBoZWlnaHQ9IjExLjc4IiByeD0iMi4yNiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTcuNTYgMTIuOTUpIHJvdGF0ZSgtNDUpIi8+CiAgPC9nPgo8L3N2Zz4K",
9393
},
9494
{
95-
title: "Auth0 Simulator",
96-
description: "Enabling testing and local development",
97-
url: "https://github.com/thefrontside/simulacrum/tree/v0/packages/auth0",
95+
title: "Simulacrum",
96+
description: "Simulation enabling testing and local development",
97+
url: "https://github.com/thefrontside/simulacrum",
9898
version: "v0",
9999
img:
100100
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmEgewogICAgICAgIGZpbGw6ICMxNDMxNWQ7CiAgICAgIH0KCiAgICAgIC5iIHsKICAgICAgICBmaWxsOiAjMjZhYmU4OwogICAgICB9CgogICAgICAuYyB7CiAgICAgICAgZmlsbDogI2Y3NGQ3YjsKICAgICAgICBmaWxsLXJ1bGU6IGV2ZW5vZGQ7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnPgogICAgPHBhdGggY2xhc3M9ImEiIGQ9Ik0xNyw1LjE2bDEwLjMzLDUuOTVWMjIuODlMMTcsMjguODQsNi42NywyMi44OVYxMS4xMUwxNyw1LjE2TTE3LC4yOCwyLjQ1LDguNjZWMjUuMzRMMTcsMzMuNzJsMTQuNTUtOC4zOFY4LjY2TDE3LC4yOFoiLz4KICAgIDxwYXRoIGNsYXNzPSJiIiBkPSJNMTcsNy42OWw4LjEyLDQuNjd2OS4yOEwxNywyNi4zMSw4Ljg4LDIxLjY0VjEyLjM2TDE3LDcuNjltMC0zLjI1TDYuMDYsMTAuNzRWMjMuMjZMMTcsMjkuNTZsMTAuOTQtNi4zVjEwLjc0TDE3LDQuNDRaIi8+CiAgICA8cG9seWdvbiBjbGFzcz0iYyIgcG9pbnRzPSIxNyAxMy44OCAxNC4yOCAxNS40NCAxNC4yOCAxOC41NiAxNyAyMC4xMiAxOS43MiAxOC41NiAxOS43MiAxNS40NCAxNyAxMy44OCIvPgogIDwvZz4KPC9zdmc+Cg==",
101-
},
102-
{
103-
title: "Bigtest",
104-
description: "Universal test runner, GraphQL driven",
105-
url: "https://frontside.com/bigtest",
106-
version: "v0",
107-
img:
108-
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmEgewogICAgICAgIGZpbGw6ICMxNDMxNWQ7CiAgICAgIH0KCiAgICAgIC5iIHsKICAgICAgICBmaWxsOiAjZmZmOwogICAgICB9CgogICAgICAuYyB7CiAgICAgICAgZmlsbDogI2Y3NGQ3YjsKICAgICAgfQoKICAgICAgLmQgewogICAgICAgIGZpbGw6ICMyNmFiZTg7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnPgogICAgPHBvbHlnb24gY2xhc3M9ImEiIHBvaW50cz0iMTYuOTYgMC4yNyAyLjU0IDUuMyAzLjU0IDI1LjIyIDE2Ljk2IDMzLjU4IDMwLjM5IDI1LjIyIDMxLjM5IDUuMyAxNi45NiAwLjI3Ii8+CiAgICA8cG9seWdvbiBjbGFzcz0iYiIgcG9pbnRzPSIxNi45NiAzLjUyIDEyLjUzIDUuMTMgMTEuNjggMTYuOTQgMTYuOTYgMTkuNTcgMTUuOTUgMjkuNzIgMTYuOTUgMzAuMzYgMTguNDMgMjkuNDIgMjMuNiAxNi45NCAxOC4zOSAxNC4xNCAyMC44OCA0Ljk0IDE2Ljk2IDMuNTIiLz4KICAgIDxwb2x5Z29uIGNsYXNzPSJjIiBwb2ludHM9IjUuMzMgNy43NCAxMi41MyA1LjEzIDExLjY4IDE2Ljk0IDE2Ljk2IDE5LjU3IDE1Ljk1IDI5LjcyIDYuNDEgMjMuNjMgNS4zMyA3Ljc0Ii8+CiAgICA8cG9seWdvbiBjbGFzcz0iZCIgcG9pbnRzPSIyNy41MiAyMy42MyAxOC40MyAyOS40MiAyMy42IDE2Ljk0IDE4LjM5IDE0LjE0IDIwLjg4IDQuOTQgMjguNiA3Ljc0IDI3LjUyIDIzLjYzIi8+CiAgPC9nPgo8L3N2Zz4K",
109-
},
101+
}
102+
// we aren't actively maintaining, remove for now
103+
// {
104+
// title: "Bigtest",
105+
// description: "Universal test runner, GraphQL driven",
106+
// url: "/bigtest",
107+
// version: "v0",
108+
// img:
109+
// "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij4KICA8ZGVmcz4KICAgIDxzdHlsZT4KICAgICAgLmEgewogICAgICAgIGZpbGw6ICMxNDMxNWQ7CiAgICAgIH0KCiAgICAgIC5iIHsKICAgICAgICBmaWxsOiAjZmZmOwogICAgICB9CgogICAgICAuYyB7CiAgICAgICAgZmlsbDogI2Y3NGQ3YjsKICAgICAgfQoKICAgICAgLmQgewogICAgICAgIGZpbGw6ICMyNmFiZTg7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnPgogICAgPHBvbHlnb24gY2xhc3M9ImEiIHBvaW50cz0iMTYuOTYgMC4yNyAyLjU0IDUuMyAzLjU0IDI1LjIyIDE2Ljk2IDMzLjU4IDMwLjM5IDI1LjIyIDMxLjM5IDUuMyAxNi45NiAwLjI3Ii8+CiAgICA8cG9seWdvbiBjbGFzcz0iYiIgcG9pbnRzPSIxNi45NiAzLjUyIDEyLjUzIDUuMTMgMTEuNjggMTYuOTQgMTYuOTYgMTkuNTcgMTUuOTUgMjkuNzIgMTYuOTUgMzAuMzYgMTguNDMgMjkuNDIgMjMuNiAxNi45NCAxOC4zOSAxNC4xNCAyMC44OCA0Ljk0IDE2Ljk2IDMuNTIiLz4KICAgIDxwb2x5Z29uIGNsYXNzPSJjIiBwb2ludHM9IjUuMzMgNy43NCAxMi41MyA1LjEzIDExLjY4IDE2Ljk0IDE2Ljk2IDE5LjU3IDE1Ljk1IDI5LjcyIDYuNDEgMjMuNjMgNS4zMyA3Ljc0Ii8+CiAgICA8cG9seWdvbiBjbGFzcz0iZCIgcG9pbnRzPSIyNy41MiAyMy42MyAxOC40MyAyOS40MiAyMy42IDE2Ljk0IDE4LjM5IDE0LjE0IDIwLjg4IDQuOTQgMjguNiA3Ljc0IDI3LjUyIDIzLjYzIi8+CiAgPC9nPgo8L3N2Zz4K",
110+
// },
110111
];

main.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ await main(function* (args) {
9494
route("/redirects", redirectsRoute()),
9595
route("/platformscript", platformscriptRoute()),
9696
$route("/platformscript/(.*)", redirect("/platformscript")),
97-
proxyRoute({ ...proxies.effection, pattern: "/effection(.*)" }),
98-
proxyRoute({ ...proxies.graphgen, pattern: "/graphgen(.*)" }),
97+
proxyRoute(proxies.effection),
98+
proxyRoute(proxies.graphgen),
9999
$route("/assets(.*)", assetsRoute("assets")),
100-
proxyRoute({ ...proxies.interactors, pattern: "/interactors(.*)" }),
100+
proxyRoute(proxies.interactors),
101101
],
102102

103103
plugins: [
@@ -127,16 +127,16 @@ function proxySites() {
127127
effection: {
128128
prefix: "effection",
129129
website: Deno.env.get("EFFECTION_URL") ??
130-
"https://effection.deno.dev",
130+
"https://effection.netlify.app",
131131
},
132132
interactors: {
133133
prefix: "interactors",
134134
website: Deno.env.get("INTERACTORS_URL") ??
135-
"https://interactors.deno.dev",
135+
"https://interactors.netlify.app",
136136
},
137137
graphgen: {
138138
prefix: "graphgen",
139-
website: Deno.env.get("GRAPHGEN_URL") ?? "https://graphgen.deno.dev",
139+
website: Deno.env.get("GRAPHGEN_URL") ?? "https://graphgen-data.netlify.app",
140140
},
141141
} as const;
142142
}

routes/proxy-route.ts

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -42,80 +42,97 @@ export function proxyRoute(options: ProxyRouteOptions): HTTPMiddleware {
4242

4343
if ([301, 302, 307, 308].includes(response.status)) {
4444
let location = response.headers.get("location");
45-
if (location?.startsWith(String(website))) {
46-
let headers = copyHeaders(response);
47-
48-
let url = new URL(request.url);
45+
if (location) {
46+
// Resolve relative Location headers against the upstream website
47+
// - Netlify returns relative redirects like "/search/""
48+
// - Deno Deploy returns absolute ones like "https://host/search/"
49+
let loc = location.startsWith("http")
50+
? new URL(location)
51+
: new URL(location, website);
52+
53+
if (loc.origin === website.origin) {
54+
let headers = copyHeaders(response);
55+
let url = new URL(request.url);
56+
57+
if (!options.root) {
58+
loc.pathname = `${options.prefix}${loc.pathname}`;
59+
}
60+
headers.location = loc.toString().replace(target.origin, url.origin);
4961

50-
let loc = new URL(location);
51-
if (!options.root) {
52-
loc.pathname = `${options.prefix}${loc.pathname}`;
62+
response = new Response(null, {
63+
status: response.status,
64+
statusText: response.statusText,
65+
headers,
66+
});
5367
}
54-
headers.location = loc.toString().replace(target.origin, url.origin);
55-
56-
response = new Response(null, {
57-
status: response.status,
58-
statusText: response.statusText,
59-
headers,
60-
});
6168
}
6269
} else if (
6370
response.headers.get("Content-Type")?.match(/html/) && !options.root
6471
) {
65-
let body = yield* call(() => response.text());
66-
let tree = fromHtml(body);
72+
try {
73+
let body = yield* call(() => response.text());
74+
let tree = fromHtml(body);
6775

68-
yield* injectPlausible(tree);
69-
yield* injectUmami(tree);
70-
yield* injectMatomo(tree);
76+
yield* injectPlausible(tree);
77+
yield* injectUmami(tree);
78+
yield* injectMatomo(tree);
7179

72-
let elements = selectAll(
73-
'[href^="/"],[src^="/"],form[action],meta[content]',
74-
tree,
75-
);
80+
let elements = selectAll(
81+
'[href^="/"],[src^="/"],form[action],meta[content]',
82+
tree,
83+
);
7684

77-
for (let element of elements) {
78-
let properties = element.properties!;
85+
for (let element of elements) {
86+
let properties = element.properties!;
7987

80-
if (properties.href) {
81-
properties.href = posixNormalize(
82-
`${base.pathname}${properties.href}`,
83-
);
84-
}
85-
if (properties.src) {
86-
properties.src = posixNormalize(`${base.pathname}${properties.src}`);
87-
}
88-
if (properties.action) {
89-
properties.action = posixNormalize(
90-
`${base.pathname}${properties.action}`,
91-
);
92-
}
93-
if (properties.content) {
94-
if (typeof properties.content === "string") {
95-
const parts = properties.content.match(/\d;\s*url=(.*)/);
96-
if (parts) {
97-
const [, url] = parts;
98-
properties.content = properties.content.replace(
99-
url,
100-
posixNormalize(`${base.pathname}${url}`),
101-
);
102-
} else if (properties.content.startsWith("http")) {
103-
properties.content = properties.content.replace(
104-
target.origin,
105-
base.href.replace(/\/?$/, ""),
106-
);
88+
if (properties.href) {
89+
properties.href = posixNormalize(
90+
`${base.pathname}${properties.href}`,
91+
);
92+
}
93+
if (properties.src) {
94+
properties.src = posixNormalize(
95+
`${base.pathname}${properties.src}`,
96+
);
97+
}
98+
if (properties.action) {
99+
properties.action = posixNormalize(
100+
`${base.pathname}${properties.action}`,
101+
);
102+
}
103+
if (properties.content) {
104+
if (typeof properties.content === "string") {
105+
const parts = properties.content.match(/\d;\s*url=(.*)/);
106+
if (parts) {
107+
const [, url] = parts;
108+
properties.content = properties.content.replace(
109+
url,
110+
posixNormalize(`${base.pathname}${url}`),
111+
);
112+
} else if (properties.content.startsWith("http")) {
113+
properties.content = properties.content.replace(
114+
target.origin,
115+
base.href.replace(/\/?$/, ""),
116+
);
117+
}
107118
}
108119
}
109120
}
121+
response = new Response(toHtml(tree), {
122+
status: response.status,
123+
statusText: response.statusText,
124+
headers: copyHeaders(response),
125+
});
126+
} catch (error) {
127+
console.error(`Proxy HTML rewrite failed for ${request.url}:`, error);
110128
}
111-
response = new Response(toHtml(tree), {
112-
status: response.status,
113-
statusText: response.statusText,
114-
headers: copyHeaders(response),
115-
});
116129
}
117130

118-
return response;
131+
return new Response(response.body, {
132+
status: response.status,
133+
statusText: response.statusText,
134+
headers: copyHeaders(response),
135+
});
119136
};
120137

121138
if (options.prefix) {
@@ -135,17 +152,15 @@ export function proxyRoute(options: ProxyRouteOptions): HTTPMiddleware {
135152
};
136153
}
137154

138-
if (options.pattern) {
139-
let handler = revolutionRoute(options.pattern, middleware);
140-
if (middleware.sitemapExtension) {
141-
Object.defineProperty(handler, "sitemapExtension", {
142-
value: middleware.sitemapExtension,
143-
});
144-
}
145-
return handler;
146-
}
155+
let pattern = options.pattern ?? `/${options.prefix}(.*)`;
147156

148-
return middleware;
157+
let handler = revolutionRoute(pattern, middleware);
158+
if (middleware.sitemapExtension) {
159+
Object.defineProperty(handler, "sitemapExtension", {
160+
value: middleware.sitemapExtension,
161+
});
162+
}
163+
return handler;
149164
}
150165

151166
// Copy an upstream response's headers, dropping the ones that describe how the

0 commit comments

Comments
 (0)