@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
package/compatibility.json
CHANGED
package/dist/cli.mjs
CHANGED
|
@@ -505,7 +505,7 @@ async function inspectRepeatedLocalePrefixes(rootDir, locales) {
|
|
|
505
505
|
severity: "error",
|
|
506
506
|
file: relativeFile,
|
|
507
507
|
message: `Repeated locale prefix "${repeatedPath}" found in generated output.`,
|
|
508
|
-
suggestion: "
|
|
508
|
+
suggestion: "Bind route-ready item.path values from useContentMany(), navigation, or search results instead of manually prefixing locale paths."
|
|
509
509
|
});
|
|
510
510
|
break;
|
|
511
511
|
}
|
|
@@ -573,7 +573,7 @@ async function inspectI18nSearchIndex(rootDir, locales) {
|
|
|
573
573
|
return false;
|
|
574
574
|
}
|
|
575
575
|
const item = record;
|
|
576
|
-
return item.locale === locale ||
|
|
576
|
+
return item.locale === locale || typeof item.path === "string" && item.path.startsWith(`/${locale}/`);
|
|
577
577
|
});
|
|
578
578
|
if (!hasLocaleRecords) {
|
|
579
579
|
findings.push({
|
|
@@ -33,6 +33,8 @@ export class CmsContractSchemaUnsupportedError extends Error {
|
|
|
33
33
|
this.unsupported = unsupported;
|
|
34
34
|
this.name = "CmsContractSchemaUnsupportedError";
|
|
35
35
|
}
|
|
36
|
+
collectionSlug;
|
|
37
|
+
unsupported;
|
|
36
38
|
}
|
|
37
39
|
export function buildCmsContract(config, options) {
|
|
38
40
|
const include = options.include ? new Set(options.include) : null;
|
|
@@ -59,7 +61,7 @@ function buildCollectionContract(slug, collection, options) {
|
|
|
59
61
|
const contract = {
|
|
60
62
|
slug,
|
|
61
63
|
label: cms.label ?? deriveLabel(slug),
|
|
62
|
-
type:
|
|
64
|
+
type: resolveCollectionType(slug, cms),
|
|
63
65
|
icon: cms.icon ?? null,
|
|
64
66
|
locales,
|
|
65
67
|
defaultLocale,
|
|
@@ -122,9 +124,11 @@ function isSingleRouteSource(collection) {
|
|
|
122
124
|
const routeSources = sources.filter((source) => typeof source === "string");
|
|
123
125
|
return routeSources.length === 1 && !/[{*?[\]]/.test(routeSources[0] ?? "");
|
|
124
126
|
}
|
|
125
|
-
function
|
|
126
|
-
if (
|
|
127
|
-
|
|
127
|
+
function resolveCollectionType(slug, cms) {
|
|
128
|
+
if (cms.type) return cms.type;
|
|
129
|
+
console.warn(
|
|
130
|
+
`[ginko-content] Collection "${slug}" has no explicit \`cms.type\`; defaulting to 'flat'. Declare \`cms: { type: 'flat' | 'tree' }\` in the collection config to silence this warning.`
|
|
131
|
+
);
|
|
128
132
|
return "flat";
|
|
129
133
|
}
|
|
130
134
|
function deriveLabel(slug) {
|
|
@@ -142,15 +146,15 @@ function buildFields(collection, cms, isLocalized) {
|
|
|
142
146
|
const existing = fields.get(key);
|
|
143
147
|
fields.set(key, mergeField(existing, key, override, isLocalized));
|
|
144
148
|
}
|
|
145
|
-
return [...fields.values()]
|
|
149
|
+
return [...fields.values()];
|
|
146
150
|
}
|
|
147
151
|
function implicitPageFields(collection, isLocalized) {
|
|
148
152
|
const fields = [
|
|
149
|
-
field({ key: "title", type: "text", required: true, localized: isLocalized }),
|
|
150
|
-
field({ key: "description", type: "textarea", localized: isLocalized })
|
|
153
|
+
field({ key: "title", type: "text", role: "title", required: true, localized: isLocalized }),
|
|
154
|
+
field({ key: "description", type: "textarea", role: "description", localized: isLocalized })
|
|
151
155
|
];
|
|
152
156
|
if (isMarkdownCollection(collection)) {
|
|
153
|
-
fields.push(field({ key: "bodyMdc", type: "richtext", localized: isLocalized }));
|
|
157
|
+
fields.push(field({ key: "bodyMdc", type: "richtext", role: "body", localized: isLocalized }));
|
|
154
158
|
}
|
|
155
159
|
return fields;
|
|
156
160
|
}
|
|
@@ -240,10 +244,7 @@ function getArrayElement(schema) {
|
|
|
240
244
|
return def?.element ?? def?.type ?? null;
|
|
241
245
|
}
|
|
242
246
|
function fieldsFromObjectSchema(schema, isLocalized) {
|
|
243
|
-
return Object.entries(getObjectShape(unwrapSchema(schema))).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]
|
|
244
|
-
...fieldFromSchema(key, child, isLocalized),
|
|
245
|
-
order: index
|
|
246
|
-
}));
|
|
247
|
+
return Object.entries(getObjectShape(unwrapSchema(schema))).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => fieldFromSchema(key, child, isLocalized));
|
|
247
248
|
}
|
|
248
249
|
function fieldFromMetadata(key, metadata, schema, isLocalized, required) {
|
|
249
250
|
const localized = metadata.localized ?? isLocalized;
|
|
@@ -313,14 +314,11 @@ function mergeField(existing, key, override, isLocalized) {
|
|
|
313
314
|
...override.description !== void 0 ? { description: override.description } : {},
|
|
314
315
|
...override.required !== void 0 ? { required: override.required } : {},
|
|
315
316
|
...override.localized !== void 0 ? { localized: override.localized } : {},
|
|
316
|
-
...override.hidden !== void 0 ? { hidden: override.hidden } : {},
|
|
317
317
|
...override.searchable !== void 0 ? { searchable: override.searchable } : {},
|
|
318
318
|
...override.sortable !== void 0 ? { sortable: override.sortable } : {},
|
|
319
|
-
...override.order !== void 0 ? { order: override.order } : {},
|
|
320
|
-
...override.width !== void 0 ? { width: override.width } : {},
|
|
321
319
|
...override.defaultValue !== void 0 ? { defaultValue: override.defaultValue } : {},
|
|
322
320
|
...override.validation !== void 0 ? { validation: override.validation } : {},
|
|
323
|
-
...override.
|
|
321
|
+
...override.editor !== void 0 ? { editor: override.editor } : {},
|
|
324
322
|
...override.options !== void 0 ? { options: override.options } : {},
|
|
325
323
|
...override.relation !== void 0 ? { relation: override.relation } : {},
|
|
326
324
|
...override.min !== void 0 ? { min: override.min } : {},
|
|
@@ -334,22 +332,19 @@ function field(input) {
|
|
|
334
332
|
return {
|
|
335
333
|
key: input.key,
|
|
336
334
|
type: input.type,
|
|
335
|
+
role: input.role ?? null,
|
|
337
336
|
label: input.label ?? null,
|
|
338
337
|
description: input.description ?? null,
|
|
339
338
|
required: input.required ?? false,
|
|
340
339
|
localized: input.localized ?? false,
|
|
341
|
-
hidden: input.hidden ?? false,
|
|
342
340
|
searchable: input.searchable ?? false,
|
|
343
341
|
sortable: input.sortable ?? false,
|
|
344
|
-
order: input.order ?? 0,
|
|
345
|
-
width: input.width ?? "full",
|
|
346
342
|
defaultValue: input.defaultValue,
|
|
347
343
|
options: input.options ?? null,
|
|
348
344
|
relation: input.relation ?? null,
|
|
349
345
|
media: input.media ?? null,
|
|
350
346
|
fields: input.fields ?? null,
|
|
351
347
|
validation: input.validation ?? null,
|
|
352
|
-
condition: input.condition ?? null,
|
|
353
348
|
min: input.min ?? null,
|
|
354
349
|
max: input.max ?? null,
|
|
355
350
|
step: input.step ?? null,
|
|
@@ -63,15 +63,13 @@ export interface CmsCollectionRouting {
|
|
|
63
63
|
export interface CmsFieldContract {
|
|
64
64
|
key: string;
|
|
65
65
|
type: ContentCmsFieldType;
|
|
66
|
+
role?: 'title' | 'description' | 'body' | null;
|
|
66
67
|
label?: string | Record<string, string> | null;
|
|
67
68
|
description?: string | null;
|
|
68
69
|
required: boolean;
|
|
69
70
|
localized: boolean;
|
|
70
|
-
hidden: boolean;
|
|
71
71
|
searchable: boolean;
|
|
72
72
|
sortable: boolean;
|
|
73
|
-
order: number;
|
|
74
|
-
width: 'full' | 'half';
|
|
75
73
|
defaultValue?: unknown;
|
|
76
74
|
options?: string[] | null;
|
|
77
75
|
relation?: ContentCmsRelationConfig | null;
|
|
@@ -81,12 +79,19 @@ export interface CmsFieldContract {
|
|
|
81
79
|
} | null;
|
|
82
80
|
fields?: CmsFieldContract[] | null;
|
|
83
81
|
validation?: Record<string, unknown> | null;
|
|
84
|
-
condition?: Record<string, unknown> | null;
|
|
85
82
|
min?: number | null;
|
|
86
83
|
max?: number | null;
|
|
87
84
|
step?: number | null;
|
|
88
85
|
slugFrom?: string | null;
|
|
89
86
|
language?: string | null;
|
|
87
|
+
/**
|
|
88
|
+
* Opaque editor-layout passthrough forwarded byte-for-byte from
|
|
89
|
+
* `ContentCmsFieldConfig.editor`. ginko-content neither types nor interprets
|
|
90
|
+
* its contents — pure layout policy (width, display order, hidden state,
|
|
91
|
+
* conditional visibility, ...) lives here and its schema is owned by the
|
|
92
|
+
* consuming CMS. Absent when the collection config supplied no `editor`.
|
|
93
|
+
*/
|
|
94
|
+
editor?: Record<string, unknown>;
|
|
90
95
|
}
|
|
91
96
|
/**
|
|
92
97
|
* Reference to a schema validation artifact. The actual artifact (a serialized,
|
|
@@ -94,9 +99,9 @@ export interface CmsFieldContract {
|
|
|
94
99
|
* shipped alongside the contract. The CMS reads the checksum to verify the
|
|
95
100
|
* artifact it holds matches the contract it imported.
|
|
96
101
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
102
|
+
* The artifact bytes are embedded so a contract consumer can validate content
|
|
103
|
+
* without fetching a second artifact, while `artifactId` and `checksum` keep the
|
|
104
|
+
* embedded payload identifiable and verifiable.
|
|
100
105
|
*/
|
|
101
106
|
export interface CmsSchemaArtifactRef {
|
|
102
107
|
/** Stable id used to look up the artifact in the artifact registry. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './document.js'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MissingDocument, ParsedContent } from '../../types/content';
|
|
2
|
+
/**
|
|
3
|
+
* True when a loader result is a {@link MissingDocument} sentinel rather than a
|
|
4
|
+
* real parsed document. Keyed on the `missing: true` discriminant that every
|
|
5
|
+
* stub site sets — NOT on `body === null`: a real document may legitimately
|
|
6
|
+
* have a null body (data-style documents from custom transformers, e.g. the
|
|
7
|
+
* transformer example's `.names` files) and must not be treated as missing.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isMissingDocument: (document: ParsedContent | MissingDocument) => document is MissingDocument;
|
|
10
|
+
/**
|
|
11
|
+
* Shared type guard narrowing a loader result to a servable
|
|
12
|
+
* {@link ParsedContent}. Replaces the per-call-site `body !== null` checks so
|
|
13
|
+
* every consumer (snapshot writer, content list, single-document lookup) agrees
|
|
14
|
+
* on what counts as a real document.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isRealDocument: (document: ParsedContent | MissingDocument) => document is ParsedContent;
|
|
@@ -76,7 +76,7 @@ export declare const resolveLocaleChain: (requestedLocale: string | undefined, d
|
|
|
76
76
|
* `storage/content.ts:createServerQueryFetch` and
|
|
77
77
|
* `memoizeRuntimeValue(event, 'graph', ...)`.
|
|
78
78
|
*
|
|
79
|
-
* INVARIANT: documents without `
|
|
79
|
+
* INVARIANT: documents without `path` are still indexed by id (so refs can
|
|
80
80
|
* find them) but are excluded from path/route/canonical lookups. Partials
|
|
81
81
|
* and navigation documents are likewise indexed by id only.
|
|
82
82
|
*/
|
|
@@ -97,6 +97,7 @@ export declare const buildContentGraph: (documents: ParsedContent[], options?: {
|
|
|
97
97
|
*/
|
|
98
98
|
export declare const resolveGraphVariant: (graph: ContentGraph, canonicalKey: string, requestedLocale?: string, options?: {
|
|
99
99
|
defaultLocale?: string;
|
|
100
|
+
locales?: string[];
|
|
100
101
|
fallback?: string[];
|
|
101
102
|
exact?: boolean;
|
|
102
103
|
localeFallback?: Record<string, string[]>;
|
|
@@ -120,6 +121,7 @@ export declare const resolveGraphVariant: (graph: ContentGraph, canonicalKey: st
|
|
|
120
121
|
*/
|
|
121
122
|
export declare const resolveGraphRouteVariant: (graph: ContentGraph, routePath: string, requestedLocale?: string, options?: {
|
|
122
123
|
defaultLocale?: string;
|
|
124
|
+
locales?: string[];
|
|
123
125
|
fallback?: string[];
|
|
124
126
|
exact?: boolean;
|
|
125
127
|
localeFallback?: Record<string, string[]>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { normalizeReferenceValue, buildReferenceTargets } from "../references/resolve.js";
|
|
2
|
+
import { sortLocalesCanonically } from "./locale.js";
|
|
2
3
|
const normalizePath = (path) => {
|
|
3
4
|
if (!path || path === "/") {
|
|
4
5
|
return "/";
|
|
@@ -27,44 +28,44 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
27
28
|
const byNavigationPath = {};
|
|
28
29
|
const defaultLocale = options.defaultLocale || "";
|
|
29
30
|
for (const document of documents) {
|
|
30
|
-
const documentId = document.
|
|
31
|
+
const documentId = document.id || `${document.collection || "content"}:${document.path || "document"}`;
|
|
31
32
|
byId[documentId] = document;
|
|
32
|
-
if (!document.
|
|
33
|
+
if (!document.path) {
|
|
33
34
|
continue;
|
|
34
35
|
}
|
|
35
|
-
const path = normalizePath(document.
|
|
36
|
+
const path = normalizePath(document.path);
|
|
36
37
|
manifest.paths[path] ||= [];
|
|
37
|
-
if (document.
|
|
38
|
+
if (document.locale === defaultLocale) {
|
|
38
39
|
manifest.paths[path].unshift(documentId);
|
|
39
40
|
} else {
|
|
40
41
|
manifest.paths[path].push(documentId);
|
|
41
42
|
}
|
|
42
|
-
if (document.
|
|
43
|
-
manifest.collections[document.
|
|
44
|
-
manifest.collections[document.
|
|
43
|
+
if (document.collection) {
|
|
44
|
+
manifest.collections[document.collection] ||= [];
|
|
45
|
+
manifest.collections[document.collection].push(documentId);
|
|
45
46
|
}
|
|
46
|
-
if (document.
|
|
47
|
-
const locale2 = document.
|
|
47
|
+
if (document.navigationFile) {
|
|
48
|
+
const locale2 = document.locale || defaultLocale;
|
|
48
49
|
byNavigationPath[path] ||= {};
|
|
49
50
|
byNavigationPath[path][locale2] = document;
|
|
50
51
|
}
|
|
51
|
-
const isVariantDocument = !document.
|
|
52
|
+
const isVariantDocument = !document.partial && !document.navigationFile && document.canonicalKey;
|
|
52
53
|
if (!isVariantDocument) {
|
|
53
54
|
continue;
|
|
54
55
|
}
|
|
55
|
-
const locale = document.
|
|
56
|
+
const locale = document.locale || defaultLocale;
|
|
56
57
|
const variant = {
|
|
57
|
-
canonicalKey: document.
|
|
58
|
+
canonicalKey: document.canonicalKey,
|
|
58
59
|
contentId: documentId,
|
|
59
60
|
locale,
|
|
60
61
|
path,
|
|
61
62
|
document
|
|
62
63
|
};
|
|
63
|
-
manifest.byCanonical[document.
|
|
64
|
-
manifest.byCanonical[document.
|
|
65
|
-
manifest.byRoute[`${locale}:${path}`] = document.
|
|
66
|
-
if (document.
|
|
67
|
-
manifest.byRef[document.ref] = document.
|
|
64
|
+
manifest.byCanonical[document.canonicalKey] ||= {};
|
|
65
|
+
manifest.byCanonical[document.canonicalKey][locale] = variant;
|
|
66
|
+
manifest.byRoute[`${locale}:${path}`] = document.canonicalKey;
|
|
67
|
+
if (document.type === "markdown" && typeof document.ref === "string" && document.ref.length) {
|
|
68
|
+
manifest.byRef[document.ref] = document.canonicalKey;
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
for (const [canonicalKey, variants] of Object.entries(manifest.byCanonical)) {
|
|
@@ -87,7 +88,7 @@ export const buildContentGraph = (documents, options = {}) => {
|
|
|
87
88
|
byRoute: manifest.byRoute,
|
|
88
89
|
byRef: manifest.byRef,
|
|
89
90
|
byNavigationPath,
|
|
90
|
-
referenceTargets: buildReferenceTargets(documents.filter((document) => !document.
|
|
91
|
+
referenceTargets: buildReferenceTargets(documents.filter((document) => !document.partial && !document.navigationFile), options.locales || []),
|
|
91
92
|
manifest
|
|
92
93
|
};
|
|
93
94
|
};
|
|
@@ -101,7 +102,7 @@ export const resolveGraphVariant = (graph, canonicalKey, requestedLocale, option
|
|
|
101
102
|
if (!Object.keys(scopedVariants).length) {
|
|
102
103
|
return null;
|
|
103
104
|
}
|
|
104
|
-
const availableLocales = Object.keys(scopedVariants);
|
|
105
|
+
const availableLocales = sortLocalesCanonically(Object.keys(scopedVariants), options);
|
|
105
106
|
const localeChain = options.exact ? requestedLocale ? [requestedLocale] : [] : options.fallback?.length ? Array.from(new Set([requestedLocale, ...options.fallback].filter(Boolean))) : resolveLocaleChain(requestedLocale, options.defaultLocale, options.localeFallback || {});
|
|
106
107
|
const resolvedLocale = localeChain.find((locale) => scopedVariants[locale]) || (options.exact ? void 0 : availableLocales[0]);
|
|
107
108
|
if (resolvedLocale === void 0) {
|
|
@@ -122,7 +123,7 @@ export const resolveGraphVariant = (graph, canonicalKey, requestedLocale, option
|
|
|
122
123
|
export const resolveGraphRouteVariant = (graph, routePath, requestedLocale, options = {}) => {
|
|
123
124
|
const normalizedPath = normalizePath(routePath);
|
|
124
125
|
const localeChain = options.exact ? requestedLocale ? [requestedLocale] : [] : options.fallback?.length ? Array.from(new Set([requestedLocale, ...options.fallback].filter(Boolean))) : resolveLocaleChain(requestedLocale, options.defaultLocale, options.localeFallback || {});
|
|
125
|
-
const localesToSearch = localeChain.length ? localeChain :
|
|
126
|
+
const localesToSearch = localeChain.length ? localeChain : sortLocalesCanonically(Object.values(graph.byCanonical).flatMap((variants) => Object.keys(variants)), options);
|
|
126
127
|
for (const locale of localesToSearch) {
|
|
127
128
|
const canonicalKey = graph.byRoute[`${locale}:${normalizedPath}`];
|
|
128
129
|
if (!canonicalKey) {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 2. **Inline locale variant id** — YAML/JSON sources can carry locale
|
|
10
10
|
* overrides inline (`i18n: { de: { title: '…' } }`). We split each
|
|
11
11
|
* such document into one variant per locale at ingest; the
|
|
12
|
-
* synthetic variants share a `
|
|
12
|
+
* synthetic variants share a `id` shape of
|
|
13
13
|
* `${sourceId}#__locale=${locale}`. `splitInlineLocaleVariantId`
|
|
14
14
|
* reverses that for lookups.
|
|
15
15
|
*
|
|
@@ -33,6 +33,11 @@ export declare const INLINE_LOCALE_ID_SEPARATOR = "#__locale=";
|
|
|
33
33
|
* buildLocaleFallbackChain('en', 'en') // []
|
|
34
34
|
*/
|
|
35
35
|
export declare const buildLocaleFallbackChain: (locale: string, defaultLocale?: string, fallback?: Record<string, string[]>) => string[];
|
|
36
|
+
/** Canonical locale order: default locale first, then configured locale order. */
|
|
37
|
+
export declare const sortLocalesCanonically: (locales: string[], config?: {
|
|
38
|
+
defaultLocale?: string;
|
|
39
|
+
locales?: string[];
|
|
40
|
+
}) => string[];
|
|
36
41
|
/**
|
|
37
42
|
* Split an inline-variant id back into `{ sourceId, locale }`. Returns the
|
|
38
43
|
* input unchanged (with `locale: undefined`) when no separator is found.
|
|
@@ -33,6 +33,17 @@ export const buildLocaleFallbackChain = (locale, defaultLocale, fallback) => {
|
|
|
33
33
|
...defaultLocale && defaultLocale !== locale ? [defaultLocale] : []
|
|
34
34
|
]));
|
|
35
35
|
};
|
|
36
|
+
export const sortLocalesCanonically = (locales, config = {}) => {
|
|
37
|
+
const order = [
|
|
38
|
+
...config.defaultLocale ? [config.defaultLocale] : [],
|
|
39
|
+
...config.locales || []
|
|
40
|
+
];
|
|
41
|
+
const rank = new Map(order.map((locale, index) => [locale, index]));
|
|
42
|
+
const inputOrder = new Map(locales.map((locale, index) => [locale, index]));
|
|
43
|
+
return Array.from(new Set(locales)).sort(
|
|
44
|
+
(left, right) => (rank.get(left) ?? Number.MAX_SAFE_INTEGER) - (rank.get(right) ?? Number.MAX_SAFE_INTEGER) || (inputOrder.get(left) ?? Number.MAX_SAFE_INTEGER) - (inputOrder.get(right) ?? Number.MAX_SAFE_INTEGER)
|
|
45
|
+
);
|
|
46
|
+
};
|
|
36
47
|
export const splitInlineLocaleVariantId = (id) => {
|
|
37
48
|
const separatorIndex = id.indexOf(INLINE_LOCALE_ID_SEPARATOR);
|
|
38
49
|
if (separatorIndex === -1) {
|
|
@@ -44,7 +55,7 @@ export const splitInlineLocaleVariantId = (id) => {
|
|
|
44
55
|
};
|
|
45
56
|
};
|
|
46
57
|
export const expandDataLocaleVariants = (document, i18nConfig) => {
|
|
47
|
-
if (!i18nConfig || document.
|
|
58
|
+
if (!i18nConfig || document.type !== "yaml" && document.type !== "json") {
|
|
48
59
|
return [document];
|
|
49
60
|
}
|
|
50
61
|
const rawI18n = isPlainObject(document.i18n) ? document.i18n : void 0;
|
|
@@ -52,15 +63,15 @@ export const expandDataLocaleVariants = (document, i18nConfig) => {
|
|
|
52
63
|
return [document];
|
|
53
64
|
}
|
|
54
65
|
const { i18n: _removed, ...baseDocument } = document;
|
|
55
|
-
const sourceLocale = document.
|
|
56
|
-
const variants = [{ ...baseDocument,
|
|
66
|
+
const sourceLocale = document.locale || i18nConfig.defaultLocale;
|
|
67
|
+
const variants = [{ ...baseDocument, locale: sourceLocale }];
|
|
57
68
|
for (const locale of i18nConfig.locales) {
|
|
58
69
|
if (locale === sourceLocale) {
|
|
59
70
|
continue;
|
|
60
71
|
}
|
|
61
72
|
const override = rawI18n[locale];
|
|
62
73
|
if (typeof override !== "undefined" && !isPlainObject(override)) {
|
|
63
|
-
console.warn(`[content] Inline i18n override for locale "${locale}" in "${document.
|
|
74
|
+
console.warn(`[content] Inline i18n override for locale "${locale}" in "${document.id}" must be an object. Skipping invalid override.`);
|
|
64
75
|
continue;
|
|
65
76
|
}
|
|
66
77
|
if (!isPlainObject(override)) {
|
|
@@ -69,8 +80,8 @@ export const expandDataLocaleVariants = (document, i18nConfig) => {
|
|
|
69
80
|
const merged = mergeLocaleOverride(baseDocument, override);
|
|
70
81
|
variants.push({
|
|
71
82
|
...merged,
|
|
72
|
-
|
|
73
|
-
|
|
83
|
+
id: `${document.id}${INLINE_LOCALE_ID_SEPARATOR}${locale}`,
|
|
84
|
+
locale
|
|
74
85
|
});
|
|
75
86
|
}
|
|
76
87
|
return variants;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare const describeId: (id: string) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
source: string;
|
|
3
|
+
path: string;
|
|
4
|
+
extension: string;
|
|
5
|
+
file: string;
|
|
6
|
+
basename: string;
|
|
7
7
|
};
|
|
8
8
|
export declare const isDraftPath: (path: string) => boolean;
|
|
9
9
|
export declare const isPartialPath: (path: string) => boolean;
|
|
@@ -4,18 +4,18 @@ import { slugifyUrlSegment } from "./slug.js";
|
|
|
4
4
|
const SEMVER_REGEX = /^(\d+)(\.\d+)*(\.x)?$/;
|
|
5
5
|
const NUMERIC_PREFIX_RE = /^(\d+)\.(.+)$/;
|
|
6
6
|
export const describeId = (id) => {
|
|
7
|
-
const [
|
|
8
|
-
const [, basename,
|
|
7
|
+
const [source, ...parts] = id.split(":");
|
|
8
|
+
const [, basename, extension] = parts[parts.length - 1]?.match(/(.*)\.([^.]+)$/) || [];
|
|
9
9
|
if (basename) {
|
|
10
10
|
parts[parts.length - 1] = basename;
|
|
11
11
|
}
|
|
12
|
-
const
|
|
12
|
+
const path = (parts || []).join("/");
|
|
13
13
|
return {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
source,
|
|
15
|
+
path,
|
|
16
|
+
extension,
|
|
17
|
+
file: extension ? `${path}.${extension}` : path,
|
|
18
|
+
basename: basename || ""
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
21
|
export const isDraftPath = (path) => /\.draft(\/|\.|$)/.test(path);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './snapshot.js'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ParsedContent } from '../../types/content';
|
|
2
|
+
export declare const CONTENT_SNAPSHOT_VERSION: 1;
|
|
3
|
+
export interface ContentSnapshot {
|
|
4
|
+
version: typeof CONTENT_SNAPSHOT_VERSION;
|
|
5
|
+
/** Must equal the runtime config's cache integrity; mismatch means a stale artifact. */
|
|
6
|
+
integrity: string;
|
|
7
|
+
generatedAt: number;
|
|
8
|
+
/** Fully-qualified, locale-suffixed ids. One per stored variant. */
|
|
9
|
+
documentIds: string[];
|
|
10
|
+
/** Source ids represented by the stored documents. Completeness is asserted on these. */
|
|
11
|
+
documentSourceIds: string[];
|
|
12
|
+
documents: ParsedContent[];
|
|
13
|
+
}
|
|
14
|
+
export interface BuildContentSnapshotArgs {
|
|
15
|
+
integrity: string;
|
|
16
|
+
documents: ParsedContent[];
|
|
17
|
+
sourceIds: string[];
|
|
18
|
+
now: number;
|
|
19
|
+
}
|
|
20
|
+
/** Build error carrying every offending path; never fail on just the first one. */
|
|
21
|
+
export declare class ContentSnapshotError extends Error {
|
|
22
|
+
}
|
|
23
|
+
export declare const buildContentSnapshot: (args: BuildContentSnapshotArgs) => ContentSnapshot;
|
|
24
|
+
export declare const isContentSnapshot: (value: unknown) => value is ContentSnapshot;
|
|
25
|
+
export declare const assertSnapshotComplete: (snapshot: ContentSnapshot, sourceIds: string[]) => void;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { splitInlineLocaleVariantId } from "./locale.js";
|
|
2
|
+
export const CONTENT_SNAPSHOT_VERSION = 1;
|
|
3
|
+
export class ContentSnapshotError extends Error {
|
|
4
|
+
}
|
|
5
|
+
const documentIdOf = (document) => document.id;
|
|
6
|
+
const documentSourceIdOf = (document) => splitInlineLocaleVariantId(documentIdOf(document)).sourceId;
|
|
7
|
+
const isPlainObject = (value) => {
|
|
8
|
+
const prototype = Object.getPrototypeOf(value);
|
|
9
|
+
return prototype === Object.prototype || prototype === null;
|
|
10
|
+
};
|
|
11
|
+
const describeSymbolKey = (symbol) => `[${String(symbol)}] (symbol-keyed property)`;
|
|
12
|
+
const collectNonJsonValues = (value, path, ancestors, offenders) => {
|
|
13
|
+
if (value === null || value === void 0 || typeof value === "string" || typeof value === "boolean") {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (typeof value === "number") {
|
|
17
|
+
if (!Number.isFinite(value)) offenders.push(path);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (typeof value !== "object") {
|
|
21
|
+
offenders.push(path);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (value instanceof Date) {
|
|
25
|
+
if (Number.isNaN(value.getTime())) offenders.push(path);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (ancestors.has(value)) {
|
|
29
|
+
offenders.push(path);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
ancestors.add(value);
|
|
33
|
+
try {
|
|
34
|
+
for (const symbol of Object.getOwnPropertySymbols(value)) {
|
|
35
|
+
if (Object.prototype.propertyIsEnumerable.call(value, symbol)) {
|
|
36
|
+
offenders.push(`${path}${describeSymbolKey(symbol)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
41
|
+
if (!(index in value)) {
|
|
42
|
+
offenders.push(`${path}[${index}]`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
collectNonJsonValues(value[index], `${path}[${index}]`, ancestors, offenders);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!isPlainObject(value)) {
|
|
50
|
+
offenders.push(path);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
for (const [key, child] of Object.entries(value)) {
|
|
54
|
+
collectNonJsonValues(child, `${path}.${key}`, ancestors, offenders);
|
|
55
|
+
}
|
|
56
|
+
} finally {
|
|
57
|
+
ancestors.delete(value);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const buildContentSnapshot = (args) => {
|
|
61
|
+
const lossy = [];
|
|
62
|
+
const documents = [];
|
|
63
|
+
for (const document of args.documents) {
|
|
64
|
+
const offenders = [];
|
|
65
|
+
collectNonJsonValues(document, "$", /* @__PURE__ */ new WeakSet(), offenders);
|
|
66
|
+
if (offenders.length) {
|
|
67
|
+
lossy.push(...offenders.map((path) => `${documentIdOf(document)}:${path}`));
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
documents.push(JSON.parse(JSON.stringify(document)));
|
|
71
|
+
}
|
|
72
|
+
if (lossy.length > 0) {
|
|
73
|
+
throw new ContentSnapshotError(
|
|
74
|
+
`[content] snapshot: ${lossy.length} non-JSON value(s) found (invalid Date, Map, circular reference, symbol key, ...): ${lossy.slice(0, 10).join(", ")}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
version: CONTENT_SNAPSHOT_VERSION,
|
|
79
|
+
integrity: args.integrity,
|
|
80
|
+
generatedAt: args.now,
|
|
81
|
+
documentIds: documents.map(documentIdOf),
|
|
82
|
+
documentSourceIds: [...new Set(documents.map(documentSourceIdOf))].sort(),
|
|
83
|
+
documents
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
export const isContentSnapshot = (value) => {
|
|
87
|
+
if (typeof value !== "object" || value === null) return false;
|
|
88
|
+
const snapshot = value;
|
|
89
|
+
return snapshot.version === CONTENT_SNAPSHOT_VERSION && typeof snapshot.integrity === "string" && typeof snapshot.generatedAt === "number" && Array.isArray(snapshot.documentIds) && Array.isArray(snapshot.documentSourceIds) && Array.isArray(snapshot.documents);
|
|
90
|
+
};
|
|
91
|
+
export const assertSnapshotComplete = (snapshot, sourceIds) => {
|
|
92
|
+
const have = new Set(snapshot.documentSourceIds);
|
|
93
|
+
const missing = [...new Set(sourceIds)].filter((id) => !have.has(id));
|
|
94
|
+
if (missing.length > 0) {
|
|
95
|
+
throw new ContentSnapshotError(
|
|
96
|
+
`[content] snapshot incomplete: ${missing.length} source document(s) missing (first ${Math.min(missing.length, 20)}): ${missing.slice(0, 20).join(", ")}. This build would silently 404 these pages in production.`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ContentProviderErrorCode = 'unknown_provider' | 'unknown_collection' | 'unsupported_provider_operation' | 'unsupported_query_operator' | 'unsupported_query_shape' | 'data_collection_route_access' | 'data_collection_search_access' | 'data_collection_sitemap_access' | 'missing_locale_route' | 'provider_config_missing' | 'provider_module_missing' | 'provider_module_invalid' | 'provider_result_invalid' | 'unsupported_provider_search_index' | 'unsupported_provider_search' | 'unsupported_provider_site_data' | 'unsupported_provider_prerender';
|
|
1
|
+
export type ContentProviderErrorCode = 'unknown_provider' | 'unknown_collection' | 'unsupported_provider_operation' | 'unsupported_query_operator' | 'unsupported_query_shape' | 'provider_query_not_json_pure' | 'data_collection_route_access' | 'data_collection_search_access' | 'data_collection_sitemap_access' | 'missing_locale_route' | 'provider_config_missing' | 'provider_module_missing' | 'provider_module_invalid' | 'provider_result_invalid' | 'unsupported_provider_search_index' | 'unsupported_provider_search' | 'unsupported_provider_site_data' | 'unsupported_provider_prerender';
|
|
2
2
|
export declare const statusForProviderError: Record<ContentProviderErrorCode, number>;
|
|
3
3
|
export interface ContentProviderError extends Error {
|
|
4
4
|
statusCode: number;
|
|
@@ -4,6 +4,7 @@ export const statusForProviderError = {
|
|
|
4
4
|
unsupported_provider_operation: 400,
|
|
5
5
|
unsupported_query_operator: 400,
|
|
6
6
|
unsupported_query_shape: 400,
|
|
7
|
+
provider_query_not_json_pure: 500,
|
|
7
8
|
data_collection_route_access: 400,
|
|
8
9
|
data_collection_search_access: 400,
|
|
9
10
|
data_collection_sitemap_access: 400,
|
|
@@ -152,11 +152,11 @@ export function createQuery(fetcher, opts = {}) {
|
|
|
152
152
|
const snapshot = { params: () => ({ ...this.params(), count: true }) };
|
|
153
153
|
return fetcher(snapshot).then(resolveQueryResult);
|
|
154
154
|
},
|
|
155
|
-
locale: (
|
|
156
|
-
const filteredWhere = queryParams.where ? ensureArray(queryParams.where).filter((item) => typeof item.
|
|
155
|
+
locale: (locale, options) => {
|
|
156
|
+
const filteredWhere = queryParams.where ? ensureArray(queryParams.where).filter((item) => typeof item.locale === "undefined") : void 0;
|
|
157
157
|
return next({
|
|
158
158
|
resolveLocale: {
|
|
159
|
-
locale
|
|
159
|
+
locale,
|
|
160
160
|
fallback: Array.isArray(options?.fallback) ? options?.fallback : Boolean(options?.fallback),
|
|
161
161
|
exact: !options?.fallback
|
|
162
162
|
},
|