Skip to content

Add framework adapters and dogfood examples#54

Open
KayleeWilliams wants to merge 4 commits into
mainfrom
framework-adapters-dogfood
Open

Add framework adapters and dogfood examples#54
KayleeWilliams wants to merge 4 commits into
mainfrom
framework-adapters-dogfood

Conversation

@KayleeWilliams
Copy link
Copy Markdown
Collaborator

Summary

  • Add first-party framework adapters for Astro, Nuxt/Nitro, SvelteKit, and TanStack Start, plus shared framework routing helpers.
  • Add shared search clients for vanilla, React, Vue, and Svelte with stale-result protection.
  • Add dogfood apps for Next.js, Astro, SvelteKit, and Nuxt using the same shared docs fixture.
  • Document the framework integration matrix and regenerate docs artifacts.

Verification

  • bun test
  • bun test packages/leadtype/src/framework-adapters.test.ts
  • bun --filter leadtype test
  • bun --filter leadtype check-types
  • bun --filter leadtype build
  • bun --filter next-example check-types
  • bun --filter astro-example check-types
  • bun --filter sveltekit-example check-types
  • bun --filter nuxt-example check-types
  • bun --filter next-example build
  • bun --filter astro-example build
  • bun --filter sveltekit-example build
  • bun --filter nuxt-example build
  • bun x ultracite check packages/leadtype/src docs apps/next-example apps/astro-example apps/sveltekit-example apps/nuxt-example examples/shared-docs .gitignore biome.jsonc

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added example apps showing Leadtype docs + search in Astro, Next.js, Nuxt, SvelteKit, and SvelteKit/TanStack starters.
    • Introduced a framework-neutral search client and framework-specific search UI helpers (React/Vue/Svelte).
  • Documentation

    • New framework integration guide comparing adapters, routing, and runtime patterns.
    • Added shared example docs and quickstart content used by the examples.

Walkthrough

Adds core framework utilities and adapter entrypoints for Astro, Next, Nuxt, SvelteKit, and TanStack; implements a framework-neutral search client plus React/Vue/Svelte wrappers; provides fully working example apps for each framework; expands package exports and Rollup entries; and adds tests, docs, linter, and ignore updates.

Changes

Multi-framework Integration Adapters and Search

Layer / File(s) Summary
Internal framework utilities
packages/leadtype/src/internal/framework.ts
Core utilities for URL/path normalization, route slug composition, path-traversal-safe markdown reading, and HTTP artifact handlers that serve sitemaps/robots or delegate to agent markdown generation.
Framework adapters
packages/leadtype/src/astro/, src/next/, src/nuxt/, src/sveltekit/, src/tanstack-start/
Framework-specific entrypoints wrapping internal utilities: static path/params generators, page-data loaders, and HTTP route/handler adapters matching each framework's conventions.
Search client and framework implementations
packages/leadtype/src/search/client.ts, search/react.ts, search/vue.ts, search/svelte.ts
Framework-neutral search client that loads and caches generated JSON artifacts; framework wrappers (React hook, Vue composable, Svelte store) that manage query state, debouncing, and stale-response suppression.
Next.js client refactor and proxy
packages/leadtype/src/next/client.ts, src/next/index.ts, apps/next-example/proxy.ts
Next client re-exports the shared search surface; Next adapter now delegates artifact handling to internal handlers and adds createDocsProxy to fetch static markdown from Next static serving.
Package exports and build wiring
packages/leadtype/package.json, packages/leadtype/rollup.config.ts, packages/leadtype/src/internal/package-surface.test.ts
Expanded package exports with framework and search subpaths, updated Rollup entries, and adapted package-surface tests for the new adapter and search entrypoints.
Astro example app
apps/astro-example/*
Astro example with MDX integration, docs source, dynamic docs pages, markdown endpoint, client search scaffolding, styles, and scripts.
Next.js example app
apps/next-example/*
Next App Router example with static params generation, MDX rendering, SearchBox client component, MDX components, proxy config, styles, and scripts.
Nuxt example app
apps/nuxt-example/*
Nuxt/Nitro example with server API for page loading, middleware/route handlers for agent artifacts, Vue search composable usage, styles, and scripts.
SvelteKit example app
apps/sveltekit-example/*
SvelteKit example with mdsvex config, server markdown endpoint, prerendered docs pages, Svelte search store, styles, and scripts.
Shared example docs fixture
examples/shared-docs/*, docs/docs.config.ts
Shared docs fixture and docs config consumed by all examples with index, quickstart, components, and search pages.
Framework adapter test suite
packages/leadtype/src/framework-adapters.test.ts
Vitest suite validating static path generation, page-data loaders, artifact handlers, and proxy behavior across adapters.
Documentation, linter, and build config
docs/build/framework-matrix.mdx, docs/quickstart.mdx, biome.jsonc, .gitignore
New framework matrix docs, updated quickstart link, Biome overrides for example app globs, and expanded .gitignore for generated artifacts and example public files.

Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • inthhq/leadtype#37: Related to MDX type-table source root resolution and typeTableBasePath usage in framework MDX setups.
  • inthhq/leadtype#51: Overlaps on core/adapter boundary, Next integration helpers, and client search surfaces.
  • inthhq/leadtype#14: Also adjusts Rollup/entries for new package entry points.

🐰 I hopped through code and stitched the strands,
Adapters sprout across many lands,
Search and docs in tidy rows,
Examples show how everything flows.
A little hop — the project grows!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch framework-adapters-dogfood

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a45c2789a4

ℹ️ 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".

Comment thread packages/leadtype/src/next/index.ts Outdated
Comment on lines +184 to +188
const response = await fetch(
new URL(
joinUrlPath(config.publicPathPrefix ?? "/", target.filePath),
url
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid recursively fetching markdown through Proxy

When this helper is used with the documented matcher in apps/next-example/proxy.ts (/docs/:path*), the internal fetch(new URL('/docs/…md', url)) is intercepted by the same Proxy before Next serves the file from public/. A request for /docs/quickstart.md (or an HTML request negotiated to markdown) therefore re-enters createDocsProxy, which fetches /docs/quickstart.md again and can recurse until the request times out instead of returning the generated markdown. The proxy needs to fetch from a path excluded by the matcher or the example/config needs to exclude generated .md assets from Proxy.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR — Adds first-party adapters for Astro, Nuxt/Nitro, SvelteKit, and TanStack Start; consolidates duplicated route-handler plumbing into internal/framework.ts; splits the search client into framework-neutral + per-framework hooks; and adds four dogfood apps over a shared MDX fixture. Two minor nits below; nothing blocking.

Key changes

  • Centralize adapter plumbing in internal/framework.ts — extracts createAgentArtifactHandler, createLoadPage, listJoinedSlugs, createPublicMarkdownReader, and slug helpers so every adapter shares one implementation.
  • Add leadtype/{astro,nuxt,sveltekit,tanstack-start} — each adapter exposes a static-paths factory, a createLoadPageData, and a server/markdown handler over the shared internal helpers.
  • Split search clientssearch/client.ts holds the framework-neutral createSearchClient (module-level artifact cache, stale-result protection); search/{react,vue,svelte}.ts wrap it; next/client.ts becomes a re-export shell.
  • Add createDocsProxy for Next Edge — fetches generated markdown from Next's static asset serving since Proxy can't read the filesystem.
  • Dogfood appsapps/{astro,next,sveltekit,nuxt}-example/ all render the same examples/shared-docs/ fixture.
  • Expand package-surface.test.ts — adds new adapter directories and a separate FRAMEWORK_RUNTIME_DIRECTORIES list so the framework-runtime ban also exempts search/{react,vue,svelte}.ts.

Summary | 75 files | 3 commits | base: mainframework-adapters-dogfood


Shared internal framework module

Before: Each adapter duplicated artifact routing, markdown reading, and slug helpers.
After: internal/framework.ts owns the shared primitives; adapters thin to per-framework glue.

createAgentArtifactHandler dual-mounts the three artifact files at both the unscoped root and the scoped <artifactBasePath>/... paths. Which set is reachable depends on framework wiring (a /docs/[...slug] catch-all won't see /robots.txt, but a root handler will); the fall-through to createAgentMarkdownResponse is unchanged. createPublicMarkdownReader keeps the previous Next traversal guard (relative.startsWith("..") || path.isAbsolute(relative)) verbatim.

packages/leadtype/src/internal/framework.ts · packages/leadtype/src/next/index.ts


Framework-neutral search client

Before: Search hook + BM25 loader lived together in next/client.ts as React-only.
After: search/client.ts exposes a framework-free createSearchClient and resolveSearchArtifactUrls; the React hook moves to search/react.ts; Vue and Svelte get their own wrappers.

Each per-framework wrapper preserves stale-result protection — the React hook keeps a latestQueryRef, while Vue and Svelte use a monotonically incrementing requestId so older awaited searches drop their results when a newer one starts.

packages/leadtype/src/search/client.ts · packages/leadtype/src/search/react.ts · packages/leadtype/src/search/svelte.ts · packages/leadtype/src/search/vue.ts


Dogfood apps over a single MDX fixture

Before: Only apps/example and apps/fumadocs-example exercised the package.
After: Four apps (Astro, Next, SvelteKit, Nuxt) render the same examples/shared-docs/ fixture through their respective adapters and ship a working browser search box.

Each app runs leadtype generate --src ../../examples/shared-docs --out public as part of dev/build/check-types, so adapter wiring is exercised against generated artifacts on every type-check. Note that every example repeats the same { ...manifestJson, version: 1 } as unknown as AgentReadabilityManifest cast — internal/framework.ts exports a normalizeManifest that does exactly this but has no callers; consider wiring it in or trimming the duplication.

examples/shared-docs/docs/docs.config.ts · apps/astro-example/src/pages/docs/[...slug].astro · apps/sveltekit-example/src/routes/docs/[...slug]/+page.svelte

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using Claude Opus𝕏

manifest: AgentReadabilityManifest
): AgentReadabilityManifest {
return { ...manifest, version: 1 };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeManifest is exported but never called anywhere in the repo (grep confirms). Every dogfood app open-codes the same { ...manifestJson, version: 1 } as unknown as AgentReadabilityManifest cast — either wire this helper in (or expose it through each adapter’s public surface) or drop the export to keep the internal module honest.

name: string
): string | undefined {
const value = headers?.[name] ?? headers?.[name.toLowerCase()];
return Array.isArray(value) ? value[0] : value;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both call sites pass already-lowercase strings ("host", "x-forwarded-proto"), and Node’s http layer normalizes incoming header keys to lowercase before populating req.headers. The name.toLowerCase() fallback never fires — consider dropping it to keep the helper to a single lookup.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

🤖 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 `@apps/astro-example/src/pages/docs/`[...slug].astro:
- Around line 45-51: The input event handler that calls await
client.search(query) should be wrapped in try/catch/finally: inside the try call
const matches = await client.search(query) and render results; in catch handle
and log the error (and show a user-facing message in status or results) so
unhandled rejections don't occur; in finally ensure status.textContent is reset
from "loading" (e.g., to "ready" or "idle") and any necessary cleanup
(results.replaceChildren() remains correct) so the UI never gets stuck in the
"loading" state; update the anonymous callback passed to input.addEventListener
accordingly to reference client.search, status.textContent, and
results.replaceChildren.

In `@apps/astro-example/src/pages/docs/`[...slug].md.ts:
- Around line 6-9: The object construction using `manifest` currently uses an
unsafe double assertion (`as unknown as AgentReadabilityManifest`) which
bypasses structural checks; replace that with TypeScript's `satisfies` operator
to validate the shape at compile time: keep the spread of `manifestJson` and
`version: 1`, and change the trailing cast to `satisfies
AgentReadabilityManifest` so the compiler enforces the structure of `manifest`
without turning off type safety for `manifestJson`/`manifest`.

In `@apps/next-example/components/search-box.tsx`:
- Line 15: The span that renders the dynamic status value (status) in SearchBox
should be announced by assistive tech, so change the element that currently
renders <span>{status}</span> to be a live region by adding ARIA attributes
(e.g., aria-live="polite" and aria-atomic="true", or role="status") so screen
readers announce updates; keep the variable name status and the SearchBox
component unchanged, and optionally apply a visually-hidden/sr-only CSS class if
you don't want the status visible but still announced.

In `@apps/next-example/next.config.mjs`:
- Around line 9-12: Replace the CWD-based resolution used for typeTableBasePath
with a path based on the config file location: instead of
path.resolve(process.cwd(), "../../examples/shared-docs") compute the directory
of this ESM module via fileURLToPath(import.meta.url) and path.dirname(...) and
then resolve "../../examples/shared-docs" against that; update the
typeTableBasePath assignment to use
path.resolve(path.dirname(fileURLToPath(import.meta.url)),
"../../examples/shared-docs") (ensure fileURLToPath is imported from "url") so
the docs fixture path is stable regardless of invocation CWD.

In `@apps/next-example/proxy.ts`:
- Around line 5-8: The manifest object is being force-cast with "as unknown as
AgentReadabilityManifest", bypassing TypeScript checks; replace this double
assertion by using a const assertion for the version literal and the `satisfies`
operator so the spreaded manifestJson keeps inferred types but is validated
against AgentReadabilityManifest at compile time—update the `manifest`
declaration (the variable named manifest built from manifestJson and version) to
use `version: 1 as const` (or include the literal in an `as const` object) and
append `satisfies AgentReadabilityManifest` instead of the double cast.

In `@apps/nuxt-example/server/routes/docs/`[...slug].md.ts:
- Around line 6-9: The manifest variable is using a double type assertion ("as
unknown as AgentReadabilityManifest") which bypasses compile-time shape checks;
replace that assertion by using TypeScript's satisfies operator so the object
created from manifestJson is validated against AgentReadabilityManifest (i.e.,
change the declaration of manifest that spreads manifestJson and sets version to
use "satisfies AgentReadabilityManifest" instead of "as unknown as
AgentReadabilityManifest"), keeping the same object shape and runtime value but
restoring proper type-level validation for manifest/manifestJson.

In `@apps/sveltekit-example/src/app.html`:
- Around line 3-7: Add a default <title> element into the document head so pages
without an explicit title aren’t untitled; update the head block that contains
%sveltekit.head% by adding a descriptive default title (e.g., a site name or
"Untitled Page") before the %sveltekit.head% token so the <title> is present
even when individual pages don’t set one.

In `@apps/sveltekit-example/src/lib/source.ts`:
- Around line 1-6: Replace the process.cwd()-based fixtureRoot computation with
a file-location-based resolution using import.meta.url: update the code that
defines fixtureRoot (currently using path.resolve(process.cwd(),
"../../examples/shared-docs")) to instead resolve the examples/shared-docs
directory relative to the current module file via path.dirname(new
URL(import.meta.url).pathname) or equivalent; change the fixtureRoot initializer
in apps/sveltekit-example/src/lib/source.ts (variable name: fixtureRoot) and
apply the identical fix in svelte.config.js so the path is correct regardless of
the working directory.

In `@apps/sveltekit-example/src/routes/docs/`[...slug]/+page.server.ts:
- Around line 1-2: The export `load` in +page.server.ts should be explicitly
typed as SvelteKit's PageServerLoad; add an import like `import type {
PageServerLoad } from './$types'` and change the signature to `export const
load: PageServerLoad = async (event) => { ... }` (or destructure the same
params) so the route's server load contract is enforced and types for
params/locals are available; keep the existing implementation but ensure the
parameter shape matches the PageServerLoad type.

In `@docs/build/framework-matrix.mdx`:
- Around line 12-19: The docs table lists non-existent dogfood apps for
"TanStack Start" and "Fumadocs" causing inconsistency; update
docs/build/framework-matrix.mdx by either removing the "TanStack Start" and
"Fumadocs" rows from the table or changing their "Dogfood app" column entries to
"Planned" or "Coming soon" (choose one approach consistently), and ensure the
verification section that enumerates implemented dogfood apps is updated to
match the table (so the set of examples in the verification text matches the
four actual apps: Next.js, Astro, SvelteKit, Nuxt).

In `@packages/leadtype/src/astro/index.ts`:
- Around line 65-80: Current code unconditionally treats any request with
context.params.slug as an artifact markdown request and drops original headers,
causing valid artifact paths (e.g. /docs/sitemap.md) to be routed incorrectly
and lose headers; fix by first checking that the request pathname corresponds to
the artifactBasePath (config.artifactBasePath or "/docs") before calling
createAgentMarkdownResponse for `${slug}.md`, and pass the original request
headers (e.g., Array.from(context.request.headers) or cloning
context.request.headers) instead of an empty object; locate the logic around
context.params.slug, createAgentMarkdownResponse, joinUrlPath and replace the
unconditional short-circuit with a conditional that verifies the request path is
under artifactBasePath and forwards request headers to
createAgentMarkdownResponse, otherwise fall through to handler(context.request).

In `@packages/leadtype/src/next/index.ts`:
- Around line 183-191: readMarkdownFile may throw if fetch fails, causing a 500
instead of falling back; wrap the fetch and response handling for the
constructed URL (using joinUrlPath and url within readMarkdownFile) in a
try-catch, and on any thrown error return null (optionally log the error) so
callers treat missing artifacts gracefully; ensure the function signature
(readMarkdownFile(target: MarkdownMirrorTarget)) still returns
Promise<string|null>.

In `@packages/leadtype/src/nuxt/index.ts`:
- Around line 65-68: Sanitize the x-forwarded-proto before building the URL:
read the header via headerValue(headers, "x-forwarded-proto"), split on commas
and take the first segment, trim and lowercase it, then validate it is "http" or
"https" (fallback to "http" if not) and assign that to the proto variable used
in the new URL(...) call; update the proto assignment near the URL construction
(referencing proto, headerValue, new URL, event.path and req?.url) so
comma-separated values or unexpected values cannot cause new URL to throw.

In `@packages/leadtype/src/search/react.ts`:
- Around line 72-73: The current stale-response check compares
latestQueryRef.current to the query string (next), which fails when overlapping
requests use the same string; instead implement request sequencing: add a
numeric/latestRequestIdRef (useRef<number>(0)), increment it when dispatching a
new request, capture the current id in the local request (e.g., localRequestId =
++latestRequestIdRef.current) and when the async response resolves only apply
state if localRequestId === latestRequestIdRef.current; update places currently
using latestQueryRef/timeoutRef for suppression to use this id-based check (keep
latestQueryRef for storing the string if needed, and clear timeoutRef logic
unchanged).
🪄 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: 5479db62-7cbc-4de0-9dcd-8b75a5ae07f6

📥 Commits

Reviewing files that changed from the base of the PR and between 8b84f60 and a45c278.

⛔ Files ignored due to path filters (6)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-nav.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-pages.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (69)
  • .gitignore
  • apps/astro-example/astro.config.mjs
  • apps/astro-example/package.json
  • apps/astro-example/public/styles.css
  • apps/astro-example/src/lib/source.ts
  • apps/astro-example/src/pages/docs/[...slug].astro
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • apps/astro-example/src/pages/index.astro
  • apps/astro-example/tsconfig.json
  • apps/next-example/app/docs/[[...slug]]/page.tsx
  • apps/next-example/app/layout.tsx
  • apps/next-example/app/page.tsx
  • apps/next-example/app/styles.css
  • apps/next-example/components/search-box.tsx
  • apps/next-example/lib/mdx-components.tsx
  • apps/next-example/lib/source.ts
  • apps/next-example/next-env.d.ts
  • apps/next-example/next.config.mjs
  • apps/next-example/package.json
  • apps/next-example/proxy.ts
  • apps/next-example/tsconfig.json
  • apps/nuxt-example/app.vue
  • apps/nuxt-example/assets/styles.css
  • apps/nuxt-example/lib/source.ts
  • apps/nuxt-example/nuxt.config.ts
  • apps/nuxt-example/package.json
  • apps/nuxt-example/pages/docs/[[slug]].vue
  • apps/nuxt-example/pages/index.vue
  • apps/nuxt-example/server/api/docs.get.ts
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/nuxt-example/tsconfig.json
  • apps/sveltekit-example/package.json
  • apps/sveltekit-example/src/app.css
  • apps/sveltekit-example/src/app.html
  • apps/sveltekit-example/src/lib/source.ts
  • apps/sveltekit-example/src/routes/+layout.svelte
  • apps/sveltekit-example/src/routes/+page.svelte
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.svelte
  • apps/sveltekit-example/svelte.config.js
  • apps/sveltekit-example/tsconfig.json
  • apps/sveltekit-example/vite.config.ts
  • biome.jsonc
  • docs/build/framework-matrix.mdx
  • docs/docs.config.ts
  • docs/quickstart.mdx
  • examples/shared-docs/README.md
  • examples/shared-docs/docs/components.mdx
  • examples/shared-docs/docs/docs.config.ts
  • examples/shared-docs/docs/index.mdx
  • examples/shared-docs/docs/quickstart.mdx
  • examples/shared-docs/docs/search.mdx
  • packages/leadtype/package.json
  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/framework-adapters.test.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/next/client.ts
  • packages/leadtype/src/next/index.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/search/client.ts
  • packages/leadtype/src/search/react.ts
  • packages/leadtype/src/search/svelte.ts
  • packages/leadtype/src/search/vue.ts
  • packages/leadtype/src/sveltekit/index.ts
  • packages/leadtype/src/tanstack-start/index.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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
Add rel="noopener" when using target="_blank" on links

Files:

  • apps/sveltekit-example/src/app.html
  • apps/next-example/lib/mdx-components.tsx
  • apps/next-example/app/layout.tsx
  • apps/next-example/app/docs/[[...slug]]/page.tsx
  • apps/next-example/app/page.tsx
  • apps/next-example/components/search-box.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when 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:

  • apps/next-example/lib/mdx-components.tsx
  • apps/next-example/app/layout.tsx
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/nuxt-example/lib/source.ts
  • apps/sveltekit-example/vite.config.ts
  • apps/sveltekit-example/src/lib/source.ts
  • apps/next-example/next-env.d.ts
  • apps/nuxt-example/server/api/docs.get.ts
  • apps/nuxt-example/nuxt.config.ts
  • apps/next-example/app/docs/[[...slug]]/page.tsx
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • packages/leadtype/src/tanstack-start/index.ts
  • docs/docs.config.ts
  • apps/next-example/lib/source.ts
  • apps/next-example/app/page.tsx
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • examples/shared-docs/docs/docs.config.ts
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/astro-example/src/lib/source.ts
  • apps/next-example/components/search-box.tsx
  • packages/leadtype/src/search/svelte.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/sveltekit/index.ts
  • apps/next-example/proxy.ts
  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/search/client.ts
  • packages/leadtype/src/search/vue.ts
  • packages/leadtype/src/next/index.ts
  • packages/leadtype/src/next/client.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/search/react.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/framework-adapters.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
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax 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
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks 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 use eval() or assign directly to document.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:

  • apps/next-example/lib/mdx-components.tsx
  • apps/next-example/app/layout.tsx
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/nuxt-example/lib/source.ts
  • apps/sveltekit-example/vite.config.ts
  • apps/sveltekit-example/src/lib/source.ts
  • apps/next-example/next-env.d.ts
  • apps/nuxt-example/server/api/docs.get.ts
  • apps/nuxt-example/nuxt.config.ts
  • apps/sveltekit-example/svelte.config.js
  • apps/next-example/app/docs/[[...slug]]/page.tsx
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • packages/leadtype/src/tanstack-start/index.ts
  • docs/docs.config.ts
  • apps/next-example/lib/source.ts
  • apps/next-example/app/page.tsx
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • examples/shared-docs/docs/docs.config.ts
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/astro-example/src/lib/source.ts
  • apps/next-example/components/search-box.tsx
  • packages/leadtype/src/search/svelte.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/sveltekit/index.ts
  • apps/next-example/proxy.ts
  • packages/leadtype/rollup.config.ts
  • packages/leadtype/src/search/client.ts
  • packages/leadtype/src/search/vue.ts
  • packages/leadtype/src/next/index.ts
  • packages/leadtype/src/next/client.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/search/react.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/framework-adapters.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 the key prop 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
Avoid dangerouslySetInnerHTML unless absolutely necessary
Use proper image components (e.g., Next.js <Image>) over <img> tags
Use Next.js <Image> component for images
Use next/head or 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 of React.forwardRef in React 19+

Files:

  • apps/next-example/lib/mdx-components.tsx
  • apps/next-example/app/layout.tsx
  • apps/next-example/app/docs/[[...slug]]/page.tsx
  • apps/next-example/app/page.tsx
  • apps/next-example/components/search-box.tsx
**/*.{svelte,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use class and for attributes (not className or htmlFor) in Solid/Svelte/Vue/Qwik

Files:

  • apps/sveltekit-example/src/routes/+layout.svelte
  • apps/sveltekit-example/src/routes/+page.svelte
  • apps/nuxt-example/app.vue
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.svelte
  • apps/nuxt-example/pages/index.vue
  • apps/nuxt-example/pages/docs/[[slug]].vue
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/tanstack-start/index.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/sveltekit/index.ts
  • packages/leadtype/src/next/index.ts
  • packages/leadtype/src/nuxt/index.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/leadtype/src/internal/package-surface.test.ts
  • packages/leadtype/src/framework-adapters.test.ts
🪛 HTMLHint (1.9.2)
apps/sveltekit-example/src/app.html

[error] 7-7: <title> must be present in tag.

(title-require)

🪛 LanguageTool
docs/build/framework-matrix.mdx

[style] ~52-~52: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ch/reactin client search components. UsecreateDocsProxy()` when a Next Proxy o...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (60)
packages/leadtype/package.json (1)

36-39: LGTM!

Also applies to: 44-47, 76-91, 116-123, 170-170, 179-179, 191-193, 220-222, 225-228

packages/leadtype/rollup.config.ts (1)

10-10: LGTM!

Also applies to: 12-12, 20-23, 30-31

packages/leadtype/src/internal/package-surface.test.ts (1)

12-25: LGTM!

Also applies to: 82-82, 84-84, 92-95, 102-103, 168-174, 182-182

examples/shared-docs/README.md (1)

1-3: LGTM!

examples/shared-docs/docs/components.mdx (1)

1-19: LGTM!

examples/shared-docs/docs/docs.config.ts (1)

1-33: LGTM!

examples/shared-docs/docs/index.mdx (1)

1-28: LGTM!

examples/shared-docs/docs/quickstart.mdx (1)

1-24: LGTM!

examples/shared-docs/docs/search.mdx (1)

1-21: LGTM!

docs/build/framework-matrix.mdx (1)

21-127: LGTM!

docs/docs.config.ts (1)

20-20: LGTM!

docs/quickstart.mdx (1)

105-105: LGTM!

.gitignore (1)

27-43: LGTM!

biome.jsonc (2)

20-20: LGTM!


56-83: LGTM!

packages/leadtype/src/search/client.ts (1)

1-160: LGTM!

packages/leadtype/src/search/svelte.ts (1)

1-115: LGTM!

packages/leadtype/src/search/vue.ts (1)

1-75: LGTM!

packages/leadtype/src/next/client.ts (1)

3-14: LGTM!

packages/leadtype/src/internal/framework.ts (1)

46-58: LGTM!

Also applies to: 60-85, 87-114, 116-211

packages/leadtype/src/sveltekit/index.ts (1)

26-53: LGTM!

packages/leadtype/src/tanstack-start/index.ts (1)

22-49: LGTM!

packages/leadtype/src/framework-adapters.test.ts (1)

96-201: LGTM!

apps/astro-example/astro.config.mjs (1)

1-19: LGTM!

apps/astro-example/public/styles.css (1)

1-68: LGTM!

apps/astro-example/src/lib/source.ts (1)

1-12: LGTM!

apps/astro-example/src/pages/docs/[...slug].md.ts (1)

11-17: LGTM!

apps/astro-example/src/pages/index.astro (1)

1-17: LGTM!

apps/astro-example/tsconfig.json (1)

1-7: LGTM!

apps/next-example/package.json (1)

1-30: LGTM!

apps/next-example/proxy.ts (1)

10-22: LGTM!

apps/next-example/tsconfig.json (1)

1-16: LGTM!

apps/next-example/app/docs/[[...slug]]/page.tsx (1)

1-40: LGTM!

apps/next-example/app/layout.tsx (1)

1-11: LGTM!

apps/next-example/app/page.tsx (1)

1-18: LGTM!

apps/next-example/app/styles.css (1)

1-78: LGTM!

apps/next-example/components/search-box.tsx (1)

1-14: LGTM!

Also applies to: 16-27

apps/next-example/lib/mdx-components.tsx (1)

1-34: LGTM!

apps/next-example/lib/source.ts (1)

1-13: LGTM!

apps/next-example/next-env.d.ts (1)

1-7: LGTM!

apps/nuxt-example/app.vue (1)

1-5: LGTM!

apps/nuxt-example/assets/styles.css (1)

1-63: LGTM!

apps/nuxt-example/lib/source.ts (1)

1-18: LGTM!

apps/nuxt-example/nuxt.config.ts (1)

1-13: LGTM!

Also applies to: 15-17

apps/nuxt-example/package.json (1)

1-26: LGTM!

apps/nuxt-example/pages/docs/[[slug]].vue (1)

1-58: LGTM!

apps/nuxt-example/pages/index.vue (1)

1-12: LGTM!

apps/nuxt-example/server/api/docs.get.ts (1)

1-21: LGTM!

apps/nuxt-example/tsconfig.json (1)

1-3: LGTM!

apps/sveltekit-example/package.json (1)

1-28: LGTM!

apps/nuxt-example/server/middleware/agent-readability.ts (1)

6-9: ⚡ Quick win

Replace the double-cast with satisfies to enable proper type checking.

as unknown as AgentReadabilityManifest bypasses structural validation and masks schema drift. Use satisfies AgentReadabilityManifest instead to leverage TypeScript's type narrowing while maintaining type safety.

Proposed fix
const manifest = {
  ...manifestJson,
  version: 1,
-} as unknown as AgentReadabilityManifest;
+} satisfies AgentReadabilityManifest;
apps/sveltekit-example/src/app.css (1)

1-63: LGTM!

apps/sveltekit-example/src/app.html (1)

1-2: LGTM!

Also applies to: 8-12

apps/sveltekit-example/src/routes/+layout.svelte (1)

1-5: LGTM!

apps/sveltekit-example/src/routes/+page.svelte (1)

1-10: LGTM!

apps/sveltekit-example/src/routes/docs/[...slug]/+page.svelte (1)

1-43: LGTM!

apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts (1)

5-8: ⚡ Quick win

The suggested fix using satisfies will not compile.

When manifestJson is imported without a type assertion, it's typed as unknown. TypeScript does not allow spreading an unknown value and immediately checking it with satisfies in the same expression—the spread operand must be a known type first.

The double assertion exists because the JSON import lacks explicit typing. Better alternatives:

  1. Add import assertion (preferred if the JSON file is stable):
import manifestJson from "../../../../static/docs/agent-readability.json" with { type: "json" };
const manifest = { ...manifestJson, version: 1 } as AgentReadabilityManifest;
  1. Or cast the spread explicitly:
const manifest = { ...(manifestJson as Record<string, unknown>), version: 1 } as AgentReadabilityManifest;

The double assertion is a valid (if verbose) workaround when the JSON source cannot be properly typed at import time.

			> Likely an incorrect or invalid review comment.
apps/sveltekit-example/svelte.config.js (1)

1-21: LGTM!

apps/sveltekit-example/tsconfig.json (1)

1-15: LGTM!

apps/sveltekit-example/vite.config.ts (1)

1-6: LGTM!

Comment thread apps/astro-example/src/pages/docs/[...slug].astro Outdated
Comment thread apps/astro-example/src/pages/docs/[...slug].md.ts Outdated
Comment thread apps/next-example/components/search-box.tsx Outdated
Comment thread apps/next-example/next.config.mjs Outdated
Comment thread apps/next-example/proxy.ts Outdated
Comment thread docs/build/framework-matrix.mdx Outdated
Comment thread packages/leadtype/src/astro/index.ts Outdated
Comment thread packages/leadtype/src/next/index.ts
Comment thread packages/leadtype/src/nuxt/index.ts Outdated
Comment thread packages/leadtype/src/search/react.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@packages/leadtype/src/llm/readability.ts`:
- Around line 126-136: normalizeAgentReadabilityManifest currently force-casts
any object and unconditionally overwrites manifest.version, which masks
incompatible or future manifests; update normalizeAgentReadabilityManifest to
validate that manifest is an object, ensure it has a version field equal to
SUPPORTED_MANIFEST_VERSION (throw a clear error if missing or mismatched),
validate required manifest properties/types (matching AgentReadabilityManifest
shape) before returning, and return the original manifest (or a validated
shallow copy) typed as AgentReadabilityManifest instead of blindly setting
version to SUPPORTED_MANIFEST_VERSION; reference the function
normalizeAgentReadabilityManifest, the AgentReadabilityManifest type, and
SUPPORTED_MANIFEST_VERSION when implementing these checks.
🪄 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: 3232242e-1897-4d1e-a1a5-b665185b4d47

📥 Commits

Reviewing files that changed from the base of the PR and between a45c278 and ba694b1.

⛔ Files ignored due to path filters (4)
  • apps/example/src/generated/agent-readability.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-content.json is excluded by !**/generated/**
  • apps/example/src/generated/docs-search-index.json is excluded by !**/generated/**
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • apps/astro-example/src/pages/docs/[...slug].astro
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • apps/example/server/utils/agent-readability.ts
  • apps/example/src/lib/docs-head.ts
  • apps/next-example/components/search-box.tsx
  • apps/next-example/next.config.mjs
  • apps/next-example/proxy.ts
  • apps/nuxt-example/nuxt.config.ts
  • apps/nuxt-example/package.json
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/sveltekit-example/src/app.html
  • apps/sveltekit-example/src/lib/source.ts
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • docs/build/framework-matrix.mdx
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/framework-adapters.test.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/llm/readability.ts
  • packages/leadtype/src/next/index.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/search/react.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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
Add rel="noopener" when using target="_blank" on links

Files:

  • apps/sveltekit-example/src/app.html
  • apps/next-example/components/search-box.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use explicit types for function parameters and return values when they enhance clarity
Prefer unknown over any when 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:

  • apps/example/src/lib/docs-head.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/llm/readability.ts
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • apps/next-example/components/search-box.tsx
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • apps/example/server/utils/agent-readability.ts
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/sveltekit-example/src/lib/source.ts
  • apps/nuxt-example/nuxt.config.ts
  • packages/leadtype/src/index.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/next-example/proxy.ts
  • packages/leadtype/src/search/react.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/framework-adapters.test.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/next/index.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
Prefer for...of loops over .forEach() and indexed for loops
Use optional chaining (?.) and nullish coalescing (??) for safer property access
Prefer template literals over string concatenation
Use destructuring for object and array assignments
Use const by default, let only when reassignment is needed, never var
Always await promises in async functions - don't forget to use the return value
Use async/await syntax 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
Remove console.log, debugger, and alert statements from production code
Throw Error objects with descriptive messages, not strings or other values
Use try-catch blocks 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 use eval() or assign directly to document.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:

  • apps/example/src/lib/docs-head.ts
  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/llm/readability.ts
  • apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts
  • apps/next-example/components/search-box.tsx
  • apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts
  • apps/astro-example/src/pages/docs/[...slug].md.ts
  • apps/example/server/utils/agent-readability.ts
  • apps/nuxt-example/server/middleware/agent-readability.ts
  • apps/sveltekit-example/src/lib/source.ts
  • apps/nuxt-example/nuxt.config.ts
  • packages/leadtype/src/index.ts
  • apps/nuxt-example/server/routes/docs/[...slug].md.ts
  • apps/next-example/proxy.ts
  • packages/leadtype/src/search/react.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/framework-adapters.test.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/internal/framework.ts
  • packages/leadtype/src/next/index.ts
**/index.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid barrel files (index files that re-export everything)

Files:

  • packages/leadtype/src/llm/index.ts
  • packages/leadtype/src/index.ts
  • packages/leadtype/src/astro/index.ts
  • packages/leadtype/src/nuxt/index.ts
  • packages/leadtype/src/next/index.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 the key prop 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
Avoid dangerouslySetInnerHTML unless absolutely necessary
Use proper image components (e.g., Next.js <Image>) over <img> tags
Use Next.js <Image> component for images
Use next/head or 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 of React.forwardRef in React 19+

Files:

  • apps/next-example/components/search-box.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{test,spec}.{js,ts,jsx,tsx}: Write assertions inside it() or test() blocks
Avoid done callbacks in async tests - use async/await instead
Don't use .only or .skip in committed code
Keep test suites reasonably flat - avoid excessive describe nesting

Files:

  • packages/leadtype/src/framework-adapters.test.ts
🪛 LanguageTool
docs/build/framework-matrix.mdx

[style] ~52-~52: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ch/reactin client search components. UsecreateDocsProxy()` when a Next Proxy o...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (23)
apps/astro-example/src/pages/docs/[...slug].astro (1)

1-68: LGTM!

apps/astro-example/src/pages/docs/[...slug].md.ts (1)

1-14: LGTM!

apps/example/server/utils/agent-readability.ts (1)

3-4: LGTM!

Also applies to: 15-16

apps/example/src/lib/docs-head.ts (1)

4-4: LGTM!

Also applies to: 8-8

apps/next-example/components/search-box.tsx (1)

1-28: LGTM!

apps/next-example/next.config.mjs (1)

1-20: LGTM!

apps/next-example/proxy.ts (1)

1-19: LGTM!

apps/nuxt-example/nuxt.config.ts (1)

1-6: LGTM!

apps/nuxt-example/server/middleware/agent-readability.ts (1)

1-14: LGTM!

apps/nuxt-example/server/routes/docs/[...slug].md.ts (1)

1-12: LGTM!

apps/sveltekit-example/src/app.html (1)

1-12: LGTM!

apps/sveltekit-example/src/lib/source.ts (1)

1-22: LGTM!

apps/sveltekit-example/src/routes/docs/[...slug].md/+server.ts (1)

1-12: LGTM!

apps/sveltekit-example/src/routes/docs/[...slug]/+page.server.ts (1)

1-25: LGTM!

docs/build/framework-matrix.mdx (1)

1-127: LGTM!

packages/leadtype/src/astro/index.ts (1)

1-64: LGTM!

packages/leadtype/src/framework-adapters.test.ts (1)

1-225: LGTM!

packages/leadtype/src/index.ts (1)

39-39: LGTM!

packages/leadtype/src/internal/framework.ts (1)

1-205: LGTM!

packages/leadtype/src/llm/index.ts (1)

76-76: LGTM!

packages/leadtype/src/next/index.ts (1)

1-6: LGTM!

Also applies to: 48-54, 142-204

packages/leadtype/src/nuxt/index.ts (1)

1-100: LGTM!

packages/leadtype/src/search/react.ts (1)

1-128: LGTM!

Comment on lines +126 to +136
export function normalizeAgentReadabilityManifest(
manifest: unknown
): AgentReadabilityManifest {
if (typeof manifest !== "object" || manifest === null) {
throw new Error("leadtype: agent-readability manifest must be an object.");
}
return {
...manifest,
version: SUPPORTED_MANIFEST_VERSION,
} as AgentReadabilityManifest;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Prevent version masking and invalid manifest coercion in normalization.

normalizeAgentReadabilityManifest currently overwrites manifest.version to 1 and force-casts arbitrary objects. That can silently accept incompatible/future manifest payloads and fail later in harder-to-debug paths.

Proposed fix
 export function normalizeAgentReadabilityManifest(
   manifest: unknown
 ): AgentReadabilityManifest {
-  if (typeof manifest !== "object" || manifest === null) {
+  if (
+    typeof manifest !== "object" ||
+    manifest === null ||
+    Array.isArray(manifest)
+  ) {
     throw new Error("leadtype: agent-readability manifest must be an object.");
   }
+  const candidate = manifest as Record<string, unknown>;
+  const version = candidate.version;
+  if (
+    version !== undefined &&
+    version !== SUPPORTED_MANIFEST_VERSION
+  ) {
+    throw new Error(
+      `leadtype: agent-readability manifest version ${String(version)} is not supported (expected ${SUPPORTED_MANIFEST_VERSION}).`
+    );
+  }
   return {
-    ...manifest,
+    ...candidate,
     version: SUPPORTED_MANIFEST_VERSION,
   } as AgentReadabilityManifest;
 }
🤖 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 126 - 136,
normalizeAgentReadabilityManifest currently force-casts any object and
unconditionally overwrites manifest.version, which masks incompatible or future
manifests; update normalizeAgentReadabilityManifest to validate that manifest is
an object, ensure it has a version field equal to SUPPORTED_MANIFEST_VERSION
(throw a clear error if missing or mismatched), validate required manifest
properties/types (matching AgentReadabilityManifest shape) before returning, and
return the original manifest (or a validated shallow copy) typed as
AgentReadabilityManifest instead of blindly setting version to
SUPPORTED_MANIFEST_VERSION; reference the function
normalizeAgentReadabilityManifest, the AgentReadabilityManifest type, and
SUPPORTED_MANIFEST_VERSION when implementing these checks.

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new issues. Reviewed the following changes:

  • Replaced the open-coded { ...manifestJson, version: 1 } as unknown as AgentReadabilityManifest cast in every dogfood with a new public normalizeAgentReadabilityManifest helper (validates the input is a non-null object, stamps the supported version, and is re-exported from leadtype and leadtype/llm); dropped the unused internal normalizeManifest.
  • Wrapped createDocsProxy's inner fetch() in try/catch so network failures degrade to the missing-markdown fallback; updated apps/next-example/proxy.ts matcher to "/docs/:path((?!.*\\.md$).*)" so .md paths fall through to Next's static asset serving instead of recursing back into the proxy. Added a framework-adapters.test.ts case for the fetch-failure path.
  • Removed Astro createDocsEndpoint's bespoke context.params?.slug short-circuit (which dropped request headers and unconditionally treated any slug as a markdown request); routing is fully delegated to the shared createAgentArtifactHandler. Added an Astro sitemap.md regression test.
  • Reworked React useLeadtypeSearch's stale-result protection to use a monotonically incrementing latestRequestIdRef, matching Vue/Svelte; overlapping requests with identical query strings no longer corrupt each other.
  • Hardened nuxt/eventToRequest: drops the dead name.toLowerCase() fallback in headerValue, takes the first comma-separated segment of host, and validates x-forwarded-proto to "https" or "http" before constructing the URL.
  • Resolved dogfood path-resolution issues by deriving paths from import.meta.url (Next next.config.mjs typeTableBasePath; SvelteKit source.ts fixtureRoot with cwd-relative + module-relative candidates).
  • Added accessibility (role="status" / aria-live="polite") to the Astro and Next dogfood search status spans, a default <title> to the SvelteKit app.html, and an error-fallback status.textContent = "error" in the Astro search handler.
  • Annotated apps/sveltekit-example/.../+page.server.ts load with PageServerLoad; marked TanStack Start and Fumadocs rows as Planned in docs/build/framework-matrix.mdx; dropped the unused @nuxtjs/mdc MDC plugin wiring from apps/nuxt-example/nuxt.config.ts and its dependency.

Pullfrog  | View workflow run | Using Claude Opus𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant