Add headless docs search and AI answers#4
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds build-time static docs index generation, an in-memory search engine with query guards and rate limiting, AI answer streaming, server search/ask endpoints, client search pages (with MDX heading ID helpers), route registration, tests, docs, and packaging/build updates including a search-generation script. Changes
Sequence Diagram(s)sequenceDiagram
participant Build as rgba(90,150,255,0.5)
participant MDX as rgba(120,200,150,0.5)
participant Generator as rgba(255,200,100,0.5)
participant FS as rgba(200,200,200,0.5)
participant JSON as rgba(150,150,250,0.5)
Build->>MDX: Read markdown docs
Build->>Generator: Invoke generateSearchIndex(docs)
Generator->>FS: Traverse docs/ and read files
FS-->>Generator: Return file contents
Generator->>Generator: Parse, tokenize, chunk, build index
Generator->>JSON: Serialize index to search-index.json
JSON-->>FS: Write file to disk
Generator-->>Build: Return counts (docs/chunks/terms)
sequenceDiagram
participant Client as rgba(120,180,255,0.5)
participant SearchAPI as rgba(180,120,255,0.5)
participant RateLimit as rgba(255,150,120,0.5)
participant Engine as rgba(120,255,180,0.5)
participant Index as rgba(200,200,100,0.5)
Client->>Client: Debounce query
Client->>SearchAPI: GET /api/docs/search?q=...
SearchAPI->>RateLimit: check("search:clientId")
alt denied
RateLimit-->>SearchAPI: deny
SearchAPI-->>Client: 429 + Retry-After
else allowed
RateLimit-->>SearchAPI: allow
SearchAPI->>Engine: searchDocs(Index, query)
Engine->>Index: score & rank chunks
Engine-->>SearchAPI: results
SearchAPI-->>Client: JSON { results }
end
sequenceDiagram
participant Client as rgba(120,180,255,0.5)
participant AskAPI as rgba(180,120,255,0.5)
participant RateLimit as rgba(255,150,120,0.5)
participant Context as rgba(200,255,150,0.5)
participant AI as rgba(255,200,100,0.5)
participant Model as rgba(150,150,250,0.5)
Client->>AskAPI: POST /api/docs/ask { query }
AskAPI->>RateLimit: check("ask:clientId")
alt denied
RateLimit-->>AskAPI: deny
AskAPI-->>Client: 429 + Retry-After
else allowed
RateLimit-->>AskAPI: allow
AskAPI->>Context: createAnswerContext(index, query)
Context-->>AskAPI: system + prompt + sources
AskAPI->>AI: streamText(model, prompts...)
AI->>Model: stream request
Model-->>AI: token stream
AI-->>AskAPI: streaming Response
AskAPI-->>Client: proxy streamed text + sources
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes 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
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f960bb74e1
ℹ️ 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".
| setAnswer(""); | ||
| setError(""); | ||
| setAnswerStatus("loading"); | ||
| const nextResults = await runSearch(trimmedQuery); |
There was a problem hiding this comment.
Skip pre-search gating when submitting long Ask queries
handleAsk always calls runSearch before posting to /api/docs/ask, so questions longer than 400 chars are rejected by /api/docs/search (maxQueryChars) even though the UI allows 600 chars and /api/docs/ask explicitly accepts askMaxQueryChars (600). In that case the Ask flow never reaches the answer endpoint and incorrectly reports “No matching docs,” which blocks valid long-form questions.
Useful? React with 👍 / 👎.
| if (chunk.done) { | ||
| break; | ||
| } | ||
| setAnswer((current) => current + decoder.decode(chunk.value)); |
There was a problem hiding this comment.
Decode streamed answer chunks in incremental mode
Each streamed chunk is decoded with decoder.decode(chunk.value) without { stream: true }, so multi-byte UTF-8 characters split across chunk boundaries can be corrupted in the rendered answer text. This appears in normal SSE/text streaming whenever chunk boundaries do not align with character boundaries.
Useful? React with 👍 / 👎.
| const chunk = index.chunks.find( | ||
| (candidate) => candidate.id === posting.chunkId | ||
| ); |
There was a problem hiding this comment.
Index chunks by id before scoring BM25 postings
The scorer does a linear index.chunks.find(...) for every posting and again for every scored chunk, which turns lookup cost into O(postings × chunks) and can dominate latency on larger docs sets. Since this path runs on every query, search response time degrades sharply as the index grows; building a Map of chunk IDs once would avoid the repeated scans.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs-smoke/scripts/search-generate.ts`:
- Line 9: Replace the relative source import with the package export to exercise
the published build: change the import that currently pulls generateSearchIndex
from "../../../packages/docs/src/search/node-index.ts" to import {
generateSearchIndex } from "@inth/docs/search/node"; update any tooling or
TypeScript config if needed so the package resolution works at runtime; ensure
the symbol generateSearchIndex is imported from the package export and
tests/scripts still run.
In `@apps/docs-smoke/src/mdx-components.tsx`:
- Around line 8-16: The textFromChildren function currently only handles
strings, numbers, and arrays and returns "" for React elements, which leads to
empty heading IDs; update textFromChildren (used for HeadingProps["children"])
to detect React elements/objects and, when an object with a props property
exists, recurse into element.props.children (also handle null/undefined/boolean
children) so text is extracted from nested elements like <code> or <span>; keep
existing behavior for strings/numbers/arrays and ensure the function always
returns a trimmed string suitable for generating anchor IDs.
In `@apps/docs-smoke/src/routes/api/docs/ask.ts`:
- Around line 65-70: The handler currently returns only the response from
streamDocsAnswer and discards sources; update the endpoint to include the
returned sources so clients can display citations — call streamDocsAnswer(...)
and capture both response and sources, then return an object containing both
(e.g., { response, sources }) or, if streaming/compatibility requires, serialize
sources into a response header (e.g., "x-doc-sources") before returning; look
for the call to streamDocsAnswer and the variable docsSearchIndex to locate the
code to change.
In `@apps/docs-smoke/src/routes/search.tsx`:
- Around line 139-145: The POST to "/api/docs/ask" (the fetch call creating
`const response = await fetch("/api/docs/ask", { ... body: JSON.stringify({
query: trimmedQuery }) })`) lacks an AbortController, so previous answer streams
keep running; create an AbortController per query, pass controller.signal into
fetch, store the controller (e.g., in a local variable or React ref) and call
controller.abort() before starting a new request or when unmounting/navigating
to cancel any in-flight answer stream and cleanup resources.
- Around line 159-168: The streaming loop that calls reader.read() can throw and
currently leaves answerStatus stuck at "streaming"; wrap the entire read loop in
a try-catch (surround the while(true) { const chunk = await reader.read(); ... }
block) to catch any errors, call setAnswerStatus("error") (or set to "idle" in a
finally) and optionally append an error message via setAnswer, and ensure
resources are cleaned (e.g., close reader) — update references in this file
around reader.read(), setAnswer(...), setAnswerStatus(...) and
decoder.decode(...) to implement the try-catch/finally handling.
In `@packages/docs/src/search/ai.ts`:
- Line 68: Replace the silent onError handler that returns undefined with one
that logs the error for observability: locate the onError callback (onError: ()
=> undefined) in packages/docs/src/search/ai.ts and change it to capture the
error parameter and write a non-throwing log (e.g., console.error or the
existing logger) including context like "AI stream error" and the error object,
so errors are recorded but still don't crash the process.
In `@packages/docs/src/search/search.ts`:
- Around line 734-773: The in-memory Map entries in createMemoryRateLimiter
never get removed causing unbounded growth; update createMemoryRateLimiter to
purge expired keys from entries: when check(identifier) runs, if an existing
entry is expired remove it before creating the new entry (use
entries.delete(identifier)), and additionally add an optional periodic cleanup
(e.g., a timer started inside createMemoryRateLimiter that iterates entries and
deletes those with resetAt <= now()) or a simple max-size eviction policy to
trim the Map; reference functions/vars: createMemoryRateLimiter, entries, check,
resetAt, MemoryRateLimiterOptions.
- Around line 554-560: The loop in searchDocs calls index.chunks.find(...) for
each posting (and again later), causing O(postings × chunks) work; create a Map
keyed by chunk.id (e.g., const chunkMap = new Map(index.chunks.map(c => [c.id,
c]))) once at the start of searchDocs and replace index.chunks.find(...) calls
with chunkMap.get(posting.chunkId) (and similarly where chunk lookups repeat) so
lookups become O(1) and avoid the quadratic behavior.
🪄 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: 2214cfa4-a82f-4e88-bc7e-be0f40f01551
⛔ Files ignored due to path filters (2)
apps/docs-smoke/src/generated/docs-search-index.jsonis excluded by!**/generated/**bun.lockis excluded by!**/*.lock
📒 Files selected for processing (31)
apps/docs-smoke/.gitignoreapps/docs-smoke/package.jsonapps/docs-smoke/scripts/mdx-convert.tsapps/docs-smoke/scripts/search-generate.tsapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/lib/search.tsapps/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routeTree.gen.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/tests/e2e/smoke.e2e.tspackages/docs/README.mdpackages/docs/agent-docs-src/docs/search.mdxpackages/docs/agent-docs/docs/llms-full.txtpackages/docs/agent-docs/docs/llms-full/generation.txtpackages/docs/agent-docs/docs/llms-full/generation/search.txtpackages/docs/agent-docs/docs/llms.txtpackages/docs/agent-docs/docs/search.mdpackages/docs/agent-docs/llms.txtpackages/docs/package.jsonpackages/docs/scripts/generate-agent-docs.tspackages/docs/src/search/ai-index.tspackages/docs/src/search/ai.test.tspackages/docs/src/search/ai.tspackages/docs/src/search/index.tspackages/docs/src/search/node-index.tspackages/docs/src/search/node.tspackages/docs/src/search/search.test.tspackages/docs/src/search/search.tspackages/docs/tsup.config.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:
apps/docs-smoke/src/lib/docs.tspackages/docs/src/search/node-index.tspackages/docs/tsup.config.tsapps/docs-smoke/scripts/mdx-convert.tspackages/docs/scripts/generate-agent-docs.tsapps/docs-smoke/scripts/search-generate.tsapps/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routes/api/docs/search.tspackages/docs/src/search/ai.test.tsapps/docs-smoke/src/routes/api/docs/ask.tspackages/docs/src/search/index.tsapps/docs-smoke/src/routes/search.tsxpackages/docs/src/search/ai.tspackages/docs/src/search/ai-index.tspackages/docs/src/search/search.test.tsapps/docs-smoke/src/routeTree.gen.tspackages/docs/src/search/node.tsapps/docs-smoke/tests/e2e/smoke.e2e.tsapps/docs-smoke/src/lib/search.tspackages/docs/src/search/search.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:
apps/docs-smoke/src/lib/docs.tspackages/docs/src/search/node-index.tspackages/docs/tsup.config.tsapps/docs-smoke/scripts/mdx-convert.tspackages/docs/scripts/generate-agent-docs.tsapps/docs-smoke/scripts/search-generate.tsapps/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routes/api/docs/search.tspackages/docs/src/search/ai.test.tsapps/docs-smoke/src/routes/api/docs/ask.tspackages/docs/src/search/index.tsapps/docs-smoke/src/routes/search.tsxpackages/docs/src/search/ai.tspackages/docs/src/search/ai-index.tspackages/docs/src/search/search.test.tsapps/docs-smoke/src/routeTree.gen.tspackages/docs/src/search/node.tsapps/docs-smoke/tests/e2e/smoke.e2e.tsapps/docs-smoke/src/lib/search.tspackages/docs/src/search/search.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/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routes/search.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/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routes/search.tsx
**/*.{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/docs/src/search/ai.test.tspackages/docs/src/search/search.test.ts
**/index.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid barrel files (index files that re-export everything)
Files:
packages/docs/src/search/index.ts
🧠 Learnings (69)
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/**/*.mdx : Include code examples where appropriate in MDX documentation pages of the docs app
Applied to files:
packages/docs/agent-docs/llms.txtapps/docs-smoke/scripts/mdx-convert.tsapps/docs-smoke/src/mdx-components.tsxpackages/docs/agent-docs-src/docs/search.mdx
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/**/*.mdx : Use MDX for documentation pages
Applied to files:
packages/docs/agent-docs/llms.txtapps/docs-smoke/scripts/mdx-convert.tsapps/docs-smoke/src/mdx-components.tsxpackages/docs/agent-docs-src/docs/search.mdx
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/app/**/*.{ts,tsx} : Use Next.js App Router conventions in the docs app
Applied to files:
apps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/app/**/page.tsx : Place page components in appropriate route segments within the docs app
Applied to files:
apps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/mdx-components.tsxapps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/app/**/page.tsx : Place page components in appropriate route segments
Applied to files:
apps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include integration tests for component combinations
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2026-03-19T22:57:45.114Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:45.114Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include unit tests for components, integration tests for component combinations, accessibility tests, and error boundary tests
Applied to files:
apps/docs-smoke/src/lib/docs.tspackages/docs/src/search/search.test.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:45.114Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:45.114Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Document components with purpose and use case, required and optional props, context requirements, example usage, and common pitfalls
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{tsx,jsx} : For each component, documentation should include: purpose and use case, required and optional props, context requirements, example usage, and common pitfalls
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/index.{ts,tsx} : Export type definitions for public API in Elements package
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.tspackages/docs/src/search/node.tsapps/docs-smoke/src/lib/search.tspackages/docs/src/search/search.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.{ts,tsx} : Export type definitions for public API
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.tspackages/docs/src/search/node.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{ts,tsx} : Export type definitions for public API in TypeScript libraries
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.tspackages/docs/src/search/node.tsapps/docs-smoke/src/lib/search.ts
📚 Learning: 2026-02-20T14:21:19.208Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2026-02-20T14:21:19.208Z
Learning: Applies to **/index.{ts,tsx,js,jsx} : Avoid barrel files (index files that re-export everything)
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/src/search/ai-index.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `export type` for types
Applied to files:
packages/docs/src/search/node-index.ts
📚 Learning: 2026-04-18T15:01:52.690Z
Learnt from: CR
Repo: inthhq/docs PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T15:01:52.690Z
Learning: Applies to **/index.{js,ts,jsx,tsx} : Avoid barrel files (index files that re-export everything)
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.ts
📚 Learning: 2026-03-19T22:57:45.114Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:45.114Z
Learning: Applies to **/*.{ts,tsx} : Export type definitions for public API and avoid TypeScript enums; use const objects or 'as const' assertions instead due to runtime overhead and tree-shaking limitations
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.ts
📚 Learning: 2026-04-16T03:27:04.353Z
Learnt from: CR
Repo: inthhq/dsar PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-16T03:27:04.353Z
Learning: Applies to **/index.{js,jsx,ts,tsx} : Avoid barrel files (index files that re-export everything)
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-02-19T01:12:44.177Z
Learnt from: CR
Repo: consentdotio/agent-skills PR: 0
File: tsdoc-jsdoc-authoring/AGENTS.md:0-0
Timestamp: 2026-02-19T01:12:44.177Z
Learning: Applies to tsdoc-jsdoc-authoring/**/index.{ts,tsx} : Use `packageDocumentation` for entrypoint docs in TSDoc comments
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.tsapps/docs-smoke/scripts/search-generate.tspackages/docs/README.mdpackages/docs/src/search/index.tspackages/docs/src/search/node.tspackages/docs/src/search/search.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't export empty modules that don't change anything
Applied to files:
packages/docs/src/search/node-index.tspackages/docs/tsup.config.ts
📚 Learning: 2026-02-20T14:21:40.180Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-20T14:21:40.180Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Avoid barrel files (index files that re-export everything)
Applied to files:
packages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/package.jsonpackages/docs/src/search/ai-index.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{ts,tsx,md} : Include TypeScript examples in Elements package documentation
Applied to files:
packages/docs/tsup.config.tspackages/docs/src/search/index.tspackages/docs/src/search/node.tspackages/docs/src/search/search.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{ts,tsx} : Include TSDoc comments for components in Elements package
Applied to files:
packages/docs/tsup.config.tspackages/docs/src/search/node.tspackages/docs/src/search/search.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't use specified modules when loaded by import or require
Applied to files:
packages/docs/tsup.config.tspackages/docs/package.json
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use the `node:` protocol for Node.js builtin modules
Applied to files:
packages/docs/tsup.config.tspackages/docs/package.jsonpackages/docs/src/search/node.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Make sure to use the "use strict" directive in script files
Applied to files:
packages/docs/tsup.config.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.{ts,tsx} : Include TypeScript examples
Applied to files:
packages/docs/tsup.config.ts
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/**/*.mdx : Use MDX for documentation pages in the docs app
Applied to files:
apps/docs-smoke/scripts/mdx-convert.tsapps/docs-smoke/src/mdx-components.tsxpackages/docs/agent-docs-src/docs/search.mdx
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't use __dirname and __filename in the global scope
Applied to files:
apps/docs-smoke/scripts/mdx-convert.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When managing URL search params, load the router-core search-params skill file from node_modules/tanstack/router-core/skills/router-core/search-params/SKILL.md
Applied to files:
packages/docs/scripts/generate-agent-docs.tsapps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.{tsx,jsx} : Follow the Radix UI primitives pattern
Applied to files:
apps/docs-smoke/package.json
📚 Learning: 2026-02-01T08:57:09.557Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/typography.mdc:0-0
Timestamp: 2026-02-01T08:57:09.557Z
Learning: Applies to **/*.{ts,tsx} : Use `text-title-h1` through `text-title-h6` tokens for heading elements, with appropriate line-height, letter-spacing, and font-weight already included
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2026-02-20T14:21:19.208Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2026-02-20T14:21:19.208Z
Learning: Applies to **/*.{tsx,jsx,html} : Use proper heading hierarchy in HTML/React components
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2026-03-19T22:57:54.730Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/typography.mdc:0-0
Timestamp: 2026-03-19T22:57:54.730Z
Learning: Applies to **/*.{ts,tsx,css} : Use `text-title-h1` through `text-title-h6` tokens for heading elements with appropriate line-height, letter-spacing, and font-weight based on semantic heading level
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Give heading elements content that's accessible to screen readers (not hidden with `aria-hidden`)
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{tsx,jsx} : Support custom styling and rendering in components
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2026-03-19T22:57:54.730Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/typography.mdc:0-0
Timestamp: 2026-03-19T22:57:54.730Z
Learning: Applies to **/*.{ts,tsx,css} : Use `text-subheading-*` tokens for uppercase subheadings with wide tracking
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2026-02-20T14:21:19.208Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2026-02-20T14:21:19.208Z
Learning: Applies to **/*.{tsx,jsx} : Use `next/head` or App Router metadata API for head elements
Applied to files:
apps/docs-smoke/src/mdx-components.tsx
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/**/*.mdx : Keep documentation organized by categories
Applied to files:
apps/docs-smoke/src/mdx-components.tsxpackages/docs/README.md
📚 Learning: 2026-02-19T01:12:44.177Z
Learnt from: CR
Repo: consentdotio/agent-skills PR: 0
File: tsdoc-jsdoc-authoring/AGENTS.md:0-0
Timestamp: 2026-02-19T01:12:44.177Z
Learning: Applies to tsdoc-jsdoc-authoring/**/*.{ts,tsx,js,jsx} : Write clear summary sentences in TSDoc and JSDoc comments
Applied to files:
packages/docs/README.md
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When adding new routes and pages, load the router-core skill file from node_modules/tanstack/router-core/skills/router-core/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/app/**/* : Use Next.js App Router conventions
Applied to files:
apps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When handling errors and 404 pages, load the router-core not-found-and-errors skill file from node_modules/tanstack/router-core/skills/router-core/not-found-and-errors/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When building API endpoints and server routes, load the start-core server-routes skill file from node_modules/tanstack/start-client-core/skills/start-core/server-routes/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/api/docs/search.tsapps/docs-smoke/src/routes/api/docs/ask.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Write unit tests for components in Elements package using Vitest
Applied to files:
packages/docs/src/search/ai.test.tspackages/docs/package.jsonpackages/docs/src/search/search.test.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Use Vitest for testing framework
Applied to files:
packages/docs/src/search/ai.test.tspackages/docs/package.jsonpackages/docs/src/search/search.test.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `import type` for types
Applied to files:
packages/docs/package.json
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `with { type: "json" }` for JSON module imports
Applied to files:
packages/docs/package.json
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Make sure all dependencies are correctly specified in React hooks
Applied to files:
packages/docs/package.json
📚 Learning: 2026-02-20T14:21:19.208Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2026-02-20T14:21:19.208Z
Learning: Applies to **/*.{tsx,jsx} : Specify all dependencies in hook dependency arrays correctly
Applied to files:
packages/docs/package.json
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Use Vitest as the testing framework for Elements package
Applied to files:
packages/docs/package.json
📚 Learning: 2026-04-16T03:27:04.353Z
Learnt from: CR
Repo: inthhq/dsar PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-16T03:27:04.353Z
Learning: Applies to **/*.{jsx,tsx} : Specify all dependencies in hook dependency arrays correctly
Applied to files:
packages/docs/package.json
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Include integration tests
Applied to files:
packages/docs/package.jsonpackages/docs/src/search/search.test.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Include integration tests for Elements package components
Applied to files:
packages/docs/package.jsonpackages/docs/src/search/search.test.ts
📚 Learning: 2025-12-01T15:20:25.102Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/open-graph.mdc:0-0
Timestamp: 2025-12-01T15:20:25.102Z
Learning: Applies to src/**/route.{ts,tsx} : Read dynamic content from `request.nextUrl.searchParams` and pass into pure component props rather than fetching during render
Applied to files:
apps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When implementing code splitting, load the router-core code-splitting skill file from node_modules/tanstack/router-core/skills/router-core/code-splitting/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/search.tsx
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When setting up navigation and links between pages, load the router-core navigation skill file from node_modules/tanstack/router-core/skills/router-core/navigation/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Test accessibility features in Elements package component tests
Applied to files:
packages/docs/src/search/search.test.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Test accessibility features
Applied to files:
packages/docs/src/search/search.test.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:58:00.031Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2026-03-19T22:58:00.031Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Write comprehensive unit tests with clear test case names describing what is being tested
Applied to files:
packages/docs/src/search/search.test.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Write unit tests for components
Applied to files:
packages/docs/src/search/search.test.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Test with screen readers in Elements package component tests
Applied to files:
packages/docs/src/search/search.test.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't import next/document outside of pages/_document.jsx in Next.js projects
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When adding auth and route guards, load the router-core auth-and-guards skill file from node_modules/tanstack/router-core/skills/router-core/auth-and-guards/SKILL.md
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When fetching data in route loaders, load the router-core data-loading skill file from node_modules/tanstack/router-core/skills/router-core/data-loading/SKILL.md
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When implementing type safety patterns, load the router-core type-safety skill file from node_modules/tanstack/router-core/skills/router-core/type-safety/SKILL.md
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-02-19T01:12:44.177Z
Learnt from: CR
Repo: consentdotio/agent-skills PR: 0
File: tsdoc-jsdoc-authoring/AGENTS.md:0-0
Timestamp: 2026-02-19T01:12:44.177Z
Learning: Applies to tsdoc-jsdoc-authoring/**/*.{js,jsx} : Use `module` for module-level docs in JSDoc comments
Applied to files:
packages/docs/src/search/node.tspackages/docs/src/search/search.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{ts,tsx} : Document all props and types in Elements package TypeScript code
Applied to files:
packages/docs/src/search/node.ts
📚 Learning: 2026-02-19T01:12:44.177Z
Learnt from: CR
Repo: consentdotio/agent-skills PR: 0
File: tsdoc-jsdoc-authoring/AGENTS.md:0-0
Timestamp: 2026-02-19T01:12:44.177Z
Learning: Applies to tsdoc-jsdoc-authoring/**/*.{js,jsx} : Document generator output with `yields` in JSDoc comments
Applied to files:
packages/docs/src/search/node.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include accessibility tests for components
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
🪛 LanguageTool
packages/docs/agent-docs/docs/search.md
[style] ~106-~106: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...s or hosted search when your docs reach very large chunk counts, when cold-start memory be...
(EN_WEAK_ADJECTIVE)
packages/docs/agent-docs-src/docs/search.mdx
[style] ~105-~105: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...s or hosted search when your docs reach very large chunk counts, when cold-start memory be...
(EN_WEAK_ADJECTIVE)
packages/docs/agent-docs/docs/llms-full/generation/search.txt
[style] ~114-~114: As an alternative to the over-used intensifier ‘very’, consider replacing this phrase.
Context: ...s or hosted search when your docs reach very large chunk counts, when cold-start memory be...
(EN_WEAK_ADJECTIVE)
🔍 Remote MCP
I've encountered the Context7 monthly quota limit. Let me search for relevant technical details using web search to verify the key APIs and patterns being used in this PR.## Additional Context Gathered for PR Review
Based on my search of available documentation and resources, here is the relevant technical context for reviewing this PR:
Vercel AI SDK Integration
The ai package (Vercel AI SDK) reduces boilerplate for streaming responses from AI providers and allows changing providers with minimal code changes. The PR's streamDocsAnswer function in packages/docs/src/search/ai.ts follows this pattern:
- The
streamTextfunction immediately starts streaming to enable sending data without waiting for the model, and suppresses errors to prevent server crashes. - The result object includes helper functions like
toUIMessageStreamResponse()which creates a UI Message stream HTTP response compatible with Next.js App Router API routes. The PR creates a custom Response withCache-Control: no-storeandContent-Type: text/plain; charset=utf-8headers instead.
Key observation: The implementation passes a streamTextImpl override parameter, which allows for custom streaming implementations and testability (as seen in ai.test.ts).
TanStack React Router File-Based Routing
Server routes in TanStack Start follow file-based routing conventions where each file with a server property in createFileRoute is treated as an API route. The PR's API routes (/api/docs/search and /api/docs/ask) follow this pattern correctly:
- Each HTTP method handler receives an object containing the
requestproperty (the incoming request object). - Handlers can return a
Responseobject orPromise<Response>.
Key observation: The implementation properly uses createFileRoute with server: { handlers: { GET/POST } } syntax for defining API handlers, which aligns with TanStack Router's conventions.
Rate Limiting and Request Guards
The PR implements several defensive patterns:
- Per-client rate limiting: Uses
docsSearchLimiters.search.check()anddocsSearchLimiters.ask.check()keyed by client identifier - Query validation:
validateDocsQueryenforces max length and rejects control characters - JSON size limiting:
readJsonWithLimitwith byte limits to prevent abuse - Retry-After headers: Properly formatted rate limit responses (HTTP 429)
These patterns are consistent with serverless/edge deployment best practices where state needs to be managed carefully.
Stream Response Handling
The /api/docs/ask route streams text responses while the /api/docs/search route returns JSON. The client-side search component uses AbortController for request cancellation on query changes, and streams the answer response via TextDecoder to build the answer string progressively.
MDX Component Integration
The PR adds heading ID generation in mdx-components.tsx by extracting plain text from children. This enables heading anchors needed for deep linking in search results (as evidenced by the tests checking URL hash matching like #quickstart).
[::web_search::]
🔇 Additional comments (43)
apps/docs-smoke/.gitignore (1)
1-6: LGTM!The additions appropriately ignore build artifacts (
.output/) and Playwright test results (test-results/) that align with the new search pipeline and e2e testing introduced in this PR.apps/docs-smoke/scripts/mdx-convert.ts (1)
22-24: LGTM!The path resolution is now consistent with
search-generate.ts, usingappRootas an intermediate variable. This improves maintainability and aligns with the sibling script's directory structure pattern.apps/docs-smoke/src/mdx-components.tsx (2)
18-31: LGTM!The
createHeadingfactory correctly:
- Prioritizes explicit
idprops when provided- Falls back to
slugifyDocsHeadingfor auto-generated IDs (matching search index anchor generation)- Converts empty strings to
undefinedto avoid invalid emptyidattributes
33-46: LGTM!The merge order is correct: custom headings → library defaults → caller overrides. This allows consuming apps to override any component while ensuring heading IDs are generated by default.
packages/docs/agent-docs/llms.txt (1)
16-16: LGTM!The new Search entry follows the existing format and accurately describes the static search index with AI answer streaming capability.
packages/docs/agent-docs/docs/llms-full/generation.txt (1)
8-9: LGTM!The new Search topic entry follows the established format and the description correctly matches the referenced
search.txtfile content.packages/docs/agent-docs/docs/llms-full.txt (1)
14-14: LGTM!The Search sub-topic is properly nested under Generation with consistent formatting and accurate description.
packages/docs/src/search/ai-index.ts (1)
1-5: LGTM!This is a focused subpath entrypoint (
./search/ai), not a barrel file. It correctly exports only the public API surface needed for AI answer streaming, aligning with the package.json exports configuration.packages/docs/agent-docs/docs/llms.txt (1)
24-28: LGTM!The Generation section summary and new Search entry are consistent with other documentation references in this PR.
apps/docs-smoke/src/lib/docs.ts (1)
9-10: LGTM!The new
/searchroute is properly added to both the type union and the route array. The structure is consistent with existing entries, and the description accurately captures the feature scope.Also applies to: 39-43
packages/docs/src/search/node-index.ts (1)
1-5: LGTM!This is a properly scoped entrypoint for the
@inth/docs/search/nodesubpath export, not a generic barrel file. It correctly usesexport typesyntax for type-only exports and exposes only the intended public API surface.packages/docs/tsup.config.ts (1)
9-11: LGTM!The new search entrypoints follow the existing naming convention and align with the package.json subpath exports. Marking
aias external is correct since it's declared as an optional peer dependency, allowing consumers to provide their own version.Also applies to: 49-49
apps/docs-smoke/package.json (1)
19-20: LGTM!The pipeline script additions follow the existing pattern and maintain a logical execution order (convert → llm → search). The
aidependency version^6.0.168satisfies the>=6.0.0peer dependency requirement from@inth/docs.Also applies to: 37-37
packages/docs/scripts/generate-agent-docs.ts (1)
53-53: LGTM!The search documentation is consistently added across all three configuration areas:
bestStartingPoints,docsSections, andtopics. TheincludePrefixes: ["search"]will correctly match search-related source files for the LLM full-context generation.Also applies to: 70-76, 133-138
apps/docs-smoke/scripts/search-generate.ts (1)
17-27: LGTM!The script correctly:
- Passes
outDirpointing to the public directory where converted markdown lives- Uses
result.outputPathfrom the generator for the copy source- Outputs a clear summary with document/chunk/term counts
apps/docs-smoke/tests/e2e/smoke.e2e.ts (3)
4-6: LGTM!Good practice defining regex patterns as top-level constants. The
QUICKSTART_HEADING_HREFpattern correctly anchors the expected hash fragment.
118-144: Well-structured conditional test for AI enablement state.The test properly:
- Fetches the AI configuration before navigation to avoid race conditions
- Uses an
aria-live="polite"region selector for accessibility-aware result targeting- Validates the deep link href includes the heading anchor
146-157: LGTM!The API test validates both the response structure and content. Using
response.ok()before parsing is correct for handling non-2xx responses.packages/docs/README.md (3)
11-13: LGTM!The package surface listing is complete and accurately describes each subpath export's purpose.
107-117: LGTM!The operational guidance about the in-memory limiter being suitable only for demos, and the recommendation to use shared stores for production, is practical and helps consumers make informed architectural decisions.
70-106:⚠️ Potential issue | 🟡 MinorFix the model identifier format in the
streamDocsAnswerexample.The model parameter uses
openai/gpt-5.4-mini, which is incorrect for the Vercel AI SDK. The OpenAI provider expects a plain model ID string like'gpt-4o-mini'or'gpt-4-turbo', not a prefixed format. Update the example to:model: process.env.DOCS_SEARCH_MODEL ?? "gpt-4o-mini"⛔ Skipped due to learnings
Learnt from: CR Repo: consentdotio/GDPRish PR: 0 File: .cursor/rules/docs-rules.mdc:0-0 Timestamp: 2026-03-19T22:57:19.913Z Learning: Applies to apps/docs/**/*.mdx : Use MDX for documentation pagesapps/docs-smoke/src/routeTree.gen.ts (1)
1-249: Auto-generated file — no review needed.This file is automatically generated by TanStack Router and correctly reflects the new
/search,/api/docs/search, and/api/docs/askroutes added in this PR.packages/docs/src/search/ai.test.ts (1)
1-59: LGTM!Well-structured test that properly validates the
streamDocsAnswerfunction by:
- Using a stub
streamTextImplto capture call arguments for verification- Checking that sources are correctly populated from the search index
- Verifying the response stream works correctly
- Asserting that model configuration, tokens, timeout, and prompt content are passed through correctly
The test follows Vitest best practices with async/await and meaningful assertions.
packages/docs/package.json (2)
30-41: LGTM!The new export subpaths are correctly configured and align with the tsup entry points defined in
tsup.config.ts. Each export includes bothtypesandimportfields for proper TypeScript and ESM support.
91-106: Theaipackage version and dependency setup are correct.Version 6.0.168 exists on npm and has no known direct security advisories. The optional peer dependency configuration is appropriate for allowing consumers to use the library without requiring the AI SDK.
apps/docs-smoke/src/routes/api/docs/search.ts (1)
1-57: LGTM!Clean implementation of the search API route with proper:
- Query validation using
validateDocsQuerywith configured max chars- Per-client rate limiting with appropriate
Retry-Afterheader calculation- Structured error handling that distinguishes
DocsSearchRequestErrorfrom unexpected errors- Early returns for rate-limited requests
The route follows TanStack Router server handler conventions correctly.
packages/docs/agent-docs/docs/search.md (1)
1-108: LGTM!Comprehensive documentation that accurately covers the search API surface:
- Correct import paths matching the package exports
- Clear examples for build-time indexing and runtime usage
- Appropriate warnings about in-memory rate limiting limitations in serverless environments
- Helpful guidance on when to consider embeddings over local indexing
The static analysis style hint about "very large" is a minor stylistic preference and doesn't warrant a change.
packages/docs/agent-docs/docs/llms-full/generation/search.txt (1)
1-116: LGTM!Full context documentation for LLM consumption is consistent with the main search.md documentation. Import paths and code examples accurately reflect the package API surface.
apps/docs-smoke/src/routes/api/docs/ask.ts (1)
1-86: LGTM overall!Well-structured API route with:
- Proper feature flag check returning 503 when AI is disabled
- Per-client rate limiting with
Retry-Afterheader- Request body size limiting via
readJsonWithLimit- Query validation with appropriate char limits for ask queries
- Comprehensive error handling
The GET endpoint for checking availability status is a nice touch for client-side feature detection.
packages/docs/src/search/index.ts (1)
1-28: LGTM!While the coding guidelines recommend avoiding barrel files, this is an appropriate use case as a package entry point defining the public API surface for
@inth/docs/search. The exports are curated (not "re-export everything") and the file serves as the contract between the package internals and consumers.This pattern is consistent with the
ai-index.tsandnode-index.tsentry points, and aligns with the package.json exports configuration.packages/docs/agent-docs-src/docs/search.mdx (1)
1-107: LGTM!The documentation is well-structured with clear sections covering the full workflow: build-time indexing, runtime search, answer context, AI SDK streaming, and abuse guards. Code examples are relevant and align with the implemented APIs in
@inth/docs/search. The production guidance for replacing in-memory rate limiting with shared storage is a helpful callout.packages/docs/src/search/search.test.ts (1)
1-279: LGTM!Comprehensive test coverage for the search functionality including normalization, heading/anchor preservation, ranking behavior, excerpts, answer context limits, and all request-guard utilities. Tests are well-organized with descriptive names and proper use of async/await.
packages/docs/src/search/ai.ts (2)
51-79: Well-structured streaming helper with good defaults.The function cleanly separates concerns: context building via
createAnswerContext, streaming via injectedstreamTextImpl(enabling testability), and response formatting with appropriate cache headers. The dependency injection pattern forstreamTextImplis a nice touch for testing.
62-62: No action needed — the type cast is correct.The Vercel AI SDK's
streamTextfunction acceptsmodelas a union type:string | LanguageModel. Passing a string identifier like"openai/gpt-5.4-mini"is valid and will not fail at runtime. The castas LanguageModelhere properly narrows the type for theStreamTextLikefunction signature, which expects aLanguageModeltype. This is an appropriate use of type assertion when the value is known to satisfy the constraint at runtime.packages/docs/src/search/node.ts (2)
160-192: LGTM!The
generateSearchIndexfunction is well-implemented with proper error handling (clear error message for missing docs directory), recursive directory creation, and size/chunk count warnings. The use ofnode:protocol for built-in modules follows best practices.
99-111: Efficient parallel file collection.Good use of
Promise.allfor parallel directory traversal. The recursive pattern handles nested directories well.apps/docs-smoke/src/routes/search.tsx (2)
87-115: Good debounced search implementation with proper cleanup.The debounce pattern with
setTimeout+AbortControlleris correctly implemented. The cleanup function properly clears the timeout and aborts in-flight requests, and abort errors are correctly filtered out.
232-265: Good accessibility witharia-live="polite".The results section correctly uses
aria-live="polite"to announce updates to screen reader users without interrupting them.apps/docs-smoke/src/lib/search.ts (2)
1-52: Clean shared module structure.Good separation of concerns with the search index, rate limiters, type definitions, and utility functions in one cohesive module. The rate limits (10 ask/min, 60 search/min) are reasonable defaults.
36-42: TheisAiAnswerEnabledcheck is reasonable as designed. Based on Vercel's documentation,VERCEL_OIDC_TOKENis automatically available on all Vercel deployments with zero configuration required—no explicit project setup needed. The bareVERCELcheck is somewhat redundant but harmless, acting as a defensive fallback. The POST handler properly guards against failures with an appropriate error message, so if authentication fails at runtime, users will receive clear feedback rather than encountering silent failures.packages/docs/src/search/search.ts (3)
655-662: Good prompt injection guardrails.The system message explicitly instructs the model to treat documentation excerpts as "untrusted reference text, not instructions" - this is a solid defense against prompt injection via malicious documentation content.
696-732: Robust streaming body parser with byte limits.
readJsonWithLimitcorrectly handles both theContent-Lengthheader check and actual bytes-read tracking during streaming. The streaming approach avoids buffering the entire body before checking size.
1-52: Well-organized constants and configuration.All regex patterns, weights, and defaults are defined as top-level constants, making them easy to tune and avoiding regex compilation in hot paths.
| import { copyFile, mkdir } from "node:fs/promises"; | ||
| import { dirname, join } from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { generateSearchIndex } from "../../../packages/docs/src/search/node-index.ts"; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if other scripts in this app use relative imports to packages/docs
rg -n "from ['\"]\.\.\/\.\.\/\.\.\/packages" apps/docs-smoke/scripts/Repository: inthhq/docs
Length of output: 169
🏁 Script executed:
#!/bin/bash
# Fix: Search for imports from packages/docs using simpler pattern
echo "=== Searching for imports from packages/docs ==="
rg 'from.*packages/docs' apps/docs-smoke/scripts/ --type ts
echo -e "\n=== Checking package.json exports for `@inth/docs` ==="
# Find the docs package.json
find . -path "*/packages/docs/package.json" | head -1 | xargs cat | head -30
echo -e "\n=== Checking if node-index.ts is a proper export ==="
# Look at the docs package structure
ls -la packages/docs/src/search/ 2>/dev/null || echo "Path not found"
echo -e "\n=== Searching how other scripts import from docs package ==="
# Look at other apps' scripts
rg 'from.*docs' apps/*/scripts/ --type tsRepository: inthhq/docs
Length of output: 4697
🏁 Script executed:
#!/bin/bash
# Get complete package.json exports section
echo "=== Complete package.json exports ==="
packages/docs/package.json | jq '.exports' 2>/dev/null || sed -n '/"exports"/,/^ },*$/p' packages/docs/package.json
echo -e "\n=== Contents of node-index.ts ==="
cat packages/docs/src/search/node-index.ts
echo -e "\n=== Contents of index.ts (search) ==="
cat packages/docs/src/search/index.tsRepository: inthhq/docs
Length of output: 1053
🏁 Script executed:
#!/bin/bash
# Read package.json properly
echo "=== Package.json exports (search related) ==="
cat packages/docs/package.json | jq '.exports | select(. != null) | keys[] | select(contains("search"))'
echo -e "\n=== Full exports object ==="
cat packages/docs/package.json | jq '.exports'Repository: inthhq/docs
Length of output: 994
Consider using the package export for consistency with Node.js deployments.
The package exports ./search/node to ./dist/search/node-index.js, which this script could import via @inth/docs/search/node. This exercises the actual published package export rather than relying on relative paths to source files.
Note: Other scripts in this app use relative imports (e.g., ../../../packages/docs/src/convert/index.ts), so this would be inconsistent within the monorepo. Use this approach only if the team standardizes on package imports for docs utilities.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/scripts/search-generate.ts` at line 9, Replace the relative
source import with the package export to exercise the published build: change
the import that currently pulls generateSearchIndex from
"../../../packages/docs/src/search/node-index.ts" to import {
generateSearchIndex } from "@inth/docs/search/node"; update any tooling or
TypeScript config if needed so the package resolution works at runtime; ensure
the symbol generateSearchIndex is imported from the package export and
tests/scripts still run.
| function textFromChildren(children: HeadingProps["children"]): string { | ||
| if (typeof children === "string" || typeof children === "number") { | ||
| return String(children); | ||
| } | ||
| if (Array.isArray(children)) { | ||
| return children.map(textFromChildren).join(" "); | ||
| } | ||
| return ""; | ||
| } |
There was a problem hiding this comment.
React element children may produce empty IDs.
The textFromChildren helper handles strings, numbers, and arrays, but returns an empty string for React elements (e.g., <h1><code>API</code></h1> or <h1><span>Hello</span></h1>). This could result in headings without anchor IDs.
Consider extracting text from React elements with a children prop:
🛠️ Proposed enhancement
function textFromChildren(children: HeadingProps["children"]): string {
if (typeof children === "string" || typeof children === "number") {
return String(children);
}
if (Array.isArray(children)) {
return children.map(textFromChildren).join(" ");
}
+ if (children && typeof children === "object" && "props" in children) {
+ return textFromChildren((children as { props?: { children?: unknown } }).props?.children);
+ }
return "";
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/src/mdx-components.tsx` around lines 8 - 16, The
textFromChildren function currently only handles strings, numbers, and arrays
and returns "" for React elements, which leads to empty heading IDs; update
textFromChildren (used for HeadingProps["children"]) to detect React
elements/objects and, when an object with a props property exists, recurse into
element.props.children (also handle null/undefined/boolean children) so text is
extracted from nested elements like <code> or <span>; keep existing behavior for
strings/numbers/arrays and ensure the function always returns a trimmed string
suitable for generating anchor IDs.
| return streamDocsAnswer({ | ||
| index: docsSearchIndex, | ||
| query, | ||
| model: process.env.DOCS_SEARCH_MODEL ?? DEFAULT_MODEL, | ||
| productName: "@inth/docs", | ||
| }).response; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Sources metadata is discarded.
The streamDocsAnswer function returns both response and sources, but only response is returned to the client. This means clients cannot display source citations alongside the streamed answer.
If this is intentional (e.g., sources are rendered client-side from the search results), this is fine. Otherwise, consider returning sources via a header or separate endpoint.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/src/routes/api/docs/ask.ts` around lines 65 - 70, The handler
currently returns only the response from streamDocsAnswer and discards sources;
update the endpoint to include the returned sources so clients can display
citations — call streamDocsAnswer(...) and capture both response and sources,
then return an object containing both (e.g., { response, sources }) or, if
streaming/compatibility requires, serialize sources into a response header
(e.g., "x-doc-sources") before returning; look for the call to streamDocsAnswer
and the variable docsSearchIndex to locate the code to change.
| const response = await fetch("/api/docs/ask", { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| }, | ||
| body: JSON.stringify({ query: trimmedQuery }), | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider adding AbortController for answer stream cancellation.
Unlike the search request, the /api/docs/ask POST doesn't use an AbortController. If the user starts a new query or navigates away while streaming, the previous stream continues in the background. For a smoother UX and resource cleanup, consider aborting in-flight answer requests when starting a new one.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/src/routes/search.tsx` around lines 139 - 145, The POST to
"/api/docs/ask" (the fetch call creating `const response = await
fetch("/api/docs/ask", { ... body: JSON.stringify({ query: trimmedQuery }) })`)
lacks an AbortController, so previous answer streams keep running; create an
AbortController per query, pass controller.signal into fetch, store the
controller (e.g., in a local variable or React ref) and call controller.abort()
before starting a new request or when unmounting/navigating to cancel any
in-flight answer stream and cleanup resources.
| while (true) { | ||
| const chunk = await reader.read(); | ||
| if (chunk.done) { | ||
| break; | ||
| } | ||
| setAnswer((current) => current + decoder.decode(chunk.value)); | ||
| } | ||
| setAnswer((current) => current + decoder.decode()); | ||
| setAnswerStatus("idle"); | ||
| } |
There was a problem hiding this comment.
Missing error handling in streaming loop.
If reader.read() throws during streaming (e.g., network disconnect), the error propagates unhandled and leaves answerStatus stuck in "streaming" state. Wrap the streaming loop in try-catch:
🛡️ Suggested fix
setAnswerStatus("streaming");
const reader = response.body.getReader();
const decoder = new TextDecoder();
- while (true) {
- const chunk = await reader.read();
- if (chunk.done) {
- break;
+ try {
+ while (true) {
+ const chunk = await reader.read();
+ if (chunk.done) {
+ break;
+ }
+ setAnswer((current) => current + decoder.decode(chunk.value));
}
- setAnswer((current) => current + decoder.decode(chunk.value));
+ setAnswer((current) => current + decoder.decode());
+ setAnswerStatus("idle");
+ } catch {
+ setAnswerStatus("error");
+ setError("Answer streaming failed.");
}
- setAnswer((current) => current + decoder.decode());
- setAnswerStatus("idle");📝 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.
| while (true) { | |
| const chunk = await reader.read(); | |
| if (chunk.done) { | |
| break; | |
| } | |
| setAnswer((current) => current + decoder.decode(chunk.value)); | |
| } | |
| setAnswer((current) => current + decoder.decode()); | |
| setAnswerStatus("idle"); | |
| } | |
| try { | |
| while (true) { | |
| const chunk = await reader.read(); | |
| if (chunk.done) { | |
| break; | |
| } | |
| setAnswer((current) => current + decoder.decode(chunk.value)); | |
| } | |
| setAnswer((current) => current + decoder.decode()); | |
| setAnswerStatus("idle"); | |
| } catch { | |
| setAnswerStatus("error"); | |
| setError("Answer streaming failed."); | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/src/routes/search.tsx` around lines 159 - 168, The streaming
loop that calls reader.read() can throw and currently leaves answerStatus stuck
at "streaming"; wrap the entire read loop in a try-catch (surround the
while(true) { const chunk = await reader.read(); ... } block) to catch any
errors, call setAnswerStatus("error") (or set to "idle" in a finally) and
optionally append an error message via setAnswer, and ensure resources are
cleaned (e.g., close reader) — update references in this file around
reader.read(), setAnswer(...), setAnswerStatus(...) and decoder.decode(...) to
implement the try-catch/finally handling.
| maxOutputTokens: options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS, | ||
| timeout: options.timeout ?? DEFAULT_TIMEOUT, | ||
| providerOptions: options.providerOptions, | ||
| onError: () => undefined, |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Silent error suppression may hinder debugging.
The onError: () => undefined callback silently discards streaming errors. While this prevents server crashes, it also makes it difficult to diagnose issues in production. Consider at minimum logging the error:
🔧 Suggested improvement
- onError: () => undefined,
+ onError: ({ error }) => {
+ console.error("[streamDocsAnswer] Stream error:", error);
+ },📝 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.
| onError: () => undefined, | |
| onError: ({ error }) => { | |
| console.error("[streamDocsAnswer] Stream error:", error); | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/docs/src/search/ai.ts` at line 68, Replace the silent onError
handler that returns undefined with one that logs the error for observability:
locate the onError callback (onError: () => undefined) in
packages/docs/src/search/ai.ts and change it to capture the error parameter and
write a non-throwing log (e.g., console.error or the existing logger) including
context like "AI stream error" and the error object, so errors are recorded but
still don't crash the process.
| for (const posting of postings) { | ||
| const chunk = index.chunks.find( | ||
| (candidate) => candidate.id === posting.chunkId | ||
| ); | ||
| if (!chunk) { | ||
| continue; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
O(n²) chunk lookup in search loop.
index.chunks.find() is called inside the posting iteration loop (and again at line 581), resulting in O(postings × chunks) complexity. For large indices with many terms and chunks, this could become a performance bottleneck.
Consider building a Map<string, DocsSearchChunk> lookup at the start of searchDocs:
⚡ Performance optimization
export function searchDocs(
index: DocsSearchIndex,
query: string,
options: SearchDocsOptions = {}
): DocsSearchResult[] {
const queryTokens = tokenize(query);
if (queryTokens.length === 0 || index.chunks.length === 0) {
return [];
}
+ const chunkById = new Map(index.chunks.map((c) => [c.id, c]));
const scores = new Map<string, number>();
// ... later in the loop:
- const chunk = index.chunks.find(
- (candidate) => candidate.id === posting.chunkId
- );
+ const chunk = chunkById.get(posting.chunkId);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/docs/src/search/search.ts` around lines 554 - 560, The loop in
searchDocs calls index.chunks.find(...) for each posting (and again later),
causing O(postings × chunks) work; create a Map keyed by chunk.id (e.g., const
chunkMap = new Map(index.chunks.map(c => [c.id, c]))) once at the start of
searchDocs and replace index.chunks.find(...) calls with
chunkMap.get(posting.chunkId) (and similarly where chunk lookups repeat) so
lookups become O(1) and avoid the quadratic behavior.
| export function createMemoryRateLimiter( | ||
| options: MemoryRateLimiterOptions | ||
| ): RateLimiter { | ||
| const entries = new Map<string, { count: number; resetAt: number }>(); | ||
| const now = options.now ?? Date.now; | ||
|
|
||
| return { | ||
| check(identifier: string): RateLimitResult { | ||
| const currentTime = now(); | ||
| const existing = entries.get(identifier); | ||
| if (!existing || existing.resetAt <= currentTime) { | ||
| const resetAt = currentTime + options.windowMs; | ||
| entries.set(identifier, { count: 1, resetAt }); | ||
| return { | ||
| allowed: true, | ||
| limit: options.limit, | ||
| remaining: Math.max(0, options.limit - 1), | ||
| resetAt, | ||
| }; | ||
| } | ||
|
|
||
| if (existing.count >= options.limit) { | ||
| return { | ||
| allowed: false, | ||
| limit: options.limit, | ||
| remaining: 0, | ||
| resetAt: existing.resetAt, | ||
| }; | ||
| } | ||
|
|
||
| existing.count += 1; | ||
| return { | ||
| allowed: true, | ||
| limit: options.limit, | ||
| remaining: Math.max(0, options.limit - existing.count), | ||
| resetAt: existing.resetAt, | ||
| }; | ||
| }, | ||
| }; | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
In-memory rate limiter entries are never cleaned up.
The entries Map grows indefinitely as new client identifiers are added, but expired entries are never removed. For long-running servers with many unique clients, this could cause memory growth.
Consider adding periodic cleanup or a max-size eviction policy:
🧹 Optional cleanup suggestion
export function createMemoryRateLimiter(
options: MemoryRateLimiterOptions
): RateLimiter {
const entries = new Map<string, { count: number; resetAt: number }>();
const now = options.now ?? Date.now;
+ const MAX_ENTRIES = 10_000;
return {
check(identifier: string): RateLimitResult {
const currentTime = now();
+
+ // Lazy cleanup of expired entries when approaching limit
+ if (entries.size > MAX_ENTRIES) {
+ for (const [key, entry] of entries) {
+ if (entry.resetAt <= currentTime) {
+ entries.delete(key);
+ }
+ }
+ }
+
const existing = entries.get(identifier);This is a minor concern since the documentation already notes that production should use shared storage (Redis/KV), but worth considering for demo/development scenarios.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/docs/src/search/search.ts` around lines 734 - 773, The in-memory Map
entries in createMemoryRateLimiter never get removed causing unbounded growth;
update createMemoryRateLimiter to purge expired keys from entries: when
check(identifier) runs, if an existing entry is expired remove it before
creating the new entry (use entries.delete(identifier)), and additionally add an
optional periodic cleanup (e.g., a timer started inside createMemoryRateLimiter
that iterates entries and deletes those with resetAt <= now()) or a simple
max-size eviction policy to trim the Map; reference functions/vars:
createMemoryRateLimiter, entries, check, resetAt, MemoryRateLimiterOptions.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/docs-smoke/content/docs/index.mdx`:
- Around line 31-34: The docs intro still says “has five package surfaces” but
you added the new package "@inth/docs/search"; update the intro sentence in
apps/docs-smoke/content/docs/index.mdx (the sentence that mentions package
surfaces) to say “six package surfaces” and ensure any adjacent counts or
pluralization remain consistent with the added "@inth/docs/search" entry.
In `@apps/docs-smoke/content/docs/search.mdx`:
- Line 37: Summary: The word "markdown" should be capitalized to "Markdown" for
consistency. Update the text string "Run conversion first, then generate the
search index from markdown:" to "Run conversion first, then generate the search
index from Markdown:" in the docs content (the line containing that sentence in
apps/docs-smoke/content/docs/search.mdx) so the proper noun "Markdown" is used
consistently.
In `@apps/docs-smoke/tests/e2e/smoke.e2e.ts`:
- Around line 141-144: The test parses JSON from the response to
request.get("/api/docs/ask") without first asserting the HTTP success status,
which masks endpoint failures as JSON parse errors; update the test around
answerConfigResponse and answerConfig to assert the response is OK (e.g., check
answerConfigResponse.ok or use your test framework's status assertion) before
calling .json(), and include a descriptive message so failures surface as an
endpoint-status issue rather than JSON parse noise.
🪄 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: e72530fb-c49f-4eed-9a8a-ffb3e14c6959
⛔ Files ignored due to path filters (1)
apps/docs-smoke/src/generated/docs-search-index.jsonis excluded by!**/generated/**
📒 Files selected for processing (7)
apps/docs-smoke/content/docs/index.mdxapps/docs-smoke/content/docs/meta.jsonapps/docs-smoke/content/docs/search.mdxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routeTree.gen.tsapps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/tests/e2e/smoke.e2e.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/tests/e2e/smoke.e2e.tsapps/docs-smoke/src/routeTree.gen.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:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/tests/e2e/smoke.e2e.tsapps/docs-smoke/src/routeTree.gen.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/docs-smoke/src/routes/docs/search.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/docs-smoke/src/routes/docs/search.tsx
🧠 Learnings (35)
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/app/**/page.tsx : Place page components in appropriate route segments within the docs app
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/tests/e2e/smoke.e2e.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/app/**/*.{ts,tsx} : Use Next.js App Router conventions in the docs app
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/app/**/page.tsx : Place page components in appropriate route segments
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When managing URL search params, load the router-core search-params skill file from node_modules/tanstack/router-core/skills/router-core/search-params/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When adding new routes and pages, load the router-core skill file from node_modules/tanstack/router-core/skills/router-core/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/app/**/* : Use Next.js App Router conventions
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/lib/docs.tsapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/app/**/{layout,page}.tsx : Keep layouts and pages separate in the docs app directory
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsx
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/src/components/**/*.tsx : Place reusable components in `src/components` within the docs app
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsx
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When adding auth and route guards, load the router-core auth-and-guards skill file from node_modules/tanstack/router-core/skills/router-core/auth-and-guards/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When fetching data in route loaders, load the router-core data-loading skill file from node_modules/tanstack/router-core/skills/router-core/data-loading/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When building API endpoints and server routes, load the start-core server-routes skill file from node_modules/tanstack/start-client-core/skills/start-core/server-routes/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When setting up navigation and links between pages, load the router-core navigation skill file from node_modules/tanstack/router-core/skills/router-core/navigation/SKILL.md
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-04-18T15:01:52.690Z
Learnt from: CR
Repo: inthhq/docs PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-18T15:01:52.690Z
Learning: Applies to **/*.{jsx,tsx} : Use Server Components for async data fetching instead of async Client Components in Next.js
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsx
📚 Learning: 2025-12-01T15:20:25.102Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/open-graph.mdc:0-0
Timestamp: 2025-12-01T15:20:25.102Z
Learning: Applies to src/**/route.{ts,tsx} : Read dynamic content from `request.nextUrl.searchParams` and pass into pure component props rather than fetching during render
Applied to files:
apps/docs-smoke/src/routes/docs/search.tsxapps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2025-12-01T15:20:25.102Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/open-graph.mdc:0-0
Timestamp: 2025-12-01T15:20:25.102Z
Learning: Applies to src/**/route.{ts,tsx} : Use whole pixel dimensions for text and key visual lines; consider `pointScaleFactor: 2` for high-DPI crispness
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include integration tests for component combinations
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2026-03-19T22:57:45.114Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:45.114Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include unit tests for components, integration tests for component combinations, accessibility tests, and error boundary tests
Applied to files:
apps/docs-smoke/src/lib/docs.tsapps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:45.114Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:45.114Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Document components with purpose and use case, required and optional props, context requirements, example usage, and common pitfalls
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{tsx,jsx} : For each component, documentation should include: purpose and use case, required and optional props, context requirements, example usage, and common pitfalls
Applied to files:
apps/docs-smoke/src/lib/docs.ts
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/**/*.mdx : Use MDX for documentation pages in the docs app
Applied to files:
apps/docs-smoke/content/docs/search.mdx
📚 Learning: 2026-03-19T22:57:19.913Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:19.913Z
Learning: Applies to apps/docs/**/*.mdx : Use MDX for documentation pages
Applied to files:
apps/docs-smoke/content/docs/search.mdx
📚 Learning: 2026-01-31T11:24:55.220Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/docs-rules.mdc:0-0
Timestamp: 2026-01-31T11:24:55.220Z
Learning: Applies to apps/docs/**/*.mdx : Include code examples where appropriate in MDX documentation pages of the docs app
Applied to files:
apps/docs-smoke/content/docs/search.mdx
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Test accessibility features in Elements package component tests
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Test accessibility features
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Test with screen readers in Elements package component tests
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Include integration tests for Elements package components
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2025-07-23T12:51:43.299Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/global-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:43.299Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Include accessibility tests for components
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:58:00.031Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2026-03-19T22:58:00.031Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Write comprehensive unit tests with clear test case names describing what is being tested
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2025-07-23T12:51:10.961Z
Learnt from: CR
Repo: consentdotio/monorepo PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2025-07-23T12:51:10.961Z
Learning: Applies to packages/elements/**/*.test.{ts,tsx} : Include integration tests
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T22:57:33.411Z
Learnt from: CR
Repo: consentdotio/GDPRish PR: 0
File: .cursor/rules/elements-rules.mdc:0-0
Timestamp: 2026-03-19T22:57:33.411Z
Learning: Applies to packages/elements/**/*.{test,spec}.{ts,tsx} : Test error boundaries in Elements package component tests
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-02-20T14:21:19.208Z
Learnt from: CR
Repo: consentdotio/dsar PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2026-02-20T14:21:19.208Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Avoid done callbacks in async tests - use async/await instead
Applied to files:
apps/docs-smoke/tests/e2e/smoke.e2e.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When implementing type safety patterns, load the router-core type-safety skill file from node_modules/tanstack/router-core/skills/router-core/type-safety/SKILL.md
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-03-19T16:08:15.951Z
Learnt from: CR
Repo: consentdotio/c-ray PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-03-19T16:08:15.951Z
Learning: When implementing code splitting, load the router-core code-splitting skill file from node_modules/tanstack/router-core/skills/router-core/code-splitting/SKILL.md
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2025-12-17T14:48:41.563Z
Learnt from: CR
Repo: consentdotio/c15t-docs PR: 0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-12-17T14:48:41.563Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Don't import next/document outside of pages/_document.jsx in Next.js projects
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
📚 Learning: 2026-04-16T03:27:04.353Z
Learnt from: CR
Repo: inthhq/dsar PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-16T03:27:04.353Z
Learning: Applies to **/index.{js,jsx,ts,tsx} : Avoid barrel files (index files that re-export everything)
Applied to files:
apps/docs-smoke/src/routeTree.gen.ts
🪛 LanguageTool
apps/docs-smoke/content/docs/search.mdx
[uncategorized] ~37-~37: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...st, then generate the search index from markdown: ```ts import { generateSearchIndex } ...
(MARKDOWN_NNP)
🔇 Additional comments (3)
apps/docs-smoke/content/docs/meta.json (1)
5-5: Good nav metadata update.Adding
"search"keeps the docs page registry aligned with the new/docs/searchpage.apps/docs-smoke/src/routes/docs/search.tsx (1)
6-12: Route wiring looks correct.
createFileRoute("/docs/search")cleanly maps to the MDX page component with no extra complexity.apps/docs-smoke/src/lib/docs.ts (1)
7-11: Nice synchronization between route types and demo nav entries.Both new paths are reflected in
DemoRoute["to"]anddemoRoutes, reducing drift risk.Also applies to: 25-29, 45-49
| "@inth/docs/search": { | ||
| type: "runtime", | ||
| description: "Static local search, source-grounded answer context, request guards, and AI SDK streaming helpers.", | ||
| }, |
There was a problem hiding this comment.
Update package-surface count in the intro.
After adding @inth/docs/search, the sentence at Line 8 (“has five package surfaces”) is stale and should be updated to six.
📝 Suggested doc fix
-`@inth/docs` has five package surfaces:
+`@inth/docs` has six package surfaces:🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/content/docs/index.mdx` around lines 31 - 34, The docs intro
still says “has five package surfaces” but you added the new package
"@inth/docs/search"; update the intro sentence in
apps/docs-smoke/content/docs/index.mdx (the sentence that mentions package
surfaces) to say “six package surfaces” and ensure any adjacent counts or
pluralization remain consistent with the added "@inth/docs/search" entry.
|
|
||
| ## Build the Index | ||
|
|
||
| Run conversion first, then generate the search index from markdown: |
There was a problem hiding this comment.
Capitalize “Markdown” for consistency.
At Line 37, use “Markdown” (proper noun) for documentation style consistency.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~37-~37: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...st, then generate the search index from markdown: ```ts import { generateSearchIndex } ...
(MARKDOWN_NNP)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/content/docs/search.mdx` at line 37, Summary: The word
"markdown" should be capitalized to "Markdown" for consistency. Update the text
string "Run conversion first, then generate the search index from markdown:" to
"Run conversion first, then generate the search index from Markdown:" in the
docs content (the line containing that sentence in
apps/docs-smoke/content/docs/search.mdx) so the proper noun "Markdown" is used
consistently.
| const answerConfigResponse = await request.get("/api/docs/ask"); | ||
| const answerConfig = (await answerConfigResponse.json()) as { | ||
| enabled: boolean; | ||
| }; |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Assert /api/docs/ask success before parsing JSON.
Add an explicit ok() assertion so failures surface as endpoint-status issues instead of JSON parse noise.
✅ Suggested test hardening
const answerConfigResponse = await request.get("/api/docs/ask");
+ expect(answerConfigResponse.ok()).toBe(true);
const answerConfig = (await answerConfigResponse.json()) as {
enabled: boolean;
};📝 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.
| const answerConfigResponse = await request.get("/api/docs/ask"); | |
| const answerConfig = (await answerConfigResponse.json()) as { | |
| enabled: boolean; | |
| }; | |
| const answerConfigResponse = await request.get("/api/docs/ask"); | |
| expect(answerConfigResponse.ok()).toBe(true); | |
| const answerConfig = (await answerConfigResponse.json()) as { | |
| enabled: boolean; | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/docs-smoke/tests/e2e/smoke.e2e.ts` around lines 141 - 144, The test
parses JSON from the response to request.get("/api/docs/ask") without first
asserting the HTTP success status, which masks endpoint failures as JSON parse
errors; update the test around answerConfigResponse and answerConfig to assert
the response is OK (e.g., check answerConfigResponse.ok or use your test
framework's status assertion) before calling .json(), and include a descriptive
message so failures surface as an endpoint-status issue rather than JSON parse
noise.
Adds a headless @inth/docs search surface with static index generation, BM25-style runtime search, abuse guards, rate limiting, and an AI SDK streaming helper. Wires the docs-smoke app with debounced realtime search, explicit AI answers using moonshotai/kimi-k2.6 by default, API routes, heading deep links, and a generated demo index. Updates package docs, agent-docs output, route generation, and e2e coverage. Verified with package tests, app typechecks, Playwright e2e, and Ultracite checks.