@silicajs/next 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache-handlers/filesystem.d.ts +33 -0
- package/dist/cache-handlers/filesystem.js +168 -0
- package/dist/cache-handlers/filesystem.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +38 -10
- package/dist/index.js.map +1 -1
- package/dist/routes/api-auth.js +10 -2
- package/dist/routes/api-auth.js.map +1 -1
- package/dist/routes/api-navigation.js +16 -2
- package/dist/routes/api-navigation.js.map +1 -1
- package/dist/routes/api-search.js +3 -10
- package/dist/routes/api-search.js.map +1 -1
- package/dist/routes/layout.js +10 -5
- package/dist/routes/layout.js.map +1 -1
- package/dist/routes/page.d.ts +3 -1
- package/dist/routes/page.js +45 -60
- package/dist/routes/page.js.map +1 -1
- package/dist/routes/sign-in.js +7 -4
- package/dist/routes/sign-in.js.map +1 -1
- package/dist/routes/tags-page.js +16 -27
- package/dist/routes/tags-page.js.map +1 -1
- package/dist/server-data.d.ts +49 -7
- package/dist/server-data.js +262 -33
- package/dist/server-data.js.map +1 -1
- package/dist/template-files/generated-app/app/(site)/[[...slug]]/page.tsx +11 -4
- package/dist/template-files/generated-app/cache-handlers/filesystem-cache.js +1 -0
- package/dist/template-files/next.config.ts +53 -10
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +68 -2
- package/dist/templates.js.map +1 -1
- package/package.json +14 -4
package/dist/routes/page.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/page.tsx"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport type { AnchorHTMLAttributes } from \"react\";\nimport { cacheLife, cacheTag } from \"next/cache\";\nimport { notFound } from \"next/navigation\";\nimport {\n getMetaDescription,\n renderMarkdown,\n renderMarkdownHtml,\n resolveWikiLink,\n slugToHref,\n type RenderContext,\n} from \"@silicajs/core/runtime\";\nimport { SilicaLink } from \"@silicajs/components/routing\";\nimport {\n loadBuildId,\n loadGraph,\n loadManifest,\n loadResolvedConfig,\n normalizeRouteSlug,\n} from \"../server-data.js\";\nimport type {\n SilicaTheme,\n ThemeBacklink,\n ThemeBreadcrumb,\n} from \"@silicajs/core/theme\";\n\nfunction MarkdownLink({\n href,\n ...props\n}: AnchorHTMLAttributes<HTMLAnchorElement>) {\n if (href && href.startsWith(\"/\") && !href.startsWith(\"/silica/\")) {\n return <SilicaLink href={href} {...props} />;\n }\n\n return <a href={href} {...props} />;\n}\n\nexport async function generateStaticParams() {\n const manifest = await getPageManifest();\n return manifest.entries.map((entry) => ({\n slug: entry.slug === \"index\" ? [] : entry.slug.split(\"/\"),\n }));\n}\n\nexport async function generateMetadata({ params }: PageProps) {\n const resolvedParams = await params;\n const slug = normalizeRouteSlug(resolvedParams?.slug);\n const manifest = await getPageManifest();\n const entry = manifest.bySlug[slug];\n if (!entry) return {};\n return {\n title: entry.title,\n description: getMetaDescription(entry),\n };\n}\n\nasync function getPageManifest() {\n \"use cache\";\n cacheLife(\"max\");\n const buildId = await loadBuildId();\n cacheTag(\"build\", `build:${buildId}`);\n return loadManifest();\n}\n\nexport type PageProps = {\n params: Promise<{ slug?: string[] }> | { slug?: string[] };\n};\n\nexport async function VaultContent({\n slug,\n theme,\n}: {\n slug: string;\n theme: SilicaTheme;\n}) {\n \"use cache\";\n cacheLife(\"max\");\n const buildId = await loadBuildId();\n cacheTag(\"build\", `build:${buildId}`, `page:${slug}`);\n\n const [manifest, graph, config] = await Promise.all([\n loadManifest(),\n loadGraph(),\n loadResolvedConfig(),\n ]);\n const entry = manifest.bySlug[slug];\n if (!entry) notFound();\n\n const renderContext = (\n currentSlug: string,\n embedDepth = 0,\n ): RenderContext => ({\n slug: currentSlug,\n allSlugs: manifest.allSlugs,\n assetBaseUrl: \"/silica\",\n wikilinkStrategy: config.wikilinks.strategy,\n tags: config.tags,\n ordering: config.ordering,\n embedDepth,\n maxEmbedDepth: 3,\n components: {\n ...theme.components,\n a: MarkdownLink,\n },\n resolveEmbed: async (target) => {\n const resolved = resolveWikiLink(\n currentSlug,\n target.path || currentSlug,\n manifest.allSlugs,\n config.wikilinks.strategy,\n config.ordering,\n );\n if (!resolved || embedDepth >= 3) return;\n const embeddedEntry = manifest.bySlug[resolved];\n if (!embeddedEntry) return;\n const embeddedRaw = await fs.readFile(embeddedEntry.file, \"utf8\");\n const scopedRaw = scopeEmbedMarkdown(embeddedRaw, target);\n return renderMarkdownHtml(\n scopedRaw,\n renderContext(resolved, embedDepth + 1),\n );\n },\n });\n\n const raw = await fs.readFile(entry.file, \"utf8\");\n const rendered = await renderMarkdown(raw, renderContext(slug));\n\n return (\n <theme.PageRenderer\n config={config}\n breadcrumbs={makeBreadcrumbs(slug, manifest)}\n backlinks={makeBacklinks(slug, manifest, graph)}\n page={{\n slug,\n title: entry.title,\n description: entry.description,\n content: rendered.content,\n frontmatter: entry.frontmatter,\n toc: rendered.toc,\n tags: entry.tags,\n entry,\n }}\n />\n );\n}\n\nfunction makeBreadcrumbs(\n slug: string,\n manifest: Awaited<ReturnType<typeof loadManifest>>,\n): ThemeBreadcrumb[] {\n if (slug === \"index\" || !slug.includes(\"/\")) return [];\n\n const breadcrumbs: ThemeBreadcrumb[] = [{ label: \"Home\", href: \"/\" }];\n const segments = slug.split(\"/\").slice(0, -1);\n let acc = \"\";\n for (const segment of segments) {\n acc = acc ? `${acc}/${segment}` : segment;\n breadcrumbs.push({\n label: prettySegment(segment),\n href: breadcrumbSegmentHref(acc, manifest),\n });\n }\n return breadcrumbs;\n}\n\nfunction breadcrumbSegmentHref(\n segmentPath: string,\n manifest: Awaited<ReturnType<typeof loadManifest>>,\n): string | undefined {\n if (manifest.bySlug[segmentPath]) return slugToHref(segmentPath);\n const indexSlug = `${segmentPath}/index`;\n if (manifest.bySlug[indexSlug]) return slugToHref(indexSlug);\n return undefined;\n}\n\nfunction makeBacklinks(\n slug: string,\n manifest: Awaited<ReturnType<typeof loadManifest>>,\n graph: Awaited<ReturnType<typeof loadGraph>>,\n): ThemeBacklink[] {\n return (graph.backlinks[slug] ?? []).map((source) => ({\n slug: source,\n title: manifest.bySlug[source]?.title ?? source,\n }));\n}\n\nfunction prettySegment(segment: string): string {\n return segment\n .replace(/[-_]/g, \" \")\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction scopeEmbedMarkdown(\n raw: string,\n target: Parameters<NonNullable<RenderContext[\"resolveEmbed\"]>>[0],\n): string {\n if (target.blockId) return extractBlock(raw, target.blockId) ?? raw;\n if (target.heading) return extractHeadingSection(raw, target.heading) ?? raw;\n return raw;\n}\n\nfunction extractHeadingSection(\n raw: string,\n heading: string,\n): string | undefined {\n const lines = raw.split(/\\r?\\n/);\n const expected = normalizeHeading(heading);\n const start = lines.findIndex((line) => {\n const parsed = parseHeading(line);\n return parsed ? normalizeHeading(parsed.text) === expected : false;\n });\n if (start === -1) return;\n\n const startHeading = parseHeading(lines[start] ?? \"\");\n if (!startHeading) return;\n let end = lines.length;\n for (let index = start + 1; index < lines.length; index += 1) {\n const nextHeading = parseHeading(lines[index] ?? \"\");\n if (nextHeading && nextHeading.depth <= startHeading.depth) {\n end = index;\n break;\n }\n }\n\n return lines.slice(start, end).join(\"\\n\").trim();\n}\n\nfunction extractBlock(raw: string, blockId: string): string | undefined {\n const lines = raw.split(/\\r?\\n/);\n const blockIdPattern = new RegExp(\n `(^|\\\\s)\\\\^${escapeRegExp(blockId)}(?=\\\\s|$)`,\n );\n const matchIndex = lines.findIndex((line) => blockIdPattern.test(line));\n if (matchIndex === -1) return;\n\n let start = matchIndex;\n while (start > 0 && lines[start - 1]?.trim()) start -= 1;\n\n let end = matchIndex + 1;\n while (end < lines.length && lines[end]?.trim()) end += 1;\n\n return lines.slice(start, end).join(\"\\n\").replace(blockIdPattern, \"\").trim();\n}\n\nfunction parseHeading(\n line: string,\n): { depth: number; text: string } | undefined {\n const match = /^(#{1,6})\\s+(.+?)\\s*#*\\s*$/.exec(line);\n if (!match) return;\n return {\n depth: match[1]!.length,\n text: match[2]!,\n };\n}\n\nfunction normalizeHeading(value: string): string {\n return value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/routes/page.tsx"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport type { AnchorHTMLAttributes } from \"react\";\nimport { cacheLife, cacheTag } from \"next/cache\";\nimport { notFound } from \"next/navigation\";\nimport {\n getMetaDescription,\n renderMarkdown,\n renderMarkdownHtml,\n type RenderContext,\n} from \"@silicajs/core/runtime\";\nimport { SilicaLink } from \"@silicajs/components/routing\";\nimport {\n getBacklinks,\n getBreadcrumbs,\n getPage,\n getPageRuntimeData,\n getPrerenderSlugs,\n getRenderKey,\n resolveWikiLinkFromDb,\n normalizeRouteSlug,\n} from \"../server-data.js\";\nimport type { SilicaTheme } from \"@silicajs/core/theme\";\n\nfunction MarkdownLink({\n href,\n ...props\n}: AnchorHTMLAttributes<HTMLAnchorElement>) {\n if (href && href.startsWith(\"/\") && !href.startsWith(\"/silica/\")) {\n return <SilicaLink href={href} {...props} />;\n }\n\n return <a href={href} {...props} />;\n}\n\nexport async function generateStaticParams() {\n const prerenderSlugs = getPrerenderSlugs();\n const slugs = prerenderSlugs.length\n ? prerenderSlugs\n : [\"__silica_prerender_placeholder__\"];\n return slugs.map((slug) => ({\n slug: slug === \"index\" ? [] : slug.split(\"/\"),\n }));\n}\n\nexport async function generateMetadata({ params }: PageProps) {\n const resolvedParams = await params;\n const slug = normalizeRouteSlug(resolvedParams?.slug);\n const renderKey = getRenderKey(slug);\n const entry = await getPageMetadata(\n slug,\n renderKey.renderHash,\n renderKey.renderEnvironmentHash,\n );\n if (!entry) return {};\n return {\n title: entry.title,\n description: getMetaDescription(entry),\n };\n}\n\nasync function getPageMetadata(\n slug: string,\n renderHash: string,\n renderEnvironmentHash: string,\n) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(\n `environment:${renderEnvironmentHash}`,\n `page:${slug}`,\n `render:${renderHash}`,\n );\n return getPage(slug);\n}\n\nexport type PageProps = {\n params: Promise<{ slug?: string[] }> | { slug?: string[] };\n};\n\nexport async function VaultContent({\n slug,\n renderHash,\n renderEnvironmentHash,\n theme,\n}: {\n slug: string;\n renderHash: string;\n renderEnvironmentHash: string;\n theme: SilicaTheme;\n}) {\n \"use cache\";\n cacheLife(\"max\");\n const data = getPageRuntimeData(slug);\n if (!data) notFound();\n const { entry, config } = data;\n cacheTag(\n `environment:${renderEnvironmentHash}`,\n `page:${slug}`,\n `render:${renderHash}`,\n );\n\n const renderContext = (\n currentSlug: string,\n embedDepth = 0,\n ): RenderContext => ({\n slug: currentSlug,\n resolveWikiLink: (_currentSlug, target) =>\n resolveWikiLinkFromDb(\n currentSlug,\n target,\n config.wikilinks.strategy,\n config.ordering,\n ),\n assetBaseUrl: \"/silica\",\n wikilinkStrategy: config.wikilinks.strategy,\n tags: config.tags,\n ordering: config.ordering,\n embedDepth,\n maxEmbedDepth: 3,\n components: {\n ...theme.components,\n a: MarkdownLink,\n },\n resolveEmbed: async (target) => {\n const resolved = resolveWikiLinkFromDb(\n currentSlug,\n target.path || currentSlug,\n config.wikilinks.strategy,\n config.ordering,\n );\n if (!resolved || embedDepth >= 3) return;\n const embeddedEntry = getPage(resolved);\n if (!embeddedEntry) return;\n const embeddedRaw = await fs.readFile(embeddedEntry.file, \"utf8\");\n const scopedRaw = scopeEmbedMarkdown(embeddedRaw, target);\n return renderMarkdownHtml(\n scopedRaw,\n renderContext(resolved, embedDepth + 1),\n );\n },\n });\n\n const raw = await fs.readFile(entry.file, \"utf8\");\n const rendered = await renderMarkdown(raw, renderContext(slug));\n\n return (\n <theme.PageRenderer\n config={config}\n breadcrumbs={getBreadcrumbs(slug)}\n backlinks={getBacklinks(slug)}\n page={{\n slug,\n title: entry.title,\n description: entry.description,\n content: rendered.content,\n frontmatter: entry.frontmatter,\n toc: rendered.toc,\n tags: entry.tags,\n entry,\n }}\n />\n );\n}\n\nfunction scopeEmbedMarkdown(\n raw: string,\n target: Parameters<NonNullable<RenderContext[\"resolveEmbed\"]>>[0],\n): string {\n if (target.blockId) return extractBlock(raw, target.blockId) ?? raw;\n if (target.heading) return extractHeadingSection(raw, target.heading) ?? raw;\n return raw;\n}\n\nfunction extractHeadingSection(\n raw: string,\n heading: string,\n): string | undefined {\n const lines = raw.split(/\\r?\\n/);\n const expected = normalizeHeading(heading);\n const start = lines.findIndex((line) => {\n const parsed = parseHeading(line);\n return parsed ? normalizeHeading(parsed.text) === expected : false;\n });\n if (start === -1) return;\n\n const startHeading = parseHeading(lines[start] ?? \"\");\n if (!startHeading) return;\n let end = lines.length;\n for (let index = start + 1; index < lines.length; index += 1) {\n const nextHeading = parseHeading(lines[index] ?? \"\");\n if (nextHeading && nextHeading.depth <= startHeading.depth) {\n end = index;\n break;\n }\n }\n\n return lines.slice(start, end).join(\"\\n\").trim();\n}\n\nfunction extractBlock(raw: string, blockId: string): string | undefined {\n const lines = raw.split(/\\r?\\n/);\n const blockIdPattern = new RegExp(\n `(^|\\\\s)\\\\^${escapeRegExp(blockId)}(?=\\\\s|$)`,\n );\n const matchIndex = lines.findIndex((line) => blockIdPattern.test(line));\n if (matchIndex === -1) return;\n\n let start = matchIndex;\n while (start > 0 && lines[start - 1]?.trim()) start -= 1;\n\n let end = matchIndex + 1;\n while (end < lines.length && lines[end]?.trim()) end += 1;\n\n return lines.slice(start, end).join(\"\\n\").replace(blockIdPattern, \"\").trim();\n}\n\nfunction parseHeading(\n line: string,\n): { depth: number; text: string } | undefined {\n const match = /^(#{1,6})\\s+(.+?)\\s*#*\\s*$/.exec(line);\n if (!match) return;\n return {\n depth: match[1]!.length,\n text: match[2]!,\n };\n}\n\nfunction normalizeHeading(value: string): string {\n return value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n"],"mappings":"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","names":[]}
|
package/dist/routes/sign-in.js
CHANGED
|
@@ -3,7 +3,7 @@ import { cacheLife, cacheTag } from "next/cache";
|
|
|
3
3
|
import { SignInShell } from "@silicajs/components";
|
|
4
4
|
import { GoogleSignInButton } from "../google-sign-in-button.js";
|
|
5
5
|
import { resolveRuntimeAuthConfig } from "../auth-config.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getCacheState, getConfig } from "../server-data.js";
|
|
7
7
|
async function SignInPage() {
|
|
8
8
|
const config = await getSignInConfig();
|
|
9
9
|
const authEnabled = resolveRuntimeAuthConfig(config).authEnabled;
|
|
@@ -19,11 +19,14 @@ async function SignInPage() {
|
|
|
19
19
|
);
|
|
20
20
|
}
|
|
21
21
|
async function getSignInConfig() {
|
|
22
|
+
const cacheState = getCacheState();
|
|
23
|
+
return getCachedSignInConfig(cacheState.renderEnvironmentHash);
|
|
24
|
+
}
|
|
25
|
+
async function getCachedSignInConfig(renderEnvironmentHash) {
|
|
22
26
|
"use cache";
|
|
23
27
|
cacheLife("max");
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return loadResolvedConfig();
|
|
28
|
+
cacheTag(`environment:${renderEnvironmentHash}`);
|
|
29
|
+
return getConfig();
|
|
27
30
|
}
|
|
28
31
|
export {
|
|
29
32
|
SignInPage as default
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/sign-in.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { SignInShell } from \"@silicajs/components\";\nimport { GoogleSignInButton } from \"../google-sign-in-button.js\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/routes/sign-in.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { SignInShell } from \"@silicajs/components\";\nimport { GoogleSignInButton } from \"../google-sign-in-button.js\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport { getCacheState, getConfig } from \"../server-data.js\";\n\nexport default async function SignInPage() {\n const config = await getSignInConfig();\n const authEnabled = resolveRuntimeAuthConfig(config).authEnabled;\n\n return (\n <SignInShell\n title={config.title}\n logo={config.logo}\n headline=\"Sign in required\"\n subheadline={\n authEnabled\n ? `${config.title} is private. Sign in with Google to access.`\n : undefined\n }\n >\n {authEnabled ? (\n <GoogleSignInButton errorCallbackURL=\"/not-allowed\" />\n ) : (\n <p className=\"text-center text-sm text-muted-foreground\">\n Authentication is not enabled for this site.\n </p>\n )}\n </SignInShell>\n );\n}\n\nasync function getSignInConfig() {\n const cacheState = getCacheState();\n return getCachedSignInConfig(cacheState.renderEnvironmentHash);\n}\n\nasync function getCachedSignInConfig(renderEnvironmentHash: string) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(`environment:${renderEnvironmentHash}`);\n return getConfig();\n}\n"],"mappings":"AAsBQ;AAtBR,SAAS,WAAW,gBAAgB;AACpC,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,gCAAgC;AACzC,SAAS,eAAe,iBAAiB;AAEzC,eAAO,aAAoC;AACzC,QAAM,SAAS,MAAM,gBAAgB;AACrC,QAAM,cAAc,yBAAyB,MAAM,EAAE;AAErD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,OAAO;AAAA,MACd,MAAM,OAAO;AAAA,MACb,UAAS;AAAA,MACT,aACE,cACI,GAAG,OAAO,KAAK,gDACf;AAAA,MAGL,wBACC,oBAAC,sBAAmB,kBAAiB,gBAAe,IAEpD,oBAAC,OAAE,WAAU,6CAA4C,0DAEzD;AAAA;AAAA,EAEJ;AAEJ;AAEA,eAAe,kBAAkB;AAC/B,QAAM,aAAa,cAAc;AACjC,SAAO,sBAAsB,WAAW,qBAAqB;AAC/D;AAEA,eAAe,sBAAsB,uBAA+B;AAClE;AACA,YAAU,KAAK;AACf,WAAS,eAAe,qBAAqB,EAAE;AAC/C,SAAO,UAAU;AACnB;","names":[]}
|
package/dist/routes/tags-page.js
CHANGED
|
@@ -2,15 +2,14 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cacheLife, cacheTag } from "next/cache";
|
|
3
3
|
import { notFound } from "next/navigation";
|
|
4
4
|
import { TagsList } from "@silicajs/components";
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
getCacheState,
|
|
7
|
+
getEntriesForTag,
|
|
8
|
+
getTagSlugs
|
|
9
|
+
} from "../server-data.js";
|
|
7
10
|
const EMPTY_TAG_STATIC_PARAM = "__silica_empty_tags__";
|
|
8
11
|
async function generateStaticParams() {
|
|
9
|
-
const
|
|
10
|
-
const tags = new Set(
|
|
11
|
-
manifest.entries.filter(isListedEntry).flatMap((entry) => entry.tags.flatMap((tag) => getTagHierarchy(tag)))
|
|
12
|
-
);
|
|
13
|
-
const params = [...tags].map((tag) => ({ tag: tag.split("/") }));
|
|
12
|
+
const params = getTagSlugs().map((tag) => ({ tag: tag.split("/") }));
|
|
14
13
|
return params.length > 0 ? params : [{ tag: [EMPTY_TAG_STATIC_PARAM] }];
|
|
15
14
|
}
|
|
16
15
|
async function generateMetadata({ params }) {
|
|
@@ -21,34 +20,24 @@ async function generateMetadata({ params }) {
|
|
|
21
20
|
}
|
|
22
21
|
async function TagsPage({ params }) {
|
|
23
22
|
const tag = routeTagToString((await params).tag);
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
TagsList,
|
|
30
|
-
{
|
|
31
|
-
manifest: {
|
|
32
|
-
...manifest,
|
|
33
|
-
entries: manifest.entries.filter(isListedEntry)
|
|
34
|
-
},
|
|
35
|
-
tag
|
|
36
|
-
}
|
|
23
|
+
const cacheState = getCacheState();
|
|
24
|
+
const entries = await getTagEntries(
|
|
25
|
+
tag,
|
|
26
|
+
cacheState.renderEnvironmentHash,
|
|
27
|
+
cacheState.tagIndexHash
|
|
37
28
|
);
|
|
29
|
+
if (entries.length === 0) notFound();
|
|
30
|
+
return /* @__PURE__ */ jsx(TagsList, { entries, tag });
|
|
38
31
|
}
|
|
39
|
-
async function
|
|
32
|
+
async function getTagEntries(tag, renderEnvironmentHash, tagIndexHash) {
|
|
40
33
|
"use cache";
|
|
41
34
|
cacheLife("max");
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return loadManifest();
|
|
35
|
+
cacheTag(`environment:${renderEnvironmentHash}`, `tags:${tagIndexHash}`);
|
|
36
|
+
return getEntriesForTag(tag);
|
|
45
37
|
}
|
|
46
38
|
function routeTagToString(tag) {
|
|
47
39
|
return Array.isArray(tag) ? tag.join("/") : tag;
|
|
48
40
|
}
|
|
49
|
-
function isListedEntry(entry) {
|
|
50
|
-
return entry.frontmatter.listed !== false;
|
|
51
|
-
}
|
|
52
41
|
export {
|
|
53
42
|
TagsPage as default,
|
|
54
43
|
generateMetadata,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/tags-page.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { notFound } from \"next/navigation\";\nimport { TagsList } from \"@silicajs/components\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/routes/tags-page.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { notFound } from \"next/navigation\";\nimport { TagsList } from \"@silicajs/components\";\nimport {\n getCacheState,\n getEntriesForTag,\n getTagSlugs,\n} from \"../server-data.js\";\n\nconst EMPTY_TAG_STATIC_PARAM = \"__silica_empty_tags__\";\n\nexport type TagsPageProps = {\n params: Promise<{ tag: string | string[] }> | { tag: string | string[] };\n};\n\nexport async function generateStaticParams() {\n const params = getTagSlugs().map((tag) => ({ tag: tag.split(\"/\") }));\n return params.length > 0 ? params : [{ tag: [EMPTY_TAG_STATIC_PARAM] }];\n}\n\nexport async function generateMetadata({ params }: TagsPageProps) {\n const tag = routeTagToString((await params).tag);\n return {\n title: `#${tag}`,\n };\n}\n\nexport default async function TagsPage({ params }: TagsPageProps) {\n const tag = routeTagToString((await params).tag);\n const cacheState = getCacheState();\n const entries = await getTagEntries(\n tag,\n cacheState.renderEnvironmentHash,\n cacheState.tagIndexHash,\n );\n if (entries.length === 0) notFound();\n return <TagsList entries={entries} tag={tag} />;\n}\n\nasync function getTagEntries(\n tag: string,\n renderEnvironmentHash: string,\n tagIndexHash: string,\n) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(`environment:${renderEnvironmentHash}`, `tags:${tagIndexHash}`);\n return getEntriesForTag(tag);\n}\n\nfunction routeTagToString(tag: string | string[]): string {\n return Array.isArray(tag) ? tag.join(\"/\") : tag;\n}\n"],"mappings":"AAoCS;AApCT,SAAS,WAAW,gBAAgB;AACpC,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,yBAAyB;AAM/B,eAAsB,uBAAuB;AAC3C,QAAM,SAAS,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,MAAM,GAAG,EAAE,EAAE;AACnE,SAAO,OAAO,SAAS,IAAI,SAAS,CAAC,EAAE,KAAK,CAAC,sBAAsB,EAAE,CAAC;AACxE;AAEA,eAAsB,iBAAiB,EAAE,OAAO,GAAkB;AAChE,QAAM,MAAM,kBAAkB,MAAM,QAAQ,GAAG;AAC/C,SAAO;AAAA,IACL,OAAO,IAAI,GAAG;AAAA,EAChB;AACF;AAEA,eAAO,SAAgC,EAAE,OAAO,GAAkB;AAChE,QAAM,MAAM,kBAAkB,MAAM,QAAQ,GAAG;AAC/C,QAAM,aAAa,cAAc;AACjC,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AACA,MAAI,QAAQ,WAAW,EAAG,UAAS;AACnC,SAAO,oBAAC,YAAS,SAAkB,KAAU;AAC/C;AAEA,eAAe,cACb,KACA,uBACA,cACA;AACA;AACA,YAAU,KAAK;AACf,WAAS,eAAe,qBAAqB,IAAI,QAAQ,YAAY,EAAE;AACvE,SAAO,iBAAiB,GAAG;AAC7B;AAEA,SAAS,iBAAiB,KAAgC;AACxD,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI;AAC9C;","names":[]}
|
package/dist/server-data.d.ts
CHANGED
|
@@ -1,12 +1,54 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { LoadedSearchIndex } from '@silicajs/search';
|
|
3
|
+
import { ResolvedSilicaConfig, RenderCacheState, ManifestEntry, Navigation } from '@silicajs/core/runtime';
|
|
2
4
|
|
|
5
|
+
type LoadedVaultDb = {
|
|
6
|
+
databasePath: string;
|
|
7
|
+
generatedAt: string;
|
|
8
|
+
renderEnvironmentHash: string;
|
|
9
|
+
config: ResolvedSilicaConfig;
|
|
10
|
+
cacheState: RenderCacheState;
|
|
11
|
+
mtimeMs: number;
|
|
12
|
+
db: Database.Database;
|
|
13
|
+
close(): void;
|
|
14
|
+
};
|
|
15
|
+
type VaultPageData = {
|
|
16
|
+
cacheState: RenderCacheState;
|
|
17
|
+
config: ResolvedSilicaConfig;
|
|
18
|
+
entry: ManifestEntry;
|
|
19
|
+
};
|
|
20
|
+
type BacklinkRow = {
|
|
21
|
+
slug: string;
|
|
22
|
+
title: string;
|
|
23
|
+
};
|
|
3
24
|
declare function getProjectRoot(): string;
|
|
4
25
|
declare function getSilicaRoot(): string;
|
|
5
|
-
declare function
|
|
6
|
-
declare function
|
|
7
|
-
declare function
|
|
8
|
-
declare function
|
|
9
|
-
declare function
|
|
26
|
+
declare function getVaultDatabasePath(): string;
|
|
27
|
+
declare function loadVaultDb(): LoadedVaultDb;
|
|
28
|
+
declare function getPage(slug: string): ManifestEntry | undefined;
|
|
29
|
+
declare function getPageRuntimeData(slug: string): VaultPageData | undefined;
|
|
30
|
+
declare function getRenderKey(slug: string): {
|
|
31
|
+
renderHash: string;
|
|
32
|
+
renderEnvironmentHash: string;
|
|
33
|
+
};
|
|
34
|
+
declare function loadRenderEnvironmentHash(): string;
|
|
35
|
+
declare function getPrerenderSlugs(): string[];
|
|
36
|
+
declare function getAllSlugs(): string[];
|
|
37
|
+
declare function getNavigation(): Navigation;
|
|
38
|
+
declare function getBacklinks(slug: string): BacklinkRow[];
|
|
39
|
+
declare function getConfig(): ResolvedSilicaConfig;
|
|
40
|
+
declare function getCacheState(): RenderCacheState;
|
|
41
|
+
declare function getTagSlugs(): string[];
|
|
42
|
+
declare function getEntriesForTag(tag: string): ManifestEntry[];
|
|
43
|
+
declare function getRelatedTagsForEntries(slugs: string[], tag: string): string[];
|
|
44
|
+
declare function resolveWikiLinkFromDb(currentSlug: string, target: string, strategy: "absolute" | "relative" | "shortest", ordering?: {
|
|
45
|
+
numericPrefixes?: boolean;
|
|
46
|
+
}): string | undefined;
|
|
47
|
+
declare function getBreadcrumbs(slug: string): {
|
|
48
|
+
label: string;
|
|
49
|
+
href?: string;
|
|
50
|
+
}[];
|
|
51
|
+
declare function loadSearchIndex(): LoadedSearchIndex;
|
|
10
52
|
declare function normalizeRouteSlug(slug?: string[]): string;
|
|
11
53
|
|
|
12
|
-
export { getProjectRoot, getSilicaRoot,
|
|
54
|
+
export { type LoadedVaultDb, type VaultPageData, getAllSlugs, getBacklinks, getBreadcrumbs, getCacheState, getConfig, getEntriesForTag, getNavigation, getPage, getPageRuntimeData, getPrerenderSlugs, getProjectRoot, getRelatedTagsForEntries, getRenderKey, getSilicaRoot, getTagSlugs, getVaultDatabasePath, loadRenderEnvironmentHash, loadSearchIndex, loadVaultDb, normalizeRouteSlug, resolveWikiLinkFromDb };
|
package/dist/server-data.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import fs from "fs
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import Database from "better-sqlite3";
|
|
4
|
+
import {
|
|
5
|
+
asFullSlug,
|
|
6
|
+
normalizeSlug,
|
|
7
|
+
resolveRelative,
|
|
8
|
+
slugToHref
|
|
9
|
+
} from "@silicajs/core/runtime";
|
|
10
|
+
const VAULT_DATABASE_FILENAME = "vault.db";
|
|
11
|
+
let loadedVaultDb;
|
|
3
12
|
function getProjectRoot() {
|
|
4
13
|
const projectRoot = process.env.SILICA_PROJECT_ROOT;
|
|
5
14
|
if (!projectRoot) {
|
|
@@ -10,50 +19,270 @@ function getProjectRoot() {
|
|
|
10
19
|
function getSilicaRoot() {
|
|
11
20
|
return path.join(getProjectRoot(), ".silica");
|
|
12
21
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
function getVaultDatabasePath() {
|
|
23
|
+
return path.join(getSilicaRoot(), VAULT_DATABASE_FILENAME);
|
|
24
|
+
}
|
|
25
|
+
function loadVaultDb() {
|
|
26
|
+
const databasePath = getVaultDatabasePath();
|
|
27
|
+
const stat = fs.statSync(databasePath);
|
|
28
|
+
if (loadedVaultDb?.databasePath === databasePath && loadedVaultDb.mtimeMs === stat.mtimeMs) {
|
|
29
|
+
return loadedVaultDb;
|
|
30
|
+
}
|
|
31
|
+
loadedVaultDb?.close();
|
|
32
|
+
const db = new Database(databasePath, {
|
|
33
|
+
fileMustExist: true,
|
|
34
|
+
readonly: true
|
|
35
|
+
});
|
|
36
|
+
db.pragma("query_only = ON");
|
|
37
|
+
const metadata = readMetadata(db);
|
|
38
|
+
loadedVaultDb = {
|
|
39
|
+
databasePath,
|
|
40
|
+
generatedAt: metadata.generatedAt,
|
|
41
|
+
renderEnvironmentHash: metadata.renderEnvironmentHash,
|
|
42
|
+
config: metadata.config,
|
|
43
|
+
cacheState: metadata.cacheState,
|
|
44
|
+
mtimeMs: stat.mtimeMs,
|
|
45
|
+
db,
|
|
46
|
+
close: () => {
|
|
47
|
+
db.close();
|
|
48
|
+
if (loadedVaultDb?.db === db) loadedVaultDb = void 0;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return loadedVaultDb;
|
|
52
|
+
}
|
|
53
|
+
function getPage(slug) {
|
|
54
|
+
const row = loadVaultDb().db.prepare("SELECT * FROM notes WHERE slug = ?").get(slug);
|
|
55
|
+
return row ? noteRowToEntry(row) : void 0;
|
|
56
|
+
}
|
|
57
|
+
function getPageRuntimeData(slug) {
|
|
58
|
+
const entry = getPage(slug);
|
|
59
|
+
if (!entry) return void 0;
|
|
21
60
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
bySlug: manifest.bySlug ?? Object.fromEntries(entries.map((entry) => [entry.slug, entry]))
|
|
61
|
+
entry,
|
|
62
|
+
config: getConfig(),
|
|
63
|
+
cacheState: getCacheState()
|
|
26
64
|
};
|
|
27
65
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
66
|
+
function getRenderKey(slug) {
|
|
67
|
+
const loaded = loadVaultDb();
|
|
68
|
+
const row = loaded.db.prepare("SELECT render_hash FROM notes WHERE slug = ?").get(slug);
|
|
69
|
+
return {
|
|
70
|
+
renderHash: row?.render_hash ?? "missing",
|
|
71
|
+
renderEnvironmentHash: loaded.renderEnvironmentHash
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function loadRenderEnvironmentHash() {
|
|
75
|
+
return loadVaultDb().renderEnvironmentHash;
|
|
32
76
|
}
|
|
33
|
-
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
);
|
|
77
|
+
function getPrerenderSlugs() {
|
|
78
|
+
return loadVaultDb().db.prepare(
|
|
79
|
+
"SELECT slug FROM notes WHERE prerender = 1 ORDER BY COALESCE(sort_key, slug), slug"
|
|
80
|
+
).all().map((row) => row.slug);
|
|
37
81
|
}
|
|
38
|
-
|
|
39
|
-
return (
|
|
82
|
+
function getAllSlugs() {
|
|
83
|
+
return loadVaultDb().db.prepare("SELECT slug FROM notes ORDER BY slug").all().map((row) => row.slug);
|
|
40
84
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
85
|
+
function getNavigation() {
|
|
86
|
+
const entries = loadVaultDb().db.prepare(
|
|
87
|
+
`
|
|
88
|
+
SELECT slug, menu_label AS title, sort_key
|
|
89
|
+
FROM notes
|
|
90
|
+
WHERE listed = 1
|
|
91
|
+
ORDER BY COALESCE(sort_key, slug), slug
|
|
92
|
+
`
|
|
93
|
+
).all();
|
|
94
|
+
return {
|
|
95
|
+
version: 1,
|
|
96
|
+
entries: entries.map((entry) => ({
|
|
97
|
+
slug: entry.slug,
|
|
98
|
+
title: entry.title,
|
|
99
|
+
sortKey: entry.sort_key ?? void 0
|
|
100
|
+
}))
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function getBacklinks(slug) {
|
|
104
|
+
return loadVaultDb().db.prepare(
|
|
105
|
+
`
|
|
106
|
+
SELECT n.slug, n.title
|
|
107
|
+
FROM links l
|
|
108
|
+
JOIN notes n ON n.slug = l.source_slug
|
|
109
|
+
WHERE l.target_slug = ?
|
|
110
|
+
AND l.kind = 'link'
|
|
111
|
+
ORDER BY n.title COLLATE NOCASE ASC, n.slug
|
|
112
|
+
`
|
|
113
|
+
).all(slug);
|
|
114
|
+
}
|
|
115
|
+
function getConfig() {
|
|
116
|
+
return loadVaultDb().config;
|
|
117
|
+
}
|
|
118
|
+
function getCacheState() {
|
|
119
|
+
return loadVaultDb().cacheState;
|
|
120
|
+
}
|
|
121
|
+
function getTagSlugs() {
|
|
122
|
+
return loadVaultDb().db.prepare("SELECT DISTINCT tag FROM note_tags ORDER BY tag").all().map((row) => row.tag);
|
|
123
|
+
}
|
|
124
|
+
function getEntriesForTag(tag) {
|
|
125
|
+
return loadVaultDb().db.prepare(
|
|
126
|
+
`
|
|
127
|
+
SELECT n.*
|
|
128
|
+
FROM notes n
|
|
129
|
+
WHERE n.listed = 1
|
|
130
|
+
AND EXISTS (
|
|
131
|
+
SELECT 1
|
|
132
|
+
FROM note_tags nt
|
|
133
|
+
WHERE nt.slug = n.slug
|
|
134
|
+
AND nt.tag = ?
|
|
135
|
+
)
|
|
136
|
+
ORDER BY n.title COLLATE NOCASE ASC, n.slug
|
|
137
|
+
`
|
|
138
|
+
).all(tag).map((row) => noteRowToEntry(row));
|
|
139
|
+
}
|
|
140
|
+
function getRelatedTagsForEntries(slugs, tag) {
|
|
141
|
+
if (slugs.length === 0) return [];
|
|
142
|
+
return loadVaultDb().db.prepare(
|
|
143
|
+
`
|
|
144
|
+
SELECT nt.tag, COUNT(*) AS count
|
|
145
|
+
FROM note_tags nt
|
|
146
|
+
WHERE nt.slug IN (${slugs.map(() => "?").join(", ")})
|
|
147
|
+
AND nt.tag != ?
|
|
148
|
+
GROUP BY nt.tag
|
|
149
|
+
ORDER BY count DESC, nt.tag ASC
|
|
150
|
+
LIMIT 12
|
|
151
|
+
`
|
|
152
|
+
).all(...slugs, tag).map((row) => row.tag);
|
|
153
|
+
}
|
|
154
|
+
function resolveWikiLinkFromDb(currentSlug, target, strategy, ordering) {
|
|
155
|
+
const [rawPath] = target.split("#");
|
|
156
|
+
const slugOptions = ordering ?? getConfig().ordering;
|
|
157
|
+
const normalizedTarget = normalizeSlug(rawPath ?? target, slugOptions);
|
|
158
|
+
const db = loadVaultDb().db;
|
|
159
|
+
if (strategy === "absolute") {
|
|
160
|
+
return lookupAlias(db, "absolute", normalizedTarget);
|
|
161
|
+
}
|
|
162
|
+
if (strategy === "relative") {
|
|
163
|
+
const relative = resolveRelative(
|
|
164
|
+
asFullSlug(currentSlug),
|
|
165
|
+
normalizedTarget,
|
|
166
|
+
slugOptions
|
|
167
|
+
);
|
|
168
|
+
const resolved = lookupAlias(db, "absolute", relative);
|
|
169
|
+
if (resolved) return resolved;
|
|
170
|
+
}
|
|
171
|
+
return lookupAlias(db, "absolute", normalizedTarget) ?? lookupAlias(db, "absolute", `${normalizedTarget}/index`) ?? lookupAlias(db, "shortest", normalizedTarget.split("/").at(-1) ?? "");
|
|
172
|
+
}
|
|
173
|
+
function getBreadcrumbs(slug) {
|
|
174
|
+
if (slug === "index" || !slug.includes("/")) return [];
|
|
175
|
+
const breadcrumbs = [
|
|
176
|
+
{ label: "Home", href: "/" }
|
|
177
|
+
];
|
|
178
|
+
const segments = slug.split("/").slice(0, -1);
|
|
179
|
+
let acc = "";
|
|
180
|
+
for (const segment of segments) {
|
|
181
|
+
acc = acc ? `${acc}/${segment}` : segment;
|
|
182
|
+
breadcrumbs.push({
|
|
183
|
+
label: prettySegment(segment),
|
|
184
|
+
href: breadcrumbSegmentHref(acc)
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return breadcrumbs;
|
|
188
|
+
}
|
|
189
|
+
function loadSearchIndex() {
|
|
190
|
+
const loaded = loadVaultDb();
|
|
191
|
+
return {
|
|
192
|
+
databasePath: loaded.databasePath,
|
|
193
|
+
db: loaded.db,
|
|
194
|
+
close: () => void 0
|
|
195
|
+
};
|
|
45
196
|
}
|
|
46
197
|
function normalizeRouteSlug(slug) {
|
|
47
198
|
return slug?.length ? slug.join("/") : "index";
|
|
48
199
|
}
|
|
200
|
+
function readMetadata(db) {
|
|
201
|
+
const rows = db.prepare("SELECT key, value FROM vault_metadata").all();
|
|
202
|
+
const metadata = Object.fromEntries(rows.map((row) => [row.key, row.value]));
|
|
203
|
+
return {
|
|
204
|
+
generatedAt: metadata.generatedAt ?? "",
|
|
205
|
+
renderEnvironmentHash: metadata.renderEnvironmentHash ?? "silica",
|
|
206
|
+
config: parseConfigMetadata(metadata.configJson),
|
|
207
|
+
cacheState: JSON.parse(metadata.cacheStateJson ?? "{}")
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function parseConfigMetadata(value) {
|
|
211
|
+
if (!value) throw new Error("vault.db is missing configJson metadata.");
|
|
212
|
+
return JSON.parse(value);
|
|
213
|
+
}
|
|
214
|
+
function lookupAlias(db, strategy, alias) {
|
|
215
|
+
const row = db.prepare(
|
|
216
|
+
`
|
|
217
|
+
SELECT slug
|
|
218
|
+
FROM slug_aliases
|
|
219
|
+
WHERE strategy_key = ?
|
|
220
|
+
AND alias = ?
|
|
221
|
+
ORDER BY sort_key, slug
|
|
222
|
+
LIMIT 2
|
|
223
|
+
`
|
|
224
|
+
).all(strategy, alias);
|
|
225
|
+
return row.length === 1 ? row[0]?.slug : void 0;
|
|
226
|
+
}
|
|
227
|
+
function noteRowToEntry(row) {
|
|
228
|
+
return {
|
|
229
|
+
slug: row.slug,
|
|
230
|
+
title: row.title,
|
|
231
|
+
menuLabel: row.menu_label,
|
|
232
|
+
description: row.description ?? void 0,
|
|
233
|
+
generatedDescription: row.generated_description ?? void 0,
|
|
234
|
+
tags: parseJsonArray(row.tags_json),
|
|
235
|
+
file: path.isAbsolute(row.file) ? row.file : path.join(getProjectRoot(), row.file),
|
|
236
|
+
relativeFile: row.relative_file,
|
|
237
|
+
sortKey: row.sort_key ?? void 0,
|
|
238
|
+
created: row.created ?? void 0,
|
|
239
|
+
modified: row.modified ?? void 0,
|
|
240
|
+
frontmatter: parseObject(row.frontmatter_json),
|
|
241
|
+
contentHash: row.content_hash,
|
|
242
|
+
embeds: getEmbeds(row.slug)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function getEmbeds(slug) {
|
|
246
|
+
return loadVaultDb().db.prepare(
|
|
247
|
+
"SELECT target_slug FROM links WHERE source_slug = ? AND kind = 'embed' ORDER BY target_slug"
|
|
248
|
+
).all(slug).map((row) => row.target_slug);
|
|
249
|
+
}
|
|
250
|
+
function breadcrumbSegmentHref(segmentPath) {
|
|
251
|
+
if (getPage(segmentPath)) return slugToHref(segmentPath);
|
|
252
|
+
const indexSlug = `${segmentPath}/index`;
|
|
253
|
+
if (getPage(indexSlug)) return slugToHref(indexSlug);
|
|
254
|
+
return void 0;
|
|
255
|
+
}
|
|
256
|
+
function prettySegment(segment) {
|
|
257
|
+
return segment.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
258
|
+
}
|
|
259
|
+
function parseObject(value) {
|
|
260
|
+
return JSON.parse(value);
|
|
261
|
+
}
|
|
262
|
+
function parseJsonArray(value) {
|
|
263
|
+
return JSON.parse(value);
|
|
264
|
+
}
|
|
49
265
|
export {
|
|
266
|
+
getAllSlugs,
|
|
267
|
+
getBacklinks,
|
|
268
|
+
getBreadcrumbs,
|
|
269
|
+
getCacheState,
|
|
270
|
+
getConfig,
|
|
271
|
+
getEntriesForTag,
|
|
272
|
+
getNavigation,
|
|
273
|
+
getPage,
|
|
274
|
+
getPageRuntimeData,
|
|
275
|
+
getPrerenderSlugs,
|
|
50
276
|
getProjectRoot,
|
|
277
|
+
getRelatedTagsForEntries,
|
|
278
|
+
getRenderKey,
|
|
51
279
|
getSilicaRoot,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
normalizeRouteSlug
|
|
280
|
+
getTagSlugs,
|
|
281
|
+
getVaultDatabasePath,
|
|
282
|
+
loadRenderEnvironmentHash,
|
|
283
|
+
loadSearchIndex,
|
|
284
|
+
loadVaultDb,
|
|
285
|
+
normalizeRouteSlug,
|
|
286
|
+
resolveWikiLinkFromDb
|
|
58
287
|
};
|
|
59
288
|
//# sourceMappingURL=server-data.js.map
|
package/dist/server-data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server-data.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"fs-extra\";\nimport type {\n Graph,\n Manifest,\n Navigation,\n ResolvedSilicaConfig,\n} from \"@silicajs/core/runtime\";\n\nexport function getProjectRoot(): string {\n const projectRoot = process.env.SILICA_PROJECT_ROOT;\n if (!projectRoot) {\n throw new Error(\"SILICA_PROJECT_ROOT must be set by the Silica CLI.\");\n }\n\n return projectRoot;\n}\n\nexport function getSilicaRoot(): string {\n return path.join(getProjectRoot(), \".silica\");\n}\n\nexport async function loadManifest(): Promise<Manifest> {\n const manifest = (await fs.readJson(\n path.join(getSilicaRoot(), \"manifest.json\"),\n )) as Omit<Manifest, \"allSlugs\" | \"bySlug\"> &\n Partial<Pick<Manifest, \"allSlugs\" | \"bySlug\">>;\n const entries = manifest.entries.map((entry) => ({\n ...entry,\n file: path.isAbsolute(entry.file)\n ? entry.file\n : path.join(getProjectRoot(), entry.file),\n }));\n return {\n ...manifest,\n entries,\n allSlugs: manifest.allSlugs ?? entries.map((entry) => entry.slug),\n bySlug:\n manifest.bySlug ??\n Object.fromEntries(entries.map((entry) => [entry.slug, entry])),\n };\n}\n\nexport async function loadGraph(): Promise<Graph> {\n return fs.readJson(\n path.join(getSilicaRoot(), \"graph.json\"),\n ) as Promise<Graph>;\n}\n\nexport async function loadNavigation(): Promise<Navigation> {\n return fs.readJson(\n path.join(getSilicaRoot(), \"navigation.json\"),\n ) as Promise<Navigation>;\n}\n\nexport async function loadBuildId(): Promise<string> {\n return (\n await fs.readFile(path.join(getSilicaRoot(), \"build-id.txt\"), \"utf8\")\n ).trim();\n}\n\nexport async function loadResolvedConfig() {\n return fs.readJson(\n path.join(getSilicaRoot(), \"config.json\"),\n ) as Promise<ResolvedSilicaConfig>;\n}\n\nexport function normalizeRouteSlug(slug?: string[]): string {\n return slug?.length ? slug.join(\"/\") : \"index\";\n}\n"],"mappings":"AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AAQR,SAAS,iBAAyB;AACvC,QAAM,cAAc,QAAQ,IAAI;AAChC,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AAEA,SAAO;AACT;AAEO,SAAS,gBAAwB;AACtC,SAAO,KAAK,KAAK,eAAe,GAAG,SAAS;AAC9C;AAEA,eAAsB,eAAkC;AACtD,QAAM,WAAY,MAAM,GAAG;AAAA,IACzB,KAAK,KAAK,cAAc,GAAG,eAAe;AAAA,EAC5C;AAEA,QAAM,UAAU,SAAS,QAAQ,IAAI,CAAC,WAAW;AAAA,IAC/C,GAAG;AAAA,IACH,MAAM,KAAK,WAAW,MAAM,IAAI,IAC5B,MAAM,OACN,KAAK,KAAK,eAAe,GAAG,MAAM,IAAI;AAAA,EAC5C,EAAE;AACF,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,UAAU,SAAS,YAAY,QAAQ,IAAI,CAAC,UAAU,MAAM,IAAI;AAAA,IAChE,QACE,SAAS,UACT,OAAO,YAAY,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;AAAA,EAClE;AACF;AAEA,eAAsB,YAA4B;AAChD,SAAO,GAAG;AAAA,IACR,KAAK,KAAK,cAAc,GAAG,YAAY;AAAA,EACzC;AACF;AAEA,eAAsB,iBAAsC;AAC1D,SAAO,GAAG;AAAA,IACR,KAAK,KAAK,cAAc,GAAG,iBAAiB;AAAA,EAC9C;AACF;AAEA,eAAsB,cAA+B;AACnD,UACE,MAAM,GAAG,SAAS,KAAK,KAAK,cAAc,GAAG,cAAc,GAAG,MAAM,GACpE,KAAK;AACT;AAEA,eAAsB,qBAAqB;AACzC,SAAO,GAAG;AAAA,IACR,KAAK,KAAK,cAAc,GAAG,aAAa;AAAA,EAC1C;AACF;AAEO,SAAS,mBAAmB,MAAyB;AAC1D,SAAO,MAAM,SAAS,KAAK,KAAK,GAAG,IAAI;AACzC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/server-data.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"node:fs\";\nimport Database from \"better-sqlite3\";\nimport type { LoadedSearchIndex } from \"@silicajs/search\";\nimport type {\n Navigation,\n ManifestEntry,\n RenderCacheState,\n ResolvedSilicaConfig,\n} from \"@silicajs/core/runtime\";\nimport {\n asFullSlug,\n normalizeSlug,\n resolveRelative,\n slugToHref,\n} from \"@silicajs/core/runtime\";\n\nconst VAULT_DATABASE_FILENAME = \"vault.db\";\n\nexport type LoadedVaultDb = {\n databasePath: string;\n generatedAt: string;\n renderEnvironmentHash: string;\n config: ResolvedSilicaConfig;\n cacheState: RenderCacheState;\n mtimeMs: number;\n db: Database.Database;\n close(): void;\n};\n\nexport type VaultPageData = {\n cacheState: RenderCacheState;\n config: ResolvedSilicaConfig;\n entry: ManifestEntry;\n};\n\ntype MetadataRows = {\n generatedAt: string;\n renderEnvironmentHash: string;\n config: ResolvedSilicaConfig;\n cacheState: RenderCacheState;\n};\n\ntype NoteRow = {\n slug: string;\n file: string;\n relative_file: string;\n title: string;\n menu_label: string;\n description: string | null;\n generated_description: string | null;\n frontmatter_json: string;\n tags_json: string;\n created: string | null;\n modified: string | null;\n sort_key: string | null;\n listed: 0 | 1;\n content_hash: string;\n render_hash: string;\n prerender: 0 | 1;\n};\n\ntype NavigationRow = {\n slug: string;\n title: string;\n sort_key: string | null;\n};\n\ntype BacklinkRow = {\n slug: string;\n title: string;\n};\n\nlet loadedVaultDb: LoadedVaultDb | undefined;\n\nexport function getProjectRoot(): string {\n const projectRoot = process.env.SILICA_PROJECT_ROOT;\n if (!projectRoot) {\n throw new Error(\"SILICA_PROJECT_ROOT must be set by the Silica CLI.\");\n }\n\n return projectRoot;\n}\n\nexport function getSilicaRoot(): string {\n return path.join(getProjectRoot(), \".silica\");\n}\n\nexport function getVaultDatabasePath(): string {\n return path.join(getSilicaRoot(), VAULT_DATABASE_FILENAME);\n}\n\nexport function loadVaultDb(): LoadedVaultDb {\n const databasePath = getVaultDatabasePath();\n const stat = fs.statSync(databasePath);\n if (\n loadedVaultDb?.databasePath === databasePath &&\n loadedVaultDb.mtimeMs === stat.mtimeMs\n ) {\n return loadedVaultDb;\n }\n\n loadedVaultDb?.close();\n\n const db = new Database(databasePath, {\n fileMustExist: true,\n readonly: true,\n });\n db.pragma(\"query_only = ON\");\n const metadata = readMetadata(db);\n loadedVaultDb = {\n databasePath,\n generatedAt: metadata.generatedAt,\n renderEnvironmentHash: metadata.renderEnvironmentHash,\n config: metadata.config,\n cacheState: metadata.cacheState,\n mtimeMs: stat.mtimeMs,\n db,\n close: () => {\n db.close();\n if (loadedVaultDb?.db === db) loadedVaultDb = undefined;\n },\n };\n return loadedVaultDb;\n}\n\nexport function getPage(slug: string): ManifestEntry | undefined {\n const row = loadVaultDb()\n .db.prepare(\"SELECT * FROM notes WHERE slug = ?\")\n .get(slug) as NoteRow | undefined;\n return row ? noteRowToEntry(row) : undefined;\n}\n\nexport function getPageRuntimeData(slug: string): VaultPageData | undefined {\n const entry = getPage(slug);\n if (!entry) return undefined;\n return {\n entry,\n config: getConfig(),\n cacheState: getCacheState(),\n };\n}\n\nexport function getRenderKey(slug: string): {\n renderHash: string;\n renderEnvironmentHash: string;\n} {\n const loaded = loadVaultDb();\n const row = loaded.db\n .prepare(\"SELECT render_hash FROM notes WHERE slug = ?\")\n .get(slug) as { render_hash: string } | undefined;\n return {\n renderHash: row?.render_hash ?? \"missing\",\n renderEnvironmentHash: loaded.renderEnvironmentHash,\n };\n}\n\nexport function loadRenderEnvironmentHash(): string {\n return loadVaultDb().renderEnvironmentHash;\n}\n\nexport function getPrerenderSlugs(): string[] {\n return loadVaultDb()\n .db.prepare(\n \"SELECT slug FROM notes WHERE prerender = 1 ORDER BY COALESCE(sort_key, slug), slug\",\n )\n .all()\n .map((row) => (row as { slug: string }).slug);\n}\n\nexport function getAllSlugs(): string[] {\n return loadVaultDb()\n .db.prepare(\"SELECT slug FROM notes ORDER BY slug\")\n .all()\n .map((row) => (row as { slug: string }).slug);\n}\n\nexport function getNavigation(): Navigation {\n const entries = loadVaultDb()\n .db.prepare(\n `\n SELECT slug, menu_label AS title, sort_key\n FROM notes\n WHERE listed = 1\n ORDER BY COALESCE(sort_key, slug), slug\n `,\n )\n .all() as NavigationRow[];\n return {\n version: 1,\n entries: entries.map((entry) => ({\n slug: entry.slug,\n title: entry.title,\n sortKey: entry.sort_key ?? undefined,\n })),\n };\n}\n\nexport function getBacklinks(slug: string): BacklinkRow[] {\n return loadVaultDb()\n .db.prepare(\n `\n SELECT n.slug, n.title\n FROM links l\n JOIN notes n ON n.slug = l.source_slug\n WHERE l.target_slug = ?\n AND l.kind = 'link'\n ORDER BY n.title COLLATE NOCASE ASC, n.slug\n `,\n )\n .all(slug) as BacklinkRow[];\n}\n\nexport function getConfig(): ResolvedSilicaConfig {\n return loadVaultDb().config;\n}\n\nexport function getCacheState(): RenderCacheState {\n return loadVaultDb().cacheState;\n}\n\nexport function getTagSlugs(): string[] {\n return loadVaultDb()\n .db.prepare(\"SELECT DISTINCT tag FROM note_tags ORDER BY tag\")\n .all()\n .map((row) => (row as { tag: string }).tag);\n}\n\nexport function getEntriesForTag(tag: string): ManifestEntry[] {\n return loadVaultDb()\n .db.prepare(\n `\n SELECT n.*\n FROM notes n\n WHERE n.listed = 1\n AND EXISTS (\n SELECT 1\n FROM note_tags nt\n WHERE nt.slug = n.slug\n AND nt.tag = ?\n )\n ORDER BY n.title COLLATE NOCASE ASC, n.slug\n `,\n )\n .all(tag)\n .map((row) => noteRowToEntry(row as NoteRow));\n}\n\nexport function getRelatedTagsForEntries(\n slugs: string[],\n tag: string,\n): string[] {\n if (slugs.length === 0) return [];\n return loadVaultDb()\n .db.prepare(\n `\n SELECT nt.tag, COUNT(*) AS count\n FROM note_tags nt\n WHERE nt.slug IN (${slugs.map(() => \"?\").join(\", \")})\n AND nt.tag != ?\n GROUP BY nt.tag\n ORDER BY count DESC, nt.tag ASC\n LIMIT 12\n `,\n )\n .all(...slugs, tag)\n .map((row) => (row as { tag: string }).tag);\n}\n\nexport function resolveWikiLinkFromDb(\n currentSlug: string,\n target: string,\n strategy: \"absolute\" | \"relative\" | \"shortest\",\n ordering?: { numericPrefixes?: boolean },\n): string | undefined {\n const [rawPath] = target.split(\"#\");\n const slugOptions = ordering ?? getConfig().ordering;\n const normalizedTarget = normalizeSlug(rawPath ?? target, slugOptions);\n const db = loadVaultDb().db;\n\n if (strategy === \"absolute\") {\n return lookupAlias(db, \"absolute\", normalizedTarget);\n }\n\n if (strategy === \"relative\") {\n const relative = resolveRelative(\n asFullSlug(currentSlug),\n normalizedTarget,\n slugOptions,\n );\n const resolved = lookupAlias(db, \"absolute\", relative);\n if (resolved) return resolved;\n }\n\n return (\n lookupAlias(db, \"absolute\", normalizedTarget) ??\n lookupAlias(db, \"absolute\", `${normalizedTarget}/index`) ??\n lookupAlias(db, \"shortest\", normalizedTarget.split(\"/\").at(-1) ?? \"\")\n );\n}\n\nexport function getBreadcrumbs(slug: string) {\n if (slug === \"index\" || !slug.includes(\"/\")) return [];\n\n const breadcrumbs: Array<{ label: string; href?: string }> = [\n { label: \"Home\", href: \"/\" },\n ];\n const segments = slug.split(\"/\").slice(0, -1);\n let acc = \"\";\n for (const segment of segments) {\n acc = acc ? `${acc}/${segment}` : segment;\n breadcrumbs.push({\n label: prettySegment(segment),\n href: breadcrumbSegmentHref(acc),\n });\n }\n return breadcrumbs;\n}\n\nexport function loadSearchIndex(): LoadedSearchIndex {\n const loaded = loadVaultDb();\n return {\n databasePath: loaded.databasePath,\n db: loaded.db,\n close: () => undefined,\n };\n}\n\nexport function normalizeRouteSlug(slug?: string[]): string {\n return slug?.length ? slug.join(\"/\") : \"index\";\n}\n\nfunction readMetadata(db: Database.Database): MetadataRows {\n const rows = db\n .prepare(\"SELECT key, value FROM vault_metadata\")\n .all() as Array<{ key: string; value: string }>;\n const metadata = Object.fromEntries(rows.map((row) => [row.key, row.value]));\n return {\n generatedAt: metadata.generatedAt ?? \"\",\n renderEnvironmentHash: metadata.renderEnvironmentHash ?? \"silica\",\n config: parseConfigMetadata(metadata.configJson),\n cacheState: JSON.parse(metadata.cacheStateJson ?? \"{}\") as RenderCacheState,\n };\n}\n\nfunction parseConfigMetadata(value: string | undefined): ResolvedSilicaConfig {\n if (!value) throw new Error(\"vault.db is missing configJson metadata.\");\n return JSON.parse(value) as ResolvedSilicaConfig;\n}\n\nfunction lookupAlias(\n db: Database.Database,\n strategy: string,\n alias: string,\n): string | undefined {\n const row = db\n .prepare(\n `\n SELECT slug\n FROM slug_aliases\n WHERE strategy_key = ?\n AND alias = ?\n ORDER BY sort_key, slug\n LIMIT 2\n `,\n )\n .all(strategy, alias) as Array<{ slug: string }>;\n return row.length === 1 ? row[0]?.slug : undefined;\n}\n\nfunction noteRowToEntry(row: NoteRow): ManifestEntry {\n return {\n slug: row.slug,\n title: row.title,\n menuLabel: row.menu_label,\n description: row.description ?? undefined,\n generatedDescription: row.generated_description ?? undefined,\n tags: parseJsonArray(row.tags_json),\n file: path.isAbsolute(row.file)\n ? row.file\n : path.join(getProjectRoot(), row.file),\n relativeFile: row.relative_file,\n sortKey: row.sort_key ?? undefined,\n created: row.created ?? undefined,\n modified: row.modified ?? undefined,\n frontmatter: parseObject(row.frontmatter_json),\n contentHash: row.content_hash,\n embeds: getEmbeds(row.slug),\n };\n}\n\nfunction getEmbeds(slug: string): string[] {\n return loadVaultDb()\n .db.prepare(\n \"SELECT target_slug FROM links WHERE source_slug = ? AND kind = 'embed' ORDER BY target_slug\",\n )\n .all(slug)\n .map((row) => (row as { target_slug: string }).target_slug);\n}\n\nfunction breadcrumbSegmentHref(segmentPath: string): string | undefined {\n if (getPage(segmentPath)) return slugToHref(segmentPath);\n const indexSlug = `${segmentPath}/index`;\n if (getPage(indexSlug)) return slugToHref(indexSlug);\n return undefined;\n}\n\nfunction prettySegment(segment: string): string {\n return segment\n .replace(/[-_]/g, \" \")\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction parseObject(value: string): Record<string, unknown> {\n return JSON.parse(value) as Record<string, unknown>;\n}\n\nfunction parseJsonArray(value: string): string[] {\n return JSON.parse(value) as string[];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import theme from "../../../silica-theme";
|
|
2
2
|
import { VaultContent } from "@silicajs/next/routes/page";
|
|
3
|
+
import { getRenderKey, normalizeRouteSlug } from "@silicajs/next/server-data";
|
|
3
4
|
export {
|
|
4
5
|
generateMetadata,
|
|
5
6
|
generateStaticParams,
|
|
@@ -11,8 +12,14 @@ export default async function Page({
|
|
|
11
12
|
params: Promise<{ slug?: string[] }> | { slug?: string[] };
|
|
12
13
|
}) {
|
|
13
14
|
const resolvedParams = await params;
|
|
14
|
-
const slug = resolvedParams?.slug
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const slug = normalizeRouteSlug(resolvedParams?.slug);
|
|
16
|
+
const renderKey = getRenderKey(slug);
|
|
17
|
+
return (
|
|
18
|
+
<VaultContent
|
|
19
|
+
slug={slug}
|
|
20
|
+
renderHash={renderKey.renderHash}
|
|
21
|
+
renderEnvironmentHash={renderKey.renderEnvironmentHash}
|
|
22
|
+
theme={theme}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
18
25
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@silicajs/next/cache-handlers/filesystem";
|