Files
supabase/apps/docs/scripts/search/sources/troubleshooting.ts
Illia Basalaiev ce5cce5030 replace github discussions with local guides in the docs search (#42335)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

feature

## What is the current behavior?

Currently, old GitHub discussions appear in the docs search instead of
troubleshooting guides in docs/guides/troubleshooting

## What is the new behavior?

Local troubleshooting guides appear in the search

## Additional context

<img width="958" height="846" alt="CleanShot 2026-01-31 at 23 37 33@2x"
src="https://github.com/user-attachments/assets/445fab5d-764a-4b4d-b4ef-c29ab675a9ae"
/>


**troubleshooting.ts** - New source loader that reads local MDX files
from content/troubleshooting/ directly instead of fetching from GitHub
Discussions API
- Generates correct docs paths: /guides/troubleshooting/{slug}
- Uses type = 'troubleshooting' for proper search result mapping
- Sets slug: undefined to avoid trailing # in URLs
- Checksum includes title/topics/keywords so metadata-only changes
trigger re-indexing
- Left comments for review 

**index.ts** - Replaced GitHub discussion sources with local
troubleshooting sources
- Removed GitHubDiscussionLoader, fetchDiscussions,
buildGithubUrlToSlugMap imports
- Added fetchTroubleshootingSources and TroubleshootingSource
- Updated SearchSource type union

**globalSearchModel.ts** - Changed type mapping from
'github-discussions' to 'troubleshooting'

**generate-embeddings.ts** - Removed GitHub App env vars from required
list (DOCS_GITHUB_APP_ID, DOCS_GITHUB_APP_INSTALLATION_ID,
DOCS_GITHUB_APP_PRIVATE_KEY) since they're no longer needed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Local troubleshooting articles are now indexed and appear directly in
search results for easier access to step‑by‑step guidance.
* Search UI now recognizes a Troubleshooting page type and shows
appropriate icons/sections.

* **Refactor**
* Search sourcing switched from external discussion feeds to local
troubleshooting sources to improve relevance and indexing consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Illia Basalaiev <illiab@IMB3.local>
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>
2026-02-23 13:54:40 +01:00

102 lines
3.3 KiB
TypeScript

import { createHash } from 'node:crypto'
import { BaseLoader, BaseSource } from './base.js'
import {
getAllTroubleshootingEntriesInternal,
getArticleSlug,
} from '../../../features/docs/Troubleshooting.utils.common.mjs'
import type { ITroubleshootingEntry } from '../../../features/docs/Troubleshooting.utils.js'
/**
* Loader for troubleshooting articles from local MDX files.
*
* The path format is `/guides/troubleshooting/{slug}` where slug is derived
* from the filename (e.g., `auth-error-handling.mdx` → `auth-error-handling`).
*/
export class TroubleshootingLoader extends BaseLoader {
type = 'troubleshooting' as const
constructor(
source: string,
public entry: ITroubleshootingEntry
) {
const slug = getArticleSlug(entry)
super(source, `/guides/troubleshooting/${slug}`)
}
async load(): Promise<TroubleshootingSource[]> {
return [new TroubleshootingSource(this.source, this.path, this.entry)]
}
}
/**
* Search source for a single troubleshooting article.
*
* Each article becomes one indexed page with a single section containing
* the full content. This differs from guide pages which may have multiple
* sections based on headings.
*/
export class TroubleshootingSource extends BaseSource {
type = 'troubleshooting' as const
constructor(
source: string,
path: string,
public entry: ITroubleshootingEntry
) {
super(source, path)
}
async process() {
const { title, topics, keywords } = this.entry.data
const content = this.entry.contentWithoutJsx
// Include title and metadata in checksum so any changes trigger re-indexing.
// This ensures updates to title, topics, or keywords are picked up even if
// the main content hasn't changed.
const checksum = createHash('sha256')
.update(JSON.stringify({ title, topics, keywords, content }))
.digest('base64')
const meta = { title, topics, keywords }
// Troubleshooting articles are single-section pages (no sub-headings indexed).
// We explicitly set slug to undefined so the database's `get_full_content_url`
// function returns the page URL without a fragment (e.g., no trailing `#slug`).
// This is handled in SQL: `CASE WHEN slug IS NULL THEN '' ELSE concat('#', slug) END`
const sections = [
{
heading: title,
slug: undefined as string | undefined,
content: `# ${title}\n${content}`,
},
]
this.checksum = checksum
this.meta = meta
this.sections = sections
return { checksum, meta, sections }
}
/**
* Returns the full article content formatted for full-text search indexing.
* The title is included as a heading to boost its relevance in search results.
*/
extractIndexedContent(): string {
return `# ${this.entry.data.title}\n\n${this.entry.contentWithoutJsx}`
}
}
/**
* Loads all troubleshooting articles from `content/troubleshooting/` directory.
*
* Each MDX file is parsed, validated, and converted to a TroubleshootingLoader.
* Hidden files (prefixed with `_`) are excluded.
*
* @returns Array of loaders, one per troubleshooting article
*/
export async function fetchTroubleshootingSources(): Promise<TroubleshootingLoader[]> {
const entries = (await getAllTroubleshootingEntriesInternal()) as ITroubleshootingEntry[]
return entries.map((entry) => new TroubleshootingLoader('troubleshooting', entry))
}