@silicajs/next 0.2.2 → 0.3.1

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.
@@ -5,12 +5,20 @@ import { notFound } from "next/navigation";
5
5
  import {
6
6
  getMetaDescription,
7
7
  renderMarkdown,
8
- renderMarkdownHtml,
9
- resolveWikiLink,
10
- slugToHref
8
+ renderMarkdownHtml
11
9
  } from "@silicajs/core/runtime";
12
10
  import { SilicaLink } from "@silicajs/components/routing";
13
- import { loadPageRuntimeData, normalizeRouteSlug } from "../server-data.js";
11
+ import {
12
+ getBacklinks,
13
+ getBreadcrumbs,
14
+ getPage,
15
+ getPageRuntimeData,
16
+ getPrerenderSlugs,
17
+ getRenderKey,
18
+ resolveAssetFromDb,
19
+ resolveWikiLinkFromDb,
20
+ normalizeRouteSlug
21
+ } from "../server-data.js";
14
22
  function MarkdownLink({
15
23
  href,
16
24
  ...props
@@ -21,42 +29,68 @@ function MarkdownLink({
21
29
  return /* @__PURE__ */ jsx("a", { href, ...props });
22
30
  }
23
31
  async function generateStaticParams() {
24
- const manifest = await getPageManifest();
25
- return manifest.entries.map((entry) => ({
26
- slug: entry.slug === "index" ? [] : entry.slug.split("/")
32
+ const prerenderSlugs = getPrerenderSlugs();
33
+ const slugs = prerenderSlugs.length ? prerenderSlugs : ["__silica_prerender_placeholder__"];
34
+ return slugs.map((slug) => ({
35
+ slug: slug === "index" ? [] : slug.split("/")
27
36
  }));
28
37
  }
29
38
  async function generateMetadata({ params }) {
30
39
  const resolvedParams = await params;
31
40
  const slug = normalizeRouteSlug(resolvedParams?.slug);
32
- const manifest = await getPageManifest();
33
- const entry = manifest.bySlug[slug];
41
+ const renderKey = getRenderKey(slug);
42
+ const entry = await getPageMetadata(
43
+ slug,
44
+ renderKey.renderHash,
45
+ renderKey.renderEnvironmentHash
46
+ );
34
47
  if (!entry) return {};
35
48
  return {
36
49
  title: entry.title,
37
50
  description: getMetaDescription(entry)
38
51
  };
39
52
  }
40
- async function getPageManifest() {
53
+ async function getPageMetadata(slug, renderHash, renderEnvironmentHash) {
41
54
  "use cache";
42
55
  cacheLife("max");
43
- const { buildId, manifest } = await loadPageRuntimeData();
44
- cacheTag("build", `build:${buildId}`);
45
- return manifest;
56
+ cacheTag(
57
+ `environment:${renderEnvironmentHash}`,
58
+ `page:${slug}`,
59
+ `render:${renderHash}`
60
+ );
61
+ return getPage(slug);
46
62
  }
47
63
  async function VaultContent({
48
64
  slug,
65
+ renderHash,
66
+ renderEnvironmentHash,
49
67
  theme
50
68
  }) {
51
69
  "use cache";
52
70
  cacheLife("max");
53
- const { buildId, manifest, graph, config, wikilinkIndex } = await loadPageRuntimeData();
54
- cacheTag("build", `build:${buildId}`, `page:${slug}`);
55
- const entry = manifest.bySlug[slug];
56
- if (!entry) notFound();
57
- const renderContext = (currentSlug, embedDepth = 0) => ({
71
+ const data = getPageRuntimeData(slug);
72
+ if (!data) notFound();
73
+ const { entry, config } = data;
74
+ cacheTag(
75
+ `environment:${renderEnvironmentHash}`,
76
+ `page:${slug}`,
77
+ `render:${renderHash}`
78
+ );
79
+ const renderContext = (currentSlug, currentSourcePath, embedDepth = 0) => ({
58
80
  slug: currentSlug,
59
- wikilinkIndex,
81
+ sourcePath: currentSourcePath,
82
+ resolveWikiLink: (_currentSlug, target) => resolveWikiLinkFromDb(
83
+ currentSlug,
84
+ target,
85
+ config.wikilinks.strategy,
86
+ config.ordering
87
+ ),
88
+ resolveAsset: (_currentSourcePath, target) => resolveAssetFromDb(
89
+ currentSourcePath,
90
+ target,
91
+ config.wikilinks.strategy,
92
+ config.ordering
93
+ ),
60
94
  assetBaseUrl: "/silica",
61
95
  wikilinkStrategy: config.wikilinks.strategy,
62
96
  tags: config.tags,
@@ -68,32 +102,34 @@ async function VaultContent({
68
102
  a: MarkdownLink
69
103
  },
70
104
  resolveEmbed: async (target) => {
71
- const resolved = resolveWikiLink(
105
+ const resolved = resolveWikiLinkFromDb(
72
106
  currentSlug,
73
107
  target.path || currentSlug,
74
- wikilinkIndex,
75
108
  config.wikilinks.strategy,
76
109
  config.ordering
77
110
  );
78
111
  if (!resolved || embedDepth >= 3) return;
79
- const embeddedEntry = manifest.bySlug[resolved];
112
+ const embeddedEntry = getPage(resolved);
80
113
  if (!embeddedEntry) return;
81
114
  const embeddedRaw = await fs.readFile(embeddedEntry.file, "utf8");
82
115
  const scopedRaw = scopeEmbedMarkdown(embeddedRaw, target);
83
116
  return renderMarkdownHtml(
84
117
  scopedRaw,
85
- renderContext(resolved, embedDepth + 1)
118
+ renderContext(resolved, embeddedEntry.sourcePath, embedDepth + 1)
86
119
  );
87
120
  }
88
121
  });
89
122
  const raw = await fs.readFile(entry.file, "utf8");
90
- const rendered = await renderMarkdown(raw, renderContext(slug));
123
+ const rendered = await renderMarkdown(
124
+ raw,
125
+ renderContext(slug, entry.sourcePath)
126
+ );
91
127
  return /* @__PURE__ */ jsx(
92
128
  theme.PageRenderer,
93
129
  {
94
130
  config,
95
- breadcrumbs: makeBreadcrumbs(slug, manifest),
96
- backlinks: makeBacklinks(slug, manifest, graph),
131
+ breadcrumbs: getBreadcrumbs(slug),
132
+ backlinks: getBacklinks(slug),
97
133
  page: {
98
134
  slug,
99
135
  title: entry.title,
@@ -107,35 +143,6 @@ async function VaultContent({
107
143
  }
108
144
  );
109
145
  }
110
- function makeBreadcrumbs(slug, manifest) {
111
- if (slug === "index" || !slug.includes("/")) return [];
112
- const breadcrumbs = [{ label: "Home", href: "/" }];
113
- const segments = slug.split("/").slice(0, -1);
114
- let acc = "";
115
- for (const segment of segments) {
116
- acc = acc ? `${acc}/${segment}` : segment;
117
- breadcrumbs.push({
118
- label: prettySegment(segment),
119
- href: breadcrumbSegmentHref(acc, manifest)
120
- });
121
- }
122
- return breadcrumbs;
123
- }
124
- function breadcrumbSegmentHref(segmentPath, manifest) {
125
- if (manifest.bySlug[segmentPath]) return slugToHref(segmentPath);
126
- const indexSlug = `${segmentPath}/index`;
127
- if (manifest.bySlug[indexSlug]) return slugToHref(indexSlug);
128
- return void 0;
129
- }
130
- function makeBacklinks(slug, manifest, graph) {
131
- return (graph.backlinks[slug] ?? []).map((source) => ({
132
- slug: source,
133
- title: manifest.bySlug[source]?.title ?? source
134
- }));
135
- }
136
- function prettySegment(segment) {
137
- return segment.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
138
- }
139
146
  function scopeEmbedMarkdown(raw, target) {
140
147
  if (target.blockId) return extractBlock(raw, target.blockId) ?? raw;
141
148
  if (target.heading) return extractHeadingSection(raw, target.heading) ?? raw;
@@ -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 Graph,\n type Manifest,\n type RenderContext,\n} from \"@silicajs/core/runtime\";\nimport { SilicaLink } from \"@silicajs/components/routing\";\nimport { loadPageRuntimeData, normalizeRouteSlug } 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, manifest } = await loadPageRuntimeData();\n cacheTag(\"build\", `build:${buildId}`);\n return manifest;\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, manifest, graph, config, wikilinkIndex } =\n await loadPageRuntimeData();\n cacheTag(\"build\", `build:${buildId}`, `page:${slug}`);\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 wikilinkIndex,\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 wikilinkIndex,\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(slug: string, manifest: Manifest): 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: Manifest,\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: Manifest,\n graph: Graph,\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 resolveAssetFromDb,\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 currentSourcePath: string,\n embedDepth = 0,\n ): RenderContext => ({\n slug: currentSlug,\n sourcePath: currentSourcePath,\n resolveWikiLink: (_currentSlug, target) =>\n resolveWikiLinkFromDb(\n currentSlug,\n target,\n config.wikilinks.strategy,\n config.ordering,\n ),\n resolveAsset: (_currentSourcePath, target) =>\n resolveAssetFromDb(\n currentSourcePath,\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, embeddedEntry.sourcePath, embedDepth + 1),\n );\n },\n });\n\n const raw = await fs.readFile(entry.file, \"utf8\");\n const rendered = await renderMarkdown(\n raw,\n renderContext(slug, entry.sourcePath),\n );\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":[]}
@@ -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 { loadBuildId, loadResolvedConfig } from "../server-data.js";
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
- const buildId = await loadBuildId();
25
- cacheTag("build", `build:${buildId}`);
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 { loadBuildId, loadResolvedConfig } 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 \"use cache\";\n cacheLife(\"max\");\n const buildId = await loadBuildId();\n cacheTag(\"build\", `build:${buildId}`);\n return loadResolvedConfig();\n}\n"],"mappings":"AAsBQ;AAtBR,SAAS,WAAW,gBAAgB;AACpC,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,gCAAgC;AACzC,SAAS,aAAa,0BAA0B;AAEhD,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;AACA,YAAU,KAAK;AACf,QAAM,UAAU,MAAM,YAAY;AAClC,WAAS,SAAS,SAAS,OAAO,EAAE;AACpC,SAAO,mBAAmB;AAC5B;","names":[]}
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":[]}
@@ -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 { getTagHierarchy, tagMatches } from "@silicajs/remark-obsidian";
6
- import { loadPageRuntimeData } from "../server-data.js";
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 manifest = await getTagsManifest();
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 manifest = await getTagsManifest();
25
- if (!manifest.entries.filter(isListedEntry).some((entry) => entry.tags.some((entryTag) => tagMatches(entryTag, tag)))) {
26
- notFound();
27
- }
28
- return /* @__PURE__ */ jsx(
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 getTagsManifest() {
32
+ async function getTagEntries(tag, renderEnvironmentHash, tagIndexHash) {
40
33
  "use cache";
41
34
  cacheLife("max");
42
- const { buildId, manifest } = await loadPageRuntimeData();
43
- cacheTag("build", `build:${buildId}`);
44
- return manifest;
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 { getTagHierarchy, tagMatches } from \"@silicajs/remark-obsidian\";\nimport { loadPageRuntimeData } 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 manifest = await getTagsManifest();\n const tags = new Set(\n manifest.entries\n .filter(isListedEntry)\n .flatMap((entry) => entry.tags.flatMap((tag) => getTagHierarchy(tag))),\n );\n const params = [...tags].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 manifest = await getTagsManifest();\n if (\n !manifest.entries\n .filter(isListedEntry)\n .some((entry) => entry.tags.some((entryTag) => tagMatches(entryTag, tag)))\n ) {\n notFound();\n }\n return (\n <TagsList\n manifest={{\n ...manifest,\n entries: manifest.entries.filter(isListedEntry),\n }}\n tag={tag}\n />\n );\n}\n\nasync function getTagsManifest() {\n \"use cache\";\n cacheLife(\"max\");\n const { buildId, manifest } = await loadPageRuntimeData();\n cacheTag(\"build\", `build:${buildId}`);\n return manifest;\n}\n\nfunction routeTagToString(tag: string | string[]): string {\n return Array.isArray(tag) ? tag.join(\"/\") : tag;\n}\n\nfunction isListedEntry(entry: { frontmatter: Record<string, unknown> }) {\n return entry.frontmatter.listed !== false;\n}\n"],"mappings":"AAyCI;AAzCJ,SAAS,WAAW,gBAAgB;AACpC,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB,kBAAkB;AAC5C,SAAS,2BAA2B;AAEpC,MAAM,yBAAyB;AAM/B,eAAsB,uBAAuB;AAC3C,QAAM,WAAW,MAAM,gBAAgB;AACvC,QAAM,OAAO,IAAI;AAAA,IACf,SAAS,QACN,OAAO,aAAa,EACpB,QAAQ,CAAC,UAAU,MAAM,KAAK,QAAQ,CAAC,QAAQ,gBAAgB,GAAG,CAAC,CAAC;AAAA,EACzE;AACA,QAAM,SAAS,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,MAAM,GAAG,EAAE,EAAE;AAC/D,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,WAAW,MAAM,gBAAgB;AACvC,MACE,CAAC,SAAS,QACP,OAAO,aAAa,EACpB,KAAK,CAAC,UAAU,MAAM,KAAK,KAAK,CAAC,aAAa,WAAW,UAAU,GAAG,CAAC,CAAC,GAC3E;AACA,aAAS;AAAA,EACX;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,QACR,GAAG;AAAA,QACH,SAAS,SAAS,QAAQ,OAAO,aAAa;AAAA,MAChD;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAEA,eAAe,kBAAkB;AAC/B;AACA,YAAU,KAAK;AACf,QAAM,EAAE,SAAS,SAAS,IAAI,MAAM,oBAAoB;AACxD,WAAS,SAAS,SAAS,OAAO,EAAE;AACpC,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAgC;AACxD,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI;AAC9C;AAEA,SAAS,cAAc,OAAiD;AACtE,SAAO,MAAM,YAAY,WAAW;AACtC;","names":[]}
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":[]}
@@ -1,20 +1,57 @@
1
- import { Graph, Manifest, Navigation, ResolvedSilicaConfig, WikiLinkResolutionIndex } from '@silicajs/core/runtime';
1
+ import Database from 'better-sqlite3';
2
+ import { LoadedSearchIndex } from '@silicajs/search';
3
+ import { ResolvedSilicaConfig, RenderCacheState, ManifestEntry, Navigation } from '@silicajs/core/runtime';
2
4
 
3
- type PageRuntimeData = {
4
- buildId: string;
5
- manifest: Manifest;
6
- graph: Graph;
5
+ type LoadedVaultDb = {
6
+ databasePath: string;
7
+ generatedAt: string;
8
+ renderEnvironmentHash: string;
7
9
  config: ResolvedSilicaConfig;
8
- wikilinkIndex: WikiLinkResolutionIndex;
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;
9
23
  };
10
24
  declare function getProjectRoot(): string;
11
25
  declare function getSilicaRoot(): string;
12
- declare function loadManifest(): Promise<Manifest>;
13
- declare function loadGraph(): Promise<Graph>;
14
- declare function loadNavigation(): Promise<Navigation>;
15
- declare function loadBuildId(): Promise<string>;
16
- declare function loadResolvedConfig(): Promise<ResolvedSilicaConfig>;
17
- declare function loadPageRuntimeData(): Promise<PageRuntimeData>;
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 resolveAssetFromDb(currentSourcePath: string, target: string, strategy: "absolute" | "relative" | "shortest", ordering?: {
48
+ numericPrefixes?: boolean;
49
+ }): string | undefined;
50
+ declare function getBreadcrumbs(slug: string): {
51
+ label: string;
52
+ href?: string;
53
+ }[];
54
+ declare function loadSearchIndex(): LoadedSearchIndex;
18
55
  declare function normalizeRouteSlug(slug?: string[]): string;
19
56
 
20
- export { type PageRuntimeData, getProjectRoot, getSilicaRoot, loadBuildId, loadGraph, loadManifest, loadNavigation, loadPageRuntimeData, loadResolvedConfig, normalizeRouteSlug };
57
+ 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, resolveAssetFromDb, resolveWikiLinkFromDb };