@lupinum/ginko-content 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compatibility.json +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/cms-contract/build.js +15 -20
- package/dist/cms-contract/types.d.ts +12 -7
- package/dist/core/content/document +1 -0
- package/dist/core/content/document.d.ts +16 -0
- package/dist/core/content/document.js +2 -0
- package/dist/core/content/graph.d.ts +3 -1
- package/dist/core/content/graph.js +21 -20
- package/dist/core/content/locale.d.ts +6 -1
- package/dist/core/content/locale.js +17 -6
- package/dist/core/content/path.d.ts +5 -5
- package/dist/core/content/path.js +8 -8
- package/dist/core/content/snapshot +1 -0
- package/dist/core/content/snapshot.d.ts +25 -0
- package/dist/core/content/snapshot.js +99 -0
- package/dist/core/provider-errors.d.ts +1 -1
- package/dist/core/provider-errors.js +1 -0
- package/dist/core/query/builder.js +3 -3
- package/dist/core/query/execute.js +75 -36
- package/dist/core/query/filter.js +2 -2
- package/dist/core/query/lower.js +79 -3
- package/dist/core/query/params.js +7 -7
- package/dist/core/query/plan.d.ts +18 -0
- package/dist/core/query/plan.js +7 -0
- package/dist/core/references/resolve.js +6 -9
- package/dist/features/agent/agent-markdown +1 -0
- package/dist/features/agent/agent-markdown.d.ts +116 -0
- package/dist/features/agent/agent-markdown.js +138 -0
- package/dist/features/agent/walker +1 -0
- package/dist/features/agent/walker.d.ts +10 -0
- package/dist/features/agent/walker.js +174 -0
- package/dist/features/collections/resolve.d.ts +2 -2
- package/dist/features/collections/resolve.js +19 -16
- package/dist/features/localization/links.js +1 -1
- package/dist/features/localization/results.d.ts +3 -3
- package/dist/features/localization/results.js +46 -41
- package/dist/features/localization/translated-slugs.js +5 -5
- package/dist/features/navigation/build.d.ts +2 -2
- package/dist/features/navigation/build.js +23 -26
- package/dist/features/navigation/canonical.d.ts +10 -11
- package/dist/features/navigation/canonical.js +26 -21
- package/dist/features/navigation/resolve.js +4 -4
- package/dist/features/navigation/tree.js +3 -3
- package/dist/{runtime → features}/query/backlinks.js +3 -5
- package/dist/{runtime → features}/query/documents.js +1 -1
- package/dist/{runtime → features}/query/localized-docs.d.ts +1 -1
- package/dist/{runtime → features}/query/localized-docs.js +3 -6
- package/dist/{runtime → features}/query/navigation.d.ts +1 -1
- package/dist/{runtime → features}/query/navigation.js +8 -8
- package/dist/{runtime → features}/query/populate.js +6 -14
- package/dist/{runtime → features}/query/unified.d.ts +4 -4
- package/dist/{runtime → features}/query/unified.js +4 -2
- package/dist/{runtime → features}/query/variants.js +4 -4
- package/dist/features/search/navigation.js +2 -2
- package/dist/features/search/sections.d.ts +1 -1
- package/dist/features/search/sections.js +1 -1
- package/dist/features/sitemap/query.d.ts +5 -5
- package/dist/features/sitemap/query.js +6 -6
- package/dist/integrations/nitro/ingest.js +9 -20
- package/dist/integrations/nitro/storage.d.ts +1 -0
- package/dist/integrations/nitro/storage.js +22 -8
- package/dist/module.d.mts +135 -812
- package/dist/module.json +1 -1
- package/dist/module.mjs +70 -27
- package/dist/parsers/csv.js +3 -3
- package/dist/parsers/index.js +3 -3
- package/dist/parsers/json.js +8 -6
- package/dist/parsers/markdown-plugins.js +9 -5
- package/dist/parsers/markdown.js +7 -6
- package/dist/parsers/path-meta.js +21 -19
- package/dist/parsers/reserved +1 -0
- package/dist/parsers/reserved.d.ts +15 -0
- package/dist/parsers/reserved.js +35 -0
- package/dist/parsers/yaml.js +6 -4
- package/dist/public/agent +1 -0
- package/dist/public/agent.d.ts +17 -0
- package/dist/public/agent.js +34 -0
- package/dist/public/client.d.ts +2 -3
- package/dist/public/client.js +1 -2
- package/dist/public/provider-query +1 -0
- package/dist/public/provider-query.d.ts +58 -0
- package/dist/public/provider-query.js +5 -0
- package/dist/public/provider.d.ts +8 -3
- package/dist/public/provider.js +2 -0
- package/dist/public/server.d.ts +7 -12
- package/dist/public/server.js +5 -36
- package/dist/runtime/app/components/ContentRenderer.d.vue.ts +3 -3
- package/dist/runtime/app/components/ContentRenderer.vue +2 -2
- package/dist/runtime/app/components/ContentRenderer.vue.d.ts +3 -3
- package/dist/runtime/app/components/ContentRendererInline.d.vue.ts +1 -1
- package/dist/runtime/app/components/ContentRendererInline.vue.d.ts +1 -1
- package/dist/runtime/app/components/Prose/ProseImg.d.vue.ts +4 -4
- package/dist/runtime/app/components/Prose/ProseImg.vue.d.ts +4 -4
- package/dist/runtime/app/components/Prose/ProsePre.d.vue.ts +1 -1
- package/dist/runtime/app/components/Prose/ProsePre.vue.d.ts +1 -1
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.d.vue.ts +1 -1
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue +4 -4
- package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue.d.ts +1 -1
- package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +3 -3
- package/dist/runtime/app/composables/preview.d.ts +1 -1
- package/dist/runtime/app/composables/query-api.d.ts +5 -5
- package/dist/runtime/app/composables/query-api.js +5 -3
- package/dist/runtime/app/composables/route.d.ts +1 -1
- package/dist/runtime/app/composables/route.js +4 -4
- package/dist/runtime/app/composables/search.js +1 -1
- package/dist/runtime/app/composables/use-content-document.js +1 -1
- package/dist/runtime/app/composables/use-content-list.js +1 -1
- package/dist/runtime/app/composables/use-content-navigation.js +2 -2
- package/dist/runtime/app/composables/use-content-page.js +4 -4
- package/dist/runtime/app/pages/content.vue +2 -1
- package/dist/runtime/markdown/plugins.js +6 -8
- package/dist/runtime/server/agent-markdown.d.ts +5 -65
- package/dist/runtime/server/agent-markdown.js +40 -315
- package/dist/runtime/server/agent-site.js +1 -1
- package/dist/runtime/server/api/agent-raw.js +1 -1
- package/dist/runtime/server/api/cache.d.ts +1 -1
- package/dist/runtime/server/api/cache.js +43 -4
- package/dist/runtime/server/api/locales.js +3 -3
- package/dist/runtime/server/api/navigation.d.ts +1 -1
- package/dist/runtime/server/api/navigation.js +3 -1
- package/dist/runtime/server/api/query.js +2 -2
- package/dist/runtime/server/api/search-index.d.ts +1 -1
- package/dist/runtime/server/api/sitemap.d.ts +1 -1
- package/dist/runtime/server/cache-adapters.d.ts +18 -0
- package/dist/runtime/server/cache-adapters.js +12 -0
- package/dist/runtime/server/collection-helpers.d.ts +2 -2
- package/dist/runtime/server/collection-helpers.js +15 -11
- package/dist/runtime/server/index.d.ts +6 -4
- package/dist/runtime/server/index.js +10 -3
- package/dist/runtime/server/middleware/agent-link-headers.js +1 -1
- package/dist/runtime/server/middleware/agent-markdown.js +1 -1
- package/dist/runtime/server/navigation-query.d.ts +2 -2
- package/dist/runtime/server/navigation-query.js +52 -7
- package/dist/runtime/server/navigation.d.ts +1 -1
- package/dist/runtime/server/provider-document +1 -0
- package/dist/runtime/server/provider-document.d.ts +59 -0
- package/dist/runtime/server/provider-document.js +48 -0
- package/dist/runtime/server/provider-query-wire +1 -0
- package/dist/runtime/server/provider-query-wire.d.ts +32 -0
- package/dist/runtime/server/provider-query-wire.js +27 -0
- package/dist/runtime/server/provider-query.d.ts +18 -9
- package/dist/runtime/server/provider-query.js +62 -28
- package/dist/runtime/server/provider-result.d.ts +4 -4
- package/dist/runtime/server/providers/filesystem.js +3 -11
- package/dist/runtime/server/providers/index.d.ts +18 -1
- package/dist/runtime/server/providers/index.js +72 -20
- package/dist/runtime/server/query-api.d.ts +5 -5
- package/dist/runtime/server/query-api.js +9 -6
- package/dist/runtime/server/query-executor.d.ts +3 -3
- package/dist/runtime/server/query-executor.js +43 -59
- package/dist/runtime/server/search.d.ts +1 -1
- package/dist/runtime/server/search.js +4 -4
- package/dist/runtime/server/sitemap.js +5 -5
- package/dist/runtime/server/storage-access.d.ts +4 -1
- package/dist/runtime/server/storage-access.js +27 -2
- package/dist/runtime/transformers/component-resolver.d.ts +1 -1
- package/dist/storage/content.d.ts +2 -6
- package/dist/storage/content.js +19 -8
- package/dist/storage/contents.d.ts +9 -1
- package/dist/storage/contents.js +26 -19
- package/dist/storage/driver.d.ts +2 -2
- package/dist/storage/driver.js +2 -1
- package/dist/storage/graph.js +4 -0
- package/dist/storage/manifest.js +3 -1
- package/dist/storage/references.js +9 -5
- package/dist/storage/snapshot-runtime +1 -0
- package/dist/storage/snapshot-runtime.d.ts +11 -0
- package/dist/storage/snapshot-runtime.js +46 -0
- package/dist/storage/validation.d.ts +1 -1
- package/dist/storage/validation.js +47 -102
- package/dist/testing/provider-contract.d.ts +14 -4
- package/dist/testing/provider-contract.js +121 -68
- package/dist/testing/provider-fixture.d.ts +1 -1
- package/dist/testing/provider-fixture.js +124 -120
- package/dist/types/config.d.ts +8 -4
- package/dist/types/content.d.ts +104 -70
- package/dist/types/fields.js +1 -1
- package/dist/types/module.d.ts +1 -1
- package/dist/types/query-parts/public.d.ts +14 -5
- package/dist/types/query-parts/results.d.ts +6 -2
- package/dist/types/query-parts/transport.d.ts +19 -0
- package/dist/types/virtual.d.ts +6 -0
- package/dist/types.d.mts +2 -2
- package/dist/web-types.json +1 -1
- package/package.json +39 -9
- package/dist/runtime/app/plugins/markdown-components +0 -1
- package/dist/runtime/app/plugins/markdown-components.d.ts +0 -2
- package/dist/runtime/app/plugins/markdown-components.js +0 -19
- /package/dist/{runtime → features/agent}/agent-paths +0 -0
- /package/dist/{runtime → features/agent}/agent-paths.d.ts +0 -0
- /package/dist/{runtime → features/agent}/agent-paths.js +0 -0
- /package/dist/{runtime → features}/query/backlinks +0 -0
- /package/dist/{runtime → features}/query/backlinks.d.ts +0 -0
- /package/dist/{runtime → features}/query/context +0 -0
- /package/dist/{runtime → features}/query/context.d.ts +0 -0
- /package/dist/{runtime → features}/query/context.js +0 -0
- /package/dist/{runtime → features}/query/documents +0 -0
- /package/dist/{runtime → features}/query/documents.d.ts +0 -0
- /package/dist/{runtime → features}/query/errors +0 -0
- /package/dist/{runtime → features}/query/errors.d.ts +0 -0
- /package/dist/{runtime → features}/query/errors.js +0 -0
- /package/dist/{runtime → features}/query/handles +0 -0
- /package/dist/{runtime → features}/query/handles.d.ts +0 -0
- /package/dist/{runtime → features}/query/handles.js +0 -0
- /package/dist/{runtime → features}/query/locale-options +0 -0
- /package/dist/{runtime → features}/query/locale-options.d.ts +0 -0
- /package/dist/{runtime → features}/query/locale-options.js +0 -0
- /package/dist/{runtime → features}/query/localized-docs +0 -0
- /package/dist/{runtime → features}/query/navigation +0 -0
- /package/dist/{runtime → features}/query/pagination +0 -0
- /package/dist/{runtime → features}/query/pagination.d.ts +0 -0
- /package/dist/{runtime → features}/query/pagination.js +0 -0
- /package/dist/{runtime → features}/query/populate +0 -0
- /package/dist/{runtime → features}/query/populate.d.ts +0 -0
- /package/dist/{runtime → features}/query/public-limits +0 -0
- /package/dist/{runtime → features}/query/public-limits.d.ts +0 -0
- /package/dist/{runtime → features}/query/public-limits.js +0 -0
- /package/dist/{runtime → features}/query/resolve +0 -0
- /package/dist/{runtime → features}/query/resolve.d.ts +0 -0
- /package/dist/{runtime → features}/query/resolve.js +0 -0
- /package/dist/{runtime → features}/query/responses +0 -0
- /package/dist/{runtime → features}/query/responses.d.ts +0 -0
- /package/dist/{runtime → features}/query/responses.js +0 -0
- /package/dist/{runtime → features}/query/routes +0 -0
- /package/dist/{runtime → features}/query/routes.d.ts +0 -0
- /package/dist/{runtime → features}/query/routes.js +0 -0
- /package/dist/{runtime → features}/query/unified +0 -0
- /package/dist/{runtime → features}/query/variants +0 -0
- /package/dist/{runtime → features}/query/variants.d.ts +0 -0
|
@@ -32,10 +32,10 @@ const localePathMatches = (entry, path) => {
|
|
|
32
32
|
const routeMetaMatchesPath = (value, path) => {
|
|
33
33
|
if (!value) return false;
|
|
34
34
|
const normalizedPath = normalizeRoutePath(path);
|
|
35
|
-
const
|
|
36
|
-
if (normalizeRoutePath(
|
|
37
|
-
const requestedRoute =
|
|
38
|
-
return normalizeRoutePath(value.path) === normalizedPath || normalizeRoutePath(value.
|
|
35
|
+
const resolved = value.resolved;
|
|
36
|
+
if (normalizeRoutePath(value.path) === normalizedPath || normalizeRoutePath(resolved?.requestedPath) === normalizedPath || normalizeRoutePath(resolved?.requestedRoute) === normalizedPath) return true;
|
|
37
|
+
const requestedRoute = resolved?.requestedRoute;
|
|
38
|
+
return normalizeRoutePath(value.path) === normalizedPath || normalizeRoutePath(value.unprefixedPath) === normalizedPath || normalizeRoutePath(requestedRoute) === normalizedPath || Object.values(value.localePaths || {}).some((entry) => localePathMatches(entry, path));
|
|
39
39
|
};
|
|
40
40
|
export async function useContentPage(handle, options = {}) {
|
|
41
41
|
const route = useRoute();
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import { defineAsyncComponent } from "vue";
|
|
2
2
|
export { resolveMarkdownPlugins } from "../../parsers/markdown-plugins";
|
|
3
|
+
const importOptionalMarkdownComponent = async (specifier) => await import(
|
|
4
|
+
/* @vite-ignore */
|
|
5
|
+
specifier
|
|
6
|
+
);
|
|
3
7
|
const builtinMarkdownPlugins = {
|
|
4
8
|
math: {
|
|
5
9
|
componentName: "Math",
|
|
6
10
|
component: defineAsyncComponent(async () => {
|
|
7
|
-
const mod = await
|
|
8
|
-
/* @vite-ignore */
|
|
9
|
-
["@comark/vue", "plugins/math"].join("/")
|
|
10
|
-
);
|
|
11
|
+
const mod = await importOptionalMarkdownComponent("@comark/vue/plugins/math");
|
|
11
12
|
return mod.Math;
|
|
12
13
|
})
|
|
13
14
|
},
|
|
14
15
|
mermaid: {
|
|
15
16
|
componentName: "Mermaid",
|
|
16
17
|
component: defineAsyncComponent(async () => {
|
|
17
|
-
const mod = await
|
|
18
|
-
/* @vite-ignore */
|
|
19
|
-
["@comark/vue", "plugins/mermaid"].join("/")
|
|
20
|
-
);
|
|
18
|
+
const mod = await importOptionalMarkdownComponent("@comark/vue/plugins/mermaid");
|
|
21
19
|
return mod.Mermaid;
|
|
22
20
|
})
|
|
23
21
|
}
|
|
@@ -1,74 +1,14 @@
|
|
|
1
1
|
import type { H3Event } from 'h3';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
aiTrain?: 'yes' | 'no';
|
|
8
|
-
}
|
|
9
|
-
export interface ResolvedAgentMarkdownOptions {
|
|
10
|
-
includeInIndex: boolean;
|
|
11
|
-
includeInFull: boolean;
|
|
12
|
-
metadata: AgentMetadataField[];
|
|
13
|
-
}
|
|
14
|
-
export interface AgentMarkdown {
|
|
15
|
-
path: string;
|
|
16
|
-
markdownPath: string;
|
|
17
|
-
rawPath: string;
|
|
18
|
-
locale?: string;
|
|
19
|
-
collection: string;
|
|
20
|
-
title: string;
|
|
21
|
-
description: string;
|
|
22
|
-
markdown: string;
|
|
23
|
-
sourceFile?: string;
|
|
24
|
-
canonicalUrl: string;
|
|
25
|
-
lastModified?: string;
|
|
26
|
-
publicSignals?: AgentMarkdownPublicSignals;
|
|
27
|
-
metadataFields: string[];
|
|
28
|
-
includeInIndex: boolean;
|
|
29
|
-
includeInFull: boolean;
|
|
30
|
-
}
|
|
31
|
-
export type AgentMarkdownMeta = Omit<AgentMarkdown, 'markdown'>;
|
|
32
|
-
export interface AgentMarkdownContext {
|
|
33
|
-
collection: string;
|
|
34
|
-
page: ParsedContent;
|
|
35
|
-
path: string;
|
|
36
|
-
locale?: string;
|
|
37
|
-
prop: (name: string) => string;
|
|
38
|
-
props: (node?: MarkdownNode) => Record<string, unknown>;
|
|
39
|
-
cleanProps: (node?: MarkdownNode) => Record<string, unknown>;
|
|
40
|
-
children: (node?: MarkdownNode) => string;
|
|
41
|
-
renderChildren: (node: MarkdownNode) => string;
|
|
42
|
-
renderNode: (node: MarkdownNode) => string;
|
|
43
|
-
blockquote: (value: string) => string;
|
|
44
|
-
jsonFence: (value: unknown) => string;
|
|
45
|
-
link: (label: string, href: string) => string;
|
|
46
|
-
omitted: (name: string, reason?: string) => string;
|
|
47
|
-
xmlComponent: (name: string, props?: Record<string, unknown>, children?: string) => string;
|
|
48
|
-
}
|
|
49
|
-
export type AgentMarkdownSerializer = (node: MarkdownNode, ctx: AgentMarkdownContext) => string | null | undefined;
|
|
50
|
-
export type AgentMarkdownSerializerMap = Record<string, AgentMarkdownSerializer>;
|
|
51
|
-
export interface AgentMarkdownSerializerRegistrationOptions {
|
|
52
|
-
override?: boolean;
|
|
53
|
-
}
|
|
54
|
-
export interface AgentMarkdownComponent {
|
|
55
|
-
render: AgentMarkdownSerializer;
|
|
56
|
-
}
|
|
57
|
-
export type AgentMarkdownComponentMap = Record<string, AgentMarkdownComponent>;
|
|
58
|
-
export declare const getMarkdownProp: (node: MarkdownNode, name: string) => string;
|
|
59
|
-
export declare const renderMarkdownChildren: (node: MarkdownNode, ctx: AgentMarkdownContext) => string;
|
|
60
|
-
export declare const blockquoteMarkdown: (value: string) => string;
|
|
61
|
-
export declare const linkMarkdown: (label: string, href: string) => string;
|
|
62
|
-
export declare const imageMarkdown: (alt: string, src: string) => string;
|
|
63
|
-
export declare const jsonFenceMarkdown: (value: unknown) => string;
|
|
64
|
-
export declare const xmlComponentMarkdown: (name: string, props?: Record<string, unknown>, children?: string) => string;
|
|
2
|
+
import type { AgentMarkdown, AgentMarkdownComponent, AgentMarkdownComponentMap, AgentMarkdownMeta, AgentMarkdownRegistry, AgentMarkdownSerializer, AgentMarkdownSerializerMap, AgentMarkdownSerializerRegistrationOptions } from '../../features/agent/agent-markdown';
|
|
3
|
+
export * from '../../features/agent/agent-markdown';
|
|
4
|
+
export { renderAgentMarkdownBody } from '../../features/agent/walker';
|
|
5
|
+
/** The current app's serializer registry the walker resolves tags against. */
|
|
6
|
+
export declare const getAgentMarkdownRegistry: () => AgentMarkdownRegistry;
|
|
65
7
|
export declare const registerAgentMarkdownSerializer: (name: string, serializer: AgentMarkdownSerializer, options?: AgentMarkdownSerializerRegistrationOptions) => void;
|
|
66
8
|
export declare const registerAgentMarkdownSerializers: (entries: AgentMarkdownSerializerMap, options?: AgentMarkdownSerializerRegistrationOptions) => void;
|
|
67
|
-
export declare const defineAgentMarkdownComponent: (component: AgentMarkdownComponent) => AgentMarkdownComponent;
|
|
68
9
|
export declare const registerAgentMarkdownComponent: (name: string, component: AgentMarkdownComponent, options?: AgentMarkdownSerializerRegistrationOptions) => void;
|
|
69
10
|
export declare const registerAgentMarkdownComponents: (entries: AgentMarkdownComponentMap, options?: AgentMarkdownSerializerRegistrationOptions) => void;
|
|
70
11
|
export declare const clearAgentMarkdownSerializers: () => void;
|
|
71
|
-
export declare const resolveAgentMarkdownOptions: (collection: ContentCollectionConfig | undefined) => ResolvedAgentMarkdownOptions | null;
|
|
72
12
|
export declare function resolveContentMarkdown(event: H3Event, collection: string, routeOrPath?: string, options?: {
|
|
73
13
|
locale?: string;
|
|
74
14
|
}): Promise<AgentMarkdown | null>;
|
|
@@ -1,324 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
createAgentMarkdownRegistry,
|
|
3
|
+
resolveAgentMarkdownOptions
|
|
4
|
+
} from "../../features/agent/agent-markdown";
|
|
5
|
+
import { renderAgentMarkdownBody } from "../../features/agent/walker";
|
|
6
|
+
import { agentMarkdownPathForRoute, agentRawPathForRoute, normalizeAgentRoutePath } from "../../features/agent/agent-paths";
|
|
7
|
+
import { getCollectionPath } from "../../features/query/routes";
|
|
4
8
|
import { getContentProvider } from "./providers/index.js";
|
|
9
|
+
import { createProviderQuery } from "./provider-query.js";
|
|
5
10
|
import { contentConfig } from "./storage-access.js";
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
export * from "../../features/agent/agent-markdown";
|
|
12
|
+
export { renderAgentMarkdownBody } from "../../features/agent/walker";
|
|
13
|
+
const appRegistry = createAgentMarkdownRegistry();
|
|
14
|
+
export const getAgentMarkdownRegistry = () => appRegistry;
|
|
15
|
+
export const registerAgentMarkdownSerializer = (name, serializer, options) => appRegistry.register(name, serializer, options);
|
|
16
|
+
export const registerAgentMarkdownSerializers = (entries, options) => appRegistry.registerMany(entries, options);
|
|
17
|
+
export const registerAgentMarkdownComponent = (name, component, options) => appRegistry.registerComponent(name, component, options);
|
|
18
|
+
export const registerAgentMarkdownComponents = (entries, options) => appRegistry.registerComponents(entries, options);
|
|
19
|
+
export const clearAgentMarkdownSerializers = () => appRegistry.clear();
|
|
8
20
|
const defaultLocale = () => contentConfig().defaultLocale || contentConfig().locales?.[0] || contentConfig().agent?.site?.defaultLocale || "en";
|
|
9
21
|
const configuredLocales = () => {
|
|
10
22
|
const locales = contentConfig().agent?.site?.locales?.length ? contentConfig().agent?.site?.locales : contentConfig().locales;
|
|
11
23
|
return locales?.length ? locales : [defaultLocale()];
|
|
12
24
|
};
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (!withoutHash) return href;
|
|
24
|
-
if (isExternalHref(withoutHash)) return href;
|
|
25
|
-
if (withoutHash.endsWith(".md")) return href;
|
|
26
|
-
const target = withoutHash.startsWith("/") ? prefixLocalizedHref(withoutHash, locale) : new URL(withoutHash, `https://agent.local${normalizeAgentRoutePath(currentPath)}`).pathname;
|
|
27
|
-
return `${agentRawPathForRoute(target)}${hash}`;
|
|
28
|
-
};
|
|
29
|
-
export const getMarkdownProp = (node, name) => {
|
|
30
|
-
const props = isRecord(node.props) ? node.props : {};
|
|
31
|
-
const value = props[name];
|
|
32
|
-
return typeof value === "string" ? value : "";
|
|
33
|
-
};
|
|
34
|
-
export const renderMarkdownChildren = (node, ctx) => ctx.renderChildren(node);
|
|
35
|
-
export const blockquoteMarkdown = (value) => value.trim().split("\n").map((line) => line ? `> ${line}` : ">").join("\n");
|
|
36
|
-
const escapeMarkdownLinkLabel = (value) => value.replace(/\\/g, "\\\\").replace(/\[/g, "\\[").replace(/\]/g, "\\]");
|
|
37
|
-
const escapeMarkdownLinkHref = (value) => value.replace(/\)/g, "%29").replace(/\s/g, "%20");
|
|
38
|
-
const isSafeMarkdownHref = (href) => {
|
|
39
|
-
if (!href) return false;
|
|
40
|
-
if (href.startsWith("//")) return false;
|
|
41
|
-
if (href.startsWith("/") || href.startsWith("#") || href.startsWith("./") || href.startsWith("../")) return true;
|
|
42
|
-
return /^(https?:|mailto:|tel:)/i.test(href);
|
|
43
|
-
};
|
|
44
|
-
export const linkMarkdown = (label, href) => {
|
|
45
|
-
const resolvedLabel = label || href;
|
|
46
|
-
if (!href || !isSafeMarkdownHref(href)) return escapeMarkdownLinkLabel(resolvedLabel);
|
|
47
|
-
return `[${escapeMarkdownLinkLabel(resolvedLabel)}](${escapeMarkdownLinkHref(href)})`;
|
|
48
|
-
};
|
|
49
|
-
export const imageMarkdown = (alt, src) => {
|
|
50
|
-
if (!src || !isSafeMarkdownHref(src)) return escapeMarkdownLinkLabel(alt || src);
|
|
51
|
-
return `})`;
|
|
52
|
-
};
|
|
53
|
-
export const jsonFenceMarkdown = (value) => `\`\`\`json
|
|
54
|
-
${JSON.stringify(value, null, 2)}
|
|
55
|
-
\`\`\``;
|
|
56
|
-
const xmlNamePattern = /^[a-z][\w.:-]*$/i;
|
|
57
|
-
const safeXmlName = (name) => xmlNamePattern.test(name) ? name : "component";
|
|
58
|
-
const escapeXmlAttribute = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
59
|
-
const isScalarXmlAttributeValue = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
60
|
-
const shouldDropAgentProp = (name) => {
|
|
61
|
-
const normalized = name.trim();
|
|
62
|
-
const sensitive = normalized.toLowerCase();
|
|
63
|
-
return !normalized || normalized === "class" || normalized === "style" || normalized === "key" || normalized === "ref" || normalized.startsWith("v-") || normalized.startsWith("@") || normalized.startsWith("on") || normalized.startsWith("data-") || normalized.startsWith("aria-") || /token|secret|password|passwd|credential|authorization|apikey|api-key|clientsecret|client-secret|privatekey|private-key|accesskey|access-key/i.test(sensitive);
|
|
64
|
-
};
|
|
65
|
-
const normalizeAgentPropName = (name) => {
|
|
66
|
-
const normalized = name.trim();
|
|
67
|
-
if (normalized.startsWith(":")) return normalized.slice(1);
|
|
68
|
-
if (normalized.startsWith("v-bind:")) return normalized.slice("v-bind:".length);
|
|
69
|
-
return normalized;
|
|
70
|
-
};
|
|
71
|
-
const cleanAgentPropValue = (value) => {
|
|
72
|
-
if (value === void 0 || value === null || value === "") return void 0;
|
|
73
|
-
if (Array.isArray(value)) {
|
|
74
|
-
const clean = value.map((entry) => cleanAgentPropValue(entry)).filter((entry) => entry !== void 0);
|
|
75
|
-
return clean.length ? clean : void 0;
|
|
76
|
-
}
|
|
77
|
-
if (isRecord(value)) {
|
|
78
|
-
const clean = cleanPropsObject(value);
|
|
79
|
-
return Object.keys(clean).length ? clean : void 0;
|
|
80
|
-
}
|
|
81
|
-
return value;
|
|
82
|
-
};
|
|
83
|
-
const cleanPropsObject = (props) => {
|
|
84
|
-
if (!isRecord(props)) return {};
|
|
85
|
-
const clean = {};
|
|
86
|
-
for (const [name, value] of Object.entries(props)) {
|
|
87
|
-
const normalizedName = normalizeAgentPropName(name);
|
|
88
|
-
const cleanedValue = cleanAgentPropValue(value);
|
|
89
|
-
if (shouldDropAgentProp(normalizedName) || cleanedValue === void 0) continue;
|
|
90
|
-
if (!(normalizedName in clean) || normalizedName === name.trim()) {
|
|
91
|
-
clean[normalizedName] = cleanedValue;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return clean;
|
|
95
|
-
};
|
|
96
|
-
export const xmlComponentMarkdown = (name, props = {}, children = "") => {
|
|
97
|
-
const tagName = safeXmlName(name);
|
|
98
|
-
const cleanProps = cleanPropsObject(props);
|
|
99
|
-
const attrs = [];
|
|
100
|
-
const complexProps = {};
|
|
101
|
-
for (const [key, value] of Object.entries(cleanProps)) {
|
|
102
|
-
if (!xmlNamePattern.test(key)) {
|
|
103
|
-
complexProps[key] = value;
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
if (isScalarXmlAttributeValue(value)) {
|
|
107
|
-
attrs.push(`${key}="${escapeXmlAttribute(String(value))}"`);
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
complexProps[key] = value;
|
|
111
|
-
}
|
|
112
|
-
const attrText = attrs.length ? ` ${attrs.join(" ")}` : "";
|
|
113
|
-
const bodyParts = [
|
|
114
|
-
Object.keys(complexProps).length ? jsonFenceMarkdown(complexProps) : "",
|
|
115
|
-
children.trim()
|
|
116
|
-
].filter(Boolean);
|
|
117
|
-
if (!bodyParts.length) return `<${tagName}${attrText} />`;
|
|
118
|
-
return `<${tagName}${attrText}>
|
|
119
|
-
${bodyParts.join("\n\n")}
|
|
120
|
-
</${tagName}>`;
|
|
121
|
-
};
|
|
122
|
-
export const registerAgentMarkdownSerializer = (name, serializer, options = {}) => {
|
|
123
|
-
const existing = serializers.get(name);
|
|
124
|
-
if (existing === serializer && !options.override) return;
|
|
125
|
-
if (existing && !options.override) {
|
|
126
|
-
throw new Error(
|
|
127
|
-
`Agent Markdown serializer "${name}" is already registered. Use { override: true } only when replacing an existing serializer intentionally.`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
serializers.set(name, serializer);
|
|
131
|
-
};
|
|
132
|
-
export const registerAgentMarkdownSerializers = (entries, options = {}) => {
|
|
133
|
-
for (const [name, serializer] of Object.entries(entries)) {
|
|
134
|
-
registerAgentMarkdownSerializer(name, serializer, options);
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
export const defineAgentMarkdownComponent = (component) => component;
|
|
138
|
-
export const registerAgentMarkdownComponent = (name, component, options = {}) => {
|
|
139
|
-
registerAgentMarkdownSerializer(name, component.render, options);
|
|
140
|
-
};
|
|
141
|
-
export const registerAgentMarkdownComponents = (entries, options = {}) => {
|
|
142
|
-
for (const [name, component] of Object.entries(entries)) {
|
|
143
|
-
registerAgentMarkdownComponent(name, component, options);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
export const clearAgentMarkdownSerializers = () => {
|
|
147
|
-
serializers.clear();
|
|
148
|
-
};
|
|
149
|
-
export const resolveAgentMarkdownOptions = (collection) => {
|
|
150
|
-
if (!collection || collection.type === "data") return null;
|
|
151
|
-
const value = collection.agent?.markdown;
|
|
152
|
-
if (value === true) {
|
|
153
|
-
return {
|
|
154
|
-
includeInIndex: true,
|
|
155
|
-
includeInFull: true,
|
|
156
|
-
metadata: []
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
if (!value || !isRecord(value)) return null;
|
|
160
|
-
return {
|
|
161
|
-
includeInIndex: value.includeInIndex !== false,
|
|
162
|
-
includeInFull: value.includeInFull !== false,
|
|
163
|
-
metadata: Array.isArray(value.metadata) ? value.metadata.filter((field) => typeof field === "string" && field.length > 0) : []
|
|
164
|
-
};
|
|
165
|
-
};
|
|
25
|
+
const buildRenderContext = (collection, page, path, locale) => ({
|
|
26
|
+
collection,
|
|
27
|
+
page,
|
|
28
|
+
path,
|
|
29
|
+
locale,
|
|
30
|
+
registry: appRegistry,
|
|
31
|
+
tagAliases: contentConfig().markdown?.tags || {},
|
|
32
|
+
defaultLocale: defaultLocale(),
|
|
33
|
+
locales: configuredLocales()
|
|
34
|
+
});
|
|
166
35
|
const collectionConfig = (collection) => contentConfig().collections?.[collection];
|
|
167
36
|
const markdownEnabledCollectionEntries = (collections) => Object.entries(contentConfig().collections || {}).filter(([name, config]) => (!collections?.length || collections.includes(name)) && resolveAgentMarkdownOptions(config));
|
|
168
37
|
const isPublicPage = (page, config) => Boolean(
|
|
169
|
-
page && config && config.type !== "data" && config.sitemap !== false && !page.
|
|
38
|
+
page && config && config.type !== "data" && config.sitemap !== false && !page.draft && !page.partial && !page.navigationFile && page.navigation !== false && page.robots !== "noindex" && page.sitemap !== false
|
|
170
39
|
);
|
|
171
40
|
const escapeMarkdownText = (value) => value.replace(/\*/g, "\\*").replace(/_/g, "\\_").replace(/\[/g, "\\[").replace(/\]/g, "\\]");
|
|
172
|
-
const textValue = (node) => {
|
|
173
|
-
if (node.type === "text") return node.value || "";
|
|
174
|
-
return (node.children || []).map((child) => textValue(child)).join("");
|
|
175
|
-
};
|
|
176
|
-
const renderChildren = (node, ctx) => (node.children || []).map((child) => renderNode(child, ctx)).join("").trim();
|
|
177
|
-
const block = (value) => value.trim() ? `${value.trim()}
|
|
178
|
-
|
|
179
|
-
` : "";
|
|
180
|
-
const renderList = (node, ctx, ordered = false) => block((node.children || []).map((child, index) => {
|
|
181
|
-
const body = renderChildren(child, ctx).replace(/\n+/g, "\n ").trim();
|
|
182
|
-
return `${ordered ? `${index + 1}.` : "-"} ${body}`;
|
|
183
|
-
}).join("\n"));
|
|
184
|
-
const renderTable = (node, ctx) => {
|
|
185
|
-
const rows = (node.children || []).flatMap(
|
|
186
|
-
(section) => section.tag === "thead" || section.tag === "tbody" ? section.children || [] : [section]
|
|
187
|
-
).filter((row) => row.tag === "tr");
|
|
188
|
-
if (!rows.length) return "";
|
|
189
|
-
const cells = rows.map(
|
|
190
|
-
(row) => (row.children || []).filter((cell) => cell.tag === "th" || cell.tag === "td").map((cell) => renderChildren(cell, ctx).replace(/\|/g, "\\|").trim())
|
|
191
|
-
);
|
|
192
|
-
const width = Math.max(...cells.map((row) => row.length));
|
|
193
|
-
const normalized = cells.map((row) => [...row, ...Array.from({ length: width - row.length }, () => "")]);
|
|
194
|
-
const [head = [], ...bodyRows] = normalized;
|
|
195
|
-
return block([
|
|
196
|
-
`| ${head.join(" | ")} |`,
|
|
197
|
-
`| ${head.map(() => "---").join(" | ")} |`,
|
|
198
|
-
...bodyRows.map((row) => `| ${row.join(" | ")} |`)
|
|
199
|
-
].join("\n"));
|
|
200
|
-
};
|
|
201
|
-
const renderUnknownComponentOmission = (name, reason) => `> Component omitted: \`${name}\`.
|
|
202
|
-
> ${reason || "This page contains an interactive or site-specific block that has no agent markdown serializer yet."}`;
|
|
203
|
-
const renderUnknownComponent = (node, ctx) => {
|
|
204
|
-
const tag = node.tag || "component";
|
|
205
|
-
const props = cleanPropsObject(node.props);
|
|
206
|
-
const children = renderChildren(node, ctx);
|
|
207
|
-
if (children || Object.keys(props).length) {
|
|
208
|
-
return block(xmlComponentMarkdown(tag, props, children));
|
|
209
|
-
}
|
|
210
|
-
return block(renderUnknownComponentOmission(tag));
|
|
211
|
-
};
|
|
212
|
-
const serializerForTag = (tag) => {
|
|
213
|
-
const markdownTags = contentConfig().markdown?.tags || {};
|
|
214
|
-
const candidates = new Set([
|
|
215
|
-
tag,
|
|
216
|
-
pascalCase(tag),
|
|
217
|
-
kebabCase(tag),
|
|
218
|
-
markdownTags[tag],
|
|
219
|
-
markdownTags[pascalCase(tag)],
|
|
220
|
-
markdownTags[kebabCase(tag)]
|
|
221
|
-
].filter((value) => Boolean(value)));
|
|
222
|
-
for (const candidate of candidates) {
|
|
223
|
-
const serializer = serializers.get(candidate);
|
|
224
|
-
if (serializer) return serializer;
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
const renderNode = (node, ctx) => {
|
|
228
|
-
if (node.type === "text") return node.value || "";
|
|
229
|
-
const tag = node.tag || "";
|
|
230
|
-
const serializer = tag ? serializerForTag(tag) : void 0;
|
|
231
|
-
if (serializer) {
|
|
232
|
-
const nodeCtx = {
|
|
233
|
-
...ctx,
|
|
234
|
-
prop: (name) => getMarkdownProp(node, name),
|
|
235
|
-
props: (target) => isRecord((target || node).props) ? (target || node).props : {},
|
|
236
|
-
cleanProps: (target) => cleanPropsObject((target || node).props),
|
|
237
|
-
children: (target) => renderChildren(target || node, nodeCtx)
|
|
238
|
-
};
|
|
239
|
-
const rendered = serializer(node, nodeCtx);
|
|
240
|
-
if (typeof rendered === "string") return block(rendered);
|
|
241
|
-
}
|
|
242
|
-
if (!tag) return renderChildren(node, ctx);
|
|
243
|
-
if (/^h[1-6]$/.test(tag)) {
|
|
244
|
-
const depth = Number(tag.slice(1));
|
|
245
|
-
return block(`${"#".repeat(Math.max(1, Math.min(6, depth)))} ${renderChildren(node, ctx)}`);
|
|
246
|
-
}
|
|
247
|
-
switch (tag) {
|
|
248
|
-
case "p":
|
|
249
|
-
return block(renderChildren(node, ctx));
|
|
250
|
-
case "blockquote":
|
|
251
|
-
return block(renderChildren(node, ctx).split("\n").map((line) => `> ${line}`).join("\n"));
|
|
252
|
-
case "strong":
|
|
253
|
-
case "b":
|
|
254
|
-
return `**${renderChildren(node, ctx)}**`;
|
|
255
|
-
case "em":
|
|
256
|
-
case "i":
|
|
257
|
-
return `_${renderChildren(node, ctx)}_`;
|
|
258
|
-
case "span":
|
|
259
|
-
return renderChildren(node, ctx);
|
|
260
|
-
case "code":
|
|
261
|
-
return `\`${node.value || textValue(node)}\``;
|
|
262
|
-
case "pre":
|
|
263
|
-
return block(`\`\`\`
|
|
264
|
-
${textValue(node)}
|
|
265
|
-
\`\`\``);
|
|
266
|
-
case "a": {
|
|
267
|
-
const href = typeof node.props?.href === "string" ? node.props.href : "";
|
|
268
|
-
const text = renderChildren(node, ctx) || href;
|
|
269
|
-
return href ? linkMarkdown(text, routeMarkdownPathForHref(href, ctx.locale, ctx.path)) : text;
|
|
270
|
-
}
|
|
271
|
-
case "ul":
|
|
272
|
-
return renderList(node, ctx);
|
|
273
|
-
case "ol":
|
|
274
|
-
return renderList(node, ctx, true);
|
|
275
|
-
case "li":
|
|
276
|
-
return renderChildren(node, ctx);
|
|
277
|
-
case "hr":
|
|
278
|
-
return "---\n\n";
|
|
279
|
-
case "br":
|
|
280
|
-
return "\n";
|
|
281
|
-
case "img": {
|
|
282
|
-
const src = typeof node.props?.src === "string" ? node.props.src : "";
|
|
283
|
-
const alt = typeof node.props?.alt === "string" ? node.props.alt : "";
|
|
284
|
-
return src ? imageMarkdown(alt, src) : escapeMarkdownLinkLabel(alt);
|
|
285
|
-
}
|
|
286
|
-
case "table":
|
|
287
|
-
return renderTable(node, ctx);
|
|
288
|
-
case "thead":
|
|
289
|
-
case "tbody":
|
|
290
|
-
case "tr":
|
|
291
|
-
case "th":
|
|
292
|
-
case "td":
|
|
293
|
-
return renderChildren(node, ctx);
|
|
294
|
-
default:
|
|
295
|
-
return renderUnknownComponent(node, ctx);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
const renderMarkdownRoot = (body, context) => {
|
|
299
|
-
if (!body?.children?.length) return "";
|
|
300
|
-
const ctx = {
|
|
301
|
-
...context,
|
|
302
|
-
prop: () => "",
|
|
303
|
-
props: (node) => node ? isRecord(node.props) ? node.props : {} : {},
|
|
304
|
-
cleanProps: (node) => cleanPropsObject(node?.props),
|
|
305
|
-
children: (node) => node ? renderChildren(node, ctx) : "",
|
|
306
|
-
renderChildren: (node) => renderChildren(node, ctx),
|
|
307
|
-
renderNode: (node) => renderNode(node, ctx),
|
|
308
|
-
blockquote: (value) => blockquoteMarkdown(value),
|
|
309
|
-
jsonFence: (value) => jsonFenceMarkdown(value),
|
|
310
|
-
link: (label, href) => linkMarkdown(label, href),
|
|
311
|
-
omitted: (name, reason) => renderUnknownComponentOmission(name, reason),
|
|
312
|
-
xmlComponent: (name, props, children) => xmlComponentMarkdown(name, props, children)
|
|
313
|
-
};
|
|
314
|
-
return body.children.map((node) => renderNode(node, ctx)).join("").trim();
|
|
315
|
-
};
|
|
316
41
|
const hasH1 = (markdown) => /^#\s+/m.test(markdown);
|
|
317
42
|
const normalizeDescription = (page) => typeof page.description === "string" && page.description.trim() ? page.description.trim() : "";
|
|
318
43
|
const renderAgentMarkdown = (page, collection, path, locale, _options) => {
|
|
319
44
|
const title = typeof page.title === "string" && page.title.trim() ? page.title.trim() : path.split("/").filter(Boolean).pop() || "Index";
|
|
320
45
|
const description = normalizeDescription(page);
|
|
321
|
-
const rendered =
|
|
46
|
+
const rendered = renderAgentMarkdownBody(page.body, buildRenderContext(collection, page, path, locale));
|
|
322
47
|
const parts = [];
|
|
323
48
|
if (!hasH1(rendered)) parts.push(`# ${escapeMarkdownText(title)}`);
|
|
324
49
|
if (description && !rendered.includes(description)) parts.push(`> ${description}`);
|
|
@@ -326,8 +51,8 @@ const renderAgentMarkdown = (page, collection, path, locale, _options) => {
|
|
|
326
51
|
return parts.join("\n\n").trim() + "\n";
|
|
327
52
|
};
|
|
328
53
|
const toAgentMarkdown = (collection, page, options) => {
|
|
329
|
-
const path = normalizeAgentRoutePath(page.path || page.
|
|
330
|
-
const locale = page.locale || page.
|
|
54
|
+
const path = normalizeAgentRoutePath(page.path || page.resolved?.requestedRoute);
|
|
55
|
+
const locale = page.locale || page.resolved?.locale || page.locale;
|
|
331
56
|
const title = typeof page.title === "string" && page.title.trim() ? page.title.trim() : path.split("/").filter(Boolean).pop() || "Index";
|
|
332
57
|
const description = normalizeDescription(page);
|
|
333
58
|
return {
|
|
@@ -339,7 +64,7 @@ const toAgentMarkdown = (collection, page, options) => {
|
|
|
339
64
|
title,
|
|
340
65
|
description,
|
|
341
66
|
markdown: renderAgentMarkdown(page, collection, path, locale, options),
|
|
342
|
-
...page.
|
|
67
|
+
...page.file?.path ? { sourceFile: page.file?.path } : {},
|
|
343
68
|
canonicalUrl: path,
|
|
344
69
|
...typeof page.updated === "string" ? { lastModified: page.updated } : {},
|
|
345
70
|
metadataFields: options.metadata,
|
|
@@ -377,11 +102,11 @@ const publicPathForLocale = (collection, config, rowPath, locale, defaultLocale2
|
|
|
377
102
|
});
|
|
378
103
|
};
|
|
379
104
|
const publicPathForQueryRow = (collection, config, row, locale) => {
|
|
380
|
-
const requested = row.path || row.
|
|
105
|
+
const requested = row.path || row.resolved?.requestedRoute;
|
|
381
106
|
if (requested) return normalizeAgentRoutePath(requested);
|
|
382
107
|
const defaultLocale2 = collectionDefaultLocale(config);
|
|
383
|
-
const rowPath = normalizeAgentRoutePath(row.
|
|
384
|
-
const resolvedLocale = row.
|
|
108
|
+
const rowPath = normalizeAgentRoutePath(row.path || "/");
|
|
109
|
+
const resolvedLocale = row.resolved?.locale || row.locale;
|
|
385
110
|
if (locale && resolvedLocale && locale !== resolvedLocale) {
|
|
386
111
|
const sourceLocalePath = publicPathForLocale(collection, config, rowPath, resolvedLocale, defaultLocale2);
|
|
387
112
|
return prefixRequestedLocale(sourceLocalePath, locale, defaultLocale2);
|
|
@@ -416,15 +141,15 @@ export async function queryMarkdownEnabledContent(event, options = {}) {
|
|
|
416
141
|
for (const [collection, config] of markdownEnabledCollectionEntries(options.collections)) {
|
|
417
142
|
const agentOptions = resolveAgentMarkdownOptions(config);
|
|
418
143
|
if (!agentOptions) continue;
|
|
419
|
-
const rows = normalizeQueryResult(await provider.query(event, {
|
|
144
|
+
const rows = normalizeQueryResult(await provider.query(event, createProviderQuery({
|
|
420
145
|
collection,
|
|
421
|
-
only: ["path", "locale", "localePaths", "
|
|
146
|
+
only: ["path", "locale", "localePaths", "resolved", "file", "draft", "partial", "navigationFile", "title", "description", "updated", "navigation", "robots", "sitemap"],
|
|
422
147
|
...options.limit ? { limit: options.limit } : {},
|
|
423
148
|
...options.locale ? { resolveLocale: { locale: options.locale, fallback: true } } : {}
|
|
424
|
-
}));
|
|
149
|
+
})));
|
|
425
150
|
for (const row of rows) {
|
|
426
151
|
if (!isPublicPage(row, config)) continue;
|
|
427
|
-
const locale = options.locale || row.
|
|
152
|
+
const locale = options.locale || row.resolved?.locale || row.locale;
|
|
428
153
|
const path = publicPathForQueryRow(collection, config, row, locale);
|
|
429
154
|
const title = typeof row.title === "string" && row.title.trim() ? row.title.trim() : path.split("/").filter(Boolean).pop() || "Index";
|
|
430
155
|
const description = normalizeDescription(row);
|
|
@@ -436,7 +161,7 @@ export async function queryMarkdownEnabledContent(event, options = {}) {
|
|
|
436
161
|
collection,
|
|
437
162
|
title,
|
|
438
163
|
description,
|
|
439
|
-
...row.
|
|
164
|
+
...row.file?.path ? { sourceFile: row.file?.path } : {},
|
|
440
165
|
canonicalUrl: path,
|
|
441
166
|
...typeof row.updated === "string" ? { lastModified: row.updated } : {},
|
|
442
167
|
metadataFields: agentOptions.metadata,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getRequestURL } from "h3";
|
|
2
2
|
import { linkMarkdown, queryMarkdownEnabledContent, resolveContentMarkdownByRoute } from "./agent-markdown.js";
|
|
3
|
-
import { agentMarkdownPathForRoute, agentRawPathForRoute, agentRoutePathFromIndexSlug, agentRoutePathFromRawSlug, normalizeAgentRoutePath } from "
|
|
3
|
+
import { agentMarkdownPathForRoute, agentRawPathForRoute, agentRoutePathFromIndexSlug, agentRoutePathFromRawSlug, normalizeAgentRoutePath } from "../../features/agent/agent-paths";
|
|
4
4
|
import { contentConfig } from "./storage-access.js";
|
|
5
5
|
const localizedValue = (value, locale, fallback = "") => {
|
|
6
6
|
if (typeof value === "string") return value;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler } from "h3";
|
|
2
2
|
import { localeFromAgentPath, resolveMarkdownForPublicRoute, routePathFromRawSlug } from "../agent-site.js";
|
|
3
3
|
import { setAgentMarkdownHeaders } from "../agent-http.js";
|
|
4
|
-
import { isUnsafeAgentRoutePath } from "
|
|
4
|
+
import { isUnsafeAgentRoutePath } from "../../../features/agent/agent-paths";
|
|
5
5
|
export default defineEventHandler(async (event) => {
|
|
6
6
|
const routePath = routePathFromRawSlug(event.context.params?.slug);
|
|
7
7
|
if (isUnsafeAgentRoutePath(routePath)) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { NavItem } from '../../../types/content';
|
|
2
2
|
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
3
|
-
contents: unknown[];
|
|
4
3
|
navigation: NavItem[];
|
|
5
4
|
generatedAt: number;
|
|
5
|
+
documentCount: number;
|
|
6
6
|
generateTime: number;
|
|
7
7
|
}>>;
|
|
8
8
|
export default _default;
|
|
@@ -1,26 +1,65 @@
|
|
|
1
1
|
import { defineEventHandler } from "h3";
|
|
2
|
+
import { isRealDocument } from "../../../core/content/document";
|
|
3
|
+
import { assertSnapshotComplete, buildContentSnapshot } from "../../../core/content/snapshot";
|
|
4
|
+
import { chunksFromArray, loadContentVariants } from "../../../storage/contents";
|
|
2
5
|
import { getContentProvider } from "../providers/index.js";
|
|
6
|
+
import { createProviderNavigationQuery } from "../provider-query.js";
|
|
3
7
|
import { createContentProviderError } from "../../../public/provider-errors";
|
|
4
|
-
import { cacheStorage } from "../storage-access.js";
|
|
8
|
+
import { cacheStorage, contentConfig, getSourceContentIds } from "../storage-access.js";
|
|
9
|
+
const hasRoutePath = (document) => typeof document.path === "string" && document.path.length > 0;
|
|
10
|
+
const describeExcludedSource = (variants) => {
|
|
11
|
+
if (variants.every((variant) => !isRealDocument(variant))) {
|
|
12
|
+
return "unreadable (source missing or failed to parse)";
|
|
13
|
+
}
|
|
14
|
+
return "no route path (parsed, but every variant lacks a path)";
|
|
15
|
+
};
|
|
5
16
|
export default defineEventHandler(async (event) => {
|
|
6
17
|
const now = Date.now();
|
|
7
|
-
const
|
|
18
|
+
const config = contentConfig();
|
|
19
|
+
const sourceIds = await getSourceContentIds(event);
|
|
20
|
+
const documents = [];
|
|
21
|
+
const excluded = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const chunk of chunksFromArray(sourceIds, 10)) {
|
|
23
|
+
const results = await Promise.all(chunk.map(async (id) => [id, await loadContentVariants(event, id)]));
|
|
24
|
+
for (const [id, variants] of results) {
|
|
25
|
+
const routable = variants.filter(isRealDocument).filter(hasRoutePath);
|
|
26
|
+
if (routable.length === 0) {
|
|
27
|
+
excluded.set(id, describeExcludedSource(variants));
|
|
28
|
+
}
|
|
29
|
+
documents.push(...routable);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (excluded.size > 0) {
|
|
33
|
+
const details = [...excluded.entries()].slice(0, 20).map(([id, reason]) => `${id}: ${reason}`).join("; ");
|
|
34
|
+
throw new Error(
|
|
35
|
+
`[content] snapshot build failed: ${excluded.size} source document(s) produced no servable content and would silently 404 in production. First ${Math.min(excluded.size, 20)} \u2014 ${details}`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const snapshot = buildContentSnapshot({
|
|
39
|
+
integrity: config.cacheIntegrity,
|
|
40
|
+
documents,
|
|
41
|
+
sourceIds,
|
|
42
|
+
now
|
|
43
|
+
});
|
|
44
|
+
assertSnapshotComplete(snapshot, sourceIds);
|
|
45
|
+
await cacheStorage(event).setItem("snapshot.json", snapshot);
|
|
8
46
|
const provider = await getContentProvider(event);
|
|
9
47
|
if (!provider.navigationQuery) {
|
|
10
48
|
throw createContentProviderError("unsupported_provider_operation", `${provider.name} does not support navigation queries`, {
|
|
11
49
|
provider: provider.name
|
|
12
50
|
});
|
|
13
51
|
}
|
|
14
|
-
const
|
|
52
|
+
const { query: navQuery, options: navOptions } = createProviderNavigationQuery({});
|
|
53
|
+
const navigation = await provider.navigationQuery(event, navQuery, navOptions);
|
|
15
54
|
await cacheStorage(event).setItem("_nav.json", navigation);
|
|
16
55
|
const meta = {
|
|
17
56
|
generatedAt: now,
|
|
57
|
+
documentCount: snapshot.documentIds.length,
|
|
18
58
|
generateTime: Date.now() - now
|
|
19
59
|
};
|
|
20
60
|
await cacheStorage(event).setItem("_meta.json", meta);
|
|
21
61
|
return {
|
|
22
62
|
...meta,
|
|
23
|
-
contents,
|
|
24
63
|
navigation
|
|
25
64
|
};
|
|
26
65
|
});
|