@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.
@@ -0,0 +1,33 @@
1
+ import { ReadableStream } from 'node:stream/web';
2
+
3
+ type CacheEntry = {
4
+ value: ReadableStream<Uint8Array>;
5
+ tags: string[];
6
+ stale: number;
7
+ timestamp: number;
8
+ expire: number;
9
+ revalidate: number;
10
+ };
11
+ type FilesystemCacheHandlerOptions = {
12
+ root?: string;
13
+ };
14
+ declare function createFilesystemCacheHandler(options?: FilesystemCacheHandlerOptions): {
15
+ get(cacheKey: string, softTags?: string[]): Promise<CacheEntry | undefined>;
16
+ set(cacheKey: string, pendingEntry: Promise<CacheEntry>): Promise<void>;
17
+ refreshTags(): Promise<void>;
18
+ getExpiration(tags: string[]): Promise<number>;
19
+ updateTags(tags: string[], durations?: {
20
+ expire?: number;
21
+ }): Promise<void>;
22
+ };
23
+ declare const _default: {
24
+ get(cacheKey: string, softTags?: string[]): Promise<CacheEntry | undefined>;
25
+ set(cacheKey: string, pendingEntry: Promise<CacheEntry>): Promise<void>;
26
+ refreshTags(): Promise<void>;
27
+ getExpiration(tags: string[]): Promise<number>;
28
+ updateTags(tags: string[], durations?: {
29
+ expire?: number;
30
+ }): Promise<void>;
31
+ };
32
+
33
+ export { type CacheEntry, type FilesystemCacheHandlerOptions, createFilesystemCacheHandler, _default as default };
@@ -0,0 +1,168 @@
1
+ import crypto from "node:crypto";
2
+ import path from "node:path";
3
+ import { ReadableStream } from "node:stream/web";
4
+ import Database from "better-sqlite3";
5
+ import fs from "fs-extra";
6
+ function createFilesystemCacheHandler(options = {}) {
7
+ const root = options.root ?? resolveCacheRoot();
8
+ const entriesRoot = path.join(root, "entries");
9
+ const tagsPath = path.join(root, "tags.json");
10
+ let tagState;
11
+ return {
12
+ async get(cacheKey, softTags = []) {
13
+ await ensureCacheRoot(entriesRoot);
14
+ await loadTagState();
15
+ const stored = await readStoredEntry(getEntryPath(entriesRoot, cacheKey));
16
+ if (!stored) return void 0;
17
+ const now = Date.now();
18
+ if (Number.isFinite(stored.expire) && stored.expire > 0 && stored.timestamp + stored.expire * 1e3 <= now) {
19
+ return void 0;
20
+ }
21
+ const expiration = getExpirationFromState([
22
+ ...stored.tags ?? [],
23
+ ...softTags
24
+ ]);
25
+ if (expiration > stored.timestamp) return void 0;
26
+ return {
27
+ ...stored,
28
+ value: streamFromBuffer(Buffer.from(stored.value, "base64"))
29
+ };
30
+ },
31
+ async set(cacheKey, pendingEntry) {
32
+ await ensureCacheRoot(entriesRoot);
33
+ const entry = await pendingEntry;
34
+ const [storedStream, returnedStream] = entry.value.tee();
35
+ entry.value = returnedStream;
36
+ const stored = {
37
+ ...entry,
38
+ value: (await bufferFromStream(storedStream)).toString("base64")
39
+ };
40
+ const destination = getEntryPath(entriesRoot, cacheKey);
41
+ await fs.ensureDir(path.dirname(destination));
42
+ await writeJsonAtomic(destination, stored);
43
+ },
44
+ async refreshTags() {
45
+ await loadTagState();
46
+ },
47
+ async getExpiration(tags) {
48
+ await loadTagState();
49
+ return getExpirationFromState(tags);
50
+ },
51
+ async updateTags(tags, durations) {
52
+ await ensureCacheRoot(entriesRoot);
53
+ await loadTagState();
54
+ const now = Date.now();
55
+ const uniqueTags = [...new Set(tags)];
56
+ tagState ??= { version: 1, tags: {} };
57
+ for (const tag of uniqueTags) {
58
+ tagState.tags[tag] = now;
59
+ }
60
+ await writeJsonAtomic(tagsPath, tagState);
61
+ if (durations?.expire === 0) {
62
+ await deleteEntriesWithTags(entriesRoot, uniqueTags);
63
+ }
64
+ }
65
+ };
66
+ async function loadTagState() {
67
+ tagState = await fs.readJson(tagsPath).catch(() => void 0) ?? {
68
+ version: 1,
69
+ tags: {}
70
+ };
71
+ }
72
+ function getExpirationFromState(tags) {
73
+ const state = tagState ?? { version: 1, tags: {} };
74
+ return Math.max(0, ...tags.map((tag) => state.tags[tag] ?? 0));
75
+ }
76
+ }
77
+ async function ensureCacheRoot(entriesRoot) {
78
+ await fs.ensureDir(entriesRoot);
79
+ }
80
+ function resolveCacheRoot() {
81
+ if (process.env.SILICA_CACHE_DIR) return process.env.SILICA_CACHE_DIR;
82
+ const projectRoot = process.env.SILICA_PROJECT_ROOT ?? process.cwd();
83
+ const config = readConfigFromVaultDb(projectRoot);
84
+ const configured = config?.render?.cache?.directory;
85
+ if (configured) {
86
+ return path.isAbsolute(configured) ? configured : path.join(projectRoot, configured);
87
+ }
88
+ return path.join(projectRoot, ".silica/cache/next");
89
+ }
90
+ function readConfigFromVaultDb(projectRoot) {
91
+ const databasePath = path.join(projectRoot, ".silica/vault.db");
92
+ if (!fs.existsSync(databasePath)) return;
93
+ const db = new Database(databasePath, {
94
+ fileMustExist: true,
95
+ readonly: true
96
+ });
97
+ try {
98
+ db.pragma("query_only = ON");
99
+ const row = db.prepare("SELECT value FROM vault_metadata WHERE key = 'configJson'").get();
100
+ return row ? JSON.parse(row.value) : void 0;
101
+ } finally {
102
+ db.close();
103
+ }
104
+ }
105
+ function getEntryPath(entriesRoot, cacheKey) {
106
+ const digest = crypto.createHash("sha256").update(cacheKey).digest("hex");
107
+ return path.join(entriesRoot, digest.slice(0, 2), `${digest}.json`);
108
+ }
109
+ async function readStoredEntry(filePath) {
110
+ try {
111
+ return await fs.readJson(filePath);
112
+ } catch {
113
+ return void 0;
114
+ }
115
+ }
116
+ async function writeJsonAtomic(filePath, value) {
117
+ const temporary = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;
118
+ await fs.ensureDir(path.dirname(filePath));
119
+ await fs.writeJson(temporary, value);
120
+ await fs.rename(temporary, filePath);
121
+ }
122
+ async function deleteEntriesWithTags(entriesRoot, tags) {
123
+ if (!await fs.pathExists(entriesRoot)) return;
124
+ const wanted = new Set(tags);
125
+ for (const filePath of await listJsonFiles(entriesRoot)) {
126
+ const entry = await readStoredEntry(filePath);
127
+ if (entry?.tags?.some((tag) => wanted.has(tag))) {
128
+ await fs.remove(filePath);
129
+ }
130
+ }
131
+ }
132
+ async function listJsonFiles(root) {
133
+ const entries = await fs.readdir(root, { withFileTypes: true });
134
+ const files = [];
135
+ for (const entry of entries) {
136
+ const absolutePath = path.join(root, entry.name);
137
+ if (entry.isDirectory()) {
138
+ files.push(...await listJsonFiles(absolutePath));
139
+ } else if (entry.isFile() && entry.name.endsWith(".json")) {
140
+ files.push(absolutePath);
141
+ }
142
+ }
143
+ return files;
144
+ }
145
+ async function bufferFromStream(stream) {
146
+ const reader = stream.getReader();
147
+ const chunks = [];
148
+ for (; ; ) {
149
+ const { done, value } = await reader.read();
150
+ if (done) break;
151
+ chunks.push(value);
152
+ }
153
+ return Buffer.concat(chunks);
154
+ }
155
+ function streamFromBuffer(buffer) {
156
+ return new ReadableStream({
157
+ start(controller) {
158
+ controller.enqueue(buffer);
159
+ controller.close();
160
+ }
161
+ });
162
+ }
163
+ var filesystem_default = createFilesystemCacheHandler();
164
+ export {
165
+ createFilesystemCacheHandler,
166
+ filesystem_default as default
167
+ };
168
+ //# sourceMappingURL=filesystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cache-handlers/filesystem.ts"],"sourcesContent":["import crypto from \"node:crypto\";\nimport path from \"node:path\";\nimport { ReadableStream } from \"node:stream/web\";\nimport Database from \"better-sqlite3\";\nimport fs from \"fs-extra\";\n\nexport type CacheEntry = {\n value: ReadableStream<Uint8Array>;\n tags: string[];\n stale: number;\n timestamp: number;\n expire: number;\n revalidate: number;\n};\n\ntype StoredCacheEntry = Omit<CacheEntry, \"value\"> & {\n value: string;\n};\n\ntype TagState = {\n version: 1;\n tags: Record<string, number>;\n};\n\nexport type FilesystemCacheHandlerOptions = {\n root?: string;\n};\n\nexport function createFilesystemCacheHandler(\n options: FilesystemCacheHandlerOptions = {},\n) {\n const root = options.root ?? resolveCacheRoot();\n const entriesRoot = path.join(root, \"entries\");\n const tagsPath = path.join(root, \"tags.json\");\n let tagState: TagState | undefined;\n\n return {\n async get(\n cacheKey: string,\n softTags: string[] = [],\n ): Promise<CacheEntry | undefined> {\n await ensureCacheRoot(entriesRoot);\n await loadTagState();\n const stored = await readStoredEntry(getEntryPath(entriesRoot, cacheKey));\n if (!stored) return undefined;\n const now = Date.now();\n if (\n Number.isFinite(stored.expire) &&\n stored.expire > 0 &&\n stored.timestamp + stored.expire * 1000 <= now\n ) {\n return undefined;\n }\n const expiration = getExpirationFromState([\n ...(stored.tags ?? []),\n ...softTags,\n ]);\n if (expiration > stored.timestamp) return undefined;\n return {\n ...stored,\n value: streamFromBuffer(Buffer.from(stored.value, \"base64\")),\n };\n },\n\n async set(\n cacheKey: string,\n pendingEntry: Promise<CacheEntry>,\n ): Promise<void> {\n await ensureCacheRoot(entriesRoot);\n const entry = await pendingEntry;\n const [storedStream, returnedStream] = entry.value.tee();\n entry.value = returnedStream;\n const stored: StoredCacheEntry = {\n ...entry,\n value: (await bufferFromStream(storedStream)).toString(\"base64\"),\n };\n const destination = getEntryPath(entriesRoot, cacheKey);\n await fs.ensureDir(path.dirname(destination));\n await writeJsonAtomic(destination, stored);\n },\n\n async refreshTags(): Promise<void> {\n await loadTagState();\n },\n\n async getExpiration(tags: string[]): Promise<number> {\n await loadTagState();\n return getExpirationFromState(tags);\n },\n\n async updateTags(\n tags: string[],\n durations?: { expire?: number },\n ): Promise<void> {\n await ensureCacheRoot(entriesRoot);\n await loadTagState();\n const now = Date.now();\n const uniqueTags = [...new Set(tags)];\n tagState ??= { version: 1, tags: {} };\n for (const tag of uniqueTags) {\n tagState.tags[tag] = now;\n }\n await writeJsonAtomic(tagsPath, tagState);\n if (durations?.expire === 0) {\n await deleteEntriesWithTags(entriesRoot, uniqueTags);\n }\n },\n };\n\n async function loadTagState(): Promise<void> {\n tagState = ((await fs.readJson(tagsPath).catch(() => undefined)) ?? {\n version: 1,\n tags: {},\n }) as TagState;\n }\n\n function getExpirationFromState(tags: string[]): number {\n const state = tagState ?? { version: 1, tags: {} };\n return Math.max(0, ...tags.map((tag) => state.tags[tag] ?? 0));\n }\n}\n\nasync function ensureCacheRoot(entriesRoot: string): Promise<void> {\n await fs.ensureDir(entriesRoot);\n}\n\nfunction resolveCacheRoot(): string {\n if (process.env.SILICA_CACHE_DIR) return process.env.SILICA_CACHE_DIR;\n const projectRoot = process.env.SILICA_PROJECT_ROOT ?? process.cwd();\n const config = readConfigFromVaultDb(projectRoot);\n const configured = config?.render?.cache?.directory;\n if (configured) {\n return path.isAbsolute(configured)\n ? configured\n : path.join(projectRoot, configured);\n }\n return path.join(projectRoot, \".silica/cache/next\");\n}\n\nfunction readConfigFromVaultDb(projectRoot: string):\n | {\n render?: { cache?: { directory?: string } };\n }\n | undefined {\n const databasePath = path.join(projectRoot, \".silica/vault.db\");\n if (!fs.existsSync(databasePath)) return;\n const db = new Database(databasePath, {\n fileMustExist: true,\n readonly: true,\n });\n try {\n db.pragma(\"query_only = ON\");\n const row = db\n .prepare(\"SELECT value FROM vault_metadata WHERE key = 'configJson'\")\n .get() as { value: string } | undefined;\n return row ? JSON.parse(row.value) : undefined;\n } finally {\n db.close();\n }\n}\n\nfunction getEntryPath(entriesRoot: string, cacheKey: string): string {\n const digest = crypto.createHash(\"sha256\").update(cacheKey).digest(\"hex\");\n return path.join(entriesRoot, digest.slice(0, 2), `${digest}.json`);\n}\n\nasync function readStoredEntry(\n filePath: string,\n): Promise<StoredCacheEntry | undefined> {\n try {\n return (await fs.readJson(filePath)) as StoredCacheEntry;\n } catch {\n return undefined;\n }\n}\n\nasync function writeJsonAtomic(\n filePath: string,\n value: unknown,\n): Promise<void> {\n const temporary = `${filePath}.${process.pid}.${crypto.randomUUID()}.tmp`;\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeJson(temporary, value);\n await fs.rename(temporary, filePath);\n}\n\nasync function deleteEntriesWithTags(\n entriesRoot: string,\n tags: string[],\n): Promise<void> {\n if (!(await fs.pathExists(entriesRoot))) return;\n const wanted = new Set(tags);\n for (const filePath of await listJsonFiles(entriesRoot)) {\n const entry = await readStoredEntry(filePath);\n if (entry?.tags?.some((tag) => wanted.has(tag))) {\n await fs.remove(filePath);\n }\n }\n}\n\nasync function listJsonFiles(root: string): Promise<string[]> {\n const entries = await fs.readdir(root, { withFileTypes: true });\n const files: string[] = [];\n for (const entry of entries) {\n const absolutePath = path.join(root, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await listJsonFiles(absolutePath)));\n } else if (entry.isFile() && entry.name.endsWith(\".json\")) {\n files.push(absolutePath);\n }\n }\n return files;\n}\n\nasync function bufferFromStream(\n stream: ReadableStream<Uint8Array>,\n): Promise<Buffer> {\n const reader = stream.getReader();\n const chunks: Uint8Array[] = [];\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n }\n return Buffer.concat(chunks);\n}\n\nfunction streamFromBuffer(buffer: Buffer): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(buffer);\n controller.close();\n },\n });\n}\n\nexport default createFilesystemCacheHandler();\n"],"mappings":"AAAA,OAAO,YAAY;AACnB,OAAO,UAAU;AACjB,SAAS,sBAAsB;AAC/B,OAAO,cAAc;AACrB,OAAO,QAAQ;AAwBR,SAAS,6BACd,UAAyC,CAAC,GAC1C;AACA,QAAM,OAAO,QAAQ,QAAQ,iBAAiB;AAC9C,QAAM,cAAc,KAAK,KAAK,MAAM,SAAS;AAC7C,QAAM,WAAW,KAAK,KAAK,MAAM,WAAW;AAC5C,MAAI;AAEJ,SAAO;AAAA,IACL,MAAM,IACJ,UACA,WAAqB,CAAC,GACW;AACjC,YAAM,gBAAgB,WAAW;AACjC,YAAM,aAAa;AACnB,YAAM,SAAS,MAAM,gBAAgB,aAAa,aAAa,QAAQ,CAAC;AACxE,UAAI,CAAC,OAAQ,QAAO;AACpB,YAAM,MAAM,KAAK,IAAI;AACrB,UACE,OAAO,SAAS,OAAO,MAAM,KAC7B,OAAO,SAAS,KAChB,OAAO,YAAY,OAAO,SAAS,OAAQ,KAC3C;AACA,eAAO;AAAA,MACT;AACA,YAAM,aAAa,uBAAuB;AAAA,QACxC,GAAI,OAAO,QAAQ,CAAC;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AACD,UAAI,aAAa,OAAO,UAAW,QAAO;AAC1C,aAAO;AAAA,QACL,GAAG;AAAA,QACH,OAAO,iBAAiB,OAAO,KAAK,OAAO,OAAO,QAAQ,CAAC;AAAA,MAC7D;AAAA,IACF;AAAA,IAEA,MAAM,IACJ,UACA,cACe;AACf,YAAM,gBAAgB,WAAW;AACjC,YAAM,QAAQ,MAAM;AACpB,YAAM,CAAC,cAAc,cAAc,IAAI,MAAM,MAAM,IAAI;AACvD,YAAM,QAAQ;AACd,YAAM,SAA2B;AAAA,QAC/B,GAAG;AAAA,QACH,QAAQ,MAAM,iBAAiB,YAAY,GAAG,SAAS,QAAQ;AAAA,MACjE;AACA,YAAM,cAAc,aAAa,aAAa,QAAQ;AACtD,YAAM,GAAG,UAAU,KAAK,QAAQ,WAAW,CAAC;AAC5C,YAAM,gBAAgB,aAAa,MAAM;AAAA,IAC3C;AAAA,IAEA,MAAM,cAA6B;AACjC,YAAM,aAAa;AAAA,IACrB;AAAA,IAEA,MAAM,cAAc,MAAiC;AACnD,YAAM,aAAa;AACnB,aAAO,uBAAuB,IAAI;AAAA,IACpC;AAAA,IAEA,MAAM,WACJ,MACA,WACe;AACf,YAAM,gBAAgB,WAAW;AACjC,YAAM,aAAa;AACnB,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,aAAa,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AACpC,mBAAa,EAAE,SAAS,GAAG,MAAM,CAAC,EAAE;AACpC,iBAAW,OAAO,YAAY;AAC5B,iBAAS,KAAK,GAAG,IAAI;AAAA,MACvB;AACA,YAAM,gBAAgB,UAAU,QAAQ;AACxC,UAAI,WAAW,WAAW,GAAG;AAC3B,cAAM,sBAAsB,aAAa,UAAU;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,eAA8B;AAC3C,eAAa,MAAM,GAAG,SAAS,QAAQ,EAAE,MAAM,MAAM,MAAS,KAAM;AAAA,MAClE,SAAS;AAAA,MACT,MAAM,CAAC;AAAA,IACT;AAAA,EACF;AAEA,WAAS,uBAAuB,MAAwB;AACtD,UAAM,QAAQ,YAAY,EAAE,SAAS,GAAG,MAAM,CAAC,EAAE;AACjD,WAAO,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,QAAQ,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,EAC/D;AACF;AAEA,eAAe,gBAAgB,aAAoC;AACjE,QAAM,GAAG,UAAU,WAAW;AAChC;AAEA,SAAS,mBAA2B;AAClC,MAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,QAAM,cAAc,QAAQ,IAAI,uBAAuB,QAAQ,IAAI;AACnE,QAAM,SAAS,sBAAsB,WAAW;AAChD,QAAM,aAAa,QAAQ,QAAQ,OAAO;AAC1C,MAAI,YAAY;AACd,WAAO,KAAK,WAAW,UAAU,IAC7B,aACA,KAAK,KAAK,aAAa,UAAU;AAAA,EACvC;AACA,SAAO,KAAK,KAAK,aAAa,oBAAoB;AACpD;AAEA,SAAS,sBAAsB,aAIjB;AACZ,QAAM,eAAe,KAAK,KAAK,aAAa,kBAAkB;AAC9D,MAAI,CAAC,GAAG,WAAW,YAAY,EAAG;AAClC,QAAM,KAAK,IAAI,SAAS,cAAc;AAAA,IACpC,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,CAAC;AACD,MAAI;AACF,OAAG,OAAO,iBAAiB;AAC3B,UAAM,MAAM,GACT,QAAQ,2DAA2D,EACnE,IAAI;AACP,WAAO,MAAM,KAAK,MAAM,IAAI,KAAK,IAAI;AAAA,EACvC,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAEA,SAAS,aAAa,aAAqB,UAA0B;AACnE,QAAM,SAAS,OAAO,WAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAK;AACxE,SAAO,KAAK,KAAK,aAAa,OAAO,MAAM,GAAG,CAAC,GAAG,GAAG,MAAM,OAAO;AACpE;AAEA,eAAe,gBACb,UACuC;AACvC,MAAI;AACF,WAAQ,MAAM,GAAG,SAAS,QAAQ;AAAA,EACpC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBACb,UACA,OACe;AACf,QAAM,YAAY,GAAG,QAAQ,IAAI,QAAQ,GAAG,IAAI,OAAO,WAAW,CAAC;AACnE,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,WAAW,KAAK;AACnC,QAAM,GAAG,OAAO,WAAW,QAAQ;AACrC;AAEA,eAAe,sBACb,aACA,MACe;AACf,MAAI,CAAE,MAAM,GAAG,WAAW,WAAW,EAAI;AACzC,QAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,aAAW,YAAY,MAAM,cAAc,WAAW,GAAG;AACvD,UAAM,QAAQ,MAAM,gBAAgB,QAAQ;AAC5C,QAAI,OAAO,MAAM,KAAK,CAAC,QAAQ,OAAO,IAAI,GAAG,CAAC,GAAG;AAC/C,YAAM,GAAG,OAAO,QAAQ;AAAA,IAC1B;AAAA,EACF;AACF;AAEA,eAAe,cAAc,MAAiC;AAC5D,QAAM,UAAU,MAAM,GAAG,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAC9D,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,SAAS;AAC3B,UAAM,eAAe,KAAK,KAAK,MAAM,MAAM,IAAI;AAC/C,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,KAAK,GAAI,MAAM,cAAc,YAAY,CAAE;AAAA,IACnD,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,OAAO,GAAG;AACzD,YAAM,KAAK,YAAY;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,iBACb,QACiB;AACjB,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,SAAuB,CAAC;AAC9B,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,KAAM;AACV,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEA,SAAS,iBAAiB,QAA4C;AACpE,SAAO,IAAI,eAA2B;AAAA,IACpC,MAAM,YAAY;AAChB,iBAAW,QAAQ,MAAM;AACzB,iBAAW,MAAM;AAAA,IACnB;AAAA,EACF,CAAC;AACH;AAEA,IAAO,qBAAQ,6BAA6B;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { TemplateFile, getSilicaTemplates, nextConfigTemplate, packageJsonTemplate, proxyTemplate, themeModuleTemplate, tsconfigTemplate } from './templates.js';
2
- export { getProjectRoot, getSilicaRoot, loadBuildId, loadGraph, loadManifest, loadNavigation, loadResolvedConfig } from './server-data.js';
2
+ export { LoadedVaultDb, getAllSlugs, getBacklinks, getBreadcrumbs, getCacheState, getConfig, getEntriesForTag, getNavigation, getPage, getPageRuntimeData, getPrerenderSlugs, getProjectRoot, getRelatedTagsForEntries, getRenderKey, getSilicaRoot, getTagSlugs, getVaultDatabasePath, loadRenderEnvironmentHash, loadSearchIndex, loadVaultDb, normalizeRouteSlug, resolveAssetFromDb, resolveWikiLinkFromDb } from './server-data.js';
3
3
  export { SilicaNextRoutingProvider } from './routing-provider.js';
4
4
  import '@silicajs/core/runtime';
5
+ import 'better-sqlite3';
6
+ import '@silicajs/search';
5
7
  import 'react/jsx-runtime';
6
8
  import 'react';
package/dist/index.js CHANGED
@@ -7,28 +7,58 @@ import {
7
7
  tsconfigTemplate
8
8
  } from "./templates.js";
9
9
  import {
10
+ getAllSlugs,
11
+ getBacklinks,
12
+ getBreadcrumbs,
13
+ getCacheState,
14
+ getConfig,
15
+ getEntriesForTag,
16
+ getNavigation,
17
+ getPage,
18
+ getPageRuntimeData,
10
19
  getProjectRoot,
20
+ getPrerenderSlugs,
21
+ getRenderKey,
22
+ getRelatedTagsForEntries,
11
23
  getSilicaRoot,
12
- loadBuildId,
13
- loadGraph,
14
- loadManifest,
15
- loadNavigation,
16
- loadResolvedConfig
24
+ getTagSlugs,
25
+ getVaultDatabasePath,
26
+ loadSearchIndex,
27
+ loadRenderEnvironmentHash,
28
+ loadVaultDb,
29
+ normalizeRouteSlug,
30
+ resolveAssetFromDb,
31
+ resolveWikiLinkFromDb
17
32
  } from "./server-data.js";
18
33
  import { SilicaNextRoutingProvider } from "./routing-provider.js";
19
34
  export {
20
35
  SilicaNextRoutingProvider,
36
+ getAllSlugs,
37
+ getBacklinks,
38
+ getBreadcrumbs,
39
+ getCacheState,
40
+ getConfig,
41
+ getEntriesForTag,
42
+ getNavigation,
43
+ getPage,
44
+ getPageRuntimeData,
45
+ getPrerenderSlugs,
21
46
  getProjectRoot,
47
+ getRelatedTagsForEntries,
48
+ getRenderKey,
22
49
  getSilicaRoot,
23
50
  getSilicaTemplates,
24
- loadBuildId,
25
- loadGraph,
26
- loadManifest,
27
- loadNavigation,
28
- loadResolvedConfig,
51
+ getTagSlugs,
52
+ getVaultDatabasePath,
53
+ loadRenderEnvironmentHash,
54
+ loadSearchIndex,
55
+ loadVaultDb,
29
56
  nextConfigTemplate,
57
+ normalizeRouteSlug,
30
58
  packageJsonTemplate,
31
59
  proxyTemplate,
60
+ resolveAssetFromDb,
61
+ resolveWikiLinkFromDb,
32
62
  themeModuleTemplate,
33
63
  tsconfigTemplate
34
64
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n getSilicaTemplates,\n nextConfigTemplate,\n packageJsonTemplate,\n proxyTemplate,\n themeModuleTemplate,\n tsconfigTemplate,\n type TemplateFile,\n} from \"./templates.js\";\nexport {\n getProjectRoot,\n getSilicaRoot,\n loadBuildId,\n loadGraph,\n loadManifest,\n loadNavigation,\n loadResolvedConfig,\n} from \"./server-data.js\";\nexport { SilicaNextRoutingProvider } from \"./routing-provider.js\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iCAAiC;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n getSilicaTemplates,\n nextConfigTemplate,\n packageJsonTemplate,\n proxyTemplate,\n themeModuleTemplate,\n tsconfigTemplate,\n type TemplateFile,\n} from \"./templates.js\";\nexport {\n getAllSlugs,\n getBacklinks,\n getBreadcrumbs,\n getCacheState,\n getConfig,\n getEntriesForTag,\n getNavigation,\n getPage,\n getPageRuntimeData,\n getProjectRoot,\n getPrerenderSlugs,\n getRenderKey,\n getRelatedTagsForEntries,\n getSilicaRoot,\n getTagSlugs,\n getVaultDatabasePath,\n loadSearchIndex,\n loadRenderEnvironmentHash,\n loadVaultDb,\n normalizeRouteSlug,\n resolveAssetFromDb,\n resolveWikiLinkFromDb,\n type LoadedVaultDb,\n} from \"./server-data.js\";\nexport { SilicaNextRoutingProvider } from \"./routing-provider.js\";\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP,SAAS,iCAAiC;","names":[]}
@@ -1,15 +1,23 @@
1
1
  import { toNextJsHandler } from "better-auth/next-js";
2
+ import { cacheLife, cacheTag } from "next/cache";
2
3
  import { silicaAuth } from "@silicajs/auth";
3
4
  import { resolveRuntimeAuthConfig } from "../auth-config.js";
4
- import { loadResolvedConfig } from "../server-data.js";
5
+ import { getCacheState, getConfig } from "../server-data.js";
5
6
  async function getAuth() {
6
- const config = await loadResolvedConfig();
7
+ const cacheState = getCacheState();
8
+ const config = await getCachedAuthConfig(cacheState.renderEnvironmentHash);
7
9
  const auth = resolveRuntimeAuthConfig(config);
8
10
  return silicaAuth({
9
11
  allowedDomains: auth.allowedDomains,
10
12
  allowedEmails: auth.allowedEmails
11
13
  });
12
14
  }
15
+ async function getCachedAuthConfig(renderEnvironmentHash) {
16
+ "use cache";
17
+ cacheLife("max");
18
+ cacheTag(`environment:${renderEnvironmentHash}`);
19
+ return getConfig();
20
+ }
13
21
  async function GET(request) {
14
22
  const auth = await getAuth();
15
23
  const handler = toNextJsHandler(auth);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/api-auth.ts"],"sourcesContent":["import { toNextJsHandler } from \"better-auth/next-js\";\nimport { silicaAuth } from \"@silicajs/auth\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport { loadResolvedConfig } from \"../server-data.js\";\n\nasync function getAuth() {\n const config = await loadResolvedConfig();\n const auth = resolveRuntimeAuthConfig(config);\n return silicaAuth({\n allowedDomains: auth.allowedDomains,\n allowedEmails: auth.allowedEmails,\n });\n}\n\nexport async function GET(request: Request) {\n const auth = await getAuth();\n const handler = toNextJsHandler(auth);\n return handler.GET(request);\n}\n\nexport async function POST(request: Request) {\n const auth = await getAuth();\n const handler = toNextJsHandler(auth);\n return handler.POST(request);\n}\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,gCAAgC;AACzC,SAAS,0BAA0B;AAEnC,eAAe,UAAU;AACvB,QAAM,SAAS,MAAM,mBAAmB;AACxC,QAAM,OAAO,yBAAyB,MAAM;AAC5C,SAAO,WAAW;AAAA,IAChB,gBAAgB,KAAK;AAAA,IACrB,eAAe,KAAK;AAAA,EACtB,CAAC;AACH;AAEA,eAAsB,IAAI,SAAkB;AAC1C,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,gBAAgB,IAAI;AACpC,SAAO,QAAQ,IAAI,OAAO;AAC5B;AAEA,eAAsB,KAAK,SAAkB;AAC3C,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,gBAAgB,IAAI;AACpC,SAAO,QAAQ,KAAK,OAAO;AAC7B;","names":[]}
1
+ {"version":3,"sources":["../../src/routes/api-auth.ts"],"sourcesContent":["import { toNextJsHandler } from \"better-auth/next-js\";\nimport { cacheLife, cacheTag } from \"next/cache\";\nimport { silicaAuth } from \"@silicajs/auth\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport { getCacheState, getConfig } from \"../server-data.js\";\n\nasync function getAuth() {\n const cacheState = getCacheState();\n const config = await getCachedAuthConfig(cacheState.renderEnvironmentHash);\n const auth = resolveRuntimeAuthConfig(config);\n return silicaAuth({\n allowedDomains: auth.allowedDomains,\n allowedEmails: auth.allowedEmails,\n });\n}\n\nasync function getCachedAuthConfig(renderEnvironmentHash: string) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(`environment:${renderEnvironmentHash}`);\n return getConfig();\n}\n\nexport async function GET(request: Request) {\n const auth = await getAuth();\n const handler = toNextJsHandler(auth);\n return handler.GET(request);\n}\n\nexport async function POST(request: Request) {\n const auth = await getAuth();\n const handler = toNextJsHandler(auth);\n return handler.POST(request);\n}\n"],"mappings":"AAAA,SAAS,uBAAuB;AAChC,SAAS,WAAW,gBAAgB;AACpC,SAAS,kBAAkB;AAC3B,SAAS,gCAAgC;AACzC,SAAS,eAAe,iBAAiB;AAEzC,eAAe,UAAU;AACvB,QAAM,aAAa,cAAc;AACjC,QAAM,SAAS,MAAM,oBAAoB,WAAW,qBAAqB;AACzE,QAAM,OAAO,yBAAyB,MAAM;AAC5C,SAAO,WAAW;AAAA,IAChB,gBAAgB,KAAK;AAAA,IACrB,eAAe,KAAK;AAAA,EACtB,CAAC;AACH;AAEA,eAAe,oBAAoB,uBAA+B;AAChE;AACA,YAAU,KAAK;AACf,WAAS,eAAe,qBAAqB,EAAE;AAC/C,SAAO,UAAU;AACnB;AAEA,eAAsB,IAAI,SAAkB;AAC1C,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,gBAAgB,IAAI;AACpC,SAAO,QAAQ,IAAI,OAAO;AAC5B;AAEA,eAAsB,KAAK,SAAkB;AAC3C,QAAM,OAAO,MAAM,QAAQ;AAC3B,QAAM,UAAU,gBAAgB,IAAI;AACpC,SAAO,QAAQ,KAAK,OAAO;AAC7B;","names":[]}
@@ -1,9 +1,23 @@
1
+ import { cacheLife, cacheTag } from "next/cache";
1
2
  import { NextResponse } from "next/server";
2
- import { loadNavigation } from "../server-data.js";
3
+ import { getCacheState, getNavigation } from "../server-data.js";
3
4
  async function GET() {
4
- const navigation = await loadNavigation();
5
+ const cacheState = getCacheState();
6
+ const navigation = await getCachedNavigation(
7
+ cacheState.renderEnvironmentHash,
8
+ cacheState.navigationHash
9
+ );
5
10
  return NextResponse.json(navigation);
6
11
  }
12
+ async function getCachedNavigation(renderEnvironmentHash, navigationHash) {
13
+ "use cache";
14
+ cacheLife("max");
15
+ cacheTag(
16
+ `environment:${renderEnvironmentHash}`,
17
+ `navigation:${navigationHash}`
18
+ );
19
+ return getNavigation();
20
+ }
7
21
  export {
8
22
  GET
9
23
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/api-navigation.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport { loadNavigation } from \"../server-data.js\";\n\nexport async function GET() {\n const navigation = await loadNavigation();\n return NextResponse.json(navigation);\n}\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAE/B,eAAsB,MAAM;AAC1B,QAAM,aAAa,MAAM,eAAe;AACxC,SAAO,aAAa,KAAK,UAAU;AACrC;","names":[]}
1
+ {"version":3,"sources":["../../src/routes/api-navigation.ts"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { NextResponse } from \"next/server\";\nimport { getCacheState, getNavigation } from \"../server-data.js\";\n\nexport async function GET() {\n const cacheState = getCacheState();\n const navigation = await getCachedNavigation(\n cacheState.renderEnvironmentHash,\n cacheState.navigationHash,\n );\n return NextResponse.json(navigation);\n}\n\nasync function getCachedNavigation(\n renderEnvironmentHash: string,\n navigationHash: string,\n) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(\n `environment:${renderEnvironmentHash}`,\n `navigation:${navigationHash}`,\n );\n return getNavigation();\n}\n"],"mappings":"AAAA,SAAS,WAAW,gBAAgB;AACpC,SAAS,oBAAoB;AAC7B,SAAS,eAAe,qBAAqB;AAE7C,eAAsB,MAAM;AAC1B,QAAM,aAAa,cAAc;AACjC,QAAM,aAAa,MAAM;AAAA,IACvB,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AACA,SAAO,aAAa,KAAK,UAAU;AACrC;AAEA,eAAe,oBACb,uBACA,gBACA;AACA;AACA,YAAU,KAAK;AACf;AAAA,IACE,eAAe,qBAAqB;AAAA,IACpC,cAAc,cAAc;AAAA,EAC9B;AACA,SAAO,cAAc;AACvB;","names":[]}
@@ -1,11 +1,6 @@
1
- import path from "node:path";
2
1
  import { NextResponse } from "next/server";
3
- import {
4
- loadSearchIndex,
5
- querySearchIndex,
6
- SEARCH_DATABASE_FILENAME
7
- } from "@silicajs/search";
8
- import { getSilicaRoot } from "../server-data.js";
2
+ import { querySearchIndex } from "@silicajs/search";
3
+ import { loadSearchIndex } from "../server-data.js";
9
4
  const MAX_QUERY_LENGTH = 120;
10
5
  const MAX_TAGS = 10;
11
6
  const MAX_TAG_LENGTH = 64;
@@ -17,9 +12,7 @@ async function GET(request) {
17
12
  }
18
13
  const parsed = parseTagQuery(query);
19
14
  const tags = [...url.searchParams.getAll("tag"), ...parsed.tags].slice(0, MAX_TAGS).map((tag) => tag.trim()).filter((tag) => tag.length > 0 && tag.length <= MAX_TAG_LENGTH);
20
- const loaded = await loadSearchIndex(
21
- path.join(getSilicaRoot(), SEARCH_DATABASE_FILENAME)
22
- );
15
+ const loaded = loadSearchIndex();
23
16
  const results = querySearchIndex(loaded, parsed.query, { tags, limit: 10 });
24
17
  return NextResponse.json({
25
18
  results: results.map(({ slug, title, titleParts, excerptParts }) => ({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/api-search.ts"],"sourcesContent":["import path from \"node:path\";\nimport { NextResponse } from \"next/server\";\nimport {\n loadSearchIndex,\n querySearchIndex,\n SEARCH_DATABASE_FILENAME,\n} from \"@silicajs/search\";\nimport { getSilicaRoot } from \"../server-data.js\";\n\nconst MAX_QUERY_LENGTH = 120;\nconst MAX_TAGS = 10;\nconst MAX_TAG_LENGTH = 64;\n\nexport async function GET(request: Request) {\n const url = new URL(request.url);\n const query = url.searchParams.get(\"q\") ?? \"\";\n if (query.length > MAX_QUERY_LENGTH) {\n return NextResponse.json({ error: \"Query is too long\" }, { status: 400 });\n }\n\n const parsed = parseTagQuery(query);\n const tags = [...url.searchParams.getAll(\"tag\"), ...parsed.tags]\n .slice(0, MAX_TAGS)\n .map((tag) => tag.trim())\n .filter((tag) => tag.length > 0 && tag.length <= MAX_TAG_LENGTH);\n const loaded = await loadSearchIndex(\n path.join(getSilicaRoot(), SEARCH_DATABASE_FILENAME),\n );\n const results = querySearchIndex(loaded, parsed.query, { tags, limit: 10 });\n return NextResponse.json({\n results: results.map(({ slug, title, titleParts, excerptParts }) => ({\n slug,\n title,\n titleParts,\n excerptParts,\n })),\n });\n}\n\nexport function parseTagQuery(query: string): {\n query: string;\n tags: string[];\n} {\n const tags: string[] = [];\n const withoutOperators = query.replace(\n /(?:^|\\s)tag:(#?\\S+)/gi,\n (_match, tag: string) => {\n tags.push(tag);\n return \" \";\n },\n );\n const withoutShortcuts = withoutOperators.replace(\n /(?:^|\\s)(#\\S+)/g,\n (_match, tag: string) => {\n tags.push(tag);\n return \" \";\n },\n );\n\n return {\n query: withoutShortcuts.replace(/\\s+/g, \" \").trim(),\n tags,\n };\n}\n"],"mappings":"AAAA,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAE9B,MAAM,mBAAmB;AACzB,MAAM,WAAW;AACjB,MAAM,iBAAiB;AAEvB,eAAsB,IAAI,SAAkB;AAC1C,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,QAAQ,IAAI,aAAa,IAAI,GAAG,KAAK;AAC3C,MAAI,MAAM,SAAS,kBAAkB;AACnC,WAAO,aAAa,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1E;AAEA,QAAM,SAAS,cAAc,KAAK;AAClC,QAAM,OAAO,CAAC,GAAG,IAAI,aAAa,OAAO,KAAK,GAAG,GAAG,OAAO,IAAI,EAC5D,MAAM,GAAG,QAAQ,EACjB,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EACvB,OAAO,CAAC,QAAQ,IAAI,SAAS,KAAK,IAAI,UAAU,cAAc;AACjE,QAAM,SAAS,MAAM;AAAA,IACnB,KAAK,KAAK,cAAc,GAAG,wBAAwB;AAAA,EACrD;AACA,QAAM,UAAU,iBAAiB,QAAQ,OAAO,OAAO,EAAE,MAAM,OAAO,GAAG,CAAC;AAC1E,SAAO,aAAa,KAAK;AAAA,IACvB,SAAS,QAAQ,IAAI,CAAC,EAAE,MAAM,OAAO,YAAY,aAAa,OAAO;AAAA,MACnE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ,CAAC;AACH;AAEO,SAAS,cAAc,OAG5B;AACA,QAAM,OAAiB,CAAC;AACxB,QAAM,mBAAmB,MAAM;AAAA,IAC7B;AAAA,IACA,CAAC,QAAQ,QAAgB;AACvB,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,mBAAmB,iBAAiB;AAAA,IACxC;AAAA,IACA,CAAC,QAAQ,QAAgB;AACvB,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,iBAAiB,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/routes/api-search.ts"],"sourcesContent":["import { NextResponse } from \"next/server\";\nimport { querySearchIndex } from \"@silicajs/search\";\nimport { loadSearchIndex } from \"../server-data.js\";\n\nconst MAX_QUERY_LENGTH = 120;\nconst MAX_TAGS = 10;\nconst MAX_TAG_LENGTH = 64;\n\nexport async function GET(request: Request) {\n const url = new URL(request.url);\n const query = url.searchParams.get(\"q\") ?? \"\";\n if (query.length > MAX_QUERY_LENGTH) {\n return NextResponse.json({ error: \"Query is too long\" }, { status: 400 });\n }\n\n const parsed = parseTagQuery(query);\n const tags = [...url.searchParams.getAll(\"tag\"), ...parsed.tags]\n .slice(0, MAX_TAGS)\n .map((tag) => tag.trim())\n .filter((tag) => tag.length > 0 && tag.length <= MAX_TAG_LENGTH);\n const loaded = loadSearchIndex();\n const results = querySearchIndex(loaded, parsed.query, { tags, limit: 10 });\n return NextResponse.json({\n results: results.map(({ slug, title, titleParts, excerptParts }) => ({\n slug,\n title,\n titleParts,\n excerptParts,\n })),\n });\n}\n\nexport function parseTagQuery(query: string): {\n query: string;\n tags: string[];\n} {\n const tags: string[] = [];\n const withoutOperators = query.replace(\n /(?:^|\\s)tag:(#?\\S+)/gi,\n (_match, tag: string) => {\n tags.push(tag);\n return \" \";\n },\n );\n const withoutShortcuts = withoutOperators.replace(\n /(?:^|\\s)(#\\S+)/g,\n (_match, tag: string) => {\n tags.push(tag);\n return \" \";\n },\n );\n\n return {\n query: withoutShortcuts.replace(/\\s+/g, \" \").trim(),\n tags,\n };\n}\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAEhC,MAAM,mBAAmB;AACzB,MAAM,WAAW;AACjB,MAAM,iBAAiB;AAEvB,eAAsB,IAAI,SAAkB;AAC1C,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,QAAQ,IAAI,aAAa,IAAI,GAAG,KAAK;AAC3C,MAAI,MAAM,SAAS,kBAAkB;AACnC,WAAO,aAAa,KAAK,EAAE,OAAO,oBAAoB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1E;AAEA,QAAM,SAAS,cAAc,KAAK;AAClC,QAAM,OAAO,CAAC,GAAG,IAAI,aAAa,OAAO,KAAK,GAAG,GAAG,OAAO,IAAI,EAC5D,MAAM,GAAG,QAAQ,EACjB,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,EACvB,OAAO,CAAC,QAAQ,IAAI,SAAS,KAAK,IAAI,UAAU,cAAc;AACjE,QAAM,SAAS,gBAAgB;AAC/B,QAAM,UAAU,iBAAiB,QAAQ,OAAO,OAAO,EAAE,MAAM,OAAO,GAAG,CAAC;AAC1E,SAAO,aAAa,KAAK;AAAA,IACvB,SAAS,QAAQ,IAAI,CAAC,EAAE,MAAM,OAAO,YAAY,aAAa,OAAO;AAAA,MACnE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ,CAAC;AACH;AAEO,SAAS,cAAc,OAG5B;AACA,QAAM,OAAiB,CAAC;AACxB,QAAM,mBAAmB,MAAM;AAAA,IAC7B;AAAA,IACA,CAAC,QAAQ,QAAgB;AACvB,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,mBAAmB,iBAAiB;AAAA,IACxC;AAAA,IACA,CAAC,QAAQ,QAAgB;AACvB,WAAK,KAAK,GAAG;AACb,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,iBAAiB,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { cacheLife, cacheTag } from "next/cache";
2
2
  import { resolveRuntimeAuthConfig } from "../auth-config.js";
3
- import { loadBuildId, loadResolvedConfig } from "../server-data.js";
3
+ import { getCacheState, getConfig } from "../server-data.js";
4
4
  async function generateMetadata() {
5
5
  const { config } = await getLayoutProps();
6
6
  return {
@@ -12,14 +12,19 @@ async function generateMetadata() {
12
12
  };
13
13
  }
14
14
  async function getLayoutProps() {
15
+ const cacheState = getCacheState();
16
+ return getCachedLayoutProps(cacheState.renderEnvironmentHash);
17
+ }
18
+ async function getCachedLayoutProps(renderEnvironmentHash) {
15
19
  "use cache";
16
20
  cacheLife("max");
17
- const buildId = await loadBuildId();
18
- cacheTag("build", `build:${buildId}`);
19
- const config = await loadResolvedConfig();
21
+ cacheTag(`environment:${renderEnvironmentHash}`);
22
+ const config = getConfig();
20
23
  const auth = resolveRuntimeAuthConfig(config);
21
24
  return {
22
- navigationEndpoint: `/api/navigation?build=${encodeURIComponent(buildId)}`,
25
+ navigationEndpoint: `/api/navigation?build=${encodeURIComponent(
26
+ renderEnvironmentHash
27
+ )}`,
23
28
  config: {
24
29
  title: config.title,
25
30
  description: config.description,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routes/layout.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport { loadBuildId, loadResolvedConfig } from \"../server-data.js\";\n\nexport async function generateMetadata() {\n const { config } = await getLayoutProps();\n return {\n title: {\n default: config.title,\n template: `%s · ${config.title}`,\n },\n description: config.description,\n };\n}\n\nexport async function getLayoutProps() {\n \"use cache\";\n cacheLife(\"max\");\n const buildId = await loadBuildId();\n cacheTag(\"build\", `build:${buildId}`);\n const config = await loadResolvedConfig();\n const auth = resolveRuntimeAuthConfig(config);\n return {\n navigationEndpoint: `/api/navigation?build=${encodeURIComponent(buildId)}`,\n config: {\n title: config.title,\n description: config.description,\n logo: config.logo,\n baseUrl: config.baseUrl,\n authEnabled: auth.authEnabled,\n },\n };\n}\n"],"mappings":"AAAA,SAAS,WAAW,gBAAgB;AACpC,SAAS,gCAAgC;AACzC,SAAS,aAAa,0BAA0B;AAEhD,eAAsB,mBAAmB;AACvC,QAAM,EAAE,OAAO,IAAI,MAAM,eAAe;AACxC,SAAO;AAAA,IACL,OAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,UAAU,WAAQ,OAAO,KAAK;AAAA,IAChC;AAAA,IACA,aAAa,OAAO;AAAA,EACtB;AACF;AAEA,eAAsB,iBAAiB;AACrC;AACA,YAAU,KAAK;AACf,QAAM,UAAU,MAAM,YAAY;AAClC,WAAS,SAAS,SAAS,OAAO,EAAE;AACpC,QAAM,SAAS,MAAM,mBAAmB;AACxC,QAAM,OAAO,yBAAyB,MAAM;AAC5C,SAAO;AAAA,IACL,oBAAoB,yBAAyB,mBAAmB,OAAO,CAAC;AAAA,IACxE,QAAQ;AAAA,MACN,OAAO,OAAO;AAAA,MACd,aAAa,OAAO;AAAA,MACpB,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/routes/layout.tsx"],"sourcesContent":["import { cacheLife, cacheTag } from \"next/cache\";\nimport { resolveRuntimeAuthConfig } from \"../auth-config.js\";\nimport { getCacheState, getConfig } from \"../server-data.js\";\n\nexport async function generateMetadata() {\n const { config } = await getLayoutProps();\n return {\n title: {\n default: config.title,\n template: `%s · ${config.title}`,\n },\n description: config.description,\n };\n}\n\nexport async function getLayoutProps() {\n const cacheState = getCacheState();\n return getCachedLayoutProps(cacheState.renderEnvironmentHash);\n}\n\nasync function getCachedLayoutProps(renderEnvironmentHash: string) {\n \"use cache\";\n cacheLife(\"max\");\n cacheTag(`environment:${renderEnvironmentHash}`);\n const config = getConfig();\n const auth = resolveRuntimeAuthConfig(config);\n return {\n navigationEndpoint: `/api/navigation?build=${encodeURIComponent(\n renderEnvironmentHash,\n )}`,\n config: {\n title: config.title,\n description: config.description,\n logo: config.logo,\n baseUrl: config.baseUrl,\n authEnabled: auth.authEnabled,\n },\n };\n}\n"],"mappings":"AAAA,SAAS,WAAW,gBAAgB;AACpC,SAAS,gCAAgC;AACzC,SAAS,eAAe,iBAAiB;AAEzC,eAAsB,mBAAmB;AACvC,QAAM,EAAE,OAAO,IAAI,MAAM,eAAe;AACxC,SAAO;AAAA,IACL,OAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,UAAU,WAAQ,OAAO,KAAK;AAAA,IAChC;AAAA,IACA,aAAa,OAAO;AAAA,EACtB;AACF;AAEA,eAAsB,iBAAiB;AACrC,QAAM,aAAa,cAAc;AACjC,SAAO,qBAAqB,WAAW,qBAAqB;AAC9D;AAEA,eAAe,qBAAqB,uBAA+B;AACjE;AACA,YAAU,KAAK;AACf,WAAS,eAAe,qBAAqB,EAAE;AAC/C,QAAM,SAAS,UAAU;AACzB,QAAM,OAAO,yBAAyB,MAAM;AAC5C,SAAO;AAAA,IACL,oBAAoB,yBAAyB;AAAA,MAC3C;AAAA,IACF,CAAC;AAAA,IACD,QAAQ;AAAA,MACN,OAAO,OAAO;AAAA,MACd,aAAa,OAAO;AAAA,MACpB,MAAM,OAAO;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,KAAK;AAAA,IACpB;AAAA,EACF;AACF;","names":[]}
@@ -18,8 +18,10 @@ type PageProps = {
18
18
  slug?: string[];
19
19
  };
20
20
  };
21
- declare function VaultContent({ slug, theme, }: {
21
+ declare function VaultContent({ slug, renderHash, renderEnvironmentHash, theme, }: {
22
22
  slug: string;
23
+ renderHash: string;
24
+ renderEnvironmentHash: string;
23
25
  theme: SilicaTheme;
24
26
  }): Promise<react_jsx_runtime.JSX.Element>;
25
27