@riebeckite/core 0.0.21 → 0.0.23
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/index.d.ts +7 -3
- package/dist/index.js +1220 -192
- package/dist/src/content/content_build_coordinator.d.ts +6 -16
- package/dist/src/content/content_build_plan.d.ts +24 -0
- package/dist/src/content/content_build_state.d.ts +22 -1
- package/dist/src/content/content_manager.d.ts +18 -2
- package/dist/src/content/content_persistent_cache.d.ts +9 -4
- package/dist/src/content/external_fingerprint.d.ts +1 -0
- package/dist/src/content/file_system_content_source.d.ts +1 -1
- package/dist/src/content/manifest_hook_cache.d.ts +7 -0
- package/dist/src/content/markdown_image.d.ts +8 -0
- package/dist/src/content/output_dependency.d.ts +3 -0
- package/dist/src/content/public_content_view.d.ts +30 -0
- package/dist/src/pipeline.d.ts +2 -0
- package/dist/src/plugin/generated_output_registry.d.ts +1 -0
- package/dist/src/plugin/plugin_runtime.d.ts +38 -2
- package/dist/src/types/content_manifest.d.ts +0 -36
- package/dist/src/types/external_dependency.d.ts +31 -0
- package/dist/src/types/output_dependency.d.ts +9 -0
- package/dist/src/types/plugin.d.ts +34 -2
- package/dist/src/types/plugin_asset.d.ts +2 -2
- package/dist/src/types/plugin_component.d.ts +2 -0
- package/dist/src/types/plugin_context.d.ts +2 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -825,17 +825,15 @@ function getFileName(filePath) {
|
|
|
825
825
|
return normalizedPath.slice(normalizedPath.lastIndexOf("/") + 1);
|
|
826
826
|
}
|
|
827
827
|
|
|
828
|
-
// src/content/content_build_state_store.ts
|
|
829
|
-
import { randomUUID } from "node:crypto";
|
|
830
|
-
import fs from "node:fs/promises";
|
|
831
|
-
import path from "node:path";
|
|
832
|
-
|
|
833
828
|
// src/content/content_build_state.ts
|
|
834
|
-
var CONTENT_BUILD_STATE_VERSION =
|
|
829
|
+
var CONTENT_BUILD_STATE_VERSION = 16;
|
|
835
830
|
var CONTENT_BUILD_STATE_DIRECTORY = ".riebeckite";
|
|
836
831
|
var CONTENT_BUILD_STATE_EXCLUDE = `${CONTENT_BUILD_STATE_DIRECTORY}/**`;
|
|
837
832
|
|
|
838
833
|
// src/content/content_build_state_store.ts
|
|
834
|
+
import { randomUUID } from "node:crypto";
|
|
835
|
+
import fs from "node:fs/promises";
|
|
836
|
+
import path from "node:path";
|
|
839
837
|
async function loadContentBuildState(statePath) {
|
|
840
838
|
try {
|
|
841
839
|
const parsed = JSON.parse(await fs.readFile(statePath, "utf8"));
|
|
@@ -876,13 +874,26 @@ async function saveContentBuildState(statePath, state2) {
|
|
|
876
874
|
const temporaryPath = `${statePath}.${randomUUID()}.tmp`;
|
|
877
875
|
await fs.mkdir(directory, { recursive: true });
|
|
878
876
|
try {
|
|
877
|
+
await waitForFaultInjection("content-build-state-save-start");
|
|
879
878
|
await fs.writeFile(temporaryPath, JSON.stringify(state2), "utf8");
|
|
880
879
|
await fs.rename(temporaryPath, statePath);
|
|
880
|
+
await waitForFaultInjection("content-build-state-committed");
|
|
881
881
|
} catch (error) {
|
|
882
882
|
await fs.rm(temporaryPath, { force: true }).catch(() => void 0);
|
|
883
883
|
throw error;
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
|
+
async function waitForFaultInjection(point) {
|
|
887
|
+
if (process.env.NODE_ENV !== "test" || process.env.RIEBECKITE_SSG_FAULT_INJECTION !== "1" || process.env.RIEBECKITE_SSG_FAULT_POINT !== point) {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
const signalFile = process.env.RIEBECKITE_SSG_FAULT_SIGNAL_FILE;
|
|
891
|
+
if (!signalFile) return;
|
|
892
|
+
await fs.writeFile(signalFile, `${point}
|
|
893
|
+
`, "utf8");
|
|
894
|
+
await new Promise(() => {
|
|
895
|
+
});
|
|
896
|
+
}
|
|
886
897
|
function resolveContentBuildStatePath(config, contentDirectory) {
|
|
887
898
|
if (config?.buildDirectory) {
|
|
888
899
|
return path.join(config.buildDirectory, "build", "content-state.json");
|
|
@@ -898,7 +909,7 @@ function isContentBuildState(value) {
|
|
|
898
909
|
return isRecord2(value) && value.version === CONTENT_BUILD_STATE_VERSION && isContentBuildStateShape(value);
|
|
899
910
|
}
|
|
900
911
|
function isContentBuildStateShape(value) {
|
|
901
|
-
if (!isRecord2(value.entries) || !isRecord2(value.contentIndex) || value.outputs !== void 0 && !isOutputDescriptors(value.outputs)) {
|
|
912
|
+
if (!isRecord2(value.entries) || !isRecord2(value.contentIndex) || !isExternalDependencies(value.externalDependencies) || value.outputs !== void 0 && !isOutputDescriptors(value.outputs) || value.manifestHookCache !== void 0 && !isManifestHookCache(value.manifestHookCache) || value.nextPublishingChangeAt !== void 0 && (typeof value.nextPublishingChangeAt !== "string" || Number.isNaN(Date.parse(value.nextPublishingChangeAt)))) {
|
|
902
913
|
return false;
|
|
903
914
|
}
|
|
904
915
|
return Object.values(value.entries).every(
|
|
@@ -909,6 +920,11 @@ function isContentBuildStateShape(value) {
|
|
|
909
920
|
(entry) => typeof entry === "string"
|
|
910
921
|
);
|
|
911
922
|
}
|
|
923
|
+
function isManifestHookCache(value) {
|
|
924
|
+
return Array.isArray(value) && value.every(
|
|
925
|
+
(entry) => isRecord2(entry) && typeof entry.pluginName === "string" && typeof entry.cacheable === "boolean" && (entry.pipelineFingerprint === void 0 || typeof entry.pipelineFingerprint === "string") && typeof entry.inputFingerprint === "string" && typeof entry.outputFingerprint === "string" && isRecord2(entry.snapshot) && Array.isArray(entry.snapshot.entries)
|
|
926
|
+
);
|
|
927
|
+
}
|
|
912
928
|
function isOutputDescriptors(value) {
|
|
913
929
|
return Array.isArray(value) && value.every(
|
|
914
930
|
(output) => isRecord2(output) && (output.kind === "content" || output.kind === "redirect" || output.kind === "plugin-page" || output.kind === "generated") && isOutputPath(output.path) && typeof output.producer === "string" && Array.isArray(output.dependencies) && output.dependencies.every(isOutputDependency)
|
|
@@ -923,7 +939,17 @@ function isOutputPath(value) {
|
|
|
923
939
|
function isOutputDependency(value) {
|
|
924
940
|
if (!isRecord2(value) || typeof value.type !== "string") return false;
|
|
925
941
|
if (value.type === "global" || value.type === "unknown") return true;
|
|
926
|
-
return value.type === "content" && typeof value.slug === "string" || value.type === "tag" && typeof value.tag === "string" || value.type === "folder" && typeof value.folder === "string";
|
|
942
|
+
return value.type === "content" && typeof value.slug === "string" || value.type === "tag" && typeof value.tag === "string" || value.type === "folder" && typeof value.folder === "string" || value.type === "file" && typeof value.path === "string" || value.type === "external" && typeof value.id === "string" || value.type === "projection" && (value.projection === "navigation" || value.projection === "recent-posts" || value.projection === "taxonomy-tags" || value.projection === "taxonomy-folders");
|
|
943
|
+
}
|
|
944
|
+
function isExternalDependencies(value) {
|
|
945
|
+
return Array.isArray(value) && value.every(
|
|
946
|
+
(dependency) => isRecord2(dependency) && typeof dependency.id === "string" && dependency.id.length > 0 && typeof dependency.fingerprint === "string" && dependency.fingerprint.length > 0 && isExternalScope(dependency.scope) && (dependency.expiresAt === void 0 || typeof dependency.expiresAt === "string" && !Number.isNaN(Date.parse(dependency.expiresAt)))
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
function isExternalScope(value) {
|
|
950
|
+
if (!isRecord2(value) || typeof value.type !== "string") return false;
|
|
951
|
+
if (value.type === "content" || value.type === "all") return true;
|
|
952
|
+
return value.type === "output" && Array.isArray(value.paths) && value.paths.every((path6) => isOutputPath(path6));
|
|
927
953
|
}
|
|
928
954
|
function isRecord2(value) {
|
|
929
955
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -1515,9 +1541,9 @@ import remarkDirective from "remark-directive";
|
|
|
1515
1541
|
import remarkFrontmatter from "remark-frontmatter";
|
|
1516
1542
|
import remarkGfm from "remark-gfm";
|
|
1517
1543
|
import remarkMath from "remark-math";
|
|
1518
|
-
import
|
|
1544
|
+
import remarkParse2 from "remark-parse";
|
|
1519
1545
|
import remarkRehype from "remark-rehype";
|
|
1520
|
-
import { unified } from "unified";
|
|
1546
|
+
import { unified as unified2 } from "unified";
|
|
1521
1547
|
import { matter as matter2 } from "vfile-matter";
|
|
1522
1548
|
|
|
1523
1549
|
// src/content/content_dependency_tracker.ts
|
|
@@ -1652,8 +1678,8 @@ function warn(logger, message, key, error) {
|
|
|
1652
1678
|
|
|
1653
1679
|
// src/content/content_persistent_cache.ts
|
|
1654
1680
|
var CONTENT_CACHE_NAMESPACE = "content";
|
|
1655
|
-
var CONTENT_CACHE_SCHEMA_VERSION =
|
|
1656
|
-
var CONTENT_CACHE_COMPATIBILITY_VERSION =
|
|
1681
|
+
var CONTENT_CACHE_SCHEMA_VERSION = 5;
|
|
1682
|
+
var CONTENT_CACHE_COMPATIBILITY_VERSION = 3;
|
|
1657
1683
|
function hash2(value) {
|
|
1658
1684
|
return createHash4("sha256").update(value).digest("hex");
|
|
1659
1685
|
}
|
|
@@ -1813,17 +1839,35 @@ function normalizeFrontmatterForCache(frontmatter) {
|
|
|
1813
1839
|
}
|
|
1814
1840
|
return normalized;
|
|
1815
1841
|
}
|
|
1816
|
-
function computePipelineFingerprint(config) {
|
|
1842
|
+
function computePipelineFingerprint(config, contentScopeFingerprint) {
|
|
1817
1843
|
const plugins = config.plugins;
|
|
1818
1844
|
const fingerprintData = {
|
|
1819
1845
|
compatibilityVersion: CONTENT_CACHE_COMPATIBILITY_VERSION,
|
|
1820
1846
|
plugins: plugins.map((p) => pluginFingerprint(p)),
|
|
1821
1847
|
content: {
|
|
1822
1848
|
filters: config.content.filters
|
|
1823
|
-
}
|
|
1849
|
+
},
|
|
1850
|
+
contentScopeFingerprint
|
|
1824
1851
|
};
|
|
1825
1852
|
return hash2(stableStringify(fingerprintData));
|
|
1826
1853
|
}
|
|
1854
|
+
function computeContentScopeFingerprint(locations) {
|
|
1855
|
+
return hash2(
|
|
1856
|
+
stableStringify(
|
|
1857
|
+
[...locations.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([slug, location]) => ({
|
|
1858
|
+
slug,
|
|
1859
|
+
permalink: location.permalink,
|
|
1860
|
+
...location.language ? { language: location.language } : {},
|
|
1861
|
+
...location.redirects ? {
|
|
1862
|
+
redirects: location.redirects.map((redirect) => ({
|
|
1863
|
+
...redirect
|
|
1864
|
+
}))
|
|
1865
|
+
} : {},
|
|
1866
|
+
...location.metadata ? { metadata: { ...location.metadata } } : {}
|
|
1867
|
+
}))
|
|
1868
|
+
)
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1827
1871
|
var pluginFingerprints = /* @__PURE__ */ new WeakMap();
|
|
1828
1872
|
function pluginFingerprint(plugin) {
|
|
1829
1873
|
const cached = pluginFingerprints.get(plugin);
|
|
@@ -1859,23 +1903,25 @@ function sanitizeForFingerprint(value) {
|
|
|
1859
1903
|
}
|
|
1860
1904
|
return value;
|
|
1861
1905
|
}
|
|
1862
|
-
function isPersistentlyCacheable(
|
|
1863
|
-
const
|
|
1864
|
-
(p) => p.name === "l10n" && p.enabled !== false
|
|
1865
|
-
);
|
|
1866
|
-
if (hasL10n) {
|
|
1867
|
-
return { cacheable: false, reason: "l10n plugin is enabled" };
|
|
1868
|
-
}
|
|
1906
|
+
function isPersistentlyCacheable(slug, config, source) {
|
|
1907
|
+
const context = source === void 0 ? void 0 : { slug, source };
|
|
1869
1908
|
const unsafePlugin = config.plugins.find((plugin) => {
|
|
1870
1909
|
if (plugin.enabled === false) return false;
|
|
1871
1910
|
if (!canAffectProcessedContent(plugin)) return false;
|
|
1872
|
-
|
|
1911
|
+
const contract = plugin.processedContentCache;
|
|
1912
|
+
if (!contract) return true;
|
|
1913
|
+
if (!context) return contract.dependencyMode === "unsafe";
|
|
1914
|
+
const applicability = getApplicability(contract.appliesToContent, context);
|
|
1915
|
+
if (applicability === "does-not-apply") return false;
|
|
1916
|
+
if (applicability === "unknown") return true;
|
|
1917
|
+
if (contract.dependencyMode === "unsafe") return true;
|
|
1918
|
+
return getContractDependencyFingerprint(contract, context) === void 0;
|
|
1873
1919
|
});
|
|
1874
1920
|
if (unsafePlugin) {
|
|
1875
1921
|
if (unsafePlugin.processedContentCache?.dependencyMode === "unsafe") {
|
|
1876
1922
|
return {
|
|
1877
1923
|
cacheable: false,
|
|
1878
|
-
reason: `plugin ${unsafePlugin.name} explicitly marks processed content cache as unsafe`
|
|
1924
|
+
reason: `plugin ${unsafePlugin.name} explicitly marks processed content cache as unsafe and cannot prove safety for this content`
|
|
1879
1925
|
};
|
|
1880
1926
|
}
|
|
1881
1927
|
return {
|
|
@@ -1885,6 +1931,68 @@ function isPersistentlyCacheable(_slug, config) {
|
|
|
1885
1931
|
}
|
|
1886
1932
|
return { cacheable: true };
|
|
1887
1933
|
}
|
|
1934
|
+
function computeContentCacheFingerprint(slug, source, config) {
|
|
1935
|
+
const context = { slug, source };
|
|
1936
|
+
const plugins = config.plugins.filter(
|
|
1937
|
+
(plugin) => plugin.enabled !== false && canAffectProcessedContent(plugin)
|
|
1938
|
+
).map((plugin) => {
|
|
1939
|
+
const contract = plugin.processedContentCache;
|
|
1940
|
+
if (!contract) return { name: plugin.name, applicability: "unknown" };
|
|
1941
|
+
const applicability = getApplicability(
|
|
1942
|
+
contract.appliesToContent,
|
|
1943
|
+
context
|
|
1944
|
+
);
|
|
1945
|
+
return {
|
|
1946
|
+
name: plugin.name,
|
|
1947
|
+
applicability,
|
|
1948
|
+
dependencyFingerprint: applicability === "applies" ? getContractDependencyFingerprint(contract, context) : void 0
|
|
1949
|
+
};
|
|
1950
|
+
});
|
|
1951
|
+
return hash2(stableStringify(plugins));
|
|
1952
|
+
}
|
|
1953
|
+
function getApplicability(appliesToContent, context) {
|
|
1954
|
+
if (!context) return "unknown";
|
|
1955
|
+
if (!appliesToContent) return "applies";
|
|
1956
|
+
try {
|
|
1957
|
+
const applicability = appliesToContent(context);
|
|
1958
|
+
return applicability === "applies" || applicability === "does-not-apply" || applicability === "unknown" ? applicability : "unknown";
|
|
1959
|
+
} catch {
|
|
1960
|
+
return "unknown";
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
function getContractDependencyFingerprint(contract, context) {
|
|
1964
|
+
if (!context) return void 0;
|
|
1965
|
+
try {
|
|
1966
|
+
const content = contract.contentDependencyFingerprint?.(context);
|
|
1967
|
+
if (contract.contentDependencyFingerprint && content === void 0)
|
|
1968
|
+
return void 0;
|
|
1969
|
+
const environment = contract.environmentFingerprint?.();
|
|
1970
|
+
if (contract.environmentFingerprint && environment === void 0)
|
|
1971
|
+
return void 0;
|
|
1972
|
+
return hash2(
|
|
1973
|
+
stableStringify({
|
|
1974
|
+
content: content ?? null,
|
|
1975
|
+
environment: environment ?? null
|
|
1976
|
+
})
|
|
1977
|
+
);
|
|
1978
|
+
} catch {
|
|
1979
|
+
return void 0;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
function hasGlobalContentDependency(config) {
|
|
1983
|
+
return config.plugins.some(
|
|
1984
|
+
(plugin) => plugin.enabled !== false && canAffectProcessedContent(plugin) && plugin.processedContentCache?.dependencyMode === "global"
|
|
1985
|
+
);
|
|
1986
|
+
}
|
|
1987
|
+
function requiresFullContentRegeneration(config) {
|
|
1988
|
+
return config.plugins.some((plugin) => {
|
|
1989
|
+
if (plugin.enabled === false || !canAffectProcessedContent(plugin)) {
|
|
1990
|
+
return false;
|
|
1991
|
+
}
|
|
1992
|
+
const contract = plugin.processedContentCache;
|
|
1993
|
+
return !contract || contract.dependencyMode === "unsafe" && !contract.appliesToContent;
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1888
1996
|
function canAffectProcessedContent(plugin) {
|
|
1889
1997
|
return Boolean(
|
|
1890
1998
|
plugin.remarkPlugins?.length || plugin.rehypePlugins?.length || plugin.extendMarkdownPipeline || plugin.extendHtmlPipeline || plugin.renderers?.length || plugin.onContentLoaded || plugin.onPostParsed || plugin.onPostProcessed
|
|
@@ -1896,6 +2004,117 @@ function extractFrontmatter(markdown) {
|
|
|
1896
2004
|
return vfile.data.matter ?? {};
|
|
1897
2005
|
}
|
|
1898
2006
|
|
|
2007
|
+
// src/content/markdown_image.ts
|
|
2008
|
+
import remarkParse from "remark-parse";
|
|
2009
|
+
import { unified } from "unified";
|
|
2010
|
+
function extractMarkdownImages(markdown, sourceSlug) {
|
|
2011
|
+
const tree = unified().use(remarkParse).parse(markdown);
|
|
2012
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2013
|
+
const references = [];
|
|
2014
|
+
const urls = [];
|
|
2015
|
+
visitMarkdownNodes(tree, (node) => {
|
|
2016
|
+
if (node.type === "definition" && typeof node.url === "string") {
|
|
2017
|
+
const identifier = normalizeIdentifier(node.identifier);
|
|
2018
|
+
if (identifier) definitions.set(identifier, node.url);
|
|
2019
|
+
}
|
|
2020
|
+
if (node.type === "image" && typeof node.url === "string") {
|
|
2021
|
+
urls.push(node.url);
|
|
2022
|
+
}
|
|
2023
|
+
if (node.type === "imageReference") {
|
|
2024
|
+
const identifier = normalizeIdentifier(node.identifier);
|
|
2025
|
+
if (identifier) references.push(identifier);
|
|
2026
|
+
}
|
|
2027
|
+
});
|
|
2028
|
+
for (const reference of references) {
|
|
2029
|
+
const url = definitions.get(reference);
|
|
2030
|
+
if (url) urls.push(url);
|
|
2031
|
+
}
|
|
2032
|
+
return uniqueImages(
|
|
2033
|
+
urls.map((url) => resolveMarkdownImage(url, sourceSlug)).filter((image) => image !== null)
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
function normalizeMarkdownImages(sourceSlug) {
|
|
2037
|
+
return () => (tree) => {
|
|
2038
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
2039
|
+
const references = /* @__PURE__ */ new Set();
|
|
2040
|
+
visitMarkdownNodes(tree, (node) => {
|
|
2041
|
+
if (node.type === "definition" && typeof node.url === "string") {
|
|
2042
|
+
const identifier = normalizeIdentifier(node.identifier);
|
|
2043
|
+
if (identifier) definitions.set(identifier, node);
|
|
2044
|
+
}
|
|
2045
|
+
if (node.type === "image" && typeof node.url === "string") {
|
|
2046
|
+
const image = resolveMarkdownImage(node.url, sourceSlug);
|
|
2047
|
+
if (image) node.url = image.url;
|
|
2048
|
+
}
|
|
2049
|
+
if (node.type === "imageReference") {
|
|
2050
|
+
const identifier = normalizeIdentifier(node.identifier);
|
|
2051
|
+
if (identifier) references.add(identifier);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
2054
|
+
for (const identifier of references) {
|
|
2055
|
+
const definition = definitions.get(identifier);
|
|
2056
|
+
if (!definition || typeof definition.url !== "string") continue;
|
|
2057
|
+
const image = resolveMarkdownImage(definition.url, sourceSlug);
|
|
2058
|
+
if (image) definition.url = image.url;
|
|
2059
|
+
}
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2062
|
+
function resolveMarkdownImage(input, sourceSlug) {
|
|
2063
|
+
if (input.startsWith("//") || /^[a-z][a-z0-9+.-]*:/i.test(input)) {
|
|
2064
|
+
return null;
|
|
2065
|
+
}
|
|
2066
|
+
const [pathAndQuery, hash4 = ""] = splitOnce(input, "#");
|
|
2067
|
+
const [rawPath, query = ""] = splitOnce(pathAndQuery, "?");
|
|
2068
|
+
const decodedPath = decodeUriPath(rawPath);
|
|
2069
|
+
if (!decodedPath || !isImagePath(decodedPath)) return null;
|
|
2070
|
+
const path6 = resolveContentAssetPath(sourceSlug, decodedPath);
|
|
2071
|
+
if (!path6) return null;
|
|
2072
|
+
const encodedPath = path6.split("/").map(encodeURIComponent).join("/");
|
|
2073
|
+
const suffix = `${query ? `?${query}` : ""}${hash4 ? `#${hash4}` : ""}`;
|
|
2074
|
+
return { path: path6, url: `/${encodedPath}${suffix}` };
|
|
2075
|
+
}
|
|
2076
|
+
function resolveContentAssetPath(sourceSlug, targetPath) {
|
|
2077
|
+
const sourceDirectory = sourceSlug.includes("/") ? sourceSlug.slice(0, sourceSlug.lastIndexOf("/")) : "";
|
|
2078
|
+
const parts = [
|
|
2079
|
+
...targetPath.startsWith("/") ? [] : sourceDirectory.split("/"),
|
|
2080
|
+
...normalizeContentPath(targetPath).replace(/^\/+/, "").split("/")
|
|
2081
|
+
];
|
|
2082
|
+
const normalized = [];
|
|
2083
|
+
for (const part of parts) {
|
|
2084
|
+
if (!part || part === ".") continue;
|
|
2085
|
+
if (part === "..") {
|
|
2086
|
+
if (normalized.length === 0) return null;
|
|
2087
|
+
normalized.pop();
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
2090
|
+
normalized.push(part);
|
|
2091
|
+
}
|
|
2092
|
+
return normalized.length > 0 ? normalized.join("/").normalize("NFC") : null;
|
|
2093
|
+
}
|
|
2094
|
+
function visitMarkdownNodes(node, visitor) {
|
|
2095
|
+
const markdownNode = node;
|
|
2096
|
+
visitor(markdownNode);
|
|
2097
|
+
for (const child of markdownNode.children ?? [])
|
|
2098
|
+
visitMarkdownNodes(child, visitor);
|
|
2099
|
+
}
|
|
2100
|
+
function normalizeIdentifier(value) {
|
|
2101
|
+
return typeof value === "string" ? value.toLowerCase() : null;
|
|
2102
|
+
}
|
|
2103
|
+
function decodeUriPath(path6) {
|
|
2104
|
+
try {
|
|
2105
|
+
return decodeURI(path6);
|
|
2106
|
+
} catch {
|
|
2107
|
+
return null;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
function splitOnce(value, separator) {
|
|
2111
|
+
const index = value.indexOf(separator);
|
|
2112
|
+
return index < 0 ? [value] : [value.slice(0, index), value.slice(index + 1)];
|
|
2113
|
+
}
|
|
2114
|
+
function uniqueImages(images) {
|
|
2115
|
+
return [...new Map(images.map((image) => [image.path, image])).values()];
|
|
2116
|
+
}
|
|
2117
|
+
|
|
1899
2118
|
// src/plugin/plugin_cache.ts
|
|
1900
2119
|
import { createHash as createHash5, randomUUID as randomUUID2 } from "node:crypto";
|
|
1901
2120
|
import fs3 from "node:fs/promises";
|
|
@@ -2086,7 +2305,8 @@ var Pipeline = class {
|
|
|
2086
2305
|
tracer: this.options.observability?.tracer
|
|
2087
2306
|
});
|
|
2088
2307
|
this.pipelineFingerprint = computePipelineFingerprint(
|
|
2089
|
-
this.options.config
|
|
2308
|
+
this.options.config,
|
|
2309
|
+
this.options.contentScopeFingerprint
|
|
2090
2310
|
);
|
|
2091
2311
|
}
|
|
2092
2312
|
}
|
|
@@ -2113,9 +2333,11 @@ var Pipeline = class {
|
|
|
2113
2333
|
const effectiveContentSource = dependencyTracker ? dependencyTracker.contentSource : this.options.contentSource;
|
|
2114
2334
|
const sourceSlug = context.sourceSlug;
|
|
2115
2335
|
if (embedDepth === 0 && this.persistentCache && this.pipelineFingerprint && sourceSlug && this.options.contentSource && this.options.config) {
|
|
2336
|
+
const persistentCache = this.persistentCache;
|
|
2116
2337
|
const cacheable = isPersistentlyCacheable(
|
|
2117
2338
|
sourceSlug,
|
|
2118
|
-
this.options.config
|
|
2339
|
+
this.options.config,
|
|
2340
|
+
markDownContent
|
|
2119
2341
|
);
|
|
2120
2342
|
if (cacheable.cacheable) {
|
|
2121
2343
|
const frontmatter = extractFrontmatter(markDownContent);
|
|
@@ -2123,12 +2345,21 @@ var Pipeline = class {
|
|
|
2123
2345
|
slug: sourceSlug,
|
|
2124
2346
|
source: markDownContent,
|
|
2125
2347
|
frontmatter,
|
|
2126
|
-
pipelineFingerprint: this.
|
|
2348
|
+
pipelineFingerprint: this.contentPipelineFingerprint(
|
|
2349
|
+
sourceSlug,
|
|
2350
|
+
markDownContent
|
|
2351
|
+
)
|
|
2127
2352
|
});
|
|
2128
|
-
const lookup = await this.
|
|
2353
|
+
const lookup = await (this.options.observability ?? noopObservability).tracer.span(
|
|
2354
|
+
"persistentContentCache.lookup",
|
|
2355
|
+
{},
|
|
2356
|
+
() => persistentCache.lookup(cacheKey)
|
|
2357
|
+
);
|
|
2129
2358
|
if (lookup.status === "hit") {
|
|
2130
|
-
const invalidDependency = await this.
|
|
2131
|
-
|
|
2359
|
+
const invalidDependency = await (this.options.observability ?? noopObservability).tracer.span(
|
|
2360
|
+
"persistentContentCache.validation",
|
|
2361
|
+
{ dependencyCount: lookup.entry.dependencies.length },
|
|
2362
|
+
() => this.findInvalidDependency(lookup.entry.dependencies)
|
|
2132
2363
|
);
|
|
2133
2364
|
if (!invalidDependency) {
|
|
2134
2365
|
this.reportContentDependencies(
|
|
@@ -2178,9 +2409,9 @@ var Pipeline = class {
|
|
|
2178
2409
|
this.options.onPersistentContentCacheResult?.("bypass");
|
|
2179
2410
|
}
|
|
2180
2411
|
}
|
|
2181
|
-
const processor =
|
|
2412
|
+
const processor = unified2();
|
|
2182
2413
|
const plugins = this.resolvePlugins();
|
|
2183
|
-
this.use(processor,
|
|
2414
|
+
this.use(processor, remarkParse2);
|
|
2184
2415
|
this.use(processor, remarkDirective);
|
|
2185
2416
|
this.use(processor, remarkFrontmatter, ["yaml", "toml"]);
|
|
2186
2417
|
this.use(processor, function loadFrontmatter() {
|
|
@@ -2220,6 +2451,9 @@ var Pipeline = class {
|
|
|
2220
2451
|
...markdownPipelineContext,
|
|
2221
2452
|
recordLinkResolution: dependencyTracker ? (id, value) => dependencyTracker.recordLinkResolution(id, value) : void 0
|
|
2222
2453
|
});
|
|
2454
|
+
if (context.sourceSlug) {
|
|
2455
|
+
this.use(processor, normalizeMarkdownImages(context.sourceSlug));
|
|
2456
|
+
}
|
|
2223
2457
|
this.use(processor, remarkRehype, { allowDangerousHtml: true });
|
|
2224
2458
|
this.use(processor, rehypeRaw);
|
|
2225
2459
|
for (const plugin of plugins) {
|
|
@@ -2236,7 +2470,11 @@ var Pipeline = class {
|
|
|
2236
2470
|
this.use(processor, rehypeKatex, { output: "mathml", strict: false });
|
|
2237
2471
|
this.use(processor, rehypeFormat);
|
|
2238
2472
|
this.use(processor, rehypeStringify, { allowDangerousHtml: true });
|
|
2239
|
-
const file = await
|
|
2473
|
+
const file = await (this.options.observability ?? noopObservability).tracer.span(
|
|
2474
|
+
"content.markdown",
|
|
2475
|
+
{ embedded: embedDepth > 0 },
|
|
2476
|
+
async () => await processor.process(markDownContent.trim())
|
|
2477
|
+
);
|
|
2240
2478
|
const result = {
|
|
2241
2479
|
frontmatter: file.data.matter || {},
|
|
2242
2480
|
html: String(file.value)
|
|
@@ -2253,7 +2491,8 @@ var Pipeline = class {
|
|
|
2253
2491
|
if (embedDepth === 0 && this.persistentCache && this.pipelineFingerprint && sourceSlug && dependencyTracker && this.options.config) {
|
|
2254
2492
|
const cacheable = isPersistentlyCacheable(
|
|
2255
2493
|
sourceSlug,
|
|
2256
|
-
this.options.config
|
|
2494
|
+
this.options.config,
|
|
2495
|
+
markDownContent
|
|
2257
2496
|
);
|
|
2258
2497
|
if (cacheable.cacheable) {
|
|
2259
2498
|
const frontmatter = extractFrontmatter(markDownContent);
|
|
@@ -2261,7 +2500,10 @@ var Pipeline = class {
|
|
|
2261
2500
|
slug: sourceSlug,
|
|
2262
2501
|
source: markDownContent,
|
|
2263
2502
|
frontmatter,
|
|
2264
|
-
pipelineFingerprint: this.
|
|
2503
|
+
pipelineFingerprint: this.contentPipelineFingerprint(
|
|
2504
|
+
sourceSlug,
|
|
2505
|
+
markDownContent
|
|
2506
|
+
)
|
|
2265
2507
|
});
|
|
2266
2508
|
const dependencies = dependencyTracker.dependencies();
|
|
2267
2509
|
const entry = {
|
|
@@ -2278,6 +2520,11 @@ var Pipeline = class {
|
|
|
2278
2520
|
reportContentDependencies(slug, dependencies) {
|
|
2279
2521
|
this.options.onContentDependencies?.(slug, dependencies);
|
|
2280
2522
|
}
|
|
2523
|
+
contentPipelineFingerprint(slug, source) {
|
|
2524
|
+
const config = this.options.config;
|
|
2525
|
+
if (!config || !this.pipelineFingerprint) return "";
|
|
2526
|
+
return `${this.pipelineFingerprint}:${computeContentCacheFingerprint(slug, source, config)}`;
|
|
2527
|
+
}
|
|
2281
2528
|
async findInvalidDependency(dependencies) {
|
|
2282
2529
|
const contentSource = this.options.contentSource;
|
|
2283
2530
|
if (!contentSource) return null;
|
|
@@ -2464,9 +2711,9 @@ function visitMarkdownLinkNodes(node, visitor) {
|
|
|
2464
2711
|
function normalizeMarkdownLinkUrl(url, context) {
|
|
2465
2712
|
if (!context.sourceSlug) return null;
|
|
2466
2713
|
if (!isMarkdownContentLink(url)) return null;
|
|
2467
|
-
const [pathAndQuery, hash4 = ""] =
|
|
2468
|
-
const [rawPath, query = ""] =
|
|
2469
|
-
const decodedPath =
|
|
2714
|
+
const [pathAndQuery, hash4 = ""] = splitOnce2(url, "#");
|
|
2715
|
+
const [rawPath, query = ""] = splitOnce2(pathAndQuery, "?");
|
|
2716
|
+
const decodedPath = decodeUriPath2(rawPath);
|
|
2470
2717
|
if (!decodedPath?.toLowerCase().endsWith(".md")) return null;
|
|
2471
2718
|
const resolvedSlug = resolveRelativeMarkdownSlug(
|
|
2472
2719
|
context.sourceSlug,
|
|
@@ -2527,14 +2774,14 @@ function resolveRelativeMarkdownSlug(sourceSlug, targetPath) {
|
|
|
2527
2774
|
}
|
|
2528
2775
|
return normalizedParts.join("/").replace(/\.md$/i, "");
|
|
2529
2776
|
}
|
|
2530
|
-
function
|
|
2777
|
+
function decodeUriPath2(path6) {
|
|
2531
2778
|
try {
|
|
2532
2779
|
return decodeURI(path6);
|
|
2533
2780
|
} catch {
|
|
2534
2781
|
return null;
|
|
2535
2782
|
}
|
|
2536
2783
|
}
|
|
2537
|
-
function
|
|
2784
|
+
function splitOnce2(value, separator) {
|
|
2538
2785
|
const index = value.indexOf(separator);
|
|
2539
2786
|
if (index < 0) return [value];
|
|
2540
2787
|
return [value.slice(0, index), value.slice(index + separator.length)];
|
|
@@ -2563,18 +2810,141 @@ function escapeRegExp(value) {
|
|
|
2563
2810
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2564
2811
|
}
|
|
2565
2812
|
|
|
2813
|
+
// src/content/manifest_hook_cache.ts
|
|
2814
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
2815
|
+
function fingerprintManifestHookInput(manifest) {
|
|
2816
|
+
return fingerprintManifest(manifestFingerprintValue(manifest));
|
|
2817
|
+
}
|
|
2818
|
+
function createManifestHookCacheEntry(pluginName, cacheable, pipelineFingerprint, inputFingerprint, manifest) {
|
|
2819
|
+
const snapshot = {
|
|
2820
|
+
entries: JSON.parse(
|
|
2821
|
+
JSON.stringify(manifest.entries)
|
|
2822
|
+
)
|
|
2823
|
+
};
|
|
2824
|
+
return {
|
|
2825
|
+
pluginName,
|
|
2826
|
+
cacheable,
|
|
2827
|
+
pipelineFingerprint,
|
|
2828
|
+
inputFingerprint,
|
|
2829
|
+
outputFingerprint: fingerprintManifestHookSnapshot(snapshot, manifest),
|
|
2830
|
+
snapshot
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
function fingerprintManifestHookSideEffects(manifest) {
|
|
2834
|
+
const value = {
|
|
2835
|
+
...manifest,
|
|
2836
|
+
entries: []
|
|
2837
|
+
};
|
|
2838
|
+
return fingerprintManifest(manifestFingerprintValue(value));
|
|
2839
|
+
}
|
|
2840
|
+
function fingerprintManifestHookSnapshot(snapshot, manifest) {
|
|
2841
|
+
return fingerprintManifest(
|
|
2842
|
+
manifestFingerprintValue({
|
|
2843
|
+
...manifest,
|
|
2844
|
+
entries: [...snapshot.entries]
|
|
2845
|
+
})
|
|
2846
|
+
);
|
|
2847
|
+
}
|
|
2848
|
+
function applyManifestHookSnapshot(manifest, snapshot) {
|
|
2849
|
+
try {
|
|
2850
|
+
const entries = structuredClone(snapshot.entries);
|
|
2851
|
+
if (!entries.every(isManifestEntry)) return false;
|
|
2852
|
+
const entriesBySlug = new Map(entries.map((entry) => [entry.slug, entry]));
|
|
2853
|
+
if (entriesBySlug.size !== entries.length) return false;
|
|
2854
|
+
manifest.entries = entries;
|
|
2855
|
+
manifest.publicEntries = manifest.publicEntries.map((entry) => entriesBySlug.get(entry.slug)).filter((entry) => entry !== void 0);
|
|
2856
|
+
manifest.discoverableEntries = manifest.discoverableEntries.map((entry) => entriesBySlug.get(entry.slug)).filter((entry) => entry !== void 0);
|
|
2857
|
+
manifest.bySlug = new Map(entries.map((entry) => [entry.slug, entry]));
|
|
2858
|
+
manifest.byContentId = new Map(
|
|
2859
|
+
entries.filter((entry) => entry.contentId !== void 0).map((entry) => [entry.contentId, entry])
|
|
2860
|
+
);
|
|
2861
|
+
manifest.byPermalink = new Map(
|
|
2862
|
+
entries.map((entry) => [entry.permalink, entry])
|
|
2863
|
+
);
|
|
2864
|
+
manifest.byRoutablePermalink = new Map(
|
|
2865
|
+
manifest.publicEntries.map((entry) => [entry.permalink, entry])
|
|
2866
|
+
);
|
|
2867
|
+
manifest.byAlias = /* @__PURE__ */ new Map();
|
|
2868
|
+
manifest.byTag = /* @__PURE__ */ new Map();
|
|
2869
|
+
manifest.byAsset = /* @__PURE__ */ new Map();
|
|
2870
|
+
manifest.outgoingLinks = /* @__PURE__ */ new Map();
|
|
2871
|
+
manifest.incomingLinks = /* @__PURE__ */ new Map();
|
|
2872
|
+
for (const entry of entries) {
|
|
2873
|
+
manifest.outgoingLinks.set(entry.slug, entry.links);
|
|
2874
|
+
for (const alias of entry.aliases ?? []) {
|
|
2875
|
+
const aliases = manifest.byAlias.get(alias.toLowerCase()) ?? [];
|
|
2876
|
+
aliases.push(entry);
|
|
2877
|
+
manifest.byAlias.set(alias.toLowerCase(), aliases);
|
|
2878
|
+
}
|
|
2879
|
+
for (const tag of entry.tags) {
|
|
2880
|
+
const tagged = manifest.byTag.get(tag) ?? [];
|
|
2881
|
+
tagged.push(entry);
|
|
2882
|
+
manifest.byTag.set(tag, tagged);
|
|
2883
|
+
}
|
|
2884
|
+
for (const asset of entry.assets) {
|
|
2885
|
+
const assets = manifest.byAsset.get(asset.path) ?? [];
|
|
2886
|
+
assets.push(entry);
|
|
2887
|
+
manifest.byAsset.set(asset.path, assets);
|
|
2888
|
+
}
|
|
2889
|
+
for (const link of entry.links) {
|
|
2890
|
+
if (link.kind !== "note" || link.slug === null || link.slug === entry.slug)
|
|
2891
|
+
continue;
|
|
2892
|
+
const incoming = manifest.incomingLinks.get(link.slug) ?? [];
|
|
2893
|
+
if (!incoming.includes(entry.slug)) incoming.push(entry.slug);
|
|
2894
|
+
manifest.incomingLinks.set(link.slug, incoming);
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
for (const entry of entries)
|
|
2898
|
+
entry.backlinks = manifest.incomingLinks.get(entry.slug) ?? [];
|
|
2899
|
+
return true;
|
|
2900
|
+
} catch {
|
|
2901
|
+
return false;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
function manifestFingerprintValue(manifest) {
|
|
2905
|
+
return {
|
|
2906
|
+
entries: manifest.entries,
|
|
2907
|
+
publicEntries: manifest.publicEntries.map((entry) => entry.slug),
|
|
2908
|
+
discoverableEntries: manifest.discoverableEntries.map(
|
|
2909
|
+
(entry) => entry.slug
|
|
2910
|
+
),
|
|
2911
|
+
redirects: [...manifest.redirects.entries()].sort(
|
|
2912
|
+
([left], [right]) => left.localeCompare(right)
|
|
2913
|
+
),
|
|
2914
|
+
publicRedirects: [...manifest.publicRedirects.entries()].sort(
|
|
2915
|
+
([left], [right]) => left.localeCompare(right)
|
|
2916
|
+
),
|
|
2917
|
+
assets: manifest.assets,
|
|
2918
|
+
clientEntries: manifest.clientEntries,
|
|
2919
|
+
diagnostics: manifest.diagnostics,
|
|
2920
|
+
generatedOutputs: manifest.generatedOutputs,
|
|
2921
|
+
folderLocations: [...manifest.folderLocations.entries()].sort(
|
|
2922
|
+
([left], [right]) => left.localeCompare(right)
|
|
2923
|
+
),
|
|
2924
|
+
pageRoutes: manifest.pageRoutes,
|
|
2925
|
+
pagePaths: manifest.pagePaths
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
function fingerprintManifest(value) {
|
|
2929
|
+
const normalized = JSON.parse(JSON.stringify(value));
|
|
2930
|
+
return createHash6("sha256").update(stableStringify(normalized)).digest("hex");
|
|
2931
|
+
}
|
|
2932
|
+
function isManifestEntry(value) {
|
|
2933
|
+
return typeof value === "object" && value !== null && typeof value.slug === "string" && typeof value.html === "string";
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2566
2936
|
// src/types/plugin_asset.ts
|
|
2567
|
-
function createStyleAsset(pluginName) {
|
|
2937
|
+
function createStyleAsset(pluginName, moduleSpecifier) {
|
|
2568
2938
|
return {
|
|
2569
2939
|
pluginName,
|
|
2570
2940
|
kind: "style",
|
|
2571
|
-
moduleSpecifier
|
|
2941
|
+
moduleSpecifier
|
|
2572
2942
|
};
|
|
2573
2943
|
}
|
|
2574
|
-
function createClientEntry(pluginName, exportName, publicConfig) {
|
|
2944
|
+
function createClientEntry(pluginName, moduleSpecifier, exportName, publicConfig) {
|
|
2575
2945
|
return {
|
|
2576
2946
|
pluginName,
|
|
2577
|
-
moduleSpecifier
|
|
2947
|
+
moduleSpecifier,
|
|
2578
2948
|
...exportName === void 0 ? {} : { exportName },
|
|
2579
2949
|
...publicConfig === void 0 ? {} : { publicConfig }
|
|
2580
2950
|
};
|
|
@@ -2646,6 +3016,9 @@ var GeneratedOutputRegistry = class {
|
|
|
2646
3016
|
(a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0
|
|
2647
3017
|
);
|
|
2648
3018
|
}
|
|
3019
|
+
count() {
|
|
3020
|
+
return this.outputs.length;
|
|
3021
|
+
}
|
|
2649
3022
|
};
|
|
2650
3023
|
|
|
2651
3024
|
// src/plugin/plugin_lifecycle.ts
|
|
@@ -2727,12 +3100,46 @@ var PluginRuntime = class {
|
|
|
2727
3100
|
isBuildTime = false;
|
|
2728
3101
|
resolvedPlugins = null;
|
|
2729
3102
|
pageDeclarations = /* @__PURE__ */ new WeakMap();
|
|
3103
|
+
externalDependencies = /* @__PURE__ */ new Map();
|
|
3104
|
+
externalDependencyFailures = [];
|
|
3105
|
+
externalDependenciesResolved = false;
|
|
3106
|
+
manifestHooksExecuted = 0;
|
|
3107
|
+
manifestHookDurationMs = 0;
|
|
3108
|
+
manifestHooksReused = 0;
|
|
3109
|
+
manifestHookCache = [];
|
|
3110
|
+
manifestHookMetricsByPlugin = /* @__PURE__ */ new Map();
|
|
2730
3111
|
getDiagnostics() {
|
|
2731
3112
|
return this.diagnostics;
|
|
2732
3113
|
}
|
|
2733
3114
|
getBuildStage() {
|
|
2734
3115
|
return this.buildStage;
|
|
2735
3116
|
}
|
|
3117
|
+
getManifestHookMetrics() {
|
|
3118
|
+
return {
|
|
3119
|
+
manifestHooksExecuted: this.manifestHooksExecuted,
|
|
3120
|
+
manifestHooksReused: this.manifestHooksReused,
|
|
3121
|
+
manifestHookCacheHit: this.manifestHooksReused,
|
|
3122
|
+
manifestHookCacheMiss: this.manifestHooksExecuted,
|
|
3123
|
+
manifestHookDurationMs: this.manifestHookDurationMs,
|
|
3124
|
+
byPlugin: Object.fromEntries(this.manifestHookMetricsByPlugin)
|
|
3125
|
+
};
|
|
3126
|
+
}
|
|
3127
|
+
getNoChangeFastPathBlockReason(previousCache, pipelineFingerprint) {
|
|
3128
|
+
let cacheIndex = 0;
|
|
3129
|
+
for (const plugin of this.plugins()) {
|
|
3130
|
+
if (plugin.buildEnd) return "plugin-build-end";
|
|
3131
|
+
if (plugin.planGeneratedOutputs) return "plugin-generated-output-plan";
|
|
3132
|
+
if (!plugin.onManifestCreated) continue;
|
|
3133
|
+
const cached = previousCache[cacheIndex];
|
|
3134
|
+
cacheIndex += 1;
|
|
3135
|
+
if (cached?.pluginName !== plugin.name || !cached.cacheable || cached.pipelineFingerprint !== pipelineFingerprint)
|
|
3136
|
+
return "manifest-hook-cache-miss";
|
|
3137
|
+
}
|
|
3138
|
+
return void 0;
|
|
3139
|
+
}
|
|
3140
|
+
getManifestHookCache() {
|
|
3141
|
+
return this.manifestHookCache;
|
|
3142
|
+
}
|
|
2736
3143
|
/**
|
|
2737
3144
|
* Starts the plugin build lifecycle exactly once, regardless of which public
|
|
2738
3145
|
* entry point (content processing or location resolution) reaches it first.
|
|
@@ -2751,6 +3158,43 @@ var PluginRuntime = class {
|
|
|
2751
3158
|
markdown
|
|
2752
3159
|
});
|
|
2753
3160
|
}
|
|
3161
|
+
async resolveExternalDependencies(contentIndex) {
|
|
3162
|
+
if (this.externalDependenciesResolved) {
|
|
3163
|
+
return {
|
|
3164
|
+
snapshots: [...this.externalDependencies.values()],
|
|
3165
|
+
failures: this.externalDependencyFailures
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
await this.startBuild(contentIndex);
|
|
3169
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
3170
|
+
const failures = [];
|
|
3171
|
+
for (const plugin of this.plugins()) {
|
|
3172
|
+
const resolve = plugin.resolveExternalDependencies;
|
|
3173
|
+
if (!resolve) continue;
|
|
3174
|
+
const results = await resolve({
|
|
3175
|
+
config: this.pipelineOptions.config,
|
|
3176
|
+
contentIndex,
|
|
3177
|
+
cache: this.cacheFor(plugin)
|
|
3178
|
+
});
|
|
3179
|
+
for (const result of results) {
|
|
3180
|
+
if (result.kind === "unavailable") {
|
|
3181
|
+
failures.push(result.failure);
|
|
3182
|
+
continue;
|
|
3183
|
+
}
|
|
3184
|
+
const snapshot = result.snapshot;
|
|
3185
|
+
if (snapshots.has(snapshot.id)) {
|
|
3186
|
+
throw new Error(
|
|
3187
|
+
`External dependency ID "${snapshot.id}" is declared more than once.`
|
|
3188
|
+
);
|
|
3189
|
+
}
|
|
3190
|
+
snapshots.set(snapshot.id, snapshot);
|
|
3191
|
+
}
|
|
3192
|
+
}
|
|
3193
|
+
this.externalDependencies = snapshots;
|
|
3194
|
+
this.externalDependencyFailures = failures;
|
|
3195
|
+
this.externalDependenciesResolved = true;
|
|
3196
|
+
return { snapshots: [...snapshots.values()], failures };
|
|
3197
|
+
}
|
|
2754
3198
|
async resolveContentLocations(entries, contentIndex) {
|
|
2755
3199
|
const context = { ...this.createContext(contentIndex), entries };
|
|
2756
3200
|
const locations = [];
|
|
@@ -2797,15 +3241,86 @@ var PluginRuntime = class {
|
|
|
2797
3241
|
}
|
|
2798
3242
|
);
|
|
2799
3243
|
}
|
|
2800
|
-
async runManifestCreated(manifest, contentIndex) {
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
3244
|
+
async runManifestCreated(manifest, contentIndex, previousCache = [], pipelineFingerprint) {
|
|
3245
|
+
const context = { ...this.createContext(contentIndex), manifest };
|
|
3246
|
+
let cacheIndex = 0;
|
|
3247
|
+
for (const plugin of this.plugins()) {
|
|
3248
|
+
const hook = plugin.onManifestCreated;
|
|
3249
|
+
if (!hook) continue;
|
|
3250
|
+
const inputFingerprint = fingerprintManifestHookInput(manifest);
|
|
3251
|
+
const cached = previousCache[cacheIndex];
|
|
3252
|
+
cacheIndex += 1;
|
|
3253
|
+
const reason = manifestHookCacheMissReason(
|
|
3254
|
+
cached,
|
|
3255
|
+
plugin.name,
|
|
3256
|
+
pipelineFingerprint,
|
|
3257
|
+
inputFingerprint
|
|
3258
|
+
);
|
|
3259
|
+
const canRestore = cached?.pluginName === plugin.name && cached.cacheable && cached.pipelineFingerprint === pipelineFingerprint && cached.inputFingerprint === inputFingerprint;
|
|
3260
|
+
const manifestBeforeRestore = canRestore ? {
|
|
3261
|
+
entries: structuredClone(manifest.entries)
|
|
3262
|
+
} : void 0;
|
|
3263
|
+
const restored = canRestore && applyManifestHookSnapshot(manifest, cached.snapshot);
|
|
3264
|
+
const cacheHit = restored && fingerprintManifestHookSnapshot(cached.snapshot, manifest) === cached.outputFingerprint;
|
|
3265
|
+
if (cacheHit) {
|
|
3266
|
+
this.manifestHooksReused += 1;
|
|
3267
|
+
this.manifestHookCache.push(cached);
|
|
3268
|
+
this.recordManifestHookMetric(plugin.name, "reused", "cache-hit", 0);
|
|
3269
|
+
continue;
|
|
2807
3270
|
}
|
|
2808
|
-
|
|
3271
|
+
if (restored && manifestBeforeRestore)
|
|
3272
|
+
applyManifestHookSnapshot(manifest, manifestBeforeRestore);
|
|
3273
|
+
const sideEffectsBefore = fingerprintManifestHookSideEffects(manifest);
|
|
3274
|
+
const outputCountBefore = this.generatedOutputs.count();
|
|
3275
|
+
const diagnosticCountBefore = this.diagnostics.length;
|
|
3276
|
+
const manifestDiagnosticCountBefore = manifest.diagnostics.length;
|
|
3277
|
+
const started = performance.now();
|
|
3278
|
+
this.manifestHooksExecuted += 1;
|
|
3279
|
+
try {
|
|
3280
|
+
await runPluginHook(
|
|
3281
|
+
plugin,
|
|
3282
|
+
"onManifestCreated",
|
|
3283
|
+
this.createPluginContext(plugin, context),
|
|
3284
|
+
hook
|
|
3285
|
+
);
|
|
3286
|
+
} finally {
|
|
3287
|
+
const durationMs = performance.now() - started;
|
|
3288
|
+
this.manifestHookDurationMs += durationMs;
|
|
3289
|
+
this.recordManifestHookMetric(
|
|
3290
|
+
plugin.name,
|
|
3291
|
+
"executed",
|
|
3292
|
+
reason,
|
|
3293
|
+
durationMs
|
|
3294
|
+
);
|
|
3295
|
+
}
|
|
3296
|
+
this.manifestHookCache.push(
|
|
3297
|
+
createManifestHookCacheEntry(
|
|
3298
|
+
plugin.name,
|
|
3299
|
+
plugin.resolveExternalDependencies === void 0 && sideEffectsBefore === fingerprintManifestHookSideEffects(manifest) && outputCountBefore === this.generatedOutputs.count() && diagnosticCountBefore === this.diagnostics.length && manifestDiagnosticCountBefore === manifest.diagnostics.length,
|
|
3300
|
+
pipelineFingerprint,
|
|
3301
|
+
inputFingerprint,
|
|
3302
|
+
manifest
|
|
3303
|
+
)
|
|
3304
|
+
);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
recordManifestHookMetric(pluginName, outcome, reason, durationMs) {
|
|
3308
|
+
const previous = this.manifestHookMetricsByPlugin.get(pluginName) ?? {
|
|
3309
|
+
executed: 0,
|
|
3310
|
+
reused: 0,
|
|
3311
|
+
cacheHit: 0,
|
|
3312
|
+
cacheMiss: 0,
|
|
3313
|
+
durationMs: 0,
|
|
3314
|
+
reason
|
|
3315
|
+
};
|
|
3316
|
+
this.manifestHookMetricsByPlugin.set(pluginName, {
|
|
3317
|
+
executed: previous.executed + (outcome === "executed" ? 1 : 0),
|
|
3318
|
+
reused: previous.reused + (outcome === "reused" ? 1 : 0),
|
|
3319
|
+
cacheHit: previous.cacheHit + (outcome === "reused" ? 1 : 0),
|
|
3320
|
+
cacheMiss: previous.cacheMiss + (outcome === "executed" ? 1 : 0),
|
|
3321
|
+
durationMs: previous.durationMs + durationMs,
|
|
3322
|
+
reason
|
|
3323
|
+
});
|
|
2809
3324
|
}
|
|
2810
3325
|
async runBuildEnd(manifest, contentIndex) {
|
|
2811
3326
|
const context = {
|
|
@@ -2817,6 +3332,30 @@ var PluginRuntime = class {
|
|
|
2817
3332
|
(plugin) => this.createPluginContext(plugin, context)
|
|
2818
3333
|
);
|
|
2819
3334
|
}
|
|
3335
|
+
async runGeneratedOutputPlans(manifest) {
|
|
3336
|
+
for (const plugin of this.plugins()) {
|
|
3337
|
+
const hook = plugin.planGeneratedOutputs;
|
|
3338
|
+
if (!hook) continue;
|
|
3339
|
+
const outputs = await hook(
|
|
3340
|
+
freezeGeneratedOutputPlanContext({
|
|
3341
|
+
manifest: {
|
|
3342
|
+
discoverableEntries: manifest.discoverableEntries,
|
|
3343
|
+
routableEntries: manifest.publicEntries
|
|
3344
|
+
},
|
|
3345
|
+
site: this.pipelineOptions.config?.site
|
|
3346
|
+
})
|
|
3347
|
+
);
|
|
3348
|
+
const sink = this.generatedOutputs.sinkFor(plugin.name);
|
|
3349
|
+
for (const output of outputs) {
|
|
3350
|
+
if (output.dependencies.length === 0) {
|
|
3351
|
+
throw new Error(
|
|
3352
|
+
`Generated output plan from "${plugin.name}" must declare at least one dependency.`
|
|
3353
|
+
);
|
|
3354
|
+
}
|
|
3355
|
+
sink.emit(output);
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
2820
3359
|
enableBuildTime() {
|
|
2821
3360
|
this.isBuildTime = true;
|
|
2822
3361
|
}
|
|
@@ -2857,6 +3396,13 @@ var PluginRuntime = class {
|
|
|
2857
3396
|
collectGeneratedOutputs() {
|
|
2858
3397
|
return this.generatedOutputs.all();
|
|
2859
3398
|
}
|
|
3399
|
+
emitCoreAsset(path6, content) {
|
|
3400
|
+
this.generatedOutputs.sinkFor("core").emitAsset({
|
|
3401
|
+
path: path6,
|
|
3402
|
+
content,
|
|
3403
|
+
dependencies: [{ type: "file", path: path6 }]
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
2860
3406
|
async resolvePage(pathname, manifest, contentIndex) {
|
|
2861
3407
|
const matches = [];
|
|
2862
3408
|
const requestedPathname = normalizePagePath(pathname);
|
|
@@ -2967,7 +3513,9 @@ var PluginRuntime = class {
|
|
|
2967
3513
|
return declarations;
|
|
2968
3514
|
}
|
|
2969
3515
|
getContentOutputDependencies() {
|
|
2970
|
-
return this.plugins().flatMap(
|
|
3516
|
+
return this.plugins().flatMap(
|
|
3517
|
+
(plugin) => plugin.contentOutputDependencies ?? []
|
|
3518
|
+
);
|
|
2971
3519
|
}
|
|
2972
3520
|
async collectDiagnostics(contentIndex) {
|
|
2973
3521
|
const tracer = this.observability().tracer;
|
|
@@ -3030,7 +3578,8 @@ var PluginRuntime = class {
|
|
|
3030
3578
|
config: this.pipelineOptions.config,
|
|
3031
3579
|
contentIndex,
|
|
3032
3580
|
contentSource: this.pipelineOptions.contentSource,
|
|
3033
|
-
diagnostics: this.diagnostics
|
|
3581
|
+
diagnostics: this.diagnostics,
|
|
3582
|
+
externalDependencies: this.externalDependencies
|
|
3034
3583
|
};
|
|
3035
3584
|
}
|
|
3036
3585
|
createPluginContext(plugin, context) {
|
|
@@ -3081,6 +3630,15 @@ var PluginRuntime = class {
|
|
|
3081
3630
|
return this.resolvedPlugins;
|
|
3082
3631
|
}
|
|
3083
3632
|
};
|
|
3633
|
+
function freezeGeneratedOutputPlanContext(context) {
|
|
3634
|
+
return deepFreeze(structuredClone(context));
|
|
3635
|
+
}
|
|
3636
|
+
function deepFreeze(value) {
|
|
3637
|
+
if (value === null || typeof value !== "object") return value;
|
|
3638
|
+
Object.freeze(value);
|
|
3639
|
+
for (const property of Object.values(value)) deepFreeze(property);
|
|
3640
|
+
return value;
|
|
3641
|
+
}
|
|
3084
3642
|
function collectPageTypeOwners(plugins) {
|
|
3085
3643
|
const pageTypes = /* @__PURE__ */ new Map();
|
|
3086
3644
|
for (const plugin of plugins) {
|
|
@@ -3143,6 +3701,16 @@ function normalizeDirectoryPagePath(pathname) {
|
|
|
3143
3701
|
const path6 = normalizePagePath(pathname);
|
|
3144
3702
|
return path6 === "/" ? path6 : `${path6}/`;
|
|
3145
3703
|
}
|
|
3704
|
+
function manifestHookCacheMissReason(cached, pluginName, pipelineFingerprint, inputFingerprint) {
|
|
3705
|
+
if (!cached) return "cache-missing";
|
|
3706
|
+
if (cached.pluginName !== pluginName) return "plugin-order-changed";
|
|
3707
|
+
if (!cached.cacheable) return "uncacheable";
|
|
3708
|
+
if (cached.pipelineFingerprint !== pipelineFingerprint)
|
|
3709
|
+
return "pipeline-fingerprint-changed";
|
|
3710
|
+
if (cached.inputFingerprint !== inputFingerprint)
|
|
3711
|
+
return "manifest-input-changed";
|
|
3712
|
+
return "snapshot-invalid";
|
|
3713
|
+
}
|
|
3146
3714
|
function normalizePagePath(pathname) {
|
|
3147
3715
|
const path6 = `/${pathname.split("/").filter(Boolean).join("/")}`;
|
|
3148
3716
|
return path6 === "/" ? path6 : path6.replace(/\/$/, "");
|
|
@@ -3450,34 +4018,46 @@ var ContentBuildCoordinator = class {
|
|
|
3450
4018
|
this.dependencies = dependencies;
|
|
3451
4019
|
}
|
|
3452
4020
|
dependencies;
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
this.
|
|
4021
|
+
plan = null;
|
|
4022
|
+
getPlan(incremental, pipelineFingerprint, fullContentRegenerationRequired = false, externalDependencies = [], externalDependencyFailures = [], publishingBuildTime = /* @__PURE__ */ new Date()) {
|
|
4023
|
+
if (this.plan) return this.plan;
|
|
4024
|
+
const plan = this.prepare(
|
|
3456
4025
|
incremental,
|
|
3457
4026
|
pipelineFingerprint,
|
|
3458
|
-
fullContentRegenerationRequired
|
|
4027
|
+
fullContentRegenerationRequired,
|
|
4028
|
+
externalDependencies,
|
|
4029
|
+
externalDependencyFailures,
|
|
4030
|
+
publishingBuildTime
|
|
3459
4031
|
);
|
|
3460
|
-
|
|
4032
|
+
this.plan = plan;
|
|
4033
|
+
void plan.catch(() => {
|
|
4034
|
+
if (this.plan === plan) this.plan = null;
|
|
4035
|
+
});
|
|
4036
|
+
return plan;
|
|
3461
4037
|
}
|
|
3462
|
-
async commit(
|
|
4038
|
+
async commit(plan, manifest, pipelineFingerprint, outputs = [], manifestEntries = manifest.entries, trackedDependencies = /* @__PURE__ */ new Map(), externalDependencies = [], processedContentCacheFingerprints = /* @__PURE__ */ new Map(), manifestHookCache = [], publishingBuildTime) {
|
|
3463
4039
|
const entriesBySlug = new Map(
|
|
3464
4040
|
manifest.entries.map((entry) => [entry.slug, entry])
|
|
3465
4041
|
);
|
|
4042
|
+
const nextChangeAt = nextPublishingChangeAt(manifest, publishingBuildTime);
|
|
3466
4043
|
const state2 = {
|
|
3467
4044
|
version: CONTENT_BUILD_STATE_VERSION,
|
|
3468
4045
|
entries: Object.fromEntries(
|
|
3469
|
-
|
|
4046
|
+
plan.currentEntries.map(({ entry, fingerprint }) => {
|
|
3470
4047
|
const manifestEntry = entriesBySlug.get(toSlug(entry.path));
|
|
3471
4048
|
return [
|
|
3472
4049
|
entry.path,
|
|
3473
4050
|
{
|
|
3474
4051
|
fingerprint,
|
|
3475
|
-
aliases:
|
|
4052
|
+
aliases: plan.currentContentAliases.get(entry.path) ?? [],
|
|
3476
4053
|
dependencies: collectDependencies2(
|
|
3477
4054
|
manifestEntry,
|
|
3478
|
-
trackedDependencies.get(toSlug(entry.path)) ??
|
|
4055
|
+
trackedDependencies.get(toSlug(entry.path)) ?? plan.previousState?.entries[entry.path]?.dependencies ?? []
|
|
3479
4056
|
),
|
|
3480
|
-
linkTargets: collectLinkTargets(manifestEntry)
|
|
4057
|
+
linkTargets: collectLinkTargets(manifestEntry),
|
|
4058
|
+
...processedContentCacheFingerprints.get(toSlug(entry.path)) ? {
|
|
4059
|
+
processedContentCacheFingerprint: processedContentCacheFingerprints.get(toSlug(entry.path))
|
|
4060
|
+
} : {}
|
|
3481
4061
|
}
|
|
3482
4062
|
];
|
|
3483
4063
|
})
|
|
@@ -3489,7 +4069,19 @@ var ContentBuildCoordinator = class {
|
|
|
3489
4069
|
),
|
|
3490
4070
|
pipelineFingerprint,
|
|
3491
4071
|
manifestEntries,
|
|
3492
|
-
outputs
|
|
4072
|
+
outputs,
|
|
4073
|
+
externalDependencies: externalDependencies.map(
|
|
4074
|
+
({ id, fingerprint, scope, expiresAt }) => ({
|
|
4075
|
+
id,
|
|
4076
|
+
fingerprint,
|
|
4077
|
+
scope,
|
|
4078
|
+
...expiresAt === void 0 ? {} : { expiresAt }
|
|
4079
|
+
})
|
|
4080
|
+
),
|
|
4081
|
+
manifestHookCache,
|
|
4082
|
+
...nextChangeAt ? {
|
|
4083
|
+
nextPublishingChangeAt: nextChangeAt
|
|
4084
|
+
} : {}
|
|
3493
4085
|
};
|
|
3494
4086
|
try {
|
|
3495
4087
|
await saveContentBuildState(this.dependencies.buildStatePath, state2);
|
|
@@ -3503,7 +4095,7 @@ var ContentBuildCoordinator = class {
|
|
|
3503
4095
|
);
|
|
3504
4096
|
}
|
|
3505
4097
|
}
|
|
3506
|
-
async prepare(incremental, pipelineFingerprint, fullContentRegenerationRequired) {
|
|
4098
|
+
async prepare(incremental, pipelineFingerprint, fullContentRegenerationRequired, externalDependencies, externalDependencyFailures, publishingBuildTime) {
|
|
3507
4099
|
const entries = await this.dependencies.observability.tracer.span(
|
|
3508
4100
|
"content.discovery",
|
|
3509
4101
|
{},
|
|
@@ -3517,12 +4109,20 @@ var ContentBuildCoordinator = class {
|
|
|
3517
4109
|
(entry) => this.dependencies.readEntry(entry)
|
|
3518
4110
|
)
|
|
3519
4111
|
);
|
|
3520
|
-
const previousState =
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
4112
|
+
const previousState = await this.dependencies.observability.tracer.span(
|
|
4113
|
+
"content.build-state.load",
|
|
4114
|
+
{ incremental },
|
|
4115
|
+
async () => incremental ? await loadContentBuildState(this.dependencies.buildStatePath) : void 0
|
|
4116
|
+
);
|
|
4117
|
+
const changeSet = await this.dependencies.observability.tracer.span(
|
|
4118
|
+
"content.change-set",
|
|
4119
|
+
{},
|
|
4120
|
+
() => previousState ? diffContentEntries(previousState, currentEntries) : allContentChanged(currentEntries)
|
|
4121
|
+
);
|
|
4122
|
+
const currentContentAliases = await this.dependencies.observability.tracer.span(
|
|
4123
|
+
"content.aliases",
|
|
4124
|
+
{},
|
|
4125
|
+
() => this.getContentAliases(currentEntries, previousState, changeSet)
|
|
3526
4126
|
);
|
|
3527
4127
|
const {
|
|
3528
4128
|
index: currentContentIndex,
|
|
@@ -3535,26 +4135,54 @@ var ContentBuildCoordinator = class {
|
|
|
3535
4135
|
currentContentAliases
|
|
3536
4136
|
)
|
|
3537
4137
|
);
|
|
3538
|
-
const
|
|
3539
|
-
changeSet,
|
|
4138
|
+
const publishingStateExpired = isPublishingStateExpired(
|
|
3540
4139
|
previousState,
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
4140
|
+
publishingBuildTime
|
|
4141
|
+
);
|
|
4142
|
+
const affected = await this.dependencies.observability.tracer.span(
|
|
4143
|
+
"content.affected",
|
|
4144
|
+
{ fullContentRegenerationRequired },
|
|
4145
|
+
() => !fullContentRegenerationRequired && !publishingStateExpired && previousState?.pipelineFingerprint === pipelineFingerprint ? determineAffectedContent(
|
|
4146
|
+
changeSet,
|
|
4147
|
+
previousState,
|
|
4148
|
+
currentEntries.map(({ entry }) => entry.path),
|
|
4149
|
+
currentContentIndex
|
|
4150
|
+
) : determineAffectedContent(
|
|
4151
|
+
allContentChanged(currentEntries),
|
|
4152
|
+
void 0,
|
|
4153
|
+
currentEntries.map(({ entry }) => entry.path),
|
|
4154
|
+
currentContentIndex
|
|
4155
|
+
)
|
|
3548
4156
|
);
|
|
4157
|
+
const fullRegenerationReasons = [];
|
|
4158
|
+
if (!incremental) fullRegenerationReasons.push("incremental-disabled");
|
|
4159
|
+
else if (!previousState)
|
|
4160
|
+
fullRegenerationReasons.push("cache-missing-or-invalid");
|
|
4161
|
+
if (previousState && previousState.pipelineFingerprint !== pipelineFingerprint)
|
|
4162
|
+
fullRegenerationReasons.push("pipeline-fingerprint-changed");
|
|
4163
|
+
if (fullContentRegenerationRequired)
|
|
4164
|
+
fullRegenerationReasons.push("content-plugin-uncacheable");
|
|
4165
|
+
if (publishingStateExpired)
|
|
4166
|
+
fullRegenerationReasons.push("publishing-state-expired");
|
|
4167
|
+
if (externalDependencyFailures.length > 0)
|
|
4168
|
+
fullRegenerationReasons.push("external-dependency-unavailable");
|
|
3549
4169
|
this.dependencies.observability.tracer.event("build.incremental", {
|
|
3550
|
-
incremental
|
|
4170
|
+
incremental,
|
|
4171
|
+
cacheValid: previousState !== void 0,
|
|
4172
|
+
fullRegenerationReasons: fullRegenerationReasons.join(","),
|
|
4173
|
+
externalDependencyFailures: externalDependencyFailures.length,
|
|
3551
4174
|
added: changeSet.added.length,
|
|
3552
4175
|
changed: changeSet.changed.length,
|
|
3553
4176
|
removed: changeSet.removed.length,
|
|
3554
4177
|
unchanged: changeSet.unchanged.length,
|
|
3555
4178
|
affected: affected.direct.size + affected.dependent.size
|
|
3556
4179
|
});
|
|
4180
|
+
const reusableOutputs = incremental && previousState?.pipelineFingerprint === pipelineFingerprint && externalDependencyFailures.length === 0 && !publishingStateExpired && externalDependenciesEqual(
|
|
4181
|
+
previousState?.externalDependencies ?? [],
|
|
4182
|
+
externalDependencies
|
|
4183
|
+
) && changeSet.added.length === 0 && changeSet.changed.length === 0 && changeSet.removed.length === 0 ? previousState?.outputs : void 0;
|
|
3557
4184
|
return {
|
|
4185
|
+
incremental,
|
|
3558
4186
|
previousState,
|
|
3559
4187
|
previousManifestEntriesBySlug: new Map(
|
|
3560
4188
|
(previousState?.manifestEntries ?? []).map((entry) => [
|
|
@@ -3567,7 +4195,12 @@ var ContentBuildCoordinator = class {
|
|
|
3567
4195
|
currentContentIndex,
|
|
3568
4196
|
currentContentIndexAmbiguities,
|
|
3569
4197
|
changeSet,
|
|
3570
|
-
affectedContent: affected
|
|
4198
|
+
affectedContent: affected,
|
|
4199
|
+
cacheValid: previousState !== void 0,
|
|
4200
|
+
fullRegenerationReasons,
|
|
4201
|
+
reusableOutputs,
|
|
4202
|
+
externalDependencies,
|
|
4203
|
+
externalDependencyFailures
|
|
3571
4204
|
};
|
|
3572
4205
|
}
|
|
3573
4206
|
async getContentAliases(currentEntries, previousState, changeSet) {
|
|
@@ -3590,6 +4223,31 @@ var ContentBuildCoordinator = class {
|
|
|
3590
4223
|
return aliases;
|
|
3591
4224
|
}
|
|
3592
4225
|
};
|
|
4226
|
+
function externalDependenciesEqual(previous, current) {
|
|
4227
|
+
if (previous.length !== current.length) return false;
|
|
4228
|
+
const currentById = new Map(
|
|
4229
|
+
current.map((dependency) => [dependency.id, dependency])
|
|
4230
|
+
);
|
|
4231
|
+
return previous.every((dependency) => {
|
|
4232
|
+
const candidate = currentById.get(dependency.id);
|
|
4233
|
+
return candidate !== void 0 && candidate.fingerprint === dependency.fingerprint && candidate.expiresAt === dependency.expiresAt && !isExpired(candidate.expiresAt);
|
|
4234
|
+
});
|
|
4235
|
+
}
|
|
4236
|
+
function isExpired(expiresAt) {
|
|
4237
|
+
return expiresAt !== void 0 && Date.parse(expiresAt) <= Date.now();
|
|
4238
|
+
}
|
|
4239
|
+
function isPublishingStateExpired(state2, buildTime) {
|
|
4240
|
+
return state2?.nextPublishingChangeAt !== void 0 && Date.parse(state2.nextPublishingChangeAt) <= buildTime.getTime();
|
|
4241
|
+
}
|
|
4242
|
+
function nextPublishingChangeAt(manifest, buildTime) {
|
|
4243
|
+
const next = manifest.entries.filter((entry) => entry.publishing.visibility === "scheduled").map((entry) => entry.publishing.publishAt?.getTime()).filter(
|
|
4244
|
+
(time) => time !== void 0 && time > buildTime.getTime()
|
|
4245
|
+
).reduce(
|
|
4246
|
+
(earliest, time) => earliest === void 0 || time < earliest ? time : earliest,
|
|
4247
|
+
void 0
|
|
4248
|
+
);
|
|
4249
|
+
return next === void 0 ? void 0 : new Date(next).toISOString();
|
|
4250
|
+
}
|
|
3593
4251
|
function readText2(content) {
|
|
3594
4252
|
return typeof content === "string" ? content : new TextDecoder().decode(content);
|
|
3595
4253
|
}
|
|
@@ -3642,7 +4300,27 @@ function collectLinkTargets(manifestEntry) {
|
|
|
3642
4300
|
].sort();
|
|
3643
4301
|
}
|
|
3644
4302
|
|
|
4303
|
+
// src/content/content_build_plan.ts
|
|
4304
|
+
function reusableOutputChangeSet(outputs) {
|
|
4305
|
+
const unchanged = [...outputs].sort(
|
|
4306
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
4307
|
+
);
|
|
4308
|
+
return {
|
|
4309
|
+
affected: [],
|
|
4310
|
+
removed: [],
|
|
4311
|
+
unchanged,
|
|
4312
|
+
fullRegenerationRequired: unchanged.some(
|
|
4313
|
+
(output) => output.dependencies.some((dependency) => dependency.type === "unknown")
|
|
4314
|
+
),
|
|
4315
|
+
candidateOutputCount: unchanged.length,
|
|
4316
|
+
affectedOutputCount: 0,
|
|
4317
|
+
removedOutputCount: 0,
|
|
4318
|
+
unchangedOutputCount: unchanged.length
|
|
4319
|
+
};
|
|
4320
|
+
}
|
|
4321
|
+
|
|
3645
4322
|
// src/content/content_entry_reader.ts
|
|
4323
|
+
var textDecoder = new TextDecoder();
|
|
3646
4324
|
var ContentEntryReader = class {
|
|
3647
4325
|
constructor(source, observability) {
|
|
3648
4326
|
this.source = source;
|
|
@@ -3681,8 +4359,18 @@ var ContentEntryReader = class {
|
|
|
3681
4359
|
read(entry) {
|
|
3682
4360
|
const cached = this.texts.get(entry.path);
|
|
3683
4361
|
if (cached) return cached;
|
|
3684
|
-
const content = this.
|
|
3685
|
-
|
|
4362
|
+
const content = this.observability.tracer.span(
|
|
4363
|
+
"content.read",
|
|
4364
|
+
{ extension: entry.path.endsWith(".md") ? "markdown" : "asset" },
|
|
4365
|
+
async () => {
|
|
4366
|
+
const value = await this.source.read(entry);
|
|
4367
|
+
const text = typeof value === "string" ? value : textDecoder.decode(value);
|
|
4368
|
+
this.observability.tracer.event("content.read.bytes", {
|
|
4369
|
+
bytes: Buffer.byteLength(text, "utf8"),
|
|
4370
|
+
extension: entry.path.endsWith(".md") ? "markdown" : "asset"
|
|
4371
|
+
});
|
|
4372
|
+
return text;
|
|
4373
|
+
}
|
|
3686
4374
|
);
|
|
3687
4375
|
const retain = entry.path.endsWith(".md");
|
|
3688
4376
|
const tracked = retain ? content : content.finally(() => this.texts.delete(entry.path));
|
|
@@ -3809,6 +4497,8 @@ async function mapConcurrent2(values, concurrency, map) {
|
|
|
3809
4497
|
import fs4 from "node:fs/promises";
|
|
3810
4498
|
import path4 from "node:path";
|
|
3811
4499
|
var INTERNAL_CONTENT_IGNORE_PATTERNS = [
|
|
4500
|
+
".riebeckite",
|
|
4501
|
+
".riebeckite/**",
|
|
3812
4502
|
".git",
|
|
3813
4503
|
".git/**",
|
|
3814
4504
|
".github",
|
|
@@ -3858,9 +4548,9 @@ var FileSystemContentSource = class {
|
|
|
3858
4548
|
return await fs4.readFile(filePath);
|
|
3859
4549
|
}
|
|
3860
4550
|
async scanDirectory(directory, parentPath2, exclusions, templaterTemplateFolder) {
|
|
3861
|
-
const directoryEntries = await fs4.readdir(directory, {
|
|
4551
|
+
const directoryEntries = (await fs4.readdir(directory, {
|
|
3862
4552
|
withFileTypes: true
|
|
3863
|
-
});
|
|
4553
|
+
})).toSorted((left, right) => left.name.localeCompare(right.name, "en"));
|
|
3864
4554
|
const entries = [];
|
|
3865
4555
|
for (const directoryEntry of directoryEntries) {
|
|
3866
4556
|
if (directoryEntry.isSymbolicLink()) continue;
|
|
@@ -4008,9 +4698,14 @@ function readOptionalStableId(value) {
|
|
|
4008
4698
|
var ManifestBuilder = class {
|
|
4009
4699
|
createEntry(slug, markdown, processed, contentIndex, location, publishing) {
|
|
4010
4700
|
const links = extractContentLinks(markdown, contentIndex);
|
|
4011
|
-
const assets =
|
|
4012
|
-
(
|
|
4013
|
-
|
|
4701
|
+
const assets = [
|
|
4702
|
+
...links.filter(
|
|
4703
|
+
(link) => (link.kind === "image" || link.kind === "attachment") && link.slug !== null
|
|
4704
|
+
).map((link) => ({ path: link.slug })),
|
|
4705
|
+
...extractMarkdownImages(markdown, slug).map((image) => ({
|
|
4706
|
+
path: image.path
|
|
4707
|
+
}))
|
|
4708
|
+
];
|
|
4014
4709
|
const contentId = resolveContentStableId(processed.frontmatter);
|
|
4015
4710
|
return {
|
|
4016
4711
|
slug,
|
|
@@ -4139,6 +4834,11 @@ function determineOutputChanges(input) {
|
|
|
4139
4834
|
(input.previousState?.outputs ?? []).map((output) => [output.path, output])
|
|
4140
4835
|
);
|
|
4141
4836
|
const changedContent = collectChangedContent(input);
|
|
4837
|
+
const changedFiles = /* @__PURE__ */ new Set([
|
|
4838
|
+
...input.changeSet.added,
|
|
4839
|
+
...input.changeSet.changed,
|
|
4840
|
+
...input.changeSet.removed
|
|
4841
|
+
]);
|
|
4142
4842
|
const changedTags = collectChangedTags(
|
|
4143
4843
|
input.previousState,
|
|
4144
4844
|
input.manifest,
|
|
@@ -4149,10 +4849,20 @@ function determineOutputChanges(input) {
|
|
|
4149
4849
|
input.manifest,
|
|
4150
4850
|
changedContent
|
|
4151
4851
|
);
|
|
4852
|
+
const changedExternal = changedExternalDependencies(input);
|
|
4853
|
+
const changedExternalScopes = changedExternalDependencyScopes(input);
|
|
4152
4854
|
const affected = /* @__PURE__ */ new Map();
|
|
4153
4855
|
const unchanged = [];
|
|
4154
4856
|
for (const output of current) {
|
|
4155
|
-
if (isOutputAffected(
|
|
4857
|
+
if (isOutputAffected(
|
|
4858
|
+
output,
|
|
4859
|
+
changedContent,
|
|
4860
|
+
changedTags,
|
|
4861
|
+
changedFolders,
|
|
4862
|
+
changedFiles,
|
|
4863
|
+
changedExternal,
|
|
4864
|
+
changedExternalScopes
|
|
4865
|
+
)) {
|
|
4156
4866
|
affected.set(output.path, output);
|
|
4157
4867
|
} else {
|
|
4158
4868
|
unchanged.push(output);
|
|
@@ -4168,7 +4878,7 @@ function determineOutputChanges(input) {
|
|
|
4168
4878
|
const removed = [...previous.values()].filter(
|
|
4169
4879
|
(output) => !currentPaths.has(output.path)
|
|
4170
4880
|
);
|
|
4171
|
-
const fullRegenerationRequired = current.some(
|
|
4881
|
+
const fullRegenerationRequired = (input.externalDependencyFailures?.length ?? 0) > 0 || current.some(
|
|
4172
4882
|
(output) => output.dependencies.some((dependency) => dependency.type === "unknown")
|
|
4173
4883
|
);
|
|
4174
4884
|
const affectedValues = [...affected.values()].sort(compareOutput);
|
|
@@ -4198,7 +4908,10 @@ function buildOutputInventory(manifest, pluginPageOutputs = [], contentOutputDep
|
|
|
4198
4908
|
});
|
|
4199
4909
|
}
|
|
4200
4910
|
for (const output of pluginPageOutputs) {
|
|
4201
|
-
addOutput(outputs, {
|
|
4911
|
+
addOutput(outputs, {
|
|
4912
|
+
...output,
|
|
4913
|
+
path: htmlOutputPath(output.path)
|
|
4914
|
+
});
|
|
4202
4915
|
}
|
|
4203
4916
|
for (const output of manifest.generatedOutputs) {
|
|
4204
4917
|
addOutput(outputs, {
|
|
@@ -4225,10 +4938,22 @@ function contentOutput(entry, dependencies) {
|
|
|
4225
4938
|
dependencies: [{ type: "content", slug: entry.slug }, ...dependencies]
|
|
4226
4939
|
};
|
|
4227
4940
|
}
|
|
4228
|
-
function isOutputAffected(output, changedContent, changedTags, changedFolders) {
|
|
4941
|
+
function isOutputAffected(output, changedContent, changedTags, changedFolders, changedFiles, changedExternal, changedExternalScopes) {
|
|
4942
|
+
if (isAffectedByExternalScope(output, changedExternalScopes)) return true;
|
|
4229
4943
|
for (const dependency of output.dependencies) {
|
|
4230
4944
|
if (dependency.type === "unknown") return true;
|
|
4945
|
+
if (dependency.type === "external" && changedExternal.has(dependency.id))
|
|
4946
|
+
return true;
|
|
4231
4947
|
if (dependency.type === "global") return changedContent.size > 0;
|
|
4948
|
+
if (dependency.type === "projection" && (dependency.projection === "navigation" || dependency.projection === "recent-posts")) {
|
|
4949
|
+
return changedContent.size > 0;
|
|
4950
|
+
}
|
|
4951
|
+
if (dependency.type === "projection" && dependency.projection === "taxonomy-tags") {
|
|
4952
|
+
return changedTags.size > 0;
|
|
4953
|
+
}
|
|
4954
|
+
if (dependency.type === "projection" && dependency.projection === "taxonomy-folders") {
|
|
4955
|
+
return changedFolders.size > 0;
|
|
4956
|
+
}
|
|
4232
4957
|
if (dependency.type === "content" && changedContent.has(dependency.slug)) {
|
|
4233
4958
|
return true;
|
|
4234
4959
|
}
|
|
@@ -4237,9 +4962,58 @@ function isOutputAffected(output, changedContent, changedTags, changedFolders) {
|
|
|
4237
4962
|
if (dependency.type === "folder" && changedFolders.has(dependency.folder)) {
|
|
4238
4963
|
return true;
|
|
4239
4964
|
}
|
|
4965
|
+
if (dependency.type === "file" && changedFiles.has(dependency.path)) {
|
|
4966
|
+
return true;
|
|
4967
|
+
}
|
|
4240
4968
|
}
|
|
4241
4969
|
return false;
|
|
4242
4970
|
}
|
|
4971
|
+
function isAffectedByExternalScope(output, changedExternalScopes) {
|
|
4972
|
+
for (const scope of changedExternalScopes.values()) {
|
|
4973
|
+
if (scope.type === "all") return true;
|
|
4974
|
+
if (scope.type === "content" && output.kind === "content") return true;
|
|
4975
|
+
if (scope.type === "output" && scope.paths.includes(output.path))
|
|
4976
|
+
return true;
|
|
4977
|
+
}
|
|
4978
|
+
return false;
|
|
4979
|
+
}
|
|
4980
|
+
function changedExternalDependencies(input) {
|
|
4981
|
+
const previous = new Map(
|
|
4982
|
+
(input.previousState?.externalDependencies ?? []).map((dependency) => [
|
|
4983
|
+
dependency.id,
|
|
4984
|
+
dependency
|
|
4985
|
+
])
|
|
4986
|
+
);
|
|
4987
|
+
const changed = /* @__PURE__ */ new Set();
|
|
4988
|
+
for (const dependency of input.externalDependencies ?? []) {
|
|
4989
|
+
const prior = previous.get(dependency.id);
|
|
4990
|
+
if (!prior || prior.fingerprint !== dependency.fingerprint || prior.expiresAt !== dependency.expiresAt || isExpired2(dependency.expiresAt))
|
|
4991
|
+
changed.add(dependency.id);
|
|
4992
|
+
previous.delete(dependency.id);
|
|
4993
|
+
}
|
|
4994
|
+
for (const id of previous.keys()) changed.add(id);
|
|
4995
|
+
return changed;
|
|
4996
|
+
}
|
|
4997
|
+
function changedExternalDependencyScopes(input) {
|
|
4998
|
+
const previous = new Map(
|
|
4999
|
+
(input.previousState?.externalDependencies ?? []).map((dependency) => [
|
|
5000
|
+
dependency.id,
|
|
5001
|
+
dependency
|
|
5002
|
+
])
|
|
5003
|
+
);
|
|
5004
|
+
const changed = /* @__PURE__ */ new Map();
|
|
5005
|
+
for (const dependency of input.externalDependencies ?? []) {
|
|
5006
|
+
const prior = previous.get(dependency.id);
|
|
5007
|
+
if (!prior || prior.fingerprint !== dependency.fingerprint || prior.expiresAt !== dependency.expiresAt || isExpired2(dependency.expiresAt)) {
|
|
5008
|
+
changed.set(dependency.id, dependency.scope);
|
|
5009
|
+
}
|
|
5010
|
+
previous.delete(dependency.id);
|
|
5011
|
+
}
|
|
5012
|
+
for (const dependency of previous.values()) {
|
|
5013
|
+
changed.set(dependency.id, dependency.scope);
|
|
5014
|
+
}
|
|
5015
|
+
return changed;
|
|
5016
|
+
}
|
|
4243
5017
|
function collectChangedContent(input) {
|
|
4244
5018
|
const changed = /* @__PURE__ */ new Set([
|
|
4245
5019
|
...input.affectedContent.direct,
|
|
@@ -4262,6 +5036,9 @@ function collectChangedContent(input) {
|
|
|
4262
5036
|
}
|
|
4263
5037
|
return changed;
|
|
4264
5038
|
}
|
|
5039
|
+
function isExpired2(expiresAt) {
|
|
5040
|
+
return expiresAt !== void 0 && Date.parse(expiresAt) <= Date.now();
|
|
5041
|
+
}
|
|
4265
5042
|
function collectChangedTags(previousState, manifest, changedContent) {
|
|
4266
5043
|
const previousBySlug = new Map(
|
|
4267
5044
|
(previousState?.manifestEntries ?? []).map((entry) => [entry.slug, entry])
|
|
@@ -4408,7 +5185,12 @@ var ContentManager = class {
|
|
|
4408
5185
|
processedContentCount = 0;
|
|
4409
5186
|
reusedContentCount = 0;
|
|
4410
5187
|
outputChangeSet = null;
|
|
5188
|
+
buildPlan = null;
|
|
5189
|
+
buildStateCommitRequested = false;
|
|
5190
|
+
buildStateCommitted = false;
|
|
5191
|
+
cacheManifestEntries = [];
|
|
4411
5192
|
trackedContentDependencies = /* @__PURE__ */ new Map();
|
|
5193
|
+
processedContentCacheFingerprints = /* @__PURE__ */ new Map();
|
|
4412
5194
|
async getAllPosts() {
|
|
4413
5195
|
return (await this.scan()).filter((entry) => entry.path.endsWith(".md")).map((entry) => ({ slug: entry.path.replace(/\.md$/, "") }));
|
|
4414
5196
|
}
|
|
@@ -4418,13 +5200,13 @@ var ContentManager = class {
|
|
|
4418
5200
|
async getPost(slug) {
|
|
4419
5201
|
return await this.entryReader.readText(`${slug}.md`);
|
|
4420
5202
|
}
|
|
4421
|
-
async getContentIndex(
|
|
5203
|
+
async getContentIndex(plan) {
|
|
4422
5204
|
if (this.contentIndex) return this.contentIndex;
|
|
4423
|
-
if (!
|
|
5205
|
+
if (!plan && this.contentIndexPromise)
|
|
4424
5206
|
return (await this.contentIndexPromise).index;
|
|
4425
|
-
if (
|
|
4426
|
-
this.contentIndex =
|
|
4427
|
-
this.contentIndexAmbiguities =
|
|
5207
|
+
if (plan) {
|
|
5208
|
+
this.contentIndex = plan.currentContentIndex;
|
|
5209
|
+
this.contentIndexAmbiguities = plan.currentContentIndexAmbiguities;
|
|
4428
5210
|
return this.contentIndex;
|
|
4429
5211
|
}
|
|
4430
5212
|
const promise = this.observability().tracer.span(
|
|
@@ -4435,14 +5217,14 @@ var ContentManager = class {
|
|
|
4435
5217
|
(entry) => this.entryReader.read(entry)
|
|
4436
5218
|
)
|
|
4437
5219
|
);
|
|
4438
|
-
if (!
|
|
5220
|
+
if (!plan) this.contentIndexPromise = promise;
|
|
4439
5221
|
try {
|
|
4440
5222
|
const built = await promise;
|
|
4441
5223
|
this.contentIndex = built.index;
|
|
4442
5224
|
this.contentIndexAmbiguities = built.ambiguities;
|
|
4443
5225
|
return this.contentIndex;
|
|
4444
5226
|
} finally {
|
|
4445
|
-
if (!
|
|
5227
|
+
if (!plan) this.contentIndexPromise = null;
|
|
4446
5228
|
}
|
|
4447
5229
|
}
|
|
4448
5230
|
async getProcessedContent(slug) {
|
|
@@ -4467,14 +5249,27 @@ var ContentManager = class {
|
|
|
4467
5249
|
this.getContentIndex(),
|
|
4468
5250
|
this.getPost(slug)
|
|
4469
5251
|
]);
|
|
5252
|
+
this.getProcessedContentCacheFingerprint(slug, rawPost);
|
|
4470
5253
|
await this.pluginRuntime.startBuild(contentIndex);
|
|
4471
5254
|
await this.pluginRuntime.runContentLoaded(slug, rawPost, contentIndex);
|
|
4472
5255
|
await this.ensureRoutableSlugs();
|
|
5256
|
+
const locations = await this.getContentLocations();
|
|
5257
|
+
if (this.pipelineOptions.config) {
|
|
5258
|
+
this.pipelineFingerprint = this.computePipelineFingerprint(locations);
|
|
5259
|
+
}
|
|
4473
5260
|
this.pipeline ??= new Pipeline(
|
|
4474
5261
|
contentIndex,
|
|
4475
|
-
|
|
5262
|
+
new Map(
|
|
5263
|
+
[...locations.entries()].map(([locationSlug, location]) => [
|
|
5264
|
+
locationSlug,
|
|
5265
|
+
location.permalink
|
|
5266
|
+
])
|
|
5267
|
+
),
|
|
4476
5268
|
(postSlug) => this.getPost(postSlug),
|
|
4477
|
-
|
|
5269
|
+
{
|
|
5270
|
+
...this.pipelineOptions,
|
|
5271
|
+
contentScopeFingerprint: this.pipelineFingerprint ?? void 0
|
|
5272
|
+
},
|
|
4478
5273
|
this.isBuildTime
|
|
4479
5274
|
);
|
|
4480
5275
|
const content = await this.pipeline.execute(rawPost, {
|
|
@@ -4504,6 +5299,7 @@ var ContentManager = class {
|
|
|
4504
5299
|
return content;
|
|
4505
5300
|
}
|
|
4506
5301
|
async getManifest(options) {
|
|
5302
|
+
this.requestBuildStateCommit(options);
|
|
4507
5303
|
if (this.manifest) return this.manifest;
|
|
4508
5304
|
if (this.manifestPromise) return await this.manifestPromise;
|
|
4509
5305
|
this.manifestPromise = this.buildManifest(options);
|
|
@@ -4517,19 +5313,19 @@ var ContentManager = class {
|
|
|
4517
5313
|
async buildManifest(options) {
|
|
4518
5314
|
if (this.manifest) return this.manifest;
|
|
4519
5315
|
this.enableBuildTime();
|
|
4520
|
-
const
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
5316
|
+
const config = this.pipelineOptions.config;
|
|
5317
|
+
const plan = await this.getBuildPlan(options);
|
|
5318
|
+
const locations = await this.getContentLocations();
|
|
5319
|
+
if (config) {
|
|
5320
|
+
this.pipelineFingerprint = this.computePipelineFingerprint(locations);
|
|
5321
|
+
}
|
|
4525
5322
|
return await this.observability().tracer.span(
|
|
4526
5323
|
"content.manifest",
|
|
4527
5324
|
{},
|
|
4528
5325
|
async () => {
|
|
4529
|
-
const [posts, contentIndex
|
|
5326
|
+
const [posts, contentIndex] = await Promise.all([
|
|
4530
5327
|
this.getAllPosts(),
|
|
4531
|
-
this.getContentIndex(
|
|
4532
|
-
this.getContentLocations()
|
|
5328
|
+
this.getContentIndex(plan)
|
|
4533
5329
|
]);
|
|
4534
5330
|
const entries = await this.observability().tracer.span(
|
|
4535
5331
|
"content.manifest.entries",
|
|
@@ -4538,12 +5334,14 @@ var ContentManager = class {
|
|
|
4538
5334
|
posts,
|
|
4539
5335
|
CONTENT_PROCESSING_CONCURRENCY,
|
|
4540
5336
|
async (post) => {
|
|
4541
|
-
const
|
|
5337
|
+
const rawPost = await this.getPost(post.slug);
|
|
5338
|
+
const reused = this.reuseManifestEntry(
|
|
5339
|
+
post.slug,
|
|
5340
|
+
rawPost,
|
|
5341
|
+
plan
|
|
5342
|
+
);
|
|
4542
5343
|
if (reused) return reused;
|
|
4543
|
-
const
|
|
4544
|
-
this.getPost(post.slug),
|
|
4545
|
-
this.getProcessedContent(post.slug)
|
|
4546
|
-
]);
|
|
5344
|
+
const processed = await this.getProcessedContent(post.slug);
|
|
4547
5345
|
const location = locations.get(post.slug);
|
|
4548
5346
|
if (!location) {
|
|
4549
5347
|
throw new Error(
|
|
@@ -4583,7 +5381,12 @@ var ContentManager = class {
|
|
|
4583
5381
|
manifest.pageRoutes = [
|
|
4584
5382
|
...await this.pluginRuntime.getPageRoutes(manifest, contentIndex)
|
|
4585
5383
|
];
|
|
4586
|
-
await this.pluginRuntime.runManifestCreated(
|
|
5384
|
+
await this.pluginRuntime.runManifestCreated(
|
|
5385
|
+
manifest,
|
|
5386
|
+
contentIndex,
|
|
5387
|
+
plan.previousState?.manifestHookCache,
|
|
5388
|
+
this.getPipelineFingerprint()
|
|
5389
|
+
);
|
|
4587
5390
|
this.synchronizeManifestHtml(manifest, cacheManifestEntries);
|
|
4588
5391
|
manifest.assets = this.pluginRuntime.collectAssets();
|
|
4589
5392
|
manifest.clientEntries = this.pluginRuntime.collectClientEntries();
|
|
@@ -4591,20 +5394,29 @@ var ContentManager = class {
|
|
|
4591
5394
|
...this.pluginRuntime.getDiagnostics(),
|
|
4592
5395
|
...await this.pluginRuntime.collectDiagnostics(contentIndex)
|
|
4593
5396
|
];
|
|
5397
|
+
await this.pluginRuntime.runGeneratedOutputPlans(manifest);
|
|
4594
5398
|
await this.pluginRuntime.runBuildEnd(manifest, contentIndex);
|
|
5399
|
+
await this.emitPublicImageAssets(manifest);
|
|
4595
5400
|
manifest.generatedOutputs = this.pluginRuntime.collectGeneratedOutputs();
|
|
4596
|
-
const pluginPageOutputs = await this.
|
|
4597
|
-
|
|
4598
|
-
|
|
5401
|
+
const pluginPageOutputs = await this.observability().tracer.span(
|
|
5402
|
+
"output.dependencies.plugin",
|
|
5403
|
+
{},
|
|
5404
|
+
() => this.pluginRuntime.getPageOutputs(manifest, contentIndex)
|
|
5405
|
+
);
|
|
5406
|
+
this.outputChangeSet = await this.observability().tracer.span(
|
|
5407
|
+
"output.dependencies.resolve",
|
|
5408
|
+
{},
|
|
5409
|
+
() => determineOutputChanges({
|
|
5410
|
+
manifest,
|
|
5411
|
+
previousState: plan.previousState,
|
|
5412
|
+
changeSet: plan.changeSet,
|
|
5413
|
+
affectedContent: plan.affectedContent,
|
|
5414
|
+
pluginPageOutputs,
|
|
5415
|
+
contentOutputDependencies: this.pluginRuntime.getContentOutputDependencies(),
|
|
5416
|
+
externalDependencies: plan.externalDependencies,
|
|
5417
|
+
externalDependencyFailures: plan.externalDependencyFailures
|
|
5418
|
+
})
|
|
4599
5419
|
);
|
|
4600
|
-
this.outputChangeSet = preparation ? determineOutputChanges({
|
|
4601
|
-
manifest,
|
|
4602
|
-
previousState: preparation.previousState,
|
|
4603
|
-
changeSet: preparation.changeSet,
|
|
4604
|
-
affectedContent: preparation.affectedContent,
|
|
4605
|
-
pluginPageOutputs,
|
|
4606
|
-
contentOutputDependencies: this.pluginRuntime.getContentOutputDependencies()
|
|
4607
|
-
}) : null;
|
|
4608
5420
|
if (this.outputChangeSet) {
|
|
4609
5421
|
this.observability().tracer.event("build.incremental.outputs", {
|
|
4610
5422
|
candidateOutputCount: this.outputChangeSet.candidateOutputCount,
|
|
@@ -4614,19 +5426,9 @@ var ContentManager = class {
|
|
|
4614
5426
|
fullRegenerationRequired: this.outputChangeSet.fullRegenerationRequired
|
|
4615
5427
|
});
|
|
4616
5428
|
}
|
|
4617
|
-
if (preparation)
|
|
4618
|
-
await this.buildCoordinator.commit(
|
|
4619
|
-
preparation,
|
|
4620
|
-
manifest,
|
|
4621
|
-
this.getPipelineFingerprint(),
|
|
4622
|
-
this.outputChangeSet ? [
|
|
4623
|
-
...this.outputChangeSet.affected,
|
|
4624
|
-
...this.outputChangeSet.unchanged
|
|
4625
|
-
] : [],
|
|
4626
|
-
cacheManifestEntries,
|
|
4627
|
-
this.trackedContentDependencies
|
|
4628
|
-
);
|
|
4629
5429
|
this.manifest = manifest;
|
|
5430
|
+
this.cacheManifestEntries = cacheManifestEntries;
|
|
5431
|
+
await this.commitBuildState();
|
|
4630
5432
|
return manifest;
|
|
4631
5433
|
}
|
|
4632
5434
|
);
|
|
@@ -4640,31 +5442,72 @@ var ContentManager = class {
|
|
|
4640
5442
|
getReusedContentCount() {
|
|
4641
5443
|
return this.reusedContentCount;
|
|
4642
5444
|
}
|
|
5445
|
+
getManifestHookMetrics() {
|
|
5446
|
+
return this.pluginRuntime.getManifestHookMetrics();
|
|
5447
|
+
}
|
|
5448
|
+
async getNoChangeFastPathBlockReason(options = {}) {
|
|
5449
|
+
const plan = await this.getBuildPlan(options);
|
|
5450
|
+
if (plan.fullRegenerationReasons.includes("publishing-state-expired"))
|
|
5451
|
+
return "publishing-state-expired";
|
|
5452
|
+
if (plan.reusableOutputs?.some(
|
|
5453
|
+
(output) => output.dependencies.some((dependency) => dependency.type === "unknown")
|
|
5454
|
+
))
|
|
5455
|
+
return "output-dependency-unknown";
|
|
5456
|
+
return this.pluginRuntime.getNoChangeFastPathBlockReason(
|
|
5457
|
+
plan.previousState?.manifestHookCache ?? [],
|
|
5458
|
+
this.getPipelineFingerprint()
|
|
5459
|
+
);
|
|
5460
|
+
}
|
|
4643
5461
|
async getOutputChangeSet(options = {}) {
|
|
4644
|
-
|
|
5462
|
+
this.requestBuildStateCommit(options);
|
|
5463
|
+
if (this.outputChangeSet) {
|
|
5464
|
+
await this.commitBuildState();
|
|
5465
|
+
return this.outputChangeSet;
|
|
5466
|
+
}
|
|
5467
|
+
const plan = await this.getBuildPlan(options);
|
|
5468
|
+
if (plan.reusableOutputs) {
|
|
5469
|
+
this.outputChangeSet = await this.observability().tracer.span(
|
|
5470
|
+
"output.dependencies.reuse",
|
|
5471
|
+
{ outputCount: plan.reusableOutputs.length },
|
|
5472
|
+
async () => reusableOutputChangeSet(plan.reusableOutputs ?? [])
|
|
5473
|
+
);
|
|
5474
|
+
return this.outputChangeSet;
|
|
5475
|
+
}
|
|
5476
|
+
await this.observability().tracer.span(
|
|
5477
|
+
"output.dependencies.manifest",
|
|
5478
|
+
{},
|
|
5479
|
+
() => this.getManifest(options)
|
|
5480
|
+
);
|
|
4645
5481
|
if (!this.outputChangeSet) {
|
|
4646
5482
|
const manifest = await this.getManifest();
|
|
4647
5483
|
const contentIndex = await this.getContentIndex();
|
|
4648
|
-
const pluginPageOutputs = await this.
|
|
4649
|
-
|
|
4650
|
-
|
|
5484
|
+
const pluginPageOutputs = await this.observability().tracer.span(
|
|
5485
|
+
"output.dependencies.plugin",
|
|
5486
|
+
{},
|
|
5487
|
+
() => this.pluginRuntime.getPageOutputs(manifest, contentIndex)
|
|
5488
|
+
);
|
|
5489
|
+
return await this.observability().tracer.span(
|
|
5490
|
+
"output.dependencies.resolve",
|
|
5491
|
+
{},
|
|
5492
|
+
() => determineOutputChanges({
|
|
5493
|
+
manifest,
|
|
5494
|
+
previousState: void 0,
|
|
5495
|
+
changeSet: {
|
|
5496
|
+
added: manifest.entries.map((entry) => `${entry.slug}.md`),
|
|
5497
|
+
changed: [],
|
|
5498
|
+
removed: [],
|
|
5499
|
+
unchanged: []
|
|
5500
|
+
},
|
|
5501
|
+
affectedContent: {
|
|
5502
|
+
direct: new Set(manifest.entries.map((entry) => entry.slug)),
|
|
5503
|
+
dependent: /* @__PURE__ */ new Set()
|
|
5504
|
+
},
|
|
5505
|
+
pluginPageOutputs,
|
|
5506
|
+
contentOutputDependencies: this.pluginRuntime.getContentOutputDependencies(),
|
|
5507
|
+
externalDependencies: plan.externalDependencies,
|
|
5508
|
+
externalDependencyFailures: plan.externalDependencyFailures
|
|
5509
|
+
})
|
|
4651
5510
|
);
|
|
4652
|
-
return determineOutputChanges({
|
|
4653
|
-
manifest,
|
|
4654
|
-
previousState: void 0,
|
|
4655
|
-
changeSet: {
|
|
4656
|
-
added: manifest.entries.map((entry) => `${entry.slug}.md`),
|
|
4657
|
-
changed: [],
|
|
4658
|
-
removed: [],
|
|
4659
|
-
unchanged: []
|
|
4660
|
-
},
|
|
4661
|
-
affectedContent: {
|
|
4662
|
-
direct: new Set(manifest.entries.map((entry) => entry.slug)),
|
|
4663
|
-
dependent: /* @__PURE__ */ new Set()
|
|
4664
|
-
},
|
|
4665
|
-
pluginPageOutputs,
|
|
4666
|
-
contentOutputDependencies: this.pluginRuntime.getContentOutputDependencies()
|
|
4667
|
-
});
|
|
4668
5511
|
}
|
|
4669
5512
|
return this.outputChangeSet;
|
|
4670
5513
|
}
|
|
@@ -4769,29 +5612,113 @@ var ContentManager = class {
|
|
|
4769
5612
|
publishStrategy() {
|
|
4770
5613
|
return this.pipelineOptions.config?.content.filters.publishStrategy ?? "explicit";
|
|
4771
5614
|
}
|
|
4772
|
-
reuseManifestEntry(slug,
|
|
4773
|
-
if (!
|
|
4774
|
-
if (
|
|
5615
|
+
reuseManifestEntry(slug, source, plan) {
|
|
5616
|
+
if (!plan.previousState?.manifestEntries) return null;
|
|
5617
|
+
if (plan.previousState.pipelineFingerprint !== this.getPipelineFingerprint()) {
|
|
5618
|
+
return null;
|
|
5619
|
+
}
|
|
5620
|
+
if (plan.affectedContent.direct.has(slug)) return null;
|
|
5621
|
+
if (plan.affectedContent.dependent.has(slug)) return null;
|
|
5622
|
+
const contentCacheFingerprint = this.getProcessedContentCacheFingerprint(
|
|
5623
|
+
slug,
|
|
5624
|
+
source
|
|
5625
|
+
);
|
|
5626
|
+
if (!contentCacheFingerprint) return null;
|
|
5627
|
+
if (plan.previousState.entries[`${slug}.md`]?.processedContentCacheFingerprint !== contentCacheFingerprint) {
|
|
4775
5628
|
return null;
|
|
4776
5629
|
}
|
|
4777
|
-
|
|
4778
|
-
if (preparation.affectedContent.dependent.has(slug)) return null;
|
|
4779
|
-
const entry = preparation.previousManifestEntriesBySlug.get(slug);
|
|
5630
|
+
const entry = plan.previousManifestEntriesBySlug.get(slug);
|
|
4780
5631
|
if (!entry) return null;
|
|
4781
5632
|
this.reusedContentCount += 1;
|
|
5633
|
+
this.processedContentCacheFingerprints.set(slug, contentCacheFingerprint);
|
|
4782
5634
|
this.observability().tracer.event("content.reuse", { slug });
|
|
4783
5635
|
return cloneManifestEntry(entry);
|
|
4784
5636
|
}
|
|
4785
5637
|
getPipelineFingerprint() {
|
|
4786
5638
|
if (!this.pipelineOptions.config) return void 0;
|
|
4787
|
-
this.pipelineFingerprint ??= computePipelineFingerprint(
|
|
4788
|
-
this.pipelineOptions.config
|
|
4789
|
-
);
|
|
5639
|
+
this.pipelineFingerprint ??= this.computePipelineFingerprint();
|
|
4790
5640
|
return this.pipelineFingerprint;
|
|
4791
5641
|
}
|
|
5642
|
+
requestBuildStateCommit(options) {
|
|
5643
|
+
if (this.pipelineOptions.commitBuildState === false) return;
|
|
5644
|
+
if (options?.incremental === true) this.buildStateCommitRequested = true;
|
|
5645
|
+
}
|
|
5646
|
+
async commitBuildState() {
|
|
5647
|
+
if (this.buildStateCommitted || !this.buildStateCommitRequested || !this.manifest || !this.outputChangeSet) {
|
|
5648
|
+
return;
|
|
5649
|
+
}
|
|
5650
|
+
const manifest = this.manifest;
|
|
5651
|
+
const outputChangeSet = this.outputChangeSet;
|
|
5652
|
+
const plan = await this.getBuildPlan();
|
|
5653
|
+
if (!plan.incremental) return;
|
|
5654
|
+
await this.observability().tracer.span(
|
|
5655
|
+
"content.build-state.save",
|
|
5656
|
+
{},
|
|
5657
|
+
() => this.buildCoordinator.commit(
|
|
5658
|
+
plan,
|
|
5659
|
+
manifest,
|
|
5660
|
+
this.getPipelineFingerprint(),
|
|
5661
|
+
[...outputChangeSet.affected, ...outputChangeSet.unchanged],
|
|
5662
|
+
this.cacheManifestEntries,
|
|
5663
|
+
this.trackedContentDependencies,
|
|
5664
|
+
plan.externalDependencies,
|
|
5665
|
+
this.processedContentCacheFingerprints,
|
|
5666
|
+
this.pluginRuntime.getManifestHookCache(),
|
|
5667
|
+
this.publishingBuildTime
|
|
5668
|
+
)
|
|
5669
|
+
);
|
|
5670
|
+
this.buildStateCommitted = true;
|
|
5671
|
+
}
|
|
5672
|
+
getBuildPlan(options) {
|
|
5673
|
+
if (this.buildPlan) return this.buildPlan;
|
|
5674
|
+
const plan = this.createBuildPlan(options);
|
|
5675
|
+
this.buildPlan = plan;
|
|
5676
|
+
void plan.catch(() => {
|
|
5677
|
+
if (this.buildPlan === plan) this.buildPlan = null;
|
|
5678
|
+
});
|
|
5679
|
+
return plan;
|
|
5680
|
+
}
|
|
5681
|
+
async createBuildPlan(options) {
|
|
5682
|
+
const config = this.pipelineOptions.config;
|
|
5683
|
+
if (config && hasGlobalContentDependency(config)) {
|
|
5684
|
+
this.pipelineFingerprint = this.computePipelineFingerprint(
|
|
5685
|
+
await this.getContentLocations()
|
|
5686
|
+
);
|
|
5687
|
+
}
|
|
5688
|
+
const contentIndex = await this.getContentIndex();
|
|
5689
|
+
const external = await this.observability().tracer.span(
|
|
5690
|
+
"external.dependencies.resolve",
|
|
5691
|
+
{},
|
|
5692
|
+
() => this.pluginRuntime.resolveExternalDependencies(contentIndex)
|
|
5693
|
+
);
|
|
5694
|
+
return this.buildCoordinator.getPlan(
|
|
5695
|
+
options?.incremental !== false,
|
|
5696
|
+
this.getPipelineFingerprint(),
|
|
5697
|
+
this.requiresFullContentRegeneration(),
|
|
5698
|
+
external.snapshots,
|
|
5699
|
+
external.failures,
|
|
5700
|
+
this.publishingBuildTime
|
|
5701
|
+
);
|
|
5702
|
+
}
|
|
5703
|
+
computePipelineFingerprint(locations) {
|
|
5704
|
+
const config = this.pipelineOptions.config;
|
|
5705
|
+
if (!config) return "";
|
|
5706
|
+
const contentScopeFingerprint = locations && hasGlobalContentDependency(config) ? computeContentScopeFingerprint(locations) : void 0;
|
|
5707
|
+
return computePipelineFingerprint(config, contentScopeFingerprint);
|
|
5708
|
+
}
|
|
4792
5709
|
requiresFullContentRegeneration() {
|
|
4793
5710
|
const config = this.pipelineOptions.config;
|
|
4794
|
-
return config ?
|
|
5711
|
+
return config ? requiresFullContentRegeneration(config) : false;
|
|
5712
|
+
}
|
|
5713
|
+
getProcessedContentCacheFingerprint(slug, source) {
|
|
5714
|
+
const config = this.pipelineOptions.config;
|
|
5715
|
+
if (!config || !isPersistentlyCacheable(slug, config, source).cacheable) {
|
|
5716
|
+
this.processedContentCacheFingerprints.set(slug, void 0);
|
|
5717
|
+
return void 0;
|
|
5718
|
+
}
|
|
5719
|
+
const fingerprint = computeContentCacheFingerprint(slug, source, config);
|
|
5720
|
+
this.processedContentCacheFingerprints.set(slug, fingerprint);
|
|
5721
|
+
return fingerprint;
|
|
4795
5722
|
}
|
|
4796
5723
|
isRoutable(slug) {
|
|
4797
5724
|
if (!this.routableSlugs) {
|
|
@@ -4834,6 +5761,21 @@ var ContentManager = class {
|
|
|
4834
5761
|
this.isBuildTime = true;
|
|
4835
5762
|
this.pluginRuntime.enableBuildTime();
|
|
4836
5763
|
}
|
|
5764
|
+
async emitPublicImageAssets(manifest) {
|
|
5765
|
+
const imagePaths = new Set(
|
|
5766
|
+
manifest.publicEntries.flatMap(
|
|
5767
|
+
(entry) => entry.assets.map((asset) => normalizeContentPath(asset.path)).filter(isImagePath)
|
|
5768
|
+
)
|
|
5769
|
+
);
|
|
5770
|
+
const entriesByPath = new Map(
|
|
5771
|
+
(await this.source.scan()).map((entry) => [entry.path, entry])
|
|
5772
|
+
);
|
|
5773
|
+
for (const path6 of imagePaths) {
|
|
5774
|
+
const entry = entriesByPath.get(path6);
|
|
5775
|
+
if (entry)
|
|
5776
|
+
this.pluginRuntime.emitCoreAsset(path6, await this.source.read(entry));
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
4837
5779
|
observability() {
|
|
4838
5780
|
return this.pipelineOptions.observability ?? noopObservability;
|
|
4839
5781
|
}
|
|
@@ -4853,8 +5795,7 @@ function cloneManifestEntry(entry) {
|
|
|
4853
5795
|
links: entry.links.map((link) => ({ ...link })),
|
|
4854
5796
|
backlinks: [...entry.backlinks],
|
|
4855
5797
|
assets: entry.assets.map((asset) => ({ ...asset })),
|
|
4856
|
-
...entry.headTags ? { headTags: [...entry.headTags] } : {}
|
|
4857
|
-
...entry.bodySlots ? { bodySlots: { ...entry.bodySlots } } : {}
|
|
5798
|
+
...entry.headTags ? { headTags: [...entry.headTags] } : {}
|
|
4858
5799
|
};
|
|
4859
5800
|
}
|
|
4860
5801
|
async function mapConcurrent3(values, concurrency, map) {
|
|
@@ -4886,6 +5827,12 @@ async function getContentSourceEntry(source, logicalPath) {
|
|
|
4886
5827
|
return (await source.scan()).find((candidate) => candidate.path === logicalPath) ?? null;
|
|
4887
5828
|
}
|
|
4888
5829
|
|
|
5830
|
+
// src/content/external_fingerprint.ts
|
|
5831
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
5832
|
+
function fingerprintExternalValue(value) {
|
|
5833
|
+
return createHash7("sha256").update(stableStringify(value)).digest("hex");
|
|
5834
|
+
}
|
|
5835
|
+
|
|
4889
5836
|
// src/content/folder_entry.ts
|
|
4890
5837
|
function resolveFolderEntry(manifest, folder, options = {}) {
|
|
4891
5838
|
const base = normalizeFolder2(folder);
|
|
@@ -5151,6 +6098,105 @@ function clampFinite(value, min, max) {
|
|
|
5151
6098
|
return clamp(value, min, max);
|
|
5152
6099
|
}
|
|
5153
6100
|
|
|
6101
|
+
// src/content/public_content_view.ts
|
|
6102
|
+
var emptyEntries = Object.freeze([]);
|
|
6103
|
+
function createPublicContentView(manifest) {
|
|
6104
|
+
const routableEntries = manifest.entries.filter(
|
|
6105
|
+
(entry) => entry.publishing.routable
|
|
6106
|
+
);
|
|
6107
|
+
const discoverableEntries = routableEntries.filter(
|
|
6108
|
+
(entry) => entry.publishing.discoverable
|
|
6109
|
+
);
|
|
6110
|
+
const routableSlugs = new Set(routableEntries.map((entry) => entry.slug));
|
|
6111
|
+
const copiesBySlug = new Map(
|
|
6112
|
+
routableEntries.map((entry) => [
|
|
6113
|
+
entry.slug,
|
|
6114
|
+
copyEntry(entry, routableSlugs)
|
|
6115
|
+
])
|
|
6116
|
+
);
|
|
6117
|
+
const discoverableSlugs = new Set(
|
|
6118
|
+
discoverableEntries.map((entry) => entry.slug)
|
|
6119
|
+
);
|
|
6120
|
+
const routableCopies = routableEntries.map((entry) => copiesBySlug.get(entry.slug)).filter(isDefined);
|
|
6121
|
+
const discoverableCopies = discoverableEntries.map((entry) => copiesBySlug.get(entry.slug)).filter(isDefined);
|
|
6122
|
+
const aliases = createAliasIndex2(routableCopies);
|
|
6123
|
+
const tags = createTagIndex(discoverableCopies);
|
|
6124
|
+
const getDiscoverableRelated = (relatedSlugs) => Object.freeze(
|
|
6125
|
+
relatedSlugs.filter((relatedSlug) => discoverableSlugs.has(relatedSlug)).map((relatedSlug) => copiesBySlug.get(relatedSlug)).filter(isDefined)
|
|
6126
|
+
);
|
|
6127
|
+
return Object.freeze({
|
|
6128
|
+
routableEntries: Object.freeze(routableCopies),
|
|
6129
|
+
discoverableEntries: Object.freeze(discoverableCopies),
|
|
6130
|
+
findRoutableBySlug: (slug) => copiesBySlug.get(slug),
|
|
6131
|
+
findDiscoverableBySlug: (slug) => discoverableSlugs.has(slug) ? copiesBySlug.get(slug) : void 0,
|
|
6132
|
+
findRoutableByAlias: (alias) => aliases.get(alias.toLowerCase()) ?? emptyEntries,
|
|
6133
|
+
getDiscoverableEntriesByTag: (tag) => tags.get(tag) ?? emptyEntries,
|
|
6134
|
+
getDiscoverableOutgoing: (slug) => getDiscoverableRelated(manifest.graph.outgoingSlugs(slug)),
|
|
6135
|
+
getDiscoverableIncoming: (slug) => getDiscoverableRelated(manifest.graph.incomingSlugs(slug)),
|
|
6136
|
+
getDiscoverableNeighbors: (slug) => getDiscoverableRelated(manifest.graph.neighborSlugs(slug))
|
|
6137
|
+
});
|
|
6138
|
+
}
|
|
6139
|
+
function copyEntry(entry, routableSlugs) {
|
|
6140
|
+
return deepFreeze2(
|
|
6141
|
+
structuredClone({
|
|
6142
|
+
slug: entry.slug,
|
|
6143
|
+
...entry.contentId === void 0 ? {} : { contentId: entry.contentId },
|
|
6144
|
+
permalink: entry.permalink,
|
|
6145
|
+
publicLocation: entry.publicLocation,
|
|
6146
|
+
title: entry.title,
|
|
6147
|
+
...entry.aliases === void 0 ? {} : { aliases: entry.aliases },
|
|
6148
|
+
publishing: {
|
|
6149
|
+
visibility: entry.publishing.visibility,
|
|
6150
|
+
routable: entry.publishing.routable,
|
|
6151
|
+
discoverable: entry.publishing.discoverable
|
|
6152
|
+
},
|
|
6153
|
+
tags: entry.tags,
|
|
6154
|
+
links: entry.links.filter(
|
|
6155
|
+
(link) => link.kind !== "note" || link.slug === null || routableSlugs.has(link.slug)
|
|
6156
|
+
),
|
|
6157
|
+
assets: entry.assets
|
|
6158
|
+
})
|
|
6159
|
+
);
|
|
6160
|
+
}
|
|
6161
|
+
function createAliasIndex2(entries) {
|
|
6162
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
6163
|
+
for (const entry of entries) {
|
|
6164
|
+
for (const alias of entry.aliases ?? []) {
|
|
6165
|
+
const matches = aliases.get(alias.toLowerCase()) ?? [];
|
|
6166
|
+
matches.push(entry);
|
|
6167
|
+
aliases.set(alias.toLowerCase(), matches);
|
|
6168
|
+
}
|
|
6169
|
+
}
|
|
6170
|
+
return new Map(
|
|
6171
|
+
[...aliases].map(([alias, entries2]) => [alias, Object.freeze(entries2)])
|
|
6172
|
+
);
|
|
6173
|
+
}
|
|
6174
|
+
function createTagIndex(entries) {
|
|
6175
|
+
const tags = /* @__PURE__ */ new Map();
|
|
6176
|
+
for (const entry of entries) {
|
|
6177
|
+
for (const tag of entry.tags) {
|
|
6178
|
+
const taggedEntries = tags.get(tag) ?? [];
|
|
6179
|
+
taggedEntries.push(entry);
|
|
6180
|
+
tags.set(tag, taggedEntries);
|
|
6181
|
+
}
|
|
6182
|
+
}
|
|
6183
|
+
return new Map(
|
|
6184
|
+
[...tags].map(([tag, entries2]) => [tag, Object.freeze(entries2)])
|
|
6185
|
+
);
|
|
6186
|
+
}
|
|
6187
|
+
function deepFreeze2(value) {
|
|
6188
|
+
if (value === null || typeof value !== "object") {
|
|
6189
|
+
return value;
|
|
6190
|
+
}
|
|
6191
|
+
for (const child of Object.values(value)) {
|
|
6192
|
+
deepFreeze2(child);
|
|
6193
|
+
}
|
|
6194
|
+
return Object.freeze(value);
|
|
6195
|
+
}
|
|
6196
|
+
function isDefined(value) {
|
|
6197
|
+
return value !== void 0;
|
|
6198
|
+
}
|
|
6199
|
+
|
|
5154
6200
|
// src/content/read_only_content_graph.ts
|
|
5155
6201
|
async function readOnlyContentGraph(source, locations) {
|
|
5156
6202
|
const entries = await source.scan();
|
|
@@ -5214,25 +6260,6 @@ function resolveBuildOutputDirectory(config) {
|
|
|
5214
6260
|
return directory ? path5.resolve(directory) : void 0;
|
|
5215
6261
|
}
|
|
5216
6262
|
|
|
5217
|
-
// src/types/content_manifest.ts
|
|
5218
|
-
var ARTICLE_SLOT = {
|
|
5219
|
-
header: "article.header",
|
|
5220
|
-
metadata: "article.metadata",
|
|
5221
|
-
aside: "article.aside",
|
|
5222
|
-
beforeContent: "article.before-content",
|
|
5223
|
-
afterContent: "article.after-content",
|
|
5224
|
-
footer: "article.footer"
|
|
5225
|
-
};
|
|
5226
|
-
function appendContentBodySlot(entry, slot, html) {
|
|
5227
|
-
if (!html.trim()) return;
|
|
5228
|
-
const previous = entry.bodySlots?.[slot];
|
|
5229
|
-
entry.bodySlots = {
|
|
5230
|
-
...entry.bodySlots,
|
|
5231
|
-
[slot]: previous ? `${previous}
|
|
5232
|
-
${html}` : html
|
|
5233
|
-
};
|
|
5234
|
-
}
|
|
5235
|
-
|
|
5236
6263
|
// src/types/plugin_endpoint.ts
|
|
5237
6264
|
function defineEndpoint(path6, handler, options = {}) {
|
|
5238
6265
|
if (options.cacheControl === void 0) {
|
|
@@ -5300,8 +6327,8 @@ function calculateReadingTime(html) {
|
|
|
5300
6327
|
return Math.max(1, Math.ceil(cjkCharacters / 500 + latinWords / 220));
|
|
5301
6328
|
}
|
|
5302
6329
|
export {
|
|
5303
|
-
ARTICLE_SLOT,
|
|
5304
6330
|
ATTACHMENTS_BASE_PATH,
|
|
6331
|
+
CONTENT_BUILD_STATE_VERSION,
|
|
5305
6332
|
CompositeTraceSink,
|
|
5306
6333
|
ConfigValidationError,
|
|
5307
6334
|
ConsoleLogger,
|
|
@@ -5315,7 +6342,6 @@ export {
|
|
|
5315
6342
|
PluginDependencyError,
|
|
5316
6343
|
PluginHookError,
|
|
5317
6344
|
SinkTracer,
|
|
5318
|
-
appendContentBodySlot,
|
|
5319
6345
|
attachErrorPath,
|
|
5320
6346
|
attachmentUrl,
|
|
5321
6347
|
buildContentCollections,
|
|
@@ -5326,6 +6352,7 @@ export {
|
|
|
5326
6352
|
createClientEntry,
|
|
5327
6353
|
createContentGraph,
|
|
5328
6354
|
createPluginMemo,
|
|
6355
|
+
createPublicContentView,
|
|
5329
6356
|
createStyleAsset,
|
|
5330
6357
|
createUnavailableGeneratedOutputSink,
|
|
5331
6358
|
defineConfig,
|
|
@@ -5338,6 +6365,7 @@ export {
|
|
|
5338
6365
|
escapeScriptJson,
|
|
5339
6366
|
extractFrontmatterAliases,
|
|
5340
6367
|
fingerprintContentEntries,
|
|
6368
|
+
fingerprintExternalValue,
|
|
5341
6369
|
getContentSourceEntry,
|
|
5342
6370
|
getEntryLanguage,
|
|
5343
6371
|
getExtension,
|