Add docs metadata helpers and deployment recipes#57
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (4)**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{test,spec}.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/index.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (11)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds typed JSON-LD generation (createDocsJsonLd, stringifyJsonLd) with override/transform support, a Next.js App Router metadata factory (createGenerateMetadata), example page wiring that emits JSON-LD, tests, and deployment/framework documentation. ChangesMetadata and JSON-LD integration
Sequence Diagram(s)sequenceDiagram
participant Route as Next Route Handler
participant Generator as createGenerateMetadata
participant Manifest as Page Manifest
participant JsonLd as createDocsJsonLd
participant Head as Page Head / Response
Route->>Generator: params + route context
Generator->>Manifest: resolve urlPath from basePath + slug
Manifest-->>Generator: page entry or not found
alt page found
Generator->>Generator: build defaults (title/description, alternates, openGraph)
Generator->>Generator: apply overrides (title/description -> cascade to openGraph)
Generator->>Head: return NextDocsMetadata (title, alternates, openGraph, etc.)
Route->>JsonLd: provide page.urlPath + overrides
JsonLd-->>Head: JsonLdValue (or null)
Head->>Route: page with optional inline JSON-LD script
else page not found
Generator-->>Head: empty {} metadata
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/build/deploy-generated-artifacts.mdx`:
- Line 201: The import for manifestJson uses a relative public path
("../../public/docs/agent-readability.json") which resolves incorrectly; update
the import statement that declares manifestJson to reference the project-root
public asset (use an absolute public path like "/docs/agent-readability.json")
so Astro will load the manifest from the public folder correctly.
In `@packages/leadtype/src/llm/readability.ts`:
- Around line 721-723: The page lookup in createDocsJsonLd uses a strict
equality on entry.urlPath === config.urlPath which misses variants with trailing
slashes or query/hash fragments; normalize both sides before comparing (e.g.,
strip trailing slash and remove query/hash) so config.manifest.pages.find
compares normalizedEntryUrl === normalizedConfigUrl; update the lookup around
config.manifest.pages and config.urlPath (and any variable named entry.urlPath)
to use the normalized values so the JSON-LD generation isn't skipped for
equivalent URLs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 166bbf04-4b26-4874-b6aa-0db339b39373
📒 Files selected for processing (12)
apps/next-example/app/docs/[[...slug]]/page.tsxdocs/build/build-a-docs-site.mdxdocs/build/deploy-generated-artifacts.mdxdocs/build/framework-matrix.mdxdocs/build/generate-static-artifacts.mdxdocs/build/optimize-docs-for-agents.mdxdocs/docs.config.tsdocs/reference/llm.mdxpackages/leadtype/src/llm/llm.test.tspackages/leadtype/src/llm/readability.tspackages/leadtype/src/next/index.tspackages/leadtype/src/next/next.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Preferunknownoveranywhen the type is genuinely unknown
Use const assertions (as const) for immutable values and literal types
Leverage TypeScript's type narrowing instead of type assertions
Files:
docs/docs.config.tspackages/leadtype/src/next/next.test.tsapps/next-example/app/docs/[[...slug]]/page.tsxpackages/leadtype/src/next/index.tspackages/leadtype/src/llm/readability.tspackages/leadtype/src/llm/llm.test.ts
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{js,ts,jsx,tsx}: Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Use arrow functions for callbacks and short functions
Preferfor...ofloops over.forEach()and indexedforloops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Useconstby default,letonly when reassignment is needed, nevervar
Alwaysawaitpromises in async functions - don't forget to use the return value
Useasync/awaitsyntax instead of promise chains for better readability
Handle errors appropriately in async code with try-catch blocks
Don't use async functions as Promise executors
Removeconsole.log,debugger, andalertstatements from production code
ThrowErrorobjects with descriptive messages, not strings or other values
Usetry-catchblocks meaningfully - don't catch errors just to rethrow them
Prefer early returns over nested conditionals for error cases
Extract complex conditions into well-named boolean variables
Use early returns to reduce nesting
Prefer simple conditionals over nested ternary operators
Don't useeval()or assign directly todocument.cookie
Avoid spread syntax in accumulators within loops
Use top-level regex literals instead of creating them in loops
Prefer specific imports over namespace imports
Use descriptive names for functions, variables, and types for meaningful naming
Add comments for complex logic, but prefer self-documenting code
Files:
docs/docs.config.tspackages/leadtype/src/next/next.test.tsapps/next-example/app/docs/[[...slug]]/page.tsxpackages/leadtype/src/next/index.tspackages/leadtype/src/llm/readability.tspackages/leadtype/src/llm/llm.test.ts
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions insideit()ortest()blocks
Avoid done callbacks in async tests - use async/await instead
Don't use.onlyor.skipin committed code
Keep test suites reasonably flat - avoid excessivedescribenesting
Files:
packages/leadtype/src/next/next.test.tspackages/leadtype/src/llm/llm.test.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx}: Use function components over class components in React
Call hooks at the top level only, never conditionally
Specify all dependencies in hook dependency arrays correctly
Use thekeyprop for elements in iterables (prefer unique IDs over array indices)
Nest children between opening and closing tags instead of passing as props
Don't define components inside other components
AvoiddangerouslySetInnerHTMLunless absolutely necessary
Use proper image components (e.g., Next.js<Image>) over<img>tags
Use Next.js<Image>component for images
Usenext/heador App Router metadata API for head elements in Next.js
Use Server Components for async data fetching instead of async Client Components in Next.js
Use ref as a prop instead ofReact.forwardRefin React 19+
Files:
apps/next-example/app/docs/[[...slug]]/page.tsx
**/*.{jsx,tsx,html}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{jsx,tsx,html}: Use semantic HTML and ARIA attributes for accessibility: provide meaningful alt text for images, use proper heading hierarchy, add labels for form inputs, include keyboard event handlers alongside mouse events, use semantic elements instead of divs with roles
Addrel="noopener"when usingtarget="_blank"on links
Files:
apps/next-example/app/docs/[[...slug]]/page.tsx
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
packages/leadtype/src/next/index.ts
🪛 LanguageTool
docs/reference/llm.mdx
[style] ~319-~319: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... type="application/ld+json">contents. UsecreateDocsHead` when your framework ac...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🔇 Additional comments (11)
docs/reference/llm.mdx (1)
243-243: LGTM!Also applies to: 255-255, 315-315, 317-317, 319-319, 323-327, 329-338, 340-340, 366-366, 368-378, 386-387
docs/build/framework-matrix.mdx (1)
36-37: LGTM!Also applies to: 55-64
docs/build/optimize-docs-for-agents.mdx (1)
162-163: LGTM!Also applies to: 166-180, 183-184
docs/build/build-a-docs-site.mdx (1)
59-59: LGTM!docs/build/generate-static-artifacts.mdx (1)
14-15: LGTM!docs/docs.config.ts (1)
21-21: LGTM!packages/leadtype/src/llm/readability.ts (1)
56-57: LGTM!Also applies to: 225-269, 276-277, 648-715, 724-745, 1101-1112
packages/leadtype/src/llm/llm.test.ts (1)
18-19: LGTM!Also applies to: 32-33, 661-669, 679-721, 1130-1149
packages/leadtype/src/next/index.ts (1)
6-6: LGTM!Also applies to: 10-10, 21-123, 144-254, 333-432
packages/leadtype/src/next/next.test.ts (1)
8-8: LGTM!Also applies to: 202-333
apps/next-example/app/docs/[[...slug]]/page.tsx (1)
1-10: LGTM!Also applies to: 16-21, 33-48
| normalizeAgentReadabilityManifest, | ||
| stringifyJsonLd, | ||
| } from "leadtype/llm/readability"; | ||
| import manifestJson from "../../public/docs/agent-readability.json"; |
There was a problem hiding this comment.
Fix Astro manifest import path in the snippet.
Line 201 points to ../../public/..., which resolves to src/public/... from src/pages/docs/[...slug].astro. For a standard Astro app, this should point to project-root public.
Suggested doc fix
-import manifestJson from "../../public/docs/agent-readability.json";
+import manifestJson from "../../../public/docs/agent-readability.json";📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import manifestJson from "../../public/docs/agent-readability.json"; | |
| import manifestJson from "../../../public/docs/agent-readability.json"; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/build/deploy-generated-artifacts.mdx` at line 201, The import for
manifestJson uses a relative public path
("../../public/docs/agent-readability.json") which resolves incorrectly; update
the import statement that declares manifestJson to reference the project-root
public asset (use an absolute public path like "/docs/agent-readability.json")
so Astro will load the manifest from the public folder correctly.
| const page = config.manifest.pages.find( | ||
| (entry) => entry.urlPath === config.urlPath | ||
| ); |
There was a problem hiding this comment.
Normalize urlPath before page lookup in createDocsJsonLd.
The lookup is strict (entry.urlPath === config.urlPath), so valid variants like trailing slash or query/hash forms can return null and silently skip JSON-LD generation.
Suggested fix
export function createDocsJsonLd(
config: CreateDocsJsonLdConfig
): JsonLdValue | null {
assertManifestVersion(config.manifest);
+ const normalizedUrlPath =
+ normalizeUrlPath(config.urlPath).replace(TRAILING_SLASH_PATTERN, "") || "/";
const page = config.manifest.pages.find(
- (entry) => entry.urlPath === config.urlPath
+ (entry) => entry.urlPath === normalizedUrlPath
);
if (!page) {
return null;
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/leadtype/src/llm/readability.ts` around lines 721 - 723, The page
lookup in createDocsJsonLd uses a strict equality on entry.urlPath ===
config.urlPath which misses variants with trailing slashes or query/hash
fragments; normalize both sides before comparing (e.g., strip trailing slash and
remove query/hash) so config.manifest.pages.find compares normalizedEntryUrl ===
normalizedConfigUrl; update the lookup around config.manifest.pages and
config.urlPath (and any variable named entry.urlPath) to use the normalized
values so the JSON-LD generation isn't skipped for equivalent URLs.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a43a8fe2b3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const page = config.manifest.pages.find( | ||
| (entry) => entry.urlPath === urlPath | ||
| ); |
There was a problem hiding this comment.
Validate manifest version before generating metadata
When createGenerateMetadata is called with a stale or future agent-readability.json, this new path reads config.manifest.pages without the manifest-version assertion used by the other runtime helpers such as createDocsJsonLd/createDocsHead. In that scenario the helper silently emits canonical and OpenGraph metadata from an incompatible manifest instead of failing loudly, so add the same version check before looking up pages.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
No new issues found.
TL;DR — Adds framework-neutral JSON-LD helpers (createDocsJsonLd / stringifyJsonLd) with override and transform hooks, a Next App Router createGenerateMetadata helper that cascades title/description into OpenGraph, and host-specific deployment recipes that are wired into the docs nav and dogfooded in the Next example.
Key changes
- JSON-LD helpers with overrides —
createDocsJsonLdreturns a Schema.orgTechArticleobject enriched withname,mainEntityOfPage, conditionalinLanguage, and anisPartOfWebSite.stringifyJsonLdescapes<,>,&, U+2028, and U+2029 for safe<script type="application/ld+json">contents. - Next App Router
createGenerateMetadata— Produces agenerateMetadatafunction with default title, description, OpenGraph, andtext/markdowncanonical alternate. Title and description cascade into OpenGraph defaults unless an explicit OpenGraph override wins. Includes escape-hatchmetadataandtransformconfig. - Deployment recipes — New
docs/build/deploy-generated-artifacts.mdxcovering Next on Vercel, Nuxt, SvelteKit, Astro, Cloudflare Workers and Pages, and plain Vite hosting, plus the output-contract table. Cross-linked fromframework-matrix,build-a-docs-site, andgenerate-static-artifacts. createDocsHeadintegration — Now accepts ajsonLdconfig that passes through tocreateDocsJsonLdand omits the JSON-LD meta entry when no page matches.- Next example dogfood —
apps/next-example/app/docs/[[...slug]]/page.tsximports the agent-readability manifest, wiresgenerateMetadata, and renders route-scoped JSON-LD withstringifyJsonLd.
Summary | 12 files | 2 commits | base: main ← KayleeWilliams/p3-issues
Framework-neutral JSON-LD helpers
Before:
renderJsonLdandrenderJsonLdScriptproduced a fixedTechArticleobject with no override surface, and a missing-page caller had to guard manually.
After:createDocsJsonLd({ urlPath, manifest, overrides, transform })returnsJsonLdValue | null, with a function-or-object overrides shape; defaults gainname,mainEntityOfPage,isPartOf, andinLanguagewhen the page has a locale.
The breadcrumb: false sentinel removes the generated breadcrumb cleanly; any other field is replaced when overridden. stringifyJsonLd is exported separately so framework-typed metadata APIs and <script> consumers share the same escape path.
packages/leadtype/src/llm/readability.ts · packages/leadtype/src/llm/llm.test.ts · docs/reference/llm.mdx
Next App Router metadata helper
Before: App Router pages had to wire up canonical, OpenGraph, and
text/markdownalternate metadata by hand against the manifest.
After:createGenerateMetadata({ manifest })returns a typedgenerateMetadatathat resolves the manifest entry from the route slug and emits title, description, alternates, and OpenGraph defaults, with cascade rules from title/description into OpenGraph.
How does the cascade behave?
A `title` override updates both `metadata.title` and `metadata.openGraph.title`, and likewise for `description`. An explicit `openGraph` override (object or callback) wins on whichever fields it sets, but unset fields keep the cascaded values. The catch-all `metadata` override merges last, and `transform` runs after every other layer.
packages/leadtype/src/next/index.ts · packages/leadtype/src/next/next.test.ts · apps/next-example/app/docs/[[...slug]]/page.tsx
Deployment recipes for generated artifacts
Before:
framework-matrixcovered command shapes but not host-specific paths for servingllms.txt, markdown mirrors, search JSON, manifest, sitemap, and robots.
After: A dedicated guide spells out static vs. runtime responsibilities per host and gives copy-paste page snippets for Next, Nuxt, SvelteKit, Astro, Cloudflare, and plain Vite.
The output-contract table at the top doubles as a checklist for what leadtype generate writes and which paths the runtime must serve.
docs/build/deploy-generated-artifacts.mdx · docs/build/framework-matrix.mdx · docs/build/build-a-docs-site.mdx · docs/docs.config.ts
Claude Opus | 𝕏
There was a problem hiding this comment.
No new issues. Reviewed the following changes:
- Added a
SUPPORTED_MANIFEST_VERSIONguard tocreateGenerateMetadata, mirroring the existingassertManifestVersionpattern inreadability.tsso stale manifests fail loudly with a regenerate-the-manifest message. - Covered the unsupported-version path with a
next.test.tscase that asserts the thrown message. - Tweaked the
createDocsJsonLd/stringifyJsonLd/createDocsHeadlead-in paragraph indocs/reference/llm.mdxto vary sentence openings.
Claude Opus | 𝕏

Summary
createGenerateMetadatahelper with metadata and OpenGraph override supportValidation
bun testand Ultracite on both commitsbun --filter leadtype buildbun --filter leadtype testbun --filter leadtype check-types./node_modules/.bin/tsgo --noEmitinapps/next-example./node_modules/.bin/next build --webpackinapps/next-examplebun x ultracite check