Skip to content

Commit 851a530

Browse files
Add cookbook with 50 workflow pattern recipes (#1564)
* Add cookbook section with 50 workflow pattern recipes Migrate the "Workflow API Explorer" decision tree concept from workflow-campaign-demos into useworkflow.dev docs as a Cookbook. Infrastructure: - docs/lib/cookbook-tree.ts: decision tree data, 50 recipe metadata entries, slug-to-category mapping - docs/components/geistdocs/cookbook-explorer.tsx: interactive "I want to..." decision tree UI with breadcrumb navigation - docs/content/docs/cookbook/index.mdx: landing page rendering CookbookExplorer component - docs/content/docs/cookbook/meta.json + 8 category meta.json files for sidebar nav - docs/content/docs/meta.json: added cookbook to docs nav between foundations and how-it-works - docs/app/[lang]/docs/[[...slug]]/page.tsx: registered CookbookExplorer component 50 recipe MDX files across 8 categories (payments, approvals, resilience, notifications, webhooks, data-processing, routing, observability), each with: - Frontmatter (title, description, type: guide, summary with use-case scenario) - Simplified code snippet (core pattern only, stripped of demo UI concerns) - Full implementation code snippet (exact source from campaign demos) - Key APIs section with links to API reference docs * ploop: iteration 1 checkpoint Automated checkpoint commit. Ploop-Iter: 1 * fix: polish cookbook public routing Keep the cookbook surface canonical at /cookbooks so docs navigation, sitemap output, and AI/chat entry points stop leaking the legacy /docs/cookbook paths. Correct the approval-chain example so the docs teach the intended sequential approval semantics instead of implying the workflow approves after the first successful level. This keeps the cookbook aligned with the docs quality bar and avoids misleading readers with inconsistent behavior. Ploop-Iter: 2 * docs: canonicalize cookbook doc routes Align cookbook-facing docs outputs with the new public route so redirects, sitemap entries, and LLM-facing exports stay consistent. This keeps the polished cookbook section discoverable at its canonical location while trimming the last demo-heavy recipe examples toward the same concise style as the rest of the docs. Ploop-Iter: 3 * ploop: iteration 4 checkpoint Automated checkpoint commit. Ploop-Iter: 4 * fix(docs): finalize cookbook route split Keep cookbook content discoverable after moving it to a first-class /cookbooks surface so navigation, canonical metadata, and markdown consumers resolve the new public URLs consistently. Avoid serving the legacy /docs/cookbook tree as if it were still part of the docs section, which reduces duplicate navigation paths and prevents stale static output from competing with the new route structure. Ploop-Iter: 5 * docs: improve cookbook discovery The cookbook landing page needs to work for both exploratory users and users who already know the pattern they want. This keeps the guided decision tree while adding shared category metadata and a searchable browse mode so recipe discovery feels faster and more consistent with the rest of the docs experience. Ploop-Iter: 6 * docs: refine cookbook pattern examples Tighten the simplified cookbook recipes so the examples teach the intended workflow semantics clearly and consistently. The changes keep the documentation focused on the core control-flow patterns reviewers called out, while removing ambiguity around partial arrivals, deadlines, and first-success behavior. Ploop-Iter: 7 * docs: decouple cookbook sidebar tree Separate cookbook navigation from the docs page tree so the standalone /cookbooks experience stays stable after the route move and the main docs sidebar no longer leaks cookbook entries.\n\nThis keeps cookbook navigation driven by explicit recipe metadata, which avoids duplicated section titles and makes the docs and cookbook surfaces easier to evolve independently.\n\nPloop-Iter: 8 * fix(docs): align cookbook public nav Keep cookbook pages on their public /cookbooks surface so metadata and copied markdown do not leak legacy /docs/cookbook paths.\n\nSimplify sidebar rendering to trust the injected page tree, which avoids route-specific filtering and keeps cookbook navigation consistent with the active layout tree.\n\nPloop-Iter: 9 * refactor(docs): decouple cookbook routing Move cookbook rendering off the shared docs route so cookbook pages can behave like a first-class docs surface without leaking cookbook-specific UI into the main docs experience. Centralizing cookbook tree filtering keeps sidebar behavior consistent in one place and avoids duplicate cookbook navigation state across layouts. Ploop-Iter: 10 * docs: improve cookbook explorer accessibility Improve the cookbooks entrypoint so loading and keyboard navigation are usable without visual cues, and keep guided and browse modes resilient while the route hydrates. Ploop-Iter: 11 * ploop: iteration 12 checkpoint Automated checkpoint commit. Ploop-Iter: 12 * docs: rename cookbooks route to cookbook (singular) * docs: add 5 cookbook overview design variations Add getRecipeHref, getRecipesByCategory, and collectSlugs helpers to cookbook-tree.ts, then create 5 distinct overview page variations at /cookbook/v1 through /cookbook/v5 for side-by-side comparison: - v1: Category Grid (zero-JS scannable overview) - v2: Search-First (real-time filtering with category pills) - v3: Accordion Catalog (expandable category sections) - v4: Decision Wizard (step-by-step guided questions) - v5: Problem-Solution Table (master-detail by scenario) Also adds .impeccable.md with project design context. * docs: remove unrelated package.json bumps and generated artifacts * docs: restructure cookbook from 50 recipes into 27 consolidated pages Restructure the cookbook based on team meeting feedback, toolbar comments, mux-ai pattern analysis, and Vercel org code search. Consolidates duplicates, adds missing patterns, ensures all examples have proper directives and type-check against the real workflow SDK. New structure: - common-patterns/ (9): saga, batching, rate-limiting, fan-out, scheduling, idempotency, webhooks, content-router, child-workflows - agent-patterns/ (5): durable-agent, tool-streaming, human-in-the-loop, tool-orchestration, stop-workflow - integrations/ (3): ai-sdk, sandbox, chat-sdk - advanced/ (6): serializable-steps, durable-objects, isomorphic-packages, secure-credentials, custom-serialization, publishing-libraries All 92 code snippets pass docs-typecheck against real workflow SDK types. Deleted 8 old category folders. Updated cookbook-tree.ts, explorer, nav. * docs: add workflow migration guides Help teams evaluating the GA launch translate existing durable workflow systems into Vercel Workflow without reverse-engineering concept parity from product docs alone. The guides focus on real migration decisions and concrete TypeScript examples so adoption can be driven by implementation clarity rather than platform marketing. Ploop-Iter: 1 * ploop: iteration 2 checkpoint Automated checkpoint commit. Ploop-Iter: 2 * docs: refine workflow migration guides Clarify the migration narrative for GA so teams evaluating a move from Temporal, Inngest, or Step Functions get examples that are realistic enough to trust and pricing guidance that matches the current platform model. The Inngest guide needed a complete order-saga flow so the durable orchestration, compensation, and streaming patterns read as a credible migration target instead of a partial sketch. The pricing language across all three guides also needed to be aligned with current Workflow and Vercel compute billing semantics to avoid creating the wrong cost expectations during evaluation. Ploop-Iter: 3 * ploop: iteration 1 checkpoint Automated checkpoint commit. Ploop-Iter: 1 * docs(skill): refine workflow migration guidance Clarify migration rules so agents choose the correct resume primitive, keep streaming guidance aligned with runtime behavior, and avoid implying Vercel-managed execution for self-hosted targets. This reduces avoidable migration mistakes in generated guidance and keeps the skill consistent with the acceptance criteria used to evaluate it. Ploop-Iter: 2 * ploop: iteration 3 checkpoint Automated checkpoint commit. Ploop-Iter: 3 * docs(skills): refine workflow migration guidance Reduce the migration skill entry point to the decision surface agents need\nso they can select the correct resume pattern without carrying duplicate\nexamples in the initial context.\n\nClarify framework precedence so prompts that explicitly ask for\nframework-agnostic boundaries do not get Hono- or Next-specific route\nshapes, while preserving framework-specific examples when requested.\n\nCentralize canonical resume examples in the shared patterns reference to\nkeep the guidance consistent across migration paths and reduce drift.\n\nPloop-Iter: 4 * docs: add workflow deep-dive references Add a cohesive set of deep-dive reference articles so the GA launch has architecture-level documentation grounded in the current SDK implementation. This gives readers verified explanations of runtime, replay, streaming, compiler, and cost-model behavior while linking the series together for easier navigation. Ploop-Iter: 1 * ploop: iteration 5 checkpoint Automated checkpoint commit. Ploop-Iter: 5 * docs: normalize deep-dive related links Keep the new deep-dive reference pages cross-linked so readers can move between adjacent runtime concepts without depending on older how-it-works pages alone. This preserves navigational consistency across the GA launch docs set and reduces the chance that architectural explanations drift into isolated pages that are harder to discover and maintain. Ploop-Iter: 2 * docs(skill): refine workflow migration routing Tighten the migration guidance so agents choose the correct resume surface and runtime boundary earlier, reducing incorrect mixed patterns in generated migrations. Add explicit fast paths for self-hosted targets and Step Functions task-token callbacks so the skill stays consistent on callback URL vs deterministic resume decisions. Ploop-Iter: 6 * docs: refine workflow migration skill guidance Clarify route selection so the migration skill composes resume, runtime, and app-boundary concerns deterministically. Add a canonical Step Functions self-hosted Hono callback recipe so migrations produce the correct callback-url pattern without mixing incompatible hook surfaces.\n\nPloop-Iter: 7 * docs: checkpoint deep-dive drafts Preserve the verified GA launch deep-dive drafts in git so the campaign work can continue from a stable checkpoint. Capture the reviewed documentation progress now to reduce risk of drift between source-backed research and the publishable drafts. Ploop-Iter: 3 * docs(skills): tighten workflow migration routing Clarify the migration skill's route-selection rules so generated guidance stays consistent across resume surfaces, runtime targets, and named framework boundaries. This reduces ambiguous outputs where agents might mix framework syntaxes or invent callback routes for webhook-based flows, which leads to migration guidance that does not match the user's runtime model. Ploop-Iter: 8 * docs: finalize workflow deep dives Clarify the runtime mechanics behind the GA deep-dive series so launch content stays aligned with the implementation and existing docs. Tightening these explanations reduces the risk of readers internalizing inaccurate mental models about replay, compilation, and workflow execution.\n\nPloop-Iter: 4 * docs(skills): refine workflow migration routing Clarify route selection so migrations choose the correct resume surface and app boundary patterns for the target runtime and framework. Strengthen verification guidance to reject invented callback routes in URL-based flows and keep examples aligned with the documented migration rules. Ploop-Iter: 9 * docs: sync compiler deep-dive runtime details Align the compiler deep-dive trio with the actual Workflow runtime so launch materials describe the same execution model users rely on. This keeps the GA narrative accurate around deterministic replay, step queue triggers, and runtime bundle responsibilities, reducing the risk of docs teaching an architecture the SDK does not implement. Ploop-Iter: 5 * docs(skill): tighten workflow migration guidance Reduce hot-path skill context so migration routing stays easier to select and verify during activation. Trimmed examples and converted long invalid samples into concise failure rules so the skill points agents to on-demand references instead of loading bulky worked code by default. Ploop-Iter: 10 * docs: tighten workflow migration guidance Clarify route-key planning and resume-surface defaults so migration outputs stay deterministic when prompts underspecify callback behavior. Strengthen the deep-dive docs to trace runtime handoffs more directly, which reduces ambiguity about how the compiler split maps to durable execution behavior. Ploop-Iter: 11 * docs: refine streaming and cost deep dives Clarify the operational model behind durable streaming and zero-cost suspension so launch materials stay source-accurate for readers comparing workflow runtimes. The updates make the workflow-step boundary, persistence path, and queue-driven cost story more explicit, reducing ambiguity around where stream I/O is allowed and why long waits do not consume compute. Ploop-Iter: 6 * ploop: iteration 12 checkpoint Automated checkpoint commit. Ploop-Iter: 12 * docs: tighten deep-dive streaming accuracy Align the launch deep dives with the current runtime so campaign content does not misstate suspension behavior or streaming backend capabilities. These edits clarify the distinct resume paths for step suspension versus timed waits and document the backend-specific streaming guarantees now available across local, Vercel, and Postgres worlds, reducing the risk that readers build incorrect mental models from launch materials. Ploop-Iter: 7 * docs(skills): refine callback resume taxonomy Clarify when migrations should use deterministic internal resume versus generated callback URLs so skill outputs stay consistent across frameworks and hosting targets. Distinguish default webhook responses from manual-response flows to prevent ambiguous guidance and keep the shared callback references directly inspectable.\n\nPloop-Iter: 13 * docs: refine deep-dive runtime wording Clarify the runtime semantics behind suspension and durable streaming so the GA launch materials stay aligned with the source of truth. These edits tighten descriptions around wake-up paths, backend behavior, and stream lifecycle details to reduce ambiguity for readers comparing the docs to the implementation. Ploop-Iter: 8 * docs: clarify webhook response mode defaults Clarify when migrations should use the default webhook behavior versus manual responses so agents make the same callback choice across the skill entrypoint, shared patterns, and API reference. This reduces avoidable ambiguity for callback-url prompts and makes the default 202 behavior explicit unless a prompt requires custom response semantics. Ploop-Iter: 14 * docs: align cost model wake-up semantics Prevent the GA launch materials from teaching an incorrect mental model about how suspended runs wake back up. The updated wording keeps the blog, social, and reference variants anchored to the real runtime paths so readers understand which transitions are queue-delayed, which are step-driven re-enqueues, and why that distinction matters for the cost story. Ploop-Iter: 9 * ploop: iteration 10 checkpoint Automated checkpoint commit. Ploop-Iter: 10 * docs: clarify webhook resume choices Explain the resume-surface decision points so migration and API guidance steer authors toward the correct webhook or hook pattern for the prompt. Reduce common callback-routing mistakes early in the docs and skill so agents make fewer wrong assumptions during workflow migrations. Ploop-Iter: 15 * docs: tighten cost model deep dives Clarify the cost-model narrative so launch materials make source-verifiable claims about suspension, wake-up paths, and polling behavior. This keeps the GA messaging aligned with the runtime's actual control flow and avoids overclaiming where the implementation has narrower semantics than the original copy suggested. Ploop-Iter: 11 * docs(skills): tighten resume routing guidance Keep the migration skill entrypoint small so agents load the routing contract only when the source actually pauses for external resume. Clarify the public webhook docs around the default callback flow to reduce accidental use of lower-level runtime APIs.\n\nPloop-Iter: 16 * docs: tighten deep-dive runtime claims Align the launch materials with the current runtime semantics so the cost-model and execution-model narrative stays defensible against the actual implementation. This keeps the GA campaign focused on claims we can support directly from source, especially around suspension, re-enqueue behavior, and the difference between orchestration compute and client-side polling helpers. Ploop-Iter: 12 * docs: correct cost model deep dive claims Align the cost-model launch content with the runtime's actual suspension and re-entry mechanics so GA messaging does not overstate identical-cost waits or imply residency that the queue-based engine does not have. This keeps the public explanation consistent with source-backed behavior around timed wake-ups, explicit workflow re-queue after step completion, and the distinction between idle worker residency and boundary I/O. Ploop-Iter: 13 * chore: remove non-cookbook files from cookbook branch Remove deep-dive articles, migration guides/skill, vercel-toolbar skill, workflow-skills test fixtures, and misc artifacts that belong in separate branches (deep-dives, migration-guides). Revert create-webhook.mdx, getting-started/meta.json, and code-transform.mdx to main versions. * docs: address toolbar feedback on cookbook pages Address Vercel toolbar comments from Nathan Rajlich, Peter Wielander, Pranay Prakash, and Karthik Kalyanaraman on the cookbook branch. In saga.mdx, remove the unnecessary `if (!(error instanceof FatalError)) throw error;` guard in the catch block — compensations should always unwind regardless of error type. Replace the `while/pop()!()` loop with a cleaner `for...of reverse()` to avoid the non-null assertion. In ai-sdk.mdx, split the "Using Different Providers" section into two subsections: "Vercel Gateway (string model IDs)" clarifying that all string model IDs route through Gateway, and "Direct Provider Access" showing how to import from provider packages like `@workflow/ai/openai` to bypass Gateway. Change the "Tool Functions as Steps" section to "Tool Functions with Steps" and reword to explain that tool execute functions can optionally include steps via "use step" but don't have to — when they aren't steps, they run in workflow context and can modify workflow state directly. In sandbox.mdx, rewrite the page to reflect that `@vercel/sandbox` now has first-class Workflow SDK support. Replace all `declare function` stubs and `// TODO` placeholders with real `import { Sandbox } from "@vercel/sandbox"`. Remove the four separate "use step" wrapper functions (provisionSandbox, runCommand, teardownSandbox, saveSandboxSnapshot) and show direct `Sandbox.create()`, `sandbox.runCommand()`, and `sandbox.destroy()` calls in the workflow function since these implicitly run as steps. Simplify the agent tool example to use inline execute functions that call Sandbox methods directly with an `activeSandbox` variable for workflow state. Across all cookbook files, replace "Workflow DevKit" with "Workflow SDK" (8 instances in 5 files: publishing-libraries.mdx, secure-credentials.mdx, ai-sdk.mdx, chat-sdk.mdx, sandbox.mdx). * docs: simplify cookbook index to plain MDX listing Replace the interactive CookbookExplorer (726-line decision tree + browse component) with a simple MDX page that lists recipes grouped by category with linked titles and descriptions. Remove v1-v5 design variations and trim cookbook-tree.ts to sidebar-only metadata. * fix type checks --------- Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com>
1 parent 8a7c59c commit 851a530

61 files changed

Lines changed: 6489 additions & 17 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { Step, Steps } from 'fumadocs-ui/components/steps';
2+
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
3+
import { createRelativeLink } from 'fumadocs-ui/mdx';
4+
import type { Metadata } from 'next';
5+
import { notFound } from 'next/navigation';
6+
import type { ComponentProps } from 'react';
7+
import {
8+
rewriteCookbookUrl,
9+
rewriteCookbookUrlsInText,
10+
} from '@/lib/geistdocs/cookbook-source';
11+
import { AskAI } from '@/components/geistdocs/ask-ai';
12+
import { CopyPage } from '@/components/geistdocs/copy-page';
13+
import {
14+
DocsBody,
15+
DocsDescription,
16+
DocsPage,
17+
DocsTitle,
18+
} from '@/components/geistdocs/docs-page';
19+
import { EditSource } from '@/components/geistdocs/edit-source';
20+
import { Feedback } from '@/components/geistdocs/feedback';
21+
import { getMDXComponents } from '@/components/geistdocs/mdx-components';
22+
import { OpenInChat } from '@/components/geistdocs/open-in-chat';
23+
import { ScrollTop } from '@/components/geistdocs/scroll-top';
24+
import { Badge } from '@/components/ui/badge';
25+
import { Separator } from '@/components/ui/separator';
26+
import { getLLMText, getPageImage, source } from '@/lib/geistdocs/source';
27+
28+
const Page = async ({ params }: PageProps<'/[lang]/cookbook/[[...slug]]'>) => {
29+
const { slug, lang } = await params;
30+
31+
// Prepend 'cookbook' to resolve from the docs source
32+
const resolvedSlug = slug ? ['cookbook', ...slug] : ['cookbook'];
33+
const page = source.getPage(resolvedSlug, lang);
34+
35+
if (!page) {
36+
notFound();
37+
}
38+
39+
const publicUrl = rewriteCookbookUrl(page.url);
40+
const publicPage = { ...page, url: publicUrl } as typeof page;
41+
42+
const markdown = rewriteCookbookUrlsInText(await getLLMText(page));
43+
const MDX = page.data.body;
44+
45+
const RelativeLink = createRelativeLink(source, publicPage);
46+
const PublicCookbookLink = (props: ComponentProps<typeof RelativeLink>) => {
47+
const href =
48+
typeof props.href === 'string'
49+
? rewriteCookbookUrl(props.href)
50+
: props.href;
51+
return <RelativeLink {...props} href={href} />;
52+
};
53+
54+
return (
55+
<DocsPage
56+
full={page.data.full}
57+
tableOfContent={{
58+
style: 'clerk',
59+
footer: (
60+
<div className="my-3 space-y-3">
61+
<Separator />
62+
<EditSource path={page.path} />
63+
<ScrollTop />
64+
<Feedback />
65+
<CopyPage text={markdown} />
66+
<AskAI href={publicUrl} />
67+
<OpenInChat href={publicUrl} />
68+
</div>
69+
),
70+
}}
71+
toc={page.data.toc}
72+
>
73+
<DocsTitle>{page.data.title}</DocsTitle>
74+
<DocsDescription>{page.data.description}</DocsDescription>
75+
<DocsBody>
76+
<MDX
77+
components={getMDXComponents({
78+
a: PublicCookbookLink,
79+
Badge,
80+
Step,
81+
Steps,
82+
Tabs,
83+
Tab,
84+
})}
85+
/>
86+
</DocsBody>
87+
</DocsPage>
88+
);
89+
};
90+
91+
export const generateStaticParams = () => {
92+
// Generate params for all cookbook pages
93+
const allParams = source.generateParams();
94+
return allParams
95+
.filter((p) => Array.isArray(p.slug) && p.slug[0] === 'cookbook')
96+
.map((p) => ({
97+
...p,
98+
slug: (p.slug as string[]).slice(1), // Remove 'cookbook' prefix
99+
}));
100+
};
101+
102+
export const generateMetadata = async ({
103+
params,
104+
}: PageProps<'/[lang]/cookbook/[[...slug]]'>) => {
105+
const { slug, lang } = await params;
106+
const resolvedSlug = slug ? ['cookbook', ...slug] : ['cookbook'];
107+
const page = source.getPage(resolvedSlug, lang);
108+
109+
if (!page) {
110+
notFound();
111+
}
112+
113+
const publicPath = rewriteCookbookUrl(page.url);
114+
115+
const metadata: Metadata = {
116+
title: page.data.title,
117+
description: page.data.description,
118+
openGraph: {
119+
images: getPageImage(page).url,
120+
},
121+
alternates: {
122+
canonical: publicPath,
123+
types: {
124+
'text/markdown': `${publicPath}.md`,
125+
},
126+
},
127+
};
128+
129+
return metadata;
130+
};
131+
132+
export default Page;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { DocsLayout } from '@/components/geistdocs/docs-layout';
2+
import { getCookbookTree } from '@/lib/geistdocs/cookbook-source';
3+
4+
const Layout = async ({
5+
children,
6+
params,
7+
}: LayoutProps<'/[lang]/cookbook'>) => {
8+
const { lang } = await params;
9+
10+
return <DocsLayout tree={getCookbookTree(lang)}>{children}</DocsLayout>;
11+
};
12+
13+
export default Layout;

docs/app/[lang]/docs/[[...slug]]/page.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { Step, Steps } from 'fumadocs-ui/components/steps';
22
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
33
import { createRelativeLink } from 'fumadocs-ui/mdx';
44
import type { Metadata } from 'next';
5-
import { notFound } from 'next/navigation';
5+
import { notFound, permanentRedirect } from 'next/navigation';
6+
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
67
import { AgentTraces } from '@/components/custom/agent-traces';
78
import { FluidComputeCallout } from '@/components/custom/fluid-compute-callout';
89
import { AskAI } from '@/components/geistdocs/ask-ai';
@@ -31,6 +32,12 @@ const WorldTestingPerformanceNoop = () => null;
3132
const Page = async ({ params }: PageProps<'/[lang]/docs/[[...slug]]'>) => {
3233
const { slug, lang } = await params;
3334

35+
if (Array.isArray(slug) && slug[0] === 'cookbook') {
36+
const rest = slug.slice(1).join('/');
37+
const legacyPath = `/docs/cookbook${rest ? `/${rest}` : ''}`;
38+
permanentRedirect(`/${lang}${rewriteCookbookUrl(legacyPath)}`);
39+
}
40+
3441
const page = source.getPage(slug, lang);
3542

3643
if (!page) {
@@ -85,7 +92,13 @@ const Page = async ({ params }: PageProps<'/[lang]/docs/[[...slug]]'>) => {
8592
);
8693
};
8794

88-
export const generateStaticParams = () => source.generateParams();
95+
export const generateStaticParams = () =>
96+
source
97+
.generateParams()
98+
.filter(
99+
(params) =>
100+
!(Array.isArray(params.slug) && params.slug[0] === 'cookbook'),
101+
);
89102

90103
export const generateMetadata = async ({
91104
params,

docs/app/[lang]/docs/layout.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { DocsLayout } from '@/components/geistdocs/docs-layout';
2-
import { source } from '@/lib/geistdocs/source';
2+
import { getDocsTreeWithoutCookbook } from '@/lib/geistdocs/cookbook-source';
33

44
const Layout = async ({ children, params }: LayoutProps<'/[lang]/docs'>) => {
55
const { lang } = await params;
66

7-
return <DocsLayout tree={source.pageTree[lang]}>{children}</DocsLayout>;
7+
return (
8+
<DocsLayout tree={getDocsTreeWithoutCookbook(lang)}>
9+
{children}
10+
</DocsLayout>
11+
);
812
};
913

1014
export default Layout;

docs/app/[lang]/llms.mdx/[[...slug]]/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { notFound } from 'next/navigation';
2+
import { rewriteCookbookUrlsInText } from '@/lib/geistdocs/cookbook-source';
23
import { getLLMText, source } from '@/lib/geistdocs/source';
34
import { i18n } from '@/lib/geistdocs/i18n';
45

@@ -18,8 +19,10 @@ export async function GET(
1819
const sitemapPath =
1920
lang === i18n.defaultLanguage ? '/sitemap.md' : `/${lang}/sitemap.md`;
2021

22+
const text = await getLLMText(page);
23+
2124
return new Response(
22-
(await getLLMText(page)) +
25+
rewriteCookbookUrlsInText(text) +
2326
`\n\n## Sitemap
2427
[Overview of all docs pages](${sitemapPath})\n`,
2528
{

docs/app/[lang]/llms.txt/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { NextRequest } from 'next/server';
2+
import { rewriteCookbookUrlsInText } from '@/lib/geistdocs/cookbook-source';
23
import { getLLMText, source } from '@/lib/geistdocs/source';
34

45
export const revalidate = false;
@@ -11,7 +12,7 @@ export const GET = async (
1112
const scan = source.getPages(lang).map(getLLMText);
1213
const scanned = await Promise.all(scan);
1314

14-
return new Response(scanned.join('\n\n'), {
15+
return new Response(rewriteCookbookUrlsInText(scanned.join('\n\n')), {
1516
headers: {
1617
'Content-Type': 'text/markdown; charset=utf-8',
1718
},

docs/app/[lang]/sitemap.md/route.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Node, Root } from 'fumadocs-core/page-tree';
2+
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
23
import { source } from '@/lib/geistdocs/source';
34

45
export const revalidate = false;
@@ -16,10 +17,10 @@ export async function GET(
1617

1718
if ('type' in node) {
1819
if (node.type === 'page') {
19-
mdText += `${indent}- [${node.name}](${node.url})\n`;
20+
mdText += `${indent}- [${node.name}](${rewriteCookbookUrl(node.url)})\n`;
2021
} else if (node.type === 'folder') {
2122
if (node.index) {
22-
mdText += `${indent}- [${node.name}](${node.index.url})\n`;
23+
mdText += `${indent}- [${node.name}](${rewriteCookbookUrl(node.index.url)})\n`;
2324
} else {
2425
mdText += `${indent}- ${node.name}\n`;
2526
}
@@ -30,7 +31,6 @@ export async function GET(
3031
}
3132
}
3233
} else if (node.children.length > 0) {
33-
// Root node
3434
for (const child of node.children) {
3535
traverseTree(child, depth);
3636
}

docs/app/sitemap.md/route.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Node, Root } from 'fumadocs-core/page-tree';
2+
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
23
import { i18n } from '@/lib/geistdocs/i18n';
34
import { source } from '@/lib/geistdocs/source';
45

@@ -13,10 +14,10 @@ export async function GET(_req: Request) {
1314

1415
if ('type' in node) {
1516
if (node.type === 'page') {
16-
mdText += `${indent}- [${node.name}](${node.url})\n`;
17+
mdText += `${indent}- [${node.name}](${rewriteCookbookUrl(node.url)})\n`;
1718
} else if (node.type === 'folder') {
1819
if (node.index) {
19-
mdText += `${indent}- [${node.name}](${node.index.url})\n`;
20+
mdText += `${indent}- [${node.name}](${rewriteCookbookUrl(node.index.url)})\n`;
2021
} else {
2122
mdText += `${indent}- ${node.name}\n`;
2223
}
@@ -27,7 +28,6 @@ export async function GET(_req: Request) {
2728
}
2829
}
2930
} else if (node.children.length > 0) {
30-
// Root node
3131
for (const child of node.children) {
3232
traverseTree(child, depth);
3333
}

docs/app/sitemap.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { MetadataRoute } from 'next';
22

3+
import { rewriteCookbookUrl } from '@/lib/geistdocs/cookbook-source';
34
import { source } from '@/lib/geistdocs/source';
45

56
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
@@ -17,7 +18,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
1718
changeFrequency: 'weekly' as const,
1819
lastModified: undefined,
1920
priority: 0.5,
20-
url: url(page.url),
21+
url: url(rewriteCookbookUrl(page.url)),
2122
});
2223
}
2324

0 commit comments

Comments
 (0)