@lupinum/ginko-content 0.1.5 → 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 +21 -34
- package/dist/module.d.mts +135 -803
- package/dist/module.json +1 -1
- package/dist/module.mjs +143 -51
- 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 +9 -2
- 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 +79 -105
- 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 +17 -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
|
@@ -47,29 +47,43 @@ const collectReferenceIssues = (schema, value, resolveReference, issues, path =
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
+
const collectDerivedReferenceIssues = (references, value, resolveReference, issues) => {
|
|
51
|
+
if (!references) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const [collection, fields] of Object.entries(references)) {
|
|
55
|
+
for (const field of fields) {
|
|
56
|
+
const fieldValue = value[field];
|
|
57
|
+
const values = Array.isArray(fieldValue) ? fieldValue : [fieldValue];
|
|
58
|
+
for (const item of values) {
|
|
59
|
+
if (typeof item === "undefined" || item === null) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (typeof item !== "string") {
|
|
63
|
+
issues.push(`${field}: expected a string reference`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (!resolveReference(item, collection === "*" ? void 0 : collection)) {
|
|
67
|
+
issues.push(`${field}: unresolved reference "${item}"${collection !== "*" ? ` in collection "${collection}"` : ""}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
50
73
|
const internalDocumentFields = /* @__PURE__ */ new Set([
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"_resolvedLocale",
|
|
65
|
-
"_requestedLocale",
|
|
66
|
-
"_fallback",
|
|
67
|
-
"_availableLocales",
|
|
68
|
-
"_variantPaths",
|
|
69
|
-
"_resolvedRefs",
|
|
70
|
-
"_source",
|
|
71
|
-
"body",
|
|
72
|
-
"draft"
|
|
74
|
+
"id",
|
|
75
|
+
"file",
|
|
76
|
+
"path",
|
|
77
|
+
"type",
|
|
78
|
+
"collection",
|
|
79
|
+
"canonicalKey",
|
|
80
|
+
"partial",
|
|
81
|
+
"draft",
|
|
82
|
+
"dir",
|
|
83
|
+
"locale",
|
|
84
|
+
"navigationFile",
|
|
85
|
+
"resolved",
|
|
86
|
+
"body"
|
|
73
87
|
]);
|
|
74
88
|
const toUserContentDocument = (document) => {
|
|
75
89
|
const userDocument = {};
|
|
@@ -81,7 +95,7 @@ const toUserContentDocument = (document) => {
|
|
|
81
95
|
return userDocument;
|
|
82
96
|
};
|
|
83
97
|
const validateNavigationDocument = (document) => {
|
|
84
|
-
if (!document.
|
|
98
|
+
if (!document.navigationFile) {
|
|
85
99
|
return ok(void 0);
|
|
86
100
|
}
|
|
87
101
|
const invalidFields = [];
|
|
@@ -106,7 +120,7 @@ const validateNavigationDocument = (document) => {
|
|
|
106
120
|
if (invalidFields.length) {
|
|
107
121
|
return fail(createContentError(
|
|
108
122
|
"INVALID_NAVIGATION_YAML",
|
|
109
|
-
document.
|
|
123
|
+
document.file?.path || document.id,
|
|
110
124
|
"malformed .navigation.yml",
|
|
111
125
|
invalidFields.join("; ")
|
|
112
126
|
));
|
|
@@ -114,13 +128,10 @@ const validateNavigationDocument = (document) => {
|
|
|
114
128
|
return ok(void 0);
|
|
115
129
|
};
|
|
116
130
|
export const getCanonicalContentId = (document, locales = []) => {
|
|
117
|
-
if (typeof document.
|
|
118
|
-
return document.
|
|
119
|
-
}
|
|
120
|
-
if (typeof document._canonicalKey === "string" && document._canonicalKey.length) {
|
|
121
|
-
return document._canonicalKey;
|
|
131
|
+
if (typeof document.canonicalKey === "string" && document.canonicalKey.length) {
|
|
132
|
+
return document.canonicalKey;
|
|
122
133
|
}
|
|
123
|
-
const file = (document.
|
|
134
|
+
const file = (document.file?.path || "").replace(/^\/+/, "");
|
|
124
135
|
const parts = file.split("/").filter(Boolean);
|
|
125
136
|
const normalized = parts[0] && locales.includes(parts[0]) ? parts.slice(1) : parts;
|
|
126
137
|
return normalized.join("/").replace(/\.[^.]+$/, "");
|
|
@@ -130,10 +141,10 @@ export const validateCollectionDocument = (document, collections = {}) => {
|
|
|
130
141
|
if (!navigationResult.ok) {
|
|
131
142
|
return navigationResult;
|
|
132
143
|
}
|
|
133
|
-
if (!document.
|
|
144
|
+
if (!document.collection) {
|
|
134
145
|
return ok(document);
|
|
135
146
|
}
|
|
136
|
-
const collection = getCollectionConfig(document.
|
|
147
|
+
const collection = getCollectionConfig(document.collection, collections);
|
|
137
148
|
const schema = collection?.schema;
|
|
138
149
|
if (!hasSafeParse(schema)) {
|
|
139
150
|
return ok(document);
|
|
@@ -149,7 +160,7 @@ export const validateCollectionDocument = (document, collections = {}) => {
|
|
|
149
160
|
const path = issue.path?.length ? issue.path.join(".") : "document";
|
|
150
161
|
return `${path}: ${issue.message}`;
|
|
151
162
|
}).join("; ");
|
|
152
|
-
const message = `Invalid content in ${document.
|
|
163
|
+
const message = `Invalid content in ${document.file?.path || document.id}${details ? ` (${details})` : ""}`;
|
|
153
164
|
if (collection?.strict === false) {
|
|
154
165
|
console.warn(message);
|
|
155
166
|
return ok(document);
|
|
@@ -158,32 +169,30 @@ export const validateCollectionDocument = (document, collections = {}) => {
|
|
|
158
169
|
"SCHEMA_VALIDATION_FAILED",
|
|
159
170
|
message,
|
|
160
171
|
{
|
|
161
|
-
file: document.
|
|
162
|
-
collection: document.
|
|
172
|
+
file: document.file?.path || document.id,
|
|
173
|
+
collection: document.collection,
|
|
163
174
|
...details ? { details } : {}
|
|
164
175
|
}
|
|
165
176
|
));
|
|
166
177
|
};
|
|
167
178
|
export const validateContentGraph = (contents, config) => {
|
|
168
179
|
const locales = config.locales || [];
|
|
169
|
-
const docs = contents.filter((content) => content && content.
|
|
170
|
-
const routeEntries = docs.filter((content) => !content.
|
|
171
|
-
const markdownEntries = routeEntries.filter((content) => content.
|
|
180
|
+
const docs = contents.filter((content) => content && content.path);
|
|
181
|
+
const routeEntries = docs.filter((content) => !content.partial && !content.navigationFile);
|
|
182
|
+
const markdownEntries = routeEntries.filter((content) => content.type === "markdown");
|
|
172
183
|
const idsByLocale = /* @__PURE__ */ new Map();
|
|
173
184
|
const pathsByLocale = /* @__PURE__ */ new Map();
|
|
174
185
|
const referenceTargets = buildReferenceTargets(routeEntries, locales);
|
|
175
186
|
const targetCollections = /* @__PURE__ */ new Map();
|
|
176
|
-
const variantsByCanonicalKey = /* @__PURE__ */ new Map();
|
|
177
187
|
const markdownVariantsByCanonicalKey = /* @__PURE__ */ new Map();
|
|
178
|
-
const explicitIdsByValue = /* @__PURE__ */ new Map();
|
|
179
188
|
const refsByValue = /* @__PURE__ */ new Map();
|
|
180
189
|
for (const document of routeEntries) {
|
|
181
|
-
const canonicalId = document.
|
|
182
|
-
if (!canonicalId || !document.
|
|
190
|
+
const canonicalId = document.canonicalKey || getCanonicalContentId(document, locales);
|
|
191
|
+
if (!canonicalId || !document.collection) {
|
|
183
192
|
continue;
|
|
184
193
|
}
|
|
185
194
|
const collections = targetCollections.get(canonicalId) || /* @__PURE__ */ new Set();
|
|
186
|
-
collections.add(document.
|
|
195
|
+
collections.add(document.collection);
|
|
187
196
|
targetCollections.set(canonicalId, collections);
|
|
188
197
|
}
|
|
189
198
|
for (const issue of collectTranslatedSlugValidationIssues(markdownEntries, {
|
|
@@ -199,85 +208,44 @@ export const validateContentGraph = (contents, config) => {
|
|
|
199
208
|
}
|
|
200
209
|
return fail(createContentError("TRANSLATED_SLUG_CONFLICT", issue.file, issue.reason, issue.details));
|
|
201
210
|
}
|
|
202
|
-
for (const document of routeEntries) {
|
|
203
|
-
const variantKey = document._canonicalKey || getCanonicalContentId(document, locales);
|
|
204
|
-
const siblings = variantsByCanonicalKey.get(variantKey) || [];
|
|
205
|
-
siblings.push(document);
|
|
206
|
-
variantsByCanonicalKey.set(variantKey, siblings);
|
|
207
|
-
}
|
|
208
211
|
for (const document of markdownEntries) {
|
|
209
|
-
const variantKey = document.
|
|
212
|
+
const variantKey = document.canonicalKey || getCanonicalContentId(document, locales);
|
|
210
213
|
const siblings = markdownVariantsByCanonicalKey.get(variantKey) || [];
|
|
211
214
|
siblings.push(document);
|
|
212
215
|
markdownVariantsByCanonicalKey.set(variantKey, siblings);
|
|
213
216
|
}
|
|
214
|
-
for (const [variantKey, variants] of variantsByCanonicalKey.entries()) {
|
|
215
|
-
const explicitIds = Array.from(new Set(variants.map((document) => typeof document.id === "string" && document.id.length ? document.id : void 0).filter((value) => Boolean(value))));
|
|
216
|
-
if (explicitIds.length > 1) {
|
|
217
|
-
return fail(createContentError(
|
|
218
|
-
"CONFLICTING_REFS",
|
|
219
|
-
variants[0]?._file || variants[0]?._id || variantKey,
|
|
220
|
-
`conflicting explicit ids across locale variants for canonical key "${variantKey}"`,
|
|
221
|
-
explicitIds.join(", ")
|
|
222
|
-
));
|
|
223
|
-
}
|
|
224
|
-
if (explicitIds.length === 1 && variants.some((document) => document.id !== explicitIds[0])) {
|
|
225
|
-
return fail(createContentError(
|
|
226
|
-
"CONFLICTING_REFS",
|
|
227
|
-
variants[0]?._file || variants[0]?._id || variantKey,
|
|
228
|
-
`explicit id "${explicitIds[0]}" must be declared consistently across locale variants for canonical key "${variantKey}"`
|
|
229
|
-
));
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
for (const document of routeEntries) {
|
|
233
|
-
const explicitId = typeof document.id === "string" && document.id.length ? document.id : void 0;
|
|
234
|
-
if (!explicitId) {
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
const variantKey = document._canonicalKey || getCanonicalContentId(document, locales);
|
|
238
|
-
const previous = explicitIdsByValue.get(explicitId);
|
|
239
|
-
if (previous && previous.variantKey !== variantKey) {
|
|
240
|
-
return fail(createContentError(
|
|
241
|
-
"CONFLICTING_REFS",
|
|
242
|
-
document._file || document._id,
|
|
243
|
-
`duplicate explicit id "${explicitId}"`,
|
|
244
|
-
`conflicts with ${previous.document._file || previous.document._id}`
|
|
245
|
-
));
|
|
246
|
-
}
|
|
247
|
-
explicitIdsByValue.set(explicitId, { document, variantKey });
|
|
248
|
-
}
|
|
249
217
|
for (const [variantKey, variants] of markdownVariantsByCanonicalKey.entries()) {
|
|
250
218
|
const explicitRefs = Array.from(new Set(variants.map((document) => typeof document.ref === "string" && document.ref.length ? document.ref : void 0).filter((value) => Boolean(value))));
|
|
251
219
|
if (explicitRefs.length > 1) {
|
|
252
220
|
return fail(createContentError(
|
|
253
221
|
"CONFLICTING_REFS",
|
|
254
|
-
variants[0]?.
|
|
222
|
+
variants[0]?.file?.path || variants[0]?.id || variantKey,
|
|
255
223
|
`conflicting refs across locale variants for canonical key "${variantKey}"`,
|
|
256
224
|
explicitRefs.join(", ")
|
|
257
225
|
));
|
|
258
226
|
}
|
|
259
227
|
}
|
|
260
228
|
for (const document of routeEntries) {
|
|
261
|
-
const canonicalId = document.
|
|
262
|
-
const localeKey = `${canonicalId}:${document.
|
|
229
|
+
const canonicalId = document.canonicalKey || getCanonicalContentId(document, locales);
|
|
230
|
+
const localeKey = `${canonicalId}:${document.locale || ""}`;
|
|
263
231
|
if (idsByLocale.has(localeKey)) {
|
|
264
232
|
const previous = idsByLocale.get(localeKey);
|
|
265
233
|
return fail(createContentError(
|
|
266
234
|
"DUPLICATE_CANONICAL_ID",
|
|
267
|
-
document.
|
|
268
|
-
`duplicate canonical id "${canonicalId}" for locale "${document.
|
|
269
|
-
`conflicts with ${previous.
|
|
235
|
+
document.file?.path || document.id,
|
|
236
|
+
`duplicate canonical id "${canonicalId}" for locale "${document.locale || "default"}"`,
|
|
237
|
+
`conflicts with ${previous.file?.path || previous.id}`
|
|
270
238
|
));
|
|
271
239
|
}
|
|
272
240
|
idsByLocale.set(localeKey, document);
|
|
273
|
-
const pathKey = `${document.
|
|
241
|
+
const pathKey = `${document.locale || ""}:${document.path || ""}`;
|
|
274
242
|
if (pathsByLocale.has(pathKey)) {
|
|
275
243
|
const previous = pathsByLocale.get(pathKey);
|
|
276
244
|
return fail(createContentError(
|
|
277
245
|
"DUPLICATE_LOCALIZED_PATH",
|
|
278
|
-
document.
|
|
279
|
-
`duplicate localized path "${document.
|
|
280
|
-
`conflicts with ${previous.
|
|
246
|
+
document.file?.path || document.id,
|
|
247
|
+
`duplicate localized path "${document.path}" for locale "${document.locale || "default"}"`,
|
|
248
|
+
`conflicts with ${previous.file?.path || previous.id}`
|
|
281
249
|
));
|
|
282
250
|
}
|
|
283
251
|
pathsByLocale.set(pathKey, document);
|
|
@@ -286,7 +254,7 @@ export const validateContentGraph = (contents, config) => {
|
|
|
286
254
|
if (typeof document.ref !== "undefined" && (typeof document.ref !== "string" || !document.ref.length)) {
|
|
287
255
|
return fail(createContentError(
|
|
288
256
|
"INVALID_REF_VALUE",
|
|
289
|
-
document.
|
|
257
|
+
document.file?.path || document.id,
|
|
290
258
|
"ref must be a non-empty string"
|
|
291
259
|
));
|
|
292
260
|
}
|
|
@@ -295,39 +263,45 @@ export const validateContentGraph = (contents, config) => {
|
|
|
295
263
|
continue;
|
|
296
264
|
}
|
|
297
265
|
const previous = refsByValue.get(ref);
|
|
298
|
-
if (previous && (previous.
|
|
266
|
+
if (previous && (previous.canonicalKey || getCanonicalContentId(previous, locales)) !== (document.canonicalKey || getCanonicalContentId(document, locales))) {
|
|
299
267
|
return fail(createContentError(
|
|
300
268
|
"CONFLICTING_REFS",
|
|
301
|
-
document.
|
|
269
|
+
document.file?.path || document.id,
|
|
302
270
|
`duplicate ref "${ref}"`,
|
|
303
|
-
`conflicts with ${previous.
|
|
271
|
+
`conflicts with ${previous.file?.path || previous.id}`
|
|
304
272
|
));
|
|
305
273
|
}
|
|
306
274
|
refsByValue.set(ref, document);
|
|
307
275
|
}
|
|
308
276
|
for (const document of docs) {
|
|
309
|
-
if (!document.
|
|
277
|
+
if (!document.collection) {
|
|
310
278
|
continue;
|
|
311
279
|
}
|
|
312
|
-
const collection = getCollectionConfig(document.
|
|
280
|
+
const collection = getCollectionConfig(document.collection, config.collections);
|
|
281
|
+
const references = collection?.references;
|
|
313
282
|
const schema = collection?.schema;
|
|
314
|
-
if (!schema) {
|
|
283
|
+
if (!schema && !references) {
|
|
315
284
|
continue;
|
|
316
285
|
}
|
|
317
286
|
const issues = [];
|
|
318
|
-
|
|
287
|
+
const resolveReference = (value, collection2) => {
|
|
319
288
|
const canonicalId = referenceTargets.get(normalizeReferenceValue(value));
|
|
320
289
|
if (!canonicalId) {
|
|
321
290
|
return false;
|
|
322
291
|
}
|
|
323
292
|
return collection2 ? targetCollections.get(canonicalId)?.has(collection2) === true : true;
|
|
324
|
-
}
|
|
293
|
+
};
|
|
294
|
+
if (schema) {
|
|
295
|
+
collectReferenceIssues(schema, document, resolveReference, issues);
|
|
296
|
+
} else {
|
|
297
|
+
collectDerivedReferenceIssues(references, document, resolveReference, issues);
|
|
298
|
+
}
|
|
325
299
|
if (!issues.length) {
|
|
326
300
|
continue;
|
|
327
301
|
}
|
|
328
302
|
const error = createContentError(
|
|
329
303
|
"SCHEMA_VALIDATION_FAILED",
|
|
330
|
-
document.
|
|
304
|
+
document.file?.path || document.id,
|
|
331
305
|
"unresolved content references",
|
|
332
306
|
issues.join("; ")
|
|
333
307
|
);
|
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import { type ContentProvider } from '../public/provider';
|
|
2
|
-
export interface
|
|
1
|
+
import { type ContentProvider, type ContentProviderCapabilities } from '../public/provider';
|
|
2
|
+
export interface ProviderContractSuiteOptions {
|
|
3
3
|
name: string;
|
|
4
4
|
expectedProviderName: string;
|
|
5
5
|
loadProvider: () => Promise<ContentProvider>;
|
|
6
6
|
createEvent: () => any;
|
|
7
|
+
/**
|
|
8
|
+
* The capabilities the provider under test declares. Each capability block
|
|
9
|
+
* runs its positive assertions only when the matching flag is `true`.
|
|
10
|
+
* Operation capabilities (`routeBackedCollections`, `navigation`,
|
|
11
|
+
* `surroundings`, `searchSections`, `sitemap`) and the query sub-capabilities
|
|
12
|
+
* (`query.limit`/`skip`/`count`) additionally assert the typed provider error
|
|
13
|
+
* when declared `false`; descriptive flags (`dataCollections`,
|
|
14
|
+
* `localizedRoutes`, `translatedSlugs`) only gate their positive block.
|
|
15
|
+
*/
|
|
16
|
+
expectedCapabilities: ContentProviderCapabilities;
|
|
7
17
|
collectNavPaths?: (items: Array<{
|
|
8
|
-
|
|
18
|
+
unprefixedPath?: string;
|
|
9
19
|
children?: any[];
|
|
10
20
|
}>) => string[];
|
|
11
21
|
}
|
|
@@ -18,7 +28,7 @@ export interface AuthorDependencyContractOptions {
|
|
|
18
28
|
key: string;
|
|
19
29
|
}>;
|
|
20
30
|
}
|
|
21
|
-
export declare const
|
|
31
|
+
export declare const runProviderContractSuite: ({ name, expectedProviderName, loadProvider, createEvent, expectedCapabilities, collectNavPaths }: ProviderContractSuiteOptions) => void;
|
|
22
32
|
export declare const createAuthorDependencyContractProvider: () => {
|
|
23
33
|
fixture: import("./provider-fixture").ProviderFixture;
|
|
24
34
|
provider: ContentProvider & {
|
|
@@ -1,42 +1,53 @@
|
|
|
1
1
|
import { expect, test } from "vitest";
|
|
2
|
-
import { contentProviderResultMarker } from "../public/provider";
|
|
2
|
+
import { contentProviderResultMarker, toContentProviderNavigationQuery, toContentProviderQuery } from "../public/provider";
|
|
3
3
|
import { createAuthorDependencyProviderFixture, createFixtureContentProvider, createProviderFixtureEvent, getProviderFixtureCacheHint } from "./provider-fixture.js";
|
|
4
4
|
const defaultCollectNavPaths = (items) => items.flatMap((item) => [
|
|
5
|
-
item.
|
|
5
|
+
item.unprefixedPath,
|
|
6
6
|
...defaultCollectNavPaths(item.children || [])
|
|
7
7
|
].filter(Boolean));
|
|
8
8
|
const unwrapProviderResult = (value) => value && typeof value === "object" && value[contentProviderResultMarker] ? value.data : value;
|
|
9
|
-
|
|
9
|
+
const expectUnsupportedOperation = (run, operation) => expect(Promise.resolve().then(run)).rejects.toMatchObject({
|
|
10
|
+
statusCode: 400,
|
|
11
|
+
statusMessage: "unsupported_provider_operation",
|
|
12
|
+
data: { code: "unsupported_provider_operation", operation }
|
|
13
|
+
});
|
|
14
|
+
const expectUnsupportedQueryShape = (run, field) => expect(Promise.resolve().then(run)).rejects.toMatchObject({
|
|
15
|
+
statusCode: 400,
|
|
16
|
+
statusMessage: "unsupported_query_shape",
|
|
17
|
+
data: { code: "unsupported_query_shape", field }
|
|
18
|
+
});
|
|
19
|
+
export const runProviderContractSuite = ({
|
|
10
20
|
name,
|
|
11
21
|
expectedProviderName,
|
|
12
22
|
loadProvider,
|
|
13
23
|
createEvent,
|
|
24
|
+
expectedCapabilities,
|
|
14
25
|
collectNavPaths = defaultCollectNavPaths
|
|
15
26
|
}) => {
|
|
27
|
+
const caps = expectedCapabilities;
|
|
16
28
|
test(`${name} exposes explicit capabilities`, async () => {
|
|
17
29
|
const provider = await loadProvider();
|
|
18
30
|
expect(provider.name).toBe(expectedProviderName);
|
|
19
31
|
expect(provider.capabilities).toMatchObject({
|
|
20
|
-
|
|
21
|
-
dataCollections: true,
|
|
22
|
-
localizedRoutes: true,
|
|
23
|
-
translatedSlugs: true,
|
|
24
|
-
navigation: true,
|
|
25
|
-
surroundings: true,
|
|
26
|
-
searchSections: true,
|
|
27
|
-
sitemap: true,
|
|
32
|
+
...caps,
|
|
28
33
|
query: {
|
|
29
|
-
limit:
|
|
30
|
-
skip:
|
|
31
|
-
count:
|
|
34
|
+
limit: caps.query.limit,
|
|
35
|
+
skip: caps.query.skip,
|
|
36
|
+
count: caps.query.count
|
|
32
37
|
}
|
|
33
38
|
});
|
|
34
|
-
expect(provider.capabilities.query.operators).
|
|
35
|
-
|
|
39
|
+
expect(provider.capabilities.query.operators).toEqual(
|
|
40
|
+
expect.arrayContaining(caps.query.operators)
|
|
41
|
+
);
|
|
36
42
|
});
|
|
37
43
|
test(`${name} returns complete localized page and route metadata`, async () => {
|
|
38
44
|
const provider = await loadProvider();
|
|
39
45
|
const event = createEvent();
|
|
46
|
+
if (!caps.routeBackedCollections) {
|
|
47
|
+
await expectUnsupportedOperation(() => provider.page?.(event, "docs", "/de/dokumentation/einstieg"), "route-backed pages");
|
|
48
|
+
await expectUnsupportedOperation(() => provider.routeMeta?.(event, "docs", "/de/dokumentation/einstieg", { locale: "de" }), "route metadata");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
40
51
|
const page = unwrapProviderResult(await provider.page?.(event, "docs", "/de/dokumentation/einstieg"));
|
|
41
52
|
expect(page).toMatchObject({
|
|
42
53
|
title: "Einstieg",
|
|
@@ -61,43 +72,62 @@ export const runSaasProviderFixtureContractSuite = ({
|
|
|
61
72
|
locale: "de"
|
|
62
73
|
})
|
|
63
74
|
});
|
|
64
|
-
});
|
|
65
|
-
test(`${name} supports localized page misses without fallback routes`, async () => {
|
|
66
|
-
const provider = await loadProvider();
|
|
67
75
|
const miss = unwrapProviderResult(await provider.page?.(createEvent(), "docs", "/de/dokumentation/not-found"));
|
|
68
76
|
expect(miss).toBeNull();
|
|
69
77
|
});
|
|
70
78
|
test(`${name} supports list queries with locale, ordering, limit, count, and projection`, async () => {
|
|
71
79
|
const provider = await loadProvider();
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
if (!caps.query.limit) {
|
|
81
|
+
await expectUnsupportedQueryShape(() => provider.query(createEvent(), toContentProviderQuery({
|
|
82
|
+
collection: "posts",
|
|
83
|
+
resolveLocale: { locale: "de", fallback: false },
|
|
84
|
+
limit: 1
|
|
85
|
+
})), "limit");
|
|
86
|
+
} else {
|
|
87
|
+
const response = unwrapProviderResult(await provider.query(createEvent(), toContentProviderQuery({
|
|
88
|
+
collection: "posts",
|
|
89
|
+
resolveLocale: { locale: "de", fallback: false },
|
|
90
|
+
sort: [{ date: -1 }],
|
|
91
|
+
limit: 1,
|
|
92
|
+
only: ["title", "path", "locale"]
|
|
93
|
+
})));
|
|
94
|
+
expect(response.result).toEqual([
|
|
95
|
+
{
|
|
96
|
+
title: "Mehrsprachiges Onboarding",
|
|
97
|
+
path: "/magazin/mehrsprachiges-onboarding",
|
|
98
|
+
locale: "de"
|
|
99
|
+
}
|
|
100
|
+
]);
|
|
101
|
+
expect(typeof response.total).toBe("number");
|
|
102
|
+
}
|
|
103
|
+
if (!caps.query.count) {
|
|
104
|
+
await expectUnsupportedQueryShape(() => provider.query(createEvent(), toContentProviderQuery({
|
|
105
|
+
collection: "posts",
|
|
106
|
+
resolveLocale: { locale: "de", fallback: false },
|
|
107
|
+
count: true
|
|
108
|
+
})), "count");
|
|
109
|
+
} else {
|
|
110
|
+
const countResponse = unwrapProviderResult(await provider.query(createEvent(), toContentProviderQuery({
|
|
111
|
+
collection: "posts",
|
|
112
|
+
resolveLocale: { locale: "de", fallback: false },
|
|
113
|
+
count: true
|
|
114
|
+
})));
|
|
115
|
+
expect(countResponse).toEqual({ result: 1 });
|
|
116
|
+
}
|
|
93
117
|
});
|
|
94
|
-
test(`${name} produces navigation
|
|
118
|
+
test(`${name} produces navigation entries`, async () => {
|
|
95
119
|
const provider = await loadProvider();
|
|
96
120
|
const event = createEvent();
|
|
121
|
+
if (!caps.navigation) {
|
|
122
|
+
await expectUnsupportedOperation(() => provider.navigation?.(event, "docs", { locale: "de" }), "navigation");
|
|
123
|
+
const wire = toContentProviderNavigationQuery({ where: { locale: "de" } });
|
|
124
|
+
await expectUnsupportedOperation(() => provider.navigationQuery?.(event, wire.query, wire.options), "navigation");
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
97
127
|
const nav = unwrapProviderResult(await provider.navigation?.(event, "docs", { locale: "de" }));
|
|
98
128
|
expect(collectNavPaths(nav || [])).toContain("/dokumentation/einstieg");
|
|
99
129
|
expect(nav?.[0]).toEqual(expect.objectContaining({
|
|
100
|
-
|
|
130
|
+
locale: "de",
|
|
101
131
|
ref: expect.any(String),
|
|
102
132
|
stableId: expect.any(String)
|
|
103
133
|
}));
|
|
@@ -112,27 +142,54 @@ export const runSaasProviderFixtureContractSuite = ({
|
|
|
112
142
|
title: expect.any(String),
|
|
113
143
|
description: expect.any(String)
|
|
114
144
|
}));
|
|
115
|
-
const
|
|
145
|
+
const globalNavWire = toContentProviderNavigationQuery({ where: { locale: "de" } });
|
|
146
|
+
const globalNav = unwrapProviderResult(await provider.navigationQuery?.(event, globalNavWire.query, globalNavWire.options));
|
|
116
147
|
const globalNavPaths = collectNavPaths(globalNav || []);
|
|
117
148
|
expect(globalNavPaths).toContain("/dokumentation/einstieg");
|
|
118
149
|
expect(globalNavPaths.length).toBeGreaterThan(0);
|
|
119
|
-
const
|
|
150
|
+
const resolvedLocaleNavWire = toContentProviderNavigationQuery({
|
|
120
151
|
collection: "docs",
|
|
121
152
|
resolveLocale: { locale: "de", fallback: false, exact: true }
|
|
122
|
-
})
|
|
153
|
+
});
|
|
154
|
+
const resolvedLocaleNav = unwrapProviderResult(await provider.navigationQuery?.(event, resolvedLocaleNavWire.query, resolvedLocaleNavWire.options));
|
|
123
155
|
expect(collectNavPaths(resolvedLocaleNav || [])).toContain("/dokumentation/einstieg");
|
|
156
|
+
expect(JSON.stringify(nav)).not.toContain("Draft Roadmap");
|
|
157
|
+
});
|
|
158
|
+
test(`${name} produces surroundings entries`, async () => {
|
|
159
|
+
const provider = await loadProvider();
|
|
160
|
+
const event = createEvent();
|
|
161
|
+
if (!caps.surroundings) {
|
|
162
|
+
await expectUnsupportedOperation(() => provider.surroundings?.(event, "docs", "/de/dokumentation/einstieg/installation", { locale: "de" }), "surroundings");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
124
165
|
const surround = unwrapProviderResult(await provider.surroundings?.(event, "docs", "/de/dokumentation/einstieg/installation", { locale: "de" }));
|
|
125
166
|
expect(surround).toHaveLength(2);
|
|
126
|
-
expect(surround?.map((item) => item?.
|
|
167
|
+
expect(surround?.map((item) => item?.unprefixedPath)).toContain("/dokumentation/einstieg/alltag");
|
|
168
|
+
});
|
|
169
|
+
test(`${name} produces search sections`, async () => {
|
|
170
|
+
const provider = await loadProvider();
|
|
171
|
+
const event = createEvent();
|
|
172
|
+
if (!caps.searchSections) {
|
|
173
|
+
await expectUnsupportedOperation(() => provider.searchSections?.(event, "docs", { locale: "de" }), "search sections");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
127
176
|
const sections = unwrapProviderResult(await provider.searchSections?.(event, "docs", { locale: "de" }));
|
|
128
177
|
expect(sections?.some((section) => section.id.startsWith("/de/dokumentation/einstieg") || section.id.startsWith("/dokumentation/einstieg"))).toBe(true);
|
|
129
178
|
expect(JSON.stringify(sections)).not.toContain("Draft Roadmap");
|
|
179
|
+
});
|
|
180
|
+
test(`${name} produces sitemap entries`, async () => {
|
|
181
|
+
const provider = await loadProvider();
|
|
182
|
+
const event = createEvent();
|
|
183
|
+
if (!caps.sitemap) {
|
|
184
|
+
await expectUnsupportedOperation(() => provider.sitemapEntries?.(event, { include: ["docs"] }), "sitemap entries");
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
130
187
|
const sitemap = unwrapProviderResult(await provider.sitemapEntries?.(event, { include: ["docs"] }));
|
|
131
188
|
expect(sitemap?.some((entry) => entry.loc.endsWith("/de/dokumentation/einstieg"))).toBe(true);
|
|
132
189
|
expect(JSON.stringify(sitemap)).not.toContain("/docs/draft-roadmap");
|
|
133
|
-
expect(JSON.stringify(nav)).not.toContain("Draft Roadmap");
|
|
134
190
|
});
|
|
135
191
|
test(`${name} emits cache hints for rendered content`, async () => {
|
|
192
|
+
if (!caps.routeBackedCollections) return;
|
|
136
193
|
const provider = await loadProvider();
|
|
137
194
|
const event = createEvent();
|
|
138
195
|
await provider.page?.(event, "posts", "/de/magazin/mehrsprachiges-onboarding");
|
|
@@ -154,38 +211,34 @@ export const runSaasProviderFixtureContractSuite = ({
|
|
|
154
211
|
}
|
|
155
212
|
});
|
|
156
213
|
test(`${name} supports data-only collection reads and rejects data-only sitemap access`, async () => {
|
|
214
|
+
if (!caps.dataCollections) return;
|
|
157
215
|
const provider = await loadProvider();
|
|
158
|
-
const response = unwrapProviderResult(await provider.query(createEvent(), {
|
|
216
|
+
const response = unwrapProviderResult(await provider.query(createEvent(), toContentProviderQuery({
|
|
159
217
|
collection: "versions",
|
|
160
218
|
resolveLocale: { locale: "en", fallback: false },
|
|
161
219
|
sort: [{ date: -1 }]
|
|
162
|
-
}));
|
|
220
|
+
})));
|
|
163
221
|
expect(response.result[0]?.title).toBe("Launch readiness");
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
222
|
+
if (caps.sitemap) {
|
|
223
|
+
await expect(provider.sitemapEntries?.(createEvent(), { include: ["versions"] })).rejects.toMatchObject({
|
|
224
|
+
statusCode: 400,
|
|
225
|
+
statusMessage: "data_collection_sitemap_access",
|
|
226
|
+
data: {
|
|
227
|
+
code: "data_collection_sitemap_access",
|
|
228
|
+
collection: "versions"
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
172
232
|
});
|
|
173
233
|
test(`${name} fails loudly for unsupported query operators and unknown collections`, async () => {
|
|
174
234
|
const provider = await loadProvider();
|
|
175
|
-
|
|
235
|
+
expect(() => toContentProviderQuery({
|
|
176
236
|
collection: "posts",
|
|
177
237
|
where: { title: { $near: "launch" } }
|
|
178
|
-
})).
|
|
179
|
-
|
|
180
|
-
statusMessage: "unsupported_query_operator",
|
|
181
|
-
data: {
|
|
182
|
-
code: "unsupported_query_operator",
|
|
183
|
-
operator: "$near"
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
await expect(provider.query(createEvent(), {
|
|
238
|
+
})).toThrow(/Unsupported content query operator: \$near/);
|
|
239
|
+
await expect(provider.query(createEvent(), toContentProviderQuery({
|
|
187
240
|
collection: "missing"
|
|
188
|
-
})).rejects.toMatchObject({
|
|
241
|
+
}))).rejects.toMatchObject({
|
|
189
242
|
statusCode: 400,
|
|
190
243
|
statusMessage: "unknown_collection",
|
|
191
244
|
data: {
|
|
@@ -63,5 +63,5 @@ export declare const createProviderFixtureEvent: (options?: ProviderFixtureEvent
|
|
|
63
63
|
export declare const createFixtureContentProvider: (fixture: ProviderFixture, name?: string) => ContentProvider & {
|
|
64
64
|
cache: ProviderFixtureCacheState;
|
|
65
65
|
};
|
|
66
|
-
export declare const
|
|
66
|
+
export declare const createDefaultProviderFixture: () => ProviderFixture;
|
|
67
67
|
export declare const createAuthorDependencyProviderFixture: () => ProviderFixture;
|