Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions apps/landing/astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ function createBundleReportPlugin() {
export default defineConfig({
adapter: cloudflare({
imageService: { build: "compile", runtime: "cloudflare-binding" },
// Keep Shiki-backed Astro code rendering out of workerd's prerender path.
prerenderEnvironment: "node",
prerenderEnvironment: "workerd",
}),
build: {
// Keep page CSS out of a separate render-blocking request for first-load LCP.
Expand Down
1 change: 1 addition & 0 deletions apps/landing/wrangler.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
name = "onequery-landing"
main = "./src/worker.ts"
compatibility_date = "2026-04-14"
compatibility_flags = ["nodejs_compat"]
logpush = true
preview_urls = true
routes = [{ pattern = "onequery.dev", custom_domain = true }]
Expand Down
9 changes: 9 additions & 0 deletions packages/astro-agent-markdown/src/content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ title: Debugging production
).toBe("debug-production-agent-runs-with-onequery");
});

it("does not treat a collection index route as a content entry", () => {
expect(
getContentEntryIdForMarkdownPath({
markdownPath: "/blog/index.md",
routePrefix: "/blog",
})
).toBeUndefined();
});

it("finds a content entry by negotiated page pathname", async () => {
await expect(
getContentMarkdownForPath({
Expand Down
7 changes: 6 additions & 1 deletion packages/astro-agent-markdown/src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ export function getContentEntryIdForMarkdownPath(input: {
return undefined;
}

return input.markdownPath.slice(routeBase.length, -markdownSuffix.length);
const entryId = input.markdownPath.slice(
routeBase.length,
-markdownSuffix.length
);

return entryId.length > 0 ? entryId : undefined;
}

export async function getContentMarkdownForPath(input: {
Expand Down
40 changes: 40 additions & 0 deletions packages/astro-agent-markdown/src/dev-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,46 @@ Context, not keys.
`);
});

it("falls back to HTML conversion for a content collection index route", async () => {
const getMarkdown = vi.fn(async () => "should not read content entry");
const onRequest = createDevMarkdownMiddleware({
contentRoutes: [
{
getMarkdown,
routePrefix: "/blog",
},
],
});
const next = vi.fn(
async () =>
new Response("<main><h1>Blog</h1><p>Latest updates.</p></main>", {
headers: { "Content-Type": "text/html; charset=utf-8" },
})
);

const response = await onRequest(
createContext(
new Request("http://localhost:4546/blog/", {
headers: { Accept: "text/markdown" },
})
),
next as unknown as MiddlewareNext
);

expect(getMarkdown).not.toHaveBeenCalled();
expect(next).toHaveBeenCalledOnce();
expect(response).toBeInstanceOf(Response);

const markdownResponse = response as Response;
expect(markdownResponse.headers.get("Content-Type")).toBe(
MARKDOWN_CONTENT_TYPE
);
expect(await markdownResponse.text()).toBe(`# Blog

Latest updates.
`);
});

it("renders HTML-derived HEAD requests with GET so token counts are available", async () => {
const onRequest = createDevMarkdownMiddleware();
const next = vi.fn(
Expand Down
23 changes: 23 additions & 0 deletions packages/astro-agent-markdown/src/html-sidecars.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,29 @@ describe("HTML Markdown sidecars", () => {
expect(count).toBe(2);
});

it("exports Markdown sidecars for HTML pages missing from the assets map", async () => {
const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "html-md-"));

await fs.mkdir(path.join(outputDir, "docs", "guide"), {
recursive: true,
});
await fs.writeFile(
path.join(outputDir, "docs", "guide", "index.html"),
"<main><h1>Guide</h1><p>Run bounded queries.</p></main>"
);

const count = await exportHtmlMarkdownSidecars({
assets: new Map(),
dir: pathToFileURL(`${outputDir}/`),
logger: createLogger(),
});

await expect(
fs.readFile(path.join(outputDir, "docs", "guide", "index.md"), "utf8")
).resolves.toContain("# Guide");
expect(count).toBe(1);
});

it("does not overwrite content collection Markdown sidecars", async () => {
const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "html-md-"));
const blogDir = path.join(outputDir, "blog/post");
Expand Down
33 changes: 33 additions & 0 deletions packages/astro-agent-markdown/src/html-sidecars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,33 @@ async function exportHtmlFile(input: {
return true;
}

async function collectHtmlFiles(directory: string) {
const htmlPaths: string[] = [];

async function visit(currentDirectory: string) {
const entries = await fs.readdir(currentDirectory, { withFileTypes: true });

await Promise.all(
entries.map(async (entry) => {
const entryPath = path.join(currentDirectory, entry.name);

if (entry.isDirectory()) {
await visit(entryPath);
return;
}

if (entry.isFile() && entry.name.endsWith(HTML_EXTENSION)) {
htmlPaths.push(entryPath);
}
})
);
}

await visit(directory);

return htmlPaths;
}

export async function exportHtmlMarkdownSidecars(
options: ExportHtmlMarkdownSidecarsOptions
) {
Expand All @@ -81,6 +108,12 @@ export async function exportHtmlMarkdownSidecars(
}
}

// Workerd prerender builds can omit static HTML pages from the hook's assets
// map, so scan the emitted client directory as the source of truth.
for (const htmlPath of await collectHtmlFiles(outputDir)) {
htmlAssetPaths.add(htmlPath);
}

for (const htmlPath of htmlAssetPaths) {
const routePath = getHtmlRoutePath(path.relative(outputDir, htmlPath));

Expand Down