build(docs): add Astro and content collection configuration

This commit is contained in:
Prad Nukala committed 2026-10-17 20:23:40 -04:00
1 parent fadfa7ff9f
commit 7f8461e692
2 files changed
+164

No files matched your search

+137
View File
@@ -0,0 +1,137 @@
// Written by `blume eject`. This is your Astro config now: edit it freely.
import { availableParallelism } from "node:os";
import { fileURLToPath } from "node:url";
import { defineConfig, fontProviders } from "astro/config";
import mdx from "@astrojs/mdx";
import tailwindcss from "@tailwindcss/vite";
import { blumeMarkdownProcessor, blumeMdxProcessor, blumeShikiTransformers, blumeTwoslashTransformer } from "blume/markdown";
import react from "@astrojs/react";
import { blumeIntegration, includeHmrPlugin, mdxSourceErrorsPlugin, prerenderDepsPlugin } from "blume/astro";
export default defineConfig({
root: ".",
srcDir: "./src",
outDir: "./dist",
publicDir: "./public",
output: "static",
site: "https://lc.prd.lk",
redirects: {"/1":{"destination":"/hash-table/two-sum","status":301},"/1.md":{"destination":"/hash-table/two-sum.md","status":301},"/1.mdx":{"destination":"/hash-table/two-sum.mdx","status":301},"/2":{"destination":"/hybrid-structures/add-two-numbers","status":301},"/2.md":{"destination":"/hybrid-structures/add-two-numbers.md","status":301},"/2.mdx":{"destination":"/hybrid-structures/add-two-numbers.mdx","status":301},"/3":{"destination":"/sliding-window/longest-substring-without-repeating-characters","status":301},"/3.md":{"destination":"/sliding-window/longest-substring-without-repeating-characters.md","status":301},"/3.mdx":{"destination":"/sliding-window/longest-substring-without-repeating-characters.mdx","status":301},"/4":{"destination":"/binary-search/median-of-two-sorted-arrays","status":301},"/4.md":{"destination":"/binary-search/median-of-two-sorted-arrays.md","status":301},"/4.mdx":{"destination":"/binary-search/median-of-two-sorted-arrays.mdx","status":301},"/11":{"destination":"/two-pointers/container-with-most-water","status":301},"/11.md":{"destination":"/two-pointers/container-with-most-water.md","status":301},"/11.mdx":{"destination":"/two-pointers/container-with-most-water.mdx","status":301},"/15":{"destination":"/two-pointers/3sum","status":301},"/15.md":{"destination":"/two-pointers/3sum.md","status":301},"/15.mdx":{"destination":"/two-pointers/3sum.mdx","status":301},"/19":{"destination":"/linked-list/remove-nth-node-from-end-of-list","status":301},"/19.md":{"destination":"/linked-list/remove-nth-node-from-end-of-list.md","status":301},"/19.mdx":{"destination":"/linked-list/remove-nth-node-from-end-of-list.mdx","status":301},"/20":{"destination":"/stack/valid-parentheses","status":301},"/20.md":{"destination":"/stack/valid-parentheses.md","status":301},"/20.mdx":{"destination":"/stack/valid-parentheses.mdx","status":301},"/21":{"destination":"/linked-list/merge-two-sorted-lists","status":301},"/21.md":{"destination":"/linked-list/merge-two-sorted-lists.md","status":301},"/21.mdx":{"destination":"/linked-list/merge-two-sorted-lists.mdx","status":301},"/23":{"destination":"/heap-priority-queue/merge-k-sorted-lists","status":301},"/23.md":{"destination":"/heap-priority-queue/merge-k-sorted-lists.md","status":301},"/23.mdx":{"destination":"/heap-priority-queue/merge-k-sorted-lists.mdx","status":301},"/33":{"destination":"/binary-search/search-in-rotated-sorted-array","status":301},"/33.md":{"destination":"/binary-search/search-in-rotated-sorted-array.md","status":301},"/33.mdx":{"destination":"/binary-search/search-in-rotated-sorted-array.mdx","status":301},"/34":{"destination":"/binary-search/find-first-and-last-position-of-element-in-sorted-array","status":301},"/34.md":{"destination":"/binary-search/find-first-and-last-position-of-element-in-sorted-array.md","status":301},"/34.mdx":{"destination":"/binary-search/find-first-and-last-position-of-element-in-sorted-array.mdx","status":301},"/35":{"destination":"/binary-search/search-insert-position","status":301},"/35.md":{"destination":"/binary-search/search-insert-position.md","status":301},"/35.mdx":{"destination":"/binary-search/search-insert-position.mdx","status":301},"/36":{"destination":"/matrix-index-math/valid-sudoku","status":301},"/36.md":{"destination":"/matrix-index-math/valid-sudoku.md","status":301},"/36.mdx":{"destination":"/matrix-index-math/valid-sudoku.mdx","status":301},"/39":{"destination":"/backtracking/combination-sum","status":301},"/39.md":{"destination":"/backtracking/combination-sum.md","status":301},"/39.mdx":{"destination":"/backtracking/combination-sum.mdx","status":301},"/42":{"destination":"/two-pointers/trapping-rain-water","status":301},"/42.md":{"destination":"/two-pointers/trapping-rain-water.md","status":301},"/42.mdx":{"destination":"/two-pointers/trapping-rain-water.mdx","status":301},"/46":{"destination":"/backtracking/permutations","status":301},"/46.md":{"destination":"/backtracking/permutations.md","status":301},"/46.mdx":{"destination":"/backtracking/permutations.mdx","status":301},"/48":{"destination":"/matrix-index-math/rotate-image","status":301},"/48.md":{"destination":"/matrix-index-math/rotate-image.md","status":301},"/48.mdx":{"destination":"/matrix-index-math/rotate-image.mdx","status":301},"/49":{"destination":"/hash-table/group-anagrams","status":301},"/49.md":{"destination":"/hash-table/group-anagrams.md","status":301},"/49.mdx":{"destination":"/hash-table/group-anagrams.mdx","status":301},"/53":{"destination":"/greedy/maximum-subarray","status":301},"/53.md":{"destination":"/greedy/maximum-subarray.md","status":301},"/53.mdx":{"destination":"/greedy/maximum-subarray.mdx","status":301},"/54":{"destination":"/matrix-index-math/spiral-matrix","status":301},"/54.md":{"destination":"/matrix-index-math/spiral-matrix.md","status":301},"/54.mdx":{"destination":"/matrix-index-math/spiral-matrix.mdx","status":301},"/55":{"destination":"/greedy/jump-game","status":301},"/55.md":{"destination":"Line truncated
fonts: [{ provider: fontProviders.local(), name: "Inter", cssVariable: "--blume-ff-inter", fallbacks: ["ui-sans-serif","system-ui","sans-serif"], options: { variants: [{"weight":"100..900","src":["node_modules/@fontsource-variable/inter/files/inter-latin-wght-normal.woff2"]}] } }, { provider: fontProviders.local(), name: "IBM Plex Mono", cssVariable: "--blume-ff-ibm-plex-mono", fallbacks: ["ui-monospace","SF Mono","Menlo","monospace"], options: { variants: [{"weight":400,"src":["node_modules/@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-400-normal.woff2"]},{"weight":500,"src":["node_modules/@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2"]}] } }],
integrations: [mdx({ processor: blumeMdxProcessor({ ...{"basePath":"","codeThemes":{"dark":"github-dark","light":"github-light"},"contentRoot":"content","deployBase":"","externalLinks":false,"headingAnchors":true,"variables":{}}, dataFile: fileURLToPath(new URL("./src/generated/data.json", import.meta.url)) }) }), react({ exclude: [/\/\.cache\/vite\//] }), blumeIntegration({"pages":[{"entrypoint":"pages/appendix.astro","pattern":"/appendix"},{"entrypoint":"pages/changelog.astro","pattern":"/changelog"},{"entrypoint":"pages/progress.astro","pattern":"/progress"}],"poweredBy":true,"redirects":[["^/1/?$","/hash-table/two-sum",301],["^/1\\.md/?$","/hash-table/two-sum.md",301],["^/1\\.mdx/?$","/hash-table/two-sum.mdx",301],["^/2/?$","/hybrid-structures/add-two-numbers",301],["^/2\\.md/?$","/hybrid-structures/add-two-numbers.md",301],["^/2\\.mdx/?$","/hybrid-structures/add-two-numbers.mdx",301],["^/3/?$","/sliding-window/longest-substring-without-repeating-characters",301],["^/3\\.md/?$","/sliding-window/longest-substring-without-repeating-characters.md",301],["^/3\\.mdx/?$","/sliding-window/longest-substring-without-repeating-characters.mdx",301],["^/4/?$","/binary-search/median-of-two-sorted-arrays",301],["^/4\\.md/?$","/binary-search/median-of-two-sorted-arrays.md",301],["^/4\\.mdx/?$","/binary-search/median-of-two-sorted-arrays.mdx",301],["^/11/?$","/two-pointers/container-with-most-water",301],["^/11\\.md/?$","/two-pointers/container-with-most-water.md",301],["^/11\\.mdx/?$","/two-pointers/container-with-most-water.mdx",301],["^/15/?$","/two-pointers/3sum",301],["^/15\\.md/?$","/two-pointers/3sum.md",301],["^/15\\.mdx/?$","/two-pointers/3sum.mdx",301],["^/19/?$","/linked-list/remove-nth-node-from-end-of-list",301],["^/19\\.md/?$","/linked-list/remove-nth-node-from-end-of-list.md",301],["^/19\\.mdx/?$","/linked-list/remove-nth-node-from-end-of-list.mdx",301],["^/20/?$","/stack/valid-parentheses",301],["^/20\\.md/?$","/stack/valid-parentheses.md",301],["^/20\\.mdx/?$","/stack/valid-parentheses.mdx",301],["^/21/?$","/linked-list/merge-two-sorted-lists",301],["^/21\\.md/?$","/linked-list/merge-two-sorted-lists.md",301],["^/21\\.mdx/?$","/linked-list/merge-two-sorted-lists.mdx",301],["^/23/?$","/heap-priority-queue/merge-k-sorted-lists",301],["^/23\\.md/?$","/heap-priority-queue/merge-k-sorted-lists.md",301],["^/23\\.mdx/?$","/heap-priority-queue/merge-k-sorted-lists.mdx",301],["^/33/?$","/binary-search/search-in-rotated-sorted-array",301],["^/33\\.md/?$","/binary-search/search-in-rotated-sorted-array.md",301],["^/33\\.mdx/?$","/binary-search/search-in-rotated-sorted-array.mdx",301],["^/34/?$","/binary-search/find-first-and-last-position-of-element-in-sorted-array",301],["^/34\\.md/?$","/binary-search/find-first-and-last-position-of-element-in-sorted-array.md",301],["^/34\\.mdx/?$","/binary-search/find-first-and-last-position-of-element-in-sorted-array.mdx",301],["^/35/?$","/binary-search/search-insert-position",301],["^/35\\.md/?$","/binary-search/search-insert-position.md",301],["^/35\\.mdx/?$","/binary-search/search-insert-position.mdx",301],["^/36/?$","/matrix-index-math/valid-sudoku",301],["^/36\\.md/?$","/matrix-index-math/valid-sudoku.md",301],["^/36\\.mdx/?$","/matrix-index-math/valid-sudoku.mdx",301],["^/39/?$","/backtracking/combination-sum",301],["^/39\\.md/?$","/backtracking/combination-sum.md",301],["^/39\\.mdx/?$","/backtracking/combination-sum.mdx",301],["^/42/?$","/two-pointers/trapping-rain-water",301],["^/42\\.md/?$","/two-pointers/trapping-rain-water.md",301],["^/42\\.mdx/?$","/two-pointers/trapping-rain-water.mdx",301],["^/46/?$","/backtracking/permutations",301],["^/46\\.md/?$","/backtracking/permutations.md",301],["^/46\\.mdx/?$","/backtracking/permutations.mdx",301],["^/48/?$","/matrix-index-math/rotate-image",301],["^/48\\.md/?$","/matrix-index-math/rotate-image.md",301],["^/48\\.mdx/?$","/matrix-index-math/rotate-image.mdx",301],["^/49/?$","/hash-table/group-anagrams",301],["^/49\\.md/?$","/hash-table/group-anagrams.md",301],["^/49\\.mdx/?$","/hash-table/group-anagrams.mdx",301],["^/53/?$","/greedy/maximum-subarray",301],["^/53\\.md/?$","/greedy/maximum-subarray.md",301],["^/53\\.mdx/?$","/greedy/maximum-subarray.mdx",301],["^/54/?$","/matrix-index-math/spiral-matrix",301],["^/54\\.md/?$","/matrix-index-math/spiral-matrix.md",301],["^/54\\.mdx/?$","/matrix-index-math/spiral-matrix.mdx",301],["^/55/?$","/greedy/jump-game",301],["^/55\\.md/?$","/greedy/jump-game.md",301],["^/55\\.mdx/?$","/greedy/jump-game.mdx",301],["^/56/?$","/intervals/merge-intervals",301],["^/56\\.md/?$","/intervals/merge-intervals.md",301],["^/56\\.mdx/?$","/intervals/merge-intervals.mdx",301],["^/57/?$","/intervals/insert-interval",301],["^/57\\.md/?$","/intervals/insert-interval.md",301],["^/57\\.mdx/?$","/intervals/insert-interval.mdx",301],["^/62/?$","/multi-d-grid-dp/unique-paths",301],["^/62\\.md/?$","/multi-d-grid-dp/unique-paths.md",301],["^/62\\.mdx/?$","/multi-d-grid-dp/unique-paths.mdx",301],["^/64/?$","Line truncated
markdown: {
processor: blumeMarkdownProcessor({ ...{"basePath":"","codeThemes":{"dark":"github-dark","light":"github-light"},"contentRoot":"content","deployBase":"","externalLinks":false,"headingAnchors":true,"variables":{}}, dataFile: fileURLToPath(new URL("./src/generated/data.json", import.meta.url)) }),
shikiConfig: {
themes: {
light: "github-light",
dark: "github-dark",
},
defaultColor: false,
transformers: [blumeTwoslashTransformer(), ...blumeShikiTransformers({"icons":true})],
},
},
devToolbar: { enabled: false },
// One canonical URL per page: canonicals, the sitemap, and hreflang all use
// the slashless form, so the slashed spelling is not a second address. Astro
// applies this itself — an on-demand route redirects, and the integration
// has the dev server redirect too, ahead of Astro's own 404 — and the Vercel
// adapter turns it into the platform's 308 route, so the Build Output config
// needs no hand-spliced redirect (see deploy/vercel-negotiation.ts). Static hosts
// serve the `index.html` directory layout as they always did.
trailingSlash: "never",
// The layouts render Astro's <ClientRouter />, and its in-place swaps read
// from the prefetch cache — fetching every link on hover/viewport hides the
// request latency behind the user's intent, so most navigations swap
// instantly.
prefetch: { prefetchAll: true },
// Prerender several pages at once. Rendering is single-threaded, but a
// page's OG card renders on a native thread and its HTML is written
// asynchronously, so the main thread would otherwise idle behind each
// page's off-thread work. Capped at 8: the gain flattens there and beyond it
// the overlap only adds memory.
build: { concurrency: Math.min(8, availableParallelism()) },
vite: {
plugins: [tailwindcss(), includeHmrPlugin(fileURLToPath(new URL("./src/generated/includes.json", import.meta.url))), mdxSourceErrorsPlugin(), prerenderDepsPlugin()],
build: {
chunkSizeWarningLimit: 2048,
rolldownOptions: {
onLog(level, log, handler) {
if (log.code === "MODULE_LEVEL_DIRECTIVE" && String(log.message).includes("use astro:head-inject")) {
return;
}
handler(level, log);
},
},
},
// Everything hydration can reach must be part of the dev dep optimizer's
// FIRST run. The Vite root is the generated runtime, so user pages,
// islands, and aliased components live outside it and are only crawled
// when first requested — and `react/compiler-runtime` is injected by the
// React Compiler, so no source scan can ever see it. A dependency discovered after
// hydration begins triggers a mid-session re-optimization whose new
// generation imports React through new `?v=` URLs; the browser then
// evaluates a second React copy and every island tears down with
// "Invalid hook call" (#157). `entries` points the startup scanner at
// the user's files (the scanner follows their imports, so their deps land
// in the initial optimization); the compiler runtime rides the include
// list because only the transform pipeline knows it exists.
//
// The mermaid/epub includes fix CJS interop instead: both lazy client-side
// imports land on CJS/UMD files (mermaid statically imports dayjs as CJS,
// epub-gen-memory's browser bundle is a browserified UMD) that break when
// served as raw ESM — mermaid throws on load and the EPUB export throws
// `epub is not a function`. They resolve through the `blume` package
// (they aren't direct deps of the generated project), so the nested
// `blume > x` form is required, and epub-gen-memory must name the
// `/bundle` subpath that is actually imported: optimizing the package
// root leaves that entry out. Production (Rollup) already handles the
// interop, so all of this only affects dev.
//
// The search adapter's client library rides the list for the same reason
// as the compiler runtime: the search dialog lazy-imports it on first
// open, and discovering it then re-optimizes and reloads the page.
optimizeDeps: {
entries: ["./pages/**/*.astro","./islands/**/*.{jsx,svelte,tsx,vue}"],
include: ["blume > mermaid","blume > @orama/orama"],
},
// Blume's render-time deps are forced external on both build environments so
// native bindings resolve at runtime and isolated linkers don't bundle
// symlinked store copies (which would surface their children as unresolvable
// imports). See RENDER_EXTERNAL_DEPS / prerenderDepsPlugin.
//
// The SSR externals go through the legacy `ssr.external` key rather than
// `environments.ssr`: defining a user-owned `environments.ssr` block
// collides with the internal environment Astro 7 builds the server under and
// detaches the adapter's server entrypoint from the rolldown input, so the
// SSR entry is emitted as `index.mjs` instead of the `entry.mjs` the
// Vercel adapter's `astro:build:done` hook then fails to find. `prerender`
// is Astro-only and has no legacy equivalent, so it stays under `environments`.
ssr: { external: ["@astrojs/markdown-satteri","@pierre/diffs","@shikijs/transformers","@takumi-rs/core","@takumi-rs/helpers","@takumi-rs/wasm","github-slugger","katex","shiki","simple-icons","takumi-js","takumi-js/helpers","zod"] },
environments: {
prerender: { resolve: { external: ["@astrojs/markdown-satteri","@pierre/diffs","@shikijs/transformers","@takumi-rs/core","@takumi-rs/helpers","@takumi-rs/wasm","github-slugger","katex","shiki","simple-icons","takumi-js","takumi-js/helpers","zod"] } },
},
resolve: {
alias: {
"blume:ask": fileURLToPath(new URL("./src/generated/Ask.astro", import.meta.url)),
"blume:consent-client": fileURLToPath(new URL("./src/generated/consent-client.ts", import.meta.url)),
"blume:examples": fileURLToPath(new URL("./src/generated/examples.ts", import.meta.url)),
"blume:examples-theme": fileURLToPath(new URL("./src/generated/examples.css", import.meta.url)),
"blume:features": fileURLToPath(new URL("./src/generated/features.ts", import.meta.url)),
"blume:search-client": fileURLToPath(new URL("./src/generated/search-client.ts", import.meta.url)),
"blume:theme": fileURLToPath(new URL("./src/generated/app.css", import.meta.url)),
"blume:ask-data": fileURLToPath(new URL("./src/generated/ask-data.json", import.meta.url)),
"blume:content-assets": fileURLToPath(new URL("./src/generated/content-assets.json", import.meta.url)),
"blume:data": fileURLToPath(new URL("./src/generated/data.json", import.meta.url)),
"blume:mcp-data": fileURLToPath(new URL("./src/generated/mcp-data.json", import.meta.url)),
"blume:openapi": fileURLToPath(new URL("./src/generated/openapi.json", import.meta.url)),
"blume:raw-markdown": fileURLToPath(new URL("./src/generated/raw-markdown.json", import.meta.url)),
"blume:rss": fileURLToPath(new URL("./src/generated/rss.json", import.meta.url)),
"blume:search-index": fileURLToPath(new URL("./src/generated/search.json", import.meta.url)),
},
},
server: {
fs: {
allow: ["."],
},
},
},
});
+27
View File
@@ -0,0 +1,27 @@
// Generated by Blume. Do not edit.
import { defineCollection } from "astro:content";
import { glob } from "astro/loaders";
import { withIncludeRefresh } from "blume/astro";
import { pageCollectionSchema } from "blume/core/schema.ts";
// withIncludeRefresh keeps <include>-bearing pages fresh: plain .md entries
// are rendered at sync time and digest-cached on the page file alone, so a
// partial edit (or a warm-cache rebuild after one) would serve stale HTML.
//
// pageCollectionSchema is the scan's page front-matter schema, so entry.data
// is typed and normalized the same way; it passes custom keys through and
// falls back to defaults for a page the scan already dropped as invalid.
//
// Astro's content store re-parses an entry only when its file or this config
// changes, so naming the Blume version (2.2.4) here re-parses
// every entry after an upgrade: none keeps what an older schema produced.
const docs = defineCollection({
loader: withIncludeRefresh(glob({
pattern: ["**/*.{md,mdx}","!**/_*","!**/.*","!**/.blume-verify/**","!**/.cache/**","!**/.git/**","!**/.next/**","!**/.turbo/**","!**/.vercel/**","!**/dist/**","!**/node_modules/**"],
base: "content",
generateId: ({ entry }) => entry,
}), "./src/generated/includes.json"),
schema: pageCollectionSchema,
});
export const collections = { docs };