fix: serve static content through Cloudflare assets

This commit is contained in:
ibelick
2026-08-28 15:01:29 +02:00
parent def668f21d
commit 2666ceb9f6
38 changed files with 174 additions and 85 deletions
+4 -1
View File
@@ -9,7 +9,10 @@ export default defineConfig({
trailingSlash: "ignore",
output: "server",
session: false,
adapter: cloudflare({ imageService: "compile" }),
adapter: cloudflare({
imageService: "compile",
prerenderEnvironment: "node",
}),
integrations: [react()],
vite: {
plugins: [tailwindcss()],
+18 -1
View File
@@ -1,5 +1,7 @@
/*
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.interfaceoffice.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
Cache-Control: public, max-age=0, must-revalidate
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.interfaceoffice.com https://collector.onedollarstats.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
Link: <https://www.ui-skills.com/llms.txt>; rel="describedby"; type="text/plain"; title="Site index for LLMs", <https://www.ui-skills.com/.well-known/api-catalog>; rel="api-catalog"; type="application/linkset+json"; title="API catalog", <https://www.ui-skills.com/.well-known/agent-skills/index.json>; rel="describedby"; type="application/json"; title="Agent skills index", <https://www.ui-skills.com/.well-known/mcp/server-card.json>; rel="service-desc"; type="application/json"; title="MCP server card", <https://www.ui-skills.com/.well-known/oauth-protected-resource>; rel="oauth-protected-resource"; type="application/json"; title="OAuth protected resource", <https://www.ui-skills.com/auth.md>; rel="service-doc"; type="text/markdown"; title="Agent auth", <https://www.ui-skills.com/design.md>; rel="service-doc"; type="text/markdown"; title="Design system", <https://www.ui-skills.com/skills/registry.json>; rel="service-desc"; type="application/json"; title="Skills registry", <https://www.ui-skills.com/sitemap.xml>; rel="sitemap"; type="application/xml"; title="Sitemap"
Permissions-Policy: camera=(), geolocation=(), microphone=()
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
@@ -10,3 +12,18 @@
/analytics/*
Cache-Control: public, max-age=3600
/_astro/*
Cache-Control: public, max-age=31536000, immutable
/.well-known/api-catalog
Content-Type: application/linkset+json; charset=utf-8
/.well-known/oauth-authorization-server
Content-Type: application/json; charset=utf-8
/.well-known/oauth-protected-resource
Content-Type: application/json; charset=utf-8
/.well-known/openid-configuration
Content-Type: application/json; charset=utf-8
+3
View File
@@ -0,0 +1,3 @@
/agent /agents 301
/mcp/server /mcp/docs 302
/agent/* /agents/:splat 301
+1 -1
View File
@@ -118,7 +118,7 @@ const commandItems = [
script.src = "/analytics/stonks.js";
script.defer = true;
script.dataset.hostname = "ui-skills.com";
script.dataset.url = "/analytics/events";
script.dataset.url = "https://collector.onedollarstats.com/events";
document.head.appendChild(script);
};
if ("requestIdleCallback" in window) {
+7 -7
View File
@@ -6,7 +6,7 @@ import { maybeNegotiateMarkdown } from "./lib/markdown-negotiation";
const securityHeaders = {
"Content-Security-Policy":
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.interfaceoffice.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; font-src 'self'; connect-src 'self' https://api.interfaceoffice.com https://collector.onedollarstats.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'",
"Permissions-Policy": "camera=(), geolocation=(), microphone=()",
"Referrer-Policy": "strict-origin-when-cross-origin",
"X-Content-Type-Options": "nosniff",
@@ -38,9 +38,14 @@ function applyResponseHeaders(
}
export const onRequest = defineMiddleware(async (context, next) => {
const url = new URL(context.request.url);
const origin = getSiteOrigin(context.site);
if (context.isPrerendered) {
return next();
}
const url = new URL(context.request.url);
if (url.pathname !== "/" && url.pathname.endsWith("/")) {
url.pathname = url.pathname.replace(/\/+$/, "");
const status =
@@ -52,11 +57,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
}
const response = await next();
if (context.isPrerendered) {
return response;
}
const withHeaders = applyResponseHeaders(response, origin, url.pathname);
return maybeNegotiateMarkdown(context.request, withHeaders);
});
@@ -3,9 +3,17 @@ import type { APIRoute } from "astro";
import {
defaultSkillContentLoader,
getRegistrySkillByDiscoveryName,
toDiscoveryName,
} from "../../../../lib/agent-skills-discovery";
import { registry } from "../../../../data/registry";
export const prerender = false;
export const prerender = true;
export function getStaticPaths() {
return registry.map((entry) => ({
params: { skill: toDiscoveryName(entry.pathSlug) },
}));
}
export const GET: APIRoute = async ({ params }) => {
const slug = params.skill;
@@ -7,6 +7,8 @@ import {
} from "../../../lib/agent-skills-discovery";
import { getSiteOrigin } from "../../../lib/agent-discovery";
export const prerender = true;
export const GET: APIRoute = async ({ site }) => {
const origin = getSiteOrigin(site);
const index = toPublicAgentSkillsIndex(await buildAgentSkillsIndex(origin));
+2
View File
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
API_CATALOG_PATH,
apiCatalogContentType,
+2
View File
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import { buildJwks, jsonHeaders } from "../../lib/oauth-discovery";
export const GET: APIRoute = () =>
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
buildMcpServerCard,
discoveryJsonHeaders,
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
buildAuthorizationServerMetadata,
getSiteOrigin,
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
buildProtectedResourceMetadata,
getSiteOrigin,
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
buildOpenIdConfiguration,
getSiteOrigin,
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../layouts/Layout.astro";
Astro.response.status = 404;
+8
View File
@@ -1,3 +1,11 @@
---
import { agents } from "../../data/agents";
export const prerender = true;
export function getStaticPaths() {
return agents.map((agent) => ({ params: { id: agent.id } }));
}
return Astro.redirect(`/agents/${Astro.params.id ?? ""}`, 301);
---
+2
View File
@@ -1,3 +1,5 @@
---
export const prerender = true;
return Astro.redirect("/agents", 301);
---
+6 -1
View File
@@ -2,10 +2,15 @@
import Layout from "../../layouts/Layout.astro";
import AgentStartHere from "../../ui/agent-start-here.astro";
export const prerender = false;
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import { agentById, agents } from "../../data/agents";
export const prerender = true;
export function getStaticPaths() {
return agents.map((agent) => ({ params: { id: agent.id } }));
}
const agentId = Astro.params.id ?? "";
const agent = agentById.get(agentId);
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../../layouts/Layout.astro";
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import { agents } from "../../data/agents";
-46
View File
@@ -1,46 +0,0 @@
import type { APIRoute } from "astro";
const COLLECTOR_URL = "https://collector.onedollarstats.com/events";
const responseHeaders = {
"Cache-Control": "no-store",
};
export const GET: APIRoute = async ({ request }) => {
const incoming = new URL(request.url);
const target = new URL(COLLECTOR_URL);
target.search = incoming.search;
const response = await fetch(target.toString(), {
method: "GET",
headers: {
"User-Agent":
request.headers.get("user-agent") ?? "ui-skills-analytics-proxy",
},
});
return new Response(null, {
status: response.status,
headers: responseHeaders,
});
};
export const POST: APIRoute = async ({ request }) => {
const body = await request.text();
const response = await fetch(COLLECTOR_URL, {
method: "POST",
body,
headers: {
"Content-Type":
request.headers.get("content-type") ?? "application/json",
},
});
return new Response(await response.text(), {
status: response.status,
headers: {
...responseHeaders,
"Content-Type": response.headers.get("content-type") ?? "text/plain",
},
});
};
+2
View File
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import {
buildAuthMarkdown,
getSiteOrigin,
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../layouts/Layout.astro";
import Breadcrumbs from "../ui/breadcrumbs.astro";
import CodeBlock from "../ui/code-block.astro";
+2
View File
@@ -1,4 +1,6 @@
import type { APIRoute } from "astro";
export const prerender = true;
import designDocument from "../../DESIGN.md?raw";
import { SEMI_STATIC_CACHE } from "../lib/cache-headers";
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../layouts/Layout.astro";
import { playbook } from "../data/playbook";
import { skills } from "../data/skills";
+2
View File
@@ -1,4 +1,6 @@
import type { APIRoute } from "astro";
export const prerender = true;
import { skills } from "../data/skills";
import { SEMI_STATIC_CACHE } from "../lib/cache-headers";
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../../layouts/Layout.astro";
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import CodeBlock from "../../ui/code-block.astro";
+2
View File
@@ -1,3 +1,5 @@
---
export const prerender = true;
return Astro.redirect("/mcp/docs");
---
+5 -1
View File
@@ -7,7 +7,11 @@ import SkillCard from "../../ui/skill-card.astro";
import { playbook, playbookBySlug } from "../../data/playbook.ts";
import { skills } from "../../data/skills.ts";
export const prerender = false;
export const prerender = true;
export function getStaticPaths() {
return playbook.map((entry) => ({ params: { slug: entry.slug } }));
}
const routeSlug = Astro.params.slug ?? "";
const slug = Array.isArray(routeSlug) ? routeSlug.join("/") : routeSlug;
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../../layouts/Layout.astro";
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import PlaybookCard from "../../ui/playbook-card.astro";
+2
View File
@@ -2,6 +2,8 @@ import type { APIRoute } from "astro";
import { SEMI_STATIC_CACHE } from "../lib/cache-headers";
export const prerender = true;
const SITE_URL = "https://www.ui-skills.com";
export const GET: APIRoute = ({ site }) => {
+2
View File
@@ -5,6 +5,8 @@ import { skills, type Skill } from "../data/skills";
import { agents } from "../data/agents";
import { playbook } from "../data/playbook";
export const prerender = true;
const SITE_URL = "https://www.ui-skills.com";
const escapeXml = (value: string) =>
+6 -1
View File
@@ -20,11 +20,16 @@ import {
getSkillsBySlug,
getSkillsBySource,
getSkillsByTopic,
getSkillRoutePaths,
} from "../../lib/skill-catalog";
import { defaultSkillContentLoader } from "../../lib/agent-skills-discovery";
import { playbookBySkillSlug } from "../../data/playbook.ts";
export const prerender = false;
export const prerender = true;
export function getStaticPaths() {
return getSkillRoutePaths();
}
const titleize = (value: string) =>
value
+11 -1
View File
@@ -1,7 +1,17 @@
import type { APIRoute } from "astro";
import { getRegistryByPath, getSkillByPath } from "../../../lib/skill-catalog";
import {
getCanonicalSkillPaths,
getRegistryByPath,
getSkillByPath,
} from "../../../lib/skill-catalog";
import { defaultSkillContentLoader } from "../../../lib/agent-skills-discovery";
export const prerender = true;
export function getStaticPaths() {
return getCanonicalSkillPaths();
}
export const GET: APIRoute = async ({ params }) => {
const routeSlug = params.slug ?? "";
const pathSlug = Array.isArray(routeSlug) ? routeSlug.join("/") : routeSlug;
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../../layouts/Layout.astro";
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import { skills } from "../../data/skills";
+2
View File
@@ -5,6 +5,8 @@ import { topics } from "../../data/topics";
import { REGISTRY_JSON_CACHE } from "../../lib/cache-headers";
export const prerender = true;
export const GET: APIRoute = () => {
return new Response(JSON.stringify({ registry, topics }), {
headers: {
+2
View File
@@ -1,5 +1,7 @@
import type { APIRoute } from "astro";
export const prerender = true;
import type { RegistrySkill } from "../../data/registry";
import { registry } from "../../data/registry";
+2
View File
@@ -1,4 +1,6 @@
---
export const prerender = true;
import Layout from "../../layouts/Layout.astro";
import Breadcrumbs from "../../ui/breadcrumbs.astro";
import TopicTag from "../../ui/topic-tag.astro";
+40 -23
View File
@@ -16,7 +16,17 @@ const port =
}));
const server = spawn(
"npx",
["wrangler", "dev", "--local", "--ip", "127.0.0.1", "--port", `${port}`],
[
"wrangler",
"dev",
"--config",
"dist/server/wrangler.json",
"--local",
"--ip",
"127.0.0.1",
"--port",
`${port}`,
],
{
stdio: ["ignore", "pipe", "pipe"],
},
@@ -94,8 +104,12 @@ try {
if (!homepageBody.includes('href="/mcp/docs"')) {
throw new Error("Homepage is missing the MCP guide link");
}
if (!homepageBody.includes('dataset.url = "/analytics/events"')) {
throw new Error("Homepage is missing the One Dollar Stats proxy loader");
if (
!homepageBody.includes(
'dataset.url = "https://collector.onedollarstats.com/events"',
)
) {
throw new Error("Homepage is missing the direct One Dollar Stats collector");
}
if (!homepageBody.includes('script.src = "/analytics/stonks.js"')) {
throw new Error("Homepage is missing the first-party One Dollar Stats loader");
@@ -117,8 +131,8 @@ try {
e: [{ t: "PageView" }],
}),
});
if (analyticsProxy.status === 404) {
throw new Error("Analytics proxy route is missing");
if (![404, 405].includes(analyticsProxy.status)) {
throw new Error("Analytics proxy route is still active");
}
const mcpDocs = await fetchLocal("/mcp/docs");
@@ -140,6 +154,24 @@ try {
throw new Error("MCP docs code blocks are missing Shiki theme colors");
}
const legacyAgent = await fetchLocal("/agent/claude-code", {
redirect: "manual",
});
if (
legacyAgent.status !== 301 ||
legacyAgent.headers.get("location") !== "/agents/claude-code"
) {
throw new Error("Legacy agent route did not return its static redirect");
}
const legacyMcp = await fetchLocal("/mcp/server", { redirect: "manual" });
if (
legacyMcp.status !== 302 ||
legacyMcp.headers.get("location") !== "/mcp/docs"
) {
throw new Error("Legacy MCP route did not return its static redirect");
}
const cliDocs = await fetchLocal("/cli");
if (cliDocs.status !== 200) {
throw new Error(`CLI docs returned ${cliDocs.status}`);
@@ -165,24 +197,6 @@ try {
throw new Error(`API catalog returned unexpected type: ${apiCatalogType}`);
}
const markdownHomepage = await fetchLocal("/", {
headers: { Accept: "text/markdown" },
});
if (markdownHomepage.status !== 200) {
throw new Error(`Markdown homepage returned ${markdownHomepage.status}`);
}
const markdownType = markdownHomepage.headers.get("content-type") ?? "";
if (!markdownType.startsWith("text/markdown")) {
throw new Error(`Markdown homepage content-type was ${markdownType}`);
}
if (markdownHomepage.headers.get("x-markdown-tokens") === null) {
throw new Error("Markdown homepage is missing x-markdown-tokens");
}
const markdownBody = await markdownHomepage.text();
if (!markdownBody.trim()) {
throw new Error("Markdown homepage body was empty");
}
const registry = await fetchLocal("/skills/registry.json");
if (registry.status !== 200) {
throw new Error(`Registry returned ${registry.status}`);
@@ -201,6 +215,9 @@ try {
if (mcp.status !== 200 || !(await mcp.text()).includes('"list_skills"')) {
throw new Error(`MCP tools/list failed with ${mcp.status}`);
}
if (mcp.headers.get("x-content-type-options") !== "nosniff") {
throw new Error("MCP response is missing dynamic security headers");
}
const invalidMcp = await fetchLocal("/mcp", {
method: "POST",
+8 -1
View File
@@ -5,6 +5,13 @@
"assets": {
"directory": "./dist",
"binding": "ASSETS",
"run_worker_first": false,
"not_found_handling": "404-page",
"run_worker_first": [
"/api/*",
"/mcp",
"/oauth/*",
"/_server-islands/*",
"/_image",
],
},
}