-
Add custom css in /src/assets/main.scss
-
The references in manifest.json point to files in the final distribution:
/dist -
/distis generated from source vianpm run build -
Start local webserver:
npm start, this will start a server onhttp://localhost:8080/
Search runs entirely in the browser. At build time, scraped JSONL entries are compiled into a gzipped Orama index (output/search-index.orama.json.gz, copied to dist/).
- Rebuild only the index:
npm run build:search-index - Full site build (index + webpack):
npm run build - Requires scraped entries in
search-index-entries/(.jsonland.json), or a committedoutput/search-index.orama.json.gzfallback for CI
GitHub Actions needs one of these in the repo:
- Preferred: commit
search-index-entries/*.jsonlafter scraping (.not-splitbackups stay gitignored) - Alternative: commit
output/search-index.orama.json.gz(CI reuses it when entries are absent)
Run a full scrape with npm run scrape (or sh scraper/main.sh). Output goes to search-index-entries/.
Browser: Puppeteer needs Chrome/Chromium. On macOS it uses Google Chrome by default; override with PUPPETEER_EXECUTABLE_PATH in .env, or run node node_modules/puppeteer/install.js.
Current inventory (generated): config/scrape-sources.md — refresh with npm run diagram:scrape.
| I want to… | Sitemap? | Where to edit |
|---|---|---|
| Index a GitHub repository | Automatic — built during scrape | config/github-repos.json |
Index a website that already has sitemap.xml |
Use theirs — point at the URL | config/generic-sites.mjs |
| Index a website with no sitemap | You create one | config/manual-sitemaps/ and config/generic-sites.mjs |
| Index one page only | None | config/single-urls/urls.json |
| Skip some URLs from a site | (uses that site’s sitemap) | config/exclude-urls/ and config/generic-sites.mjs |
| Add content without scraping | None | config/manual-entries/ |
Indexes source files + issues via the GitHub API. You do not add a sitemap file — scrape generates it.
- Open
config/github-repos.json. - Append an object:
{ "owner": "WebOfTrust", "repo": "keripy", "branch": "main", "category": "Code" }| Field | Required | Meaning |
|---|---|---|
owner |
yes | GitHub org/user |
repo |
yes | Repository name |
branch |
yes | Branch to index |
category |
yes | Search facet (e.g. Code) |
skipCrawl |
no | true = keep existing JSONL; skip sitemap + scrape |
- Run
npm run scrape(builds the sitemap, then scrapes). - Optional:
npm run diagram:scrape.
Output: search-index-entries/{owner}-{repo}-{branch}.jsonl.
Not for GitHub Pages (*.github.io). Those are normal websites — use the website recipes below.
Typical for Docusaurus, ReadTheDocs, many docs sites. You point at their sitemap — you do not create one.
- Confirm the site publishes a sitemap (try
https://example.com/sitemap.xml). - Open
config/generic-sites.mjs. - Copy a similar block (e.g. eSSIF-Lab for Docusaurus, keripy for ReadTheDocs, keri.foundation for WordPress).
- Set at least:
sourceType: 'remoteXMLsitemap'sourcePath: 'https://…/sitemap.xml'siteName,source,category,destinationFiledomQueryForContent: DOM_QUERY.docusaurus(or.readTheDocs/.wordpressEntryContent)
- In the export at the bottom, add:
scrape(configYourSite, scrapeSimple.docusaurus); // or readTheDocs / wordpressOnly lines in that export actually run.
- Optional: skip unwanted URLs — see Skip some URLs.
npm run diagram:scrape, thennpm run scrape.
You must create a sitemap and wire it — dropping an XML file alone does nothing.
- Create an XML sitemap, e.g.
config/manual-sitemaps/my-site.xml:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://example.com/page-a</loc></url>
<url><loc>https://example.com/page-b</loc></url>
</urlset>(At scrape start this is copied to scraper/sitemaps/.)
- Open
config/generic-sites.mjsand add a config like Slack archive:
const configMySite = {
sitemap: await createInput({
sourceType: 'localXMLsitemap',
sourcePath: 'scraper/sitemaps/my-site.xml',
}),
siteName: 'My Site',
source: 'My Site',
category: 'Blogs',
author: '',
destinationFile: 'search-index-entries/my-site.jsonl',
domQueryForContent: DOM_QUERY.body, // or another DOM_QUERY.* that fits
};- Add to the export:
scrape(configMySite, scrapeSimple.body); npm run diagram:scrape, thennpm run scrape.
No sitemap. One JSON object per page.
- Open
config/single-urls/urls.json. - Append:
{
"url": "https://example.com/post",
"siteName": "Example Blog",
"pageTitle": "My Post Title",
"source": "Blogposts",
"author": "Ada",
"category": "Blogs",
"querySelector": "article p, article h1, article h2, article li"
}| Field | Required | Meaning |
|---|---|---|
url |
yes | Page to scrape |
querySelector |
yes | CSS selector(s) for main content |
pageTitle |
yes | Title in index + output filename |
siteName / source / category |
recommended | Facets in search |
author / type |
optional |
npm run scrape.
Output: search-index-entries/site-{index}-{pageTitle-slug}.jsonl
({index} = position in the array — inserting in the middle renumbers later files.)
Only applies to sites configured in generic-sites.mjs.
- Create
config/exclude-urls/my-site.json:
[
"newsroom",
"https://example.com/exact-page/"
]- Fragments like
"newsroom"= substring match (drops any URL containing it). - Full
http(s)://…URLs = exact match (trailing slash ignored).
- In that site’s
createInput({…})ingeneric-sites.mjs, set:
excludeURLs: 'config/exclude-urls/my-site.json',npm run scrape.
If the file is missing, the scraper logs an error and continues with no excludes.
- Put a
.jsonor.jsonlfile inconfig/manual-entries/. - Match the usual entry shape (
url,content,pageTitle,category, …). - Run
npm run scrape(or at least the copy step) — files are copied intosearch-index-entries/.
Examples already there: handmade.json, gleifPDF.jsonl.
DOM presets live in scraper/modules/genericSiteScrape.mjs: DOM_QUERY.docusaurus, .readTheDocs, .wordpressEntryContent, .gleif, .body, plus makeScraper / scrapeSimple.*.