@lupinum/ginko-content 0.1.2 → 0.1.3

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.
Files changed (189) hide show
  1. package/README.md +18 -4
  2. package/compatibility.json +1 -1
  3. package/dist/cli.mjs +317 -294
  4. package/dist/cms-import/index.js +5 -1
  5. package/dist/config.d.mts +1 -1
  6. package/dist/config.mjs +1 -1
  7. package/dist/core/cache-hints.d.ts +9 -1
  8. package/dist/core/content/collection.js +1 -1
  9. package/dist/core/content/path.js +1 -1
  10. package/dist/core/errors.js +5 -1
  11. package/dist/core/provider-errors +1 -0
  12. package/dist/core/provider-errors.d.ts +10 -0
  13. package/dist/core/provider-errors.js +27 -0
  14. package/dist/core/query/execute.js +12 -3
  15. package/dist/core/query/filter.js +2 -2
  16. package/dist/core/query/lower.js +5 -4
  17. package/dist/features/navigation/build.js +14 -6
  18. package/dist/features/navigation/canonical.js +1 -1
  19. package/dist/features/sitemap/query.js +2 -2
  20. package/dist/integrations/nitro/ingest.d.ts +3 -3
  21. package/dist/integrations/nitro/ingest.js +3 -3
  22. package/dist/integrations/nitro/storage.js +3 -1
  23. package/dist/module.d.mts +151 -526
  24. package/dist/module.json +1 -1
  25. package/dist/module.mjs +1091 -722
  26. package/dist/parsers/csv.js +4 -3
  27. package/dist/parsers/index.d.ts +2 -5
  28. package/dist/parsers/index.js +2 -2
  29. package/dist/parsers/markdown-plugins.d.ts +1 -0
  30. package/dist/parsers/markdown-plugins.js +83 -1
  31. package/dist/parsers/markdown.js +1 -1
  32. package/dist/public/client.d.ts +3 -2
  33. package/dist/public/client.js +2 -2
  34. package/dist/public/provider-errors.d.ts +2 -1
  35. package/dist/public/provider-errors.js +1 -18
  36. package/dist/public/provider.d.ts +3 -10
  37. package/dist/public/server.d.ts +6 -1
  38. package/dist/public/server.js +33 -0
  39. package/dist/runtime/agent-paths +1 -0
  40. package/dist/runtime/agent-paths.d.ts +6 -0
  41. package/dist/runtime/agent-paths.js +41 -0
  42. package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +1 -1
  43. package/dist/runtime/app/composables/head.d.ts +3 -0
  44. package/dist/runtime/app/composables/head.js +2 -1
  45. package/dist/runtime/app/composables/hot-reload +1 -0
  46. package/dist/runtime/app/composables/hot-reload.d.ts +5 -0
  47. package/dist/runtime/app/composables/hot-reload.js +15 -0
  48. package/dist/runtime/app/composables/locale-context.d.ts +1 -1
  49. package/dist/runtime/app/composables/locale-context.js +2 -1
  50. package/dist/runtime/app/composables/locale.js +2 -2
  51. package/dist/runtime/app/composables/search.js +10 -6
  52. package/dist/runtime/app/composables/use-content-document +1 -0
  53. package/dist/runtime/app/composables/use-content-document.d.ts +29 -0
  54. package/dist/runtime/app/composables/use-content-document.js +44 -0
  55. package/dist/runtime/app/composables/use-content-list +1 -0
  56. package/dist/runtime/app/composables/use-content-list.d.ts +43 -0
  57. package/dist/runtime/app/composables/use-content-list.js +98 -0
  58. package/dist/runtime/app/composables/use-content-navigation +1 -0
  59. package/dist/runtime/app/composables/use-content-navigation.d.ts +40 -0
  60. package/dist/runtime/app/composables/use-content-navigation.js +102 -0
  61. package/dist/runtime/app/composables/use-content-page +1 -0
  62. package/dist/runtime/app/composables/use-content-page.d.ts +47 -0
  63. package/dist/runtime/app/composables/use-content-page.js +142 -0
  64. package/dist/runtime/app/composables/use-content-shared +1 -0
  65. package/dist/runtime/app/composables/use-content-shared.d.ts +13 -0
  66. package/dist/runtime/app/composables/use-content-shared.js +29 -0
  67. package/dist/runtime/app/composables/use-content.d.ts +11 -206
  68. package/dist/runtime/app/composables/use-content.js +4 -377
  69. package/dist/runtime/app/plugins/hot-reload +1 -0
  70. package/dist/runtime/app/plugins/hot-reload.js +6 -0
  71. package/dist/runtime/query/backlinks +1 -0
  72. package/dist/runtime/query/backlinks.d.ts +8 -0
  73. package/dist/runtime/query/backlinks.js +90 -0
  74. package/dist/runtime/query/context +1 -0
  75. package/dist/runtime/query/context.d.ts +20 -0
  76. package/dist/runtime/query/context.js +0 -0
  77. package/dist/runtime/query/documents +1 -0
  78. package/dist/runtime/query/documents.d.ts +6 -0
  79. package/dist/runtime/query/documents.js +98 -0
  80. package/dist/runtime/query/errors +1 -0
  81. package/dist/runtime/query/errors.d.ts +1 -0
  82. package/dist/runtime/query/errors.js +4 -0
  83. package/dist/runtime/query/handles +1 -0
  84. package/dist/runtime/query/handles.d.ts +2 -0
  85. package/dist/runtime/query/handles.js +7 -0
  86. package/dist/runtime/query/locale-options +1 -0
  87. package/dist/runtime/query/locale-options.d.ts +5 -0
  88. package/dist/runtime/query/locale-options.js +14 -0
  89. package/dist/runtime/query/localized-docs +1 -0
  90. package/dist/runtime/query/localized-docs.d.ts +17 -0
  91. package/dist/runtime/query/localized-docs.js +44 -0
  92. package/dist/runtime/query/navigation +1 -0
  93. package/dist/runtime/query/navigation.d.ts +22 -0
  94. package/dist/runtime/query/navigation.js +73 -0
  95. package/dist/runtime/query/pagination +1 -0
  96. package/dist/runtime/query/pagination.d.ts +7 -0
  97. package/dist/runtime/query/pagination.js +78 -0
  98. package/dist/runtime/query/populate +1 -0
  99. package/dist/runtime/query/populate.d.ts +9 -0
  100. package/dist/runtime/query/populate.js +106 -0
  101. package/dist/runtime/query/responses +1 -0
  102. package/dist/runtime/query/responses.d.ts +10 -0
  103. package/dist/runtime/query/responses.js +47 -0
  104. package/dist/runtime/query/unified.d.ts +4 -20
  105. package/dist/runtime/query/unified.js +14 -544
  106. package/dist/runtime/query/variants +1 -0
  107. package/dist/runtime/query/variants.d.ts +11 -0
  108. package/dist/runtime/query/variants.js +36 -0
  109. package/dist/runtime/server/agent-http +1 -0
  110. package/dist/runtime/server/agent-http.d.ts +7 -0
  111. package/dist/runtime/server/agent-http.js +36 -0
  112. package/dist/runtime/server/agent-markdown +1 -0
  113. package/dist/runtime/server/agent-markdown.d.ts +83 -0
  114. package/dist/runtime/server/agent-markdown.js +449 -0
  115. package/dist/runtime/server/agent-site +1 -0
  116. package/dist/runtime/server/agent-site.d.ts +38 -0
  117. package/dist/runtime/server/agent-site.js +273 -0
  118. package/dist/runtime/server/api/agent-llms +1 -0
  119. package/dist/runtime/server/api/agent-llms-full +1 -0
  120. package/dist/runtime/server/api/agent-llms-full.d.ts +2 -0
  121. package/dist/runtime/server/api/agent-llms-full.js +13 -0
  122. package/dist/runtime/server/api/agent-llms.d.ts +2 -0
  123. package/dist/runtime/server/api/agent-llms.js +14 -0
  124. package/dist/runtime/server/api/agent-raw +1 -0
  125. package/dist/runtime/server/api/agent-raw.d.ts +2 -0
  126. package/dist/runtime/server/api/agent-raw.js +17 -0
  127. package/dist/runtime/server/api/locales.d.ts +2 -2
  128. package/dist/runtime/server/api/locales.js +4 -2
  129. package/dist/runtime/server/api/navigation.d.ts +1 -1
  130. package/dist/runtime/server/api/query.d.ts +1 -1
  131. package/dist/runtime/server/api/query.js +4 -1
  132. package/dist/runtime/server/api/revalidate.js +2 -2
  133. package/dist/runtime/server/api/site-data.d.ts +1 -1
  134. package/dist/runtime/server/collection-helpers.js +2 -1
  135. package/dist/runtime/server/middleware/agent-link-headers +1 -0
  136. package/dist/runtime/server/middleware/agent-link-headers.d.ts +2 -0
  137. package/dist/runtime/server/middleware/agent-link-headers.js +42 -0
  138. package/dist/runtime/server/middleware/agent-markdown +1 -0
  139. package/dist/runtime/server/middleware/agent-markdown.d.ts +2 -0
  140. package/dist/runtime/server/middleware/agent-markdown.js +43 -0
  141. package/dist/runtime/server/plugins/sitemap.js +1 -0
  142. package/dist/runtime/server/provider-query.d.ts +8 -5
  143. package/dist/runtime/server/provider-query.js +50 -8
  144. package/dist/runtime/server/provider-result.d.ts +19 -2
  145. package/dist/runtime/server/providers/filesystem.js +4 -1
  146. package/dist/runtime/server/providers/index.d.ts +3 -1
  147. package/dist/runtime/server/providers/index.js +2 -2
  148. package/dist/runtime/server/query-api.js +2 -1
  149. package/dist/runtime/server/query-executor.d.ts +3 -2
  150. package/dist/runtime/server/query-executor.js +13 -5
  151. package/dist/runtime/server/search.js +1 -1
  152. package/dist/runtime/server/sitemap-provider.js +40 -1
  153. package/dist/runtime/server/sitemap.js +3 -2
  154. package/dist/runtime/transformers/component-resolver.js +2 -1
  155. package/dist/runtime/utils/content-components.d.ts +0 -5
  156. package/dist/storage/content.d.ts +2 -9
  157. package/dist/storage/references.d.ts +1 -8
  158. package/dist/storage/references.js +9 -4
  159. package/dist/testing/provider-contract.js +3 -4
  160. package/dist/testing/provider-fixture.d.ts +3 -1
  161. package/dist/testing/provider-fixture.js +27 -14
  162. package/dist/types/config.d.ts +77 -0
  163. package/dist/types/config.js +23 -0
  164. package/dist/types/module.d.ts +15 -5
  165. package/dist/types/query-parts/collections +1 -0
  166. package/dist/types/query-parts/collections.d.ts +15 -0
  167. package/dist/types/query-parts/collections.js +0 -0
  168. package/dist/types/query-parts/public +1 -0
  169. package/dist/types/query-parts/public.d.ts +202 -0
  170. package/dist/types/query-parts/public.js +0 -0
  171. package/dist/types/query-parts/results +1 -0
  172. package/dist/types/query-parts/results.d.ts +95 -0
  173. package/dist/types/query-parts/results.js +0 -0
  174. package/dist/types/query-parts/transport +1 -0
  175. package/dist/types/query-parts/transport.d.ts +103 -0
  176. package/dist/types/query-parts/transport.js +0 -0
  177. package/dist/types/query.d.ts +4 -870
  178. package/dist/types/query.js +4 -0
  179. package/dist/types/runtime.d.ts +2 -2
  180. package/dist/types/virtual.d.ts +54 -0
  181. package/dist/types.d.mts +2 -2
  182. package/dist/web-types.json +1 -1
  183. package/package.json +5 -5
  184. package/dist/runtime/app/composables/web-socket +0 -1
  185. package/dist/runtime/app/composables/web-socket.d.ts +0 -3
  186. package/dist/runtime/app/composables/web-socket.js +0 -65
  187. package/dist/runtime/app/plugins/ws +0 -1
  188. package/dist/runtime/app/plugins/ws.js +0 -7
  189. /package/dist/runtime/app/plugins/{ws.d.ts → hot-reload.d.ts} +0 -0
@@ -1,560 +1,30 @@
1
- import { compileQueryParams } from "../../core/query/filter";
2
- import { decorateLocalePathsWithFallbacks, localizePageResult } from "../../features/localization/results";
3
- import { normalizeContentPath, normalizeRouteMounts } from "../../features/localization/path";
4
- import { normalizeReferenceValue } from "../../core/references/resolve";
5
- import { collectTopLevelReferenceFields, collectTopLevelReferenceFieldsByTarget } from "../../core/references/schema";
6
- import { MAX_PUBLIC_QUERY_LIMIT, MAX_PUBLIC_QUERY_SKIP } from "./public-limits.js";
7
- const NAVIGATION_INTERNAL_FIELDS = [
8
- "_id",
9
- "_path",
10
- "_file",
11
- "_canonicalKey",
12
- "_locale",
13
- "_draft",
14
- "navigation",
15
- "title"
16
- ];
17
- const LOCALIZED_DOC_INTERNAL_FIELDS = [
18
- "_id",
19
- "_path",
20
- "_file",
21
- "_canonicalKey",
22
- "_locale",
23
- "_resolvedLocale",
24
- "_requestedLocale",
25
- "_fallback",
26
- "_availableLocales",
27
- "_variantPaths",
28
- "_requestedPath",
29
- "_requestedRoute",
30
- "_requestedRef",
31
- "_extension"
32
- ];
33
- export const navigationSelectFields = (fields = []) => [
34
- .../* @__PURE__ */ new Set([...NAVIGATION_INTERNAL_FIELDS, ...fields])
35
- ];
36
- const isNotFoundError = (error) => {
37
- const statusCode = error?.statusCode ?? error?.response?.status;
38
- return statusCode === 404;
39
- };
40
- const isQueryEnvelope = (response) => Boolean(response && typeof response === "object" && "result" in response);
41
- const unwrapResponse = (response) => {
42
- if (!response) return null;
43
- if (isQueryEnvelope(response)) {
44
- const result = response.result;
45
- return result ?? null;
46
- }
47
- return response;
48
- };
49
- const unwrapFindResponse = (response) => {
50
- if (!response) {
51
- return { result: [], total: 0, skip: 0, limit: 0, hasTotal: false };
52
- }
53
- if (isQueryEnvelope(response)) {
54
- const result2 = Array.isArray(response.result) ? response.result : response.result ? [response.result] : [];
55
- const hasTotal = typeof response.total === "number";
56
- return {
57
- result: result2,
58
- total: hasTotal ? response.total : result2.length,
59
- skip: typeof response.skip === "number" ? response.skip : 0,
60
- limit: typeof response.limit === "number" ? response.limit : result2.length,
61
- hasTotal
62
- };
63
- }
64
- const result = Array.isArray(response) ? response : [response];
65
- return { result, total: result.length, skip: 0, limit: result.length, hasTotal: false };
66
- };
67
- const unwrapCountResponse = (response) => {
68
- if (typeof response === "number") {
69
- return response;
70
- }
71
- if (isQueryEnvelope(response) && typeof response.result === "number") {
72
- return response.result;
73
- }
74
- return null;
75
- };
76
- const decorate = (doc, collection, runtime, requestedLocale) => {
77
- if (!doc) return null;
78
- const collectionI18n = runtime?.collections?.[collection]?.i18n;
79
- const collectionLocales = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.locales : void 0;
80
- const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
81
- const locales = collectionLocales?.length ? collectionLocales : runtime?.locales?.length ? runtime.locales : [];
82
- const defaultLocale = collectionDefault || runtime?.defaultLocale;
83
- const routeMounts = normalizeRouteMounts(runtime?.collections?.[collection]?.route, locales, defaultLocale);
84
- const hasLocaleConfig = Boolean(locales.length || defaultLocale);
85
- const page = hasLocaleConfig ? doc : {
86
- ...doc,
87
- _locale: "",
88
- _resolvedLocale: void 0,
89
- _requestedLocale: void 0,
90
- _variantPaths: void 0,
91
- _availableLocales: []
92
- };
93
- const result = localizePageResult(page, hasLocaleConfig ? requestedLocale : void 0, defaultLocale, locales, routeMounts);
94
- const fallbackLocale = doc._resolvedLocale || requestedLocale || defaultLocale;
95
- result.localePaths = decorateLocalePathsWithFallbacks(result.localePaths, locales, fallbackLocale, defaultLocale, routeMounts);
96
- return result;
97
- };
98
- const collectionRouteRoots = (collection, runtime) => {
99
- const collectionConfig = runtime?.collections?.[collection];
100
- const collectionI18n = collectionConfig?.i18n;
101
- const collectionLocales = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.locales : void 0;
102
- const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
103
- const locales = collectionLocales?.length ? collectionLocales : runtime?.locales?.length ? runtime.locales : [];
104
- const defaultLocale = collectionDefault || runtime?.defaultLocale;
105
- const routeMounts = normalizeRouteMounts(collectionConfig?.route, locales, defaultLocale);
106
- return new Set(Object.values(routeMounts || {}).map((value) => normalizeContentPath(value)));
107
- };
108
- const isCollectionRouteRoot = (path, collection, runtime) => collectionRouteRoots(collection, runtime).has(normalizeContentPath(path));
109
- const isAncestorRoutePath = (path, childPath) => {
110
- const normalized = normalizeContentPath(path);
111
- const child = normalizeContentPath(childPath);
112
- return normalized === "/" ? child !== "/" : child.startsWith(`${normalized}/`);
113
- };
114
- const isNavigationRootPath = (path, flat) => Boolean(flat[0]?.path && isAncestorRoutePath(path, flat[0].path));
115
- const collectionDefaultLocale = (collection, runtime) => {
116
- const collectionI18n = runtime?.collections?.[collection]?.i18n;
117
- const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
118
- return collectionDefault || runtime?.defaultLocale;
119
- };
120
- const resolveFallback = (fallback, collection, runtime) => {
121
- if (fallback !== "default") return fallback;
122
- return collectionDefaultLocale(collection, runtime);
123
- };
124
- const explainResolution = (collection, requestedBy, normalizedBy, requestedLocale, requestedFallback, doc) => {
125
- const resolvedLocale = doc?.resolved?.locale || doc?.locale;
126
- return {
127
- requested: {
128
- collection,
129
- by: requestedBy,
130
- ...requestedLocale ? { locale: requestedLocale } : {},
131
- ...requestedFallback !== void 0 ? { fallback: requestedFallback } : {}
132
- },
133
- normalized: {
134
- by: normalizedBy
135
- },
136
- matched: {
137
- found: Boolean(doc),
138
- collection,
139
- ...doc?.path ? { path: doc.path } : {},
140
- ...doc?.canonicalPath ? { canonicalPath: doc.canonicalPath } : {},
141
- ...doc?.ref ? { ref: doc.ref } : {},
142
- ...resolvedLocale ? { locale: resolvedLocale } : {}
143
- },
144
- fallback: {
145
- used: Boolean(requestedLocale && resolvedLocale && requestedLocale !== resolvedLocale),
146
- ...requestedLocale && resolvedLocale && requestedLocale !== resolvedLocale ? { locale: resolvedLocale } : {}
147
- }
148
- };
149
- };
150
- const ensureCollectionName = (handle) => {
151
- if (typeof handle === "string") return handle;
152
- if (!handle || typeof handle !== "object" || typeof handle.name !== "string") {
153
- throw new TypeError("query API: expected a string collection name or a collection handle from defineContentConfig({ collections }). Use useContentPage('docs') or config.collections.docs.");
154
- }
155
- return handle.name;
156
- };
157
- const isRecord = (value) => {
158
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
159
- };
160
- const populateReferenceValue = async (context, target, value, locale, fallback) => {
161
- if (typeof value !== "string" || !value) {
162
- return null;
163
- }
164
- return one(context, target, {
165
- by: { ref: value },
166
- ...locale ? { locale } : {},
167
- ...fallback !== void 0 ? { fallback } : {}
168
- });
169
- };
170
- const wildcardReferenceTarget = "*";
171
- const collectReferenceFieldsByTarget = (source, sourceCollection, runtime) => {
172
- if (typeof source !== "string") {
173
- return collectTopLevelReferenceFieldsByTarget(source.schema);
174
- }
175
- return runtime?.collections?.[sourceCollection]?.references || {};
176
- };
177
- const invertReferenceFields = (references) => {
178
- const fields = /* @__PURE__ */ new Map();
179
- for (const [target, targetFields] of Object.entries(references)) {
180
- for (const field of targetFields) {
181
- const targets = fields.get(field) || [];
182
- targets.push(target);
183
- fields.set(field, targets);
184
- }
185
- }
186
- return fields;
187
- };
188
- const createPopulateTargetMismatchError = (sourceCollection, field, expectedTargets, actualTarget) => new Error([
189
- `Cannot populate "${sourceCollection}.${field}" from "${actualTarget}".`,
190
- `Reference metadata declares "${sourceCollection}.${field}" points to ${expectedTargets.map((target) => `"${target}"`).join(" or ")}.`,
191
- `Change populate.${field} to the declared target collection, or update ${sourceCollection}.schema relation metadata.`
192
- ].join(" "));
193
- const validatePopulateSpec = (source, sourceCollection, runtime, populate) => {
194
- if (!populate || !isRecord(populate)) {
195
- return;
196
- }
197
- const references = collectReferenceFieldsByTarget(source, sourceCollection, runtime);
198
- const fieldTargets = invertReferenceFields(references);
199
- if (!fieldTargets.size) {
200
- return;
201
- }
202
- for (const [field, target] of Object.entries(populate)) {
203
- const declaredTargets = fieldTargets.get(field);
204
- if (!declaredTargets?.length) {
205
- continue;
206
- }
207
- const actualTarget = ensureCollectionName(target);
208
- if (declaredTargets.includes(actualTarget) || declaredTargets.includes(wildcardReferenceTarget)) {
209
- continue;
210
- }
211
- throw createPopulateTargetMismatchError(
212
- sourceCollection,
213
- field,
214
- declaredTargets.filter((target2) => target2 !== wildcardReferenceTarget),
215
- actualTarget
216
- );
217
- }
218
- };
219
- const populateDocument = async (context, doc, populate, locale, fallback) => {
220
- if (!populate || !isRecord(populate)) {
221
- return doc;
222
- }
223
- const populated = { ...doc };
224
- await Promise.all(Object.entries(populate).map(async ([field, target]) => {
225
- const value = doc[field];
226
- if (Array.isArray(value)) {
227
- const resolved = await Promise.all(value.map((item) => populateReferenceValue(context, target, item, locale, fallback)));
228
- populated[field] = resolved.filter(Boolean);
229
- return;
230
- }
231
- populated[field] = await populateReferenceValue(context, target, value, locale, fallback);
232
- }));
233
- return populated;
234
- };
235
- const selectWithPopulate = (select, populate) => {
236
- if (!select) {
237
- return void 0;
238
- }
239
- return [.../* @__PURE__ */ new Set([
240
- ...select,
241
- ...LOCALIZED_DOC_INTERNAL_FIELDS,
242
- ...populate && isRecord(populate) ? Object.keys(populate) : []
243
- ])];
244
- };
1
+ import { resolveBacklinks } from "./backlinks.js";
2
+ import { resolveNeighbors, resolveTree } from "./navigation.js";
3
+ import { resolvePagination } from "./pagination.js";
4
+ import { resolveVariants } from "./variants.js";
5
+ import { resolveDocument, resolveDocumentOnly, resolveManyDocuments } from "./documents.js";
6
+ export { navigationSelectFields } from "./navigation.js";
245
7
  export async function resolveOne(context, handle, options) {
246
- const collection = ensureCollectionName(handle);
247
- const runtime = context.runtime;
248
- validatePopulateSpec(handle, collection, runtime, options.populate);
249
- const by = options.by;
250
- const fallback = resolveFallback(options.fallback, collection, runtime);
251
- const params = compileQueryParams({
252
- collection,
253
- by,
254
- locale: options.locale,
255
- fallback,
256
- select: selectWithPopulate(options.select, options.populate)
257
- });
258
- params.first = true;
259
- let response;
260
- try {
261
- response = await context.transport("query", params);
262
- } catch (error) {
263
- if (isNotFoundError(error)) {
264
- const explain2 = explainResolution(collection, options.by, by, options.locale, options.fallback, null);
265
- return { doc: null, explain: explain2 };
266
- }
267
- throw error;
268
- }
269
- const unwrapped = unwrapResponse(response);
270
- const doc = Array.isArray(unwrapped) ? unwrapped[0] ?? null : unwrapped ?? null;
271
- const decorated = decorate(doc, collection, runtime, options.locale);
272
- const populated = decorated ? await populateDocument(context, decorated, options.populate, options.locale, options.fallback) : null;
273
- const explain = explainResolution(collection, options.by, by, options.locale, options.fallback, decorated);
274
- return {
275
- doc: populated,
276
- explain
277
- };
8
+ return resolveDocument(context, one, handle, options);
278
9
  }
279
10
  export async function one(context, handle, options) {
280
- const result = await resolveOne(context, handle, options);
281
- return result.doc;
11
+ return resolveDocumentOnly(context, handle, options);
282
12
  }
283
13
  export async function many(context, handle, options = {}) {
284
- const collection = ensureCollectionName(handle);
285
- const runtime = context.runtime;
286
- validatePopulateSpec(handle, collection, runtime, options.populate);
287
- const fallback = resolveFallback(options.fallback, collection, runtime);
288
- const params = compileQueryParams({
289
- collection,
290
- where: options.where,
291
- sort: options.sort,
292
- limit: options.limit,
293
- skip: options.skip,
294
- locale: options.locale,
295
- fallback,
296
- select: selectWithPopulate(options.select, options.populate)
297
- });
298
- let response;
299
- try {
300
- response = await context.transport("query", params);
301
- } catch (error) {
302
- if (isNotFoundError(error)) return [];
303
- throw error;
304
- }
305
- const unwrapped = unwrapResponse(response);
306
- const list = Array.isArray(unwrapped) ? unwrapped : unwrapped ? [unwrapped] : [];
307
- const decorated = list.map((doc) => decorate(doc, collection, runtime, options.locale)).filter((doc) => Boolean(doc));
308
- const populated = await Promise.all(decorated.map((doc) => populateDocument(context, doc, options.populate, options.locale, options.fallback)));
309
- return populated;
14
+ return resolveManyDocuments(context, one, handle, options);
310
15
  }
311
- const normalizePositiveInteger = (value, fallback) => {
312
- const number = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
313
- return Math.max(1, number);
314
- };
315
16
  export async function paginate(context, handle, options) {
316
- const collection = ensureCollectionName(handle);
317
- const runtime = context.runtime;
318
- validatePopulateSpec(handle, collection, runtime, options.populate);
319
- const requestedPage = normalizePositiveInteger(options.page, 1);
320
- const limit = Math.min(normalizePositiveInteger(options.limit, 10), MAX_PUBLIC_QUERY_LIMIT);
321
- const skip = Math.min((requestedPage - 1) * limit, MAX_PUBLIC_QUERY_SKIP);
322
- const page = Math.floor(skip / limit) + 1;
323
- const fallback = resolveFallback(options.fallback, collection, runtime);
324
- const params = compileQueryParams({
325
- collection,
326
- where: options.where,
327
- sort: options.sort,
328
- limit,
329
- skip,
330
- locale: options.locale,
331
- fallback,
332
- select: selectWithPopulate(options.select, options.populate)
333
- });
334
- const countParams = compileQueryParams({
335
- collection,
336
- where: options.where,
337
- locale: options.locale,
338
- fallback
339
- });
340
- countParams.count = true;
341
- let response;
342
- try {
343
- response = await context.transport("query", params);
344
- } catch (error) {
345
- if (isNotFoundError(error)) {
346
- return {
347
- data: [],
348
- page,
349
- limit,
350
- total: 0,
351
- pageCount: 0,
352
- hasNext: false,
353
- hasPrev: page > 1,
354
- nextPage: null,
355
- prevPage: page > 1 ? page - 1 : null
356
- };
357
- }
358
- throw error;
359
- }
360
- const envelope = unwrapFindResponse(response);
361
- let total = envelope.total;
362
- if (!envelope.hasTotal) {
363
- const countResponse = await context.transport("query", countParams);
364
- total = unwrapCountResponse(countResponse) ?? envelope.total;
365
- }
366
- const decorated = envelope.result.map((doc) => decorate(doc, collection, runtime, options.locale)).filter((doc) => Boolean(doc));
367
- const populated = await Promise.all(decorated.map((doc) => populateDocument(context, doc, options.populate, options.locale, options.fallback)));
368
- const pageCount = total > 0 ? Math.ceil(total / limit) : 0;
369
- return {
370
- data: populated,
371
- page,
372
- limit,
373
- total,
374
- pageCount,
375
- hasNext: page < pageCount,
376
- hasPrev: page > 1,
377
- nextPage: page < pageCount ? page + 1 : null,
378
- prevPage: page > 1 ? page - 1 : null
379
- };
17
+ return resolvePagination(context, one, handle, options);
380
18
  }
381
- const backlinkSources = (value) => Array.isArray(value) ? [...value] : [value];
382
- const isBacklinkFieldMap = (value) => {
383
- return Boolean(value) && typeof value === "object" && !Array.isArray(value);
384
- };
385
- const resolveExplicitBacklinkFields = (fields, sourceName) => {
386
- if (Array.isArray(fields)) {
387
- return fields.filter((field) => typeof field === "string" && field.length > 0);
388
- }
389
- if (!isBacklinkFieldMap(fields)) {
390
- return [];
391
- }
392
- const sourceFields = fields?.[sourceName];
393
- return Array.isArray(sourceFields) ? sourceFields.filter((field) => typeof field === "string" && field.length > 0) : [];
394
- };
395
- const inferBacklinkFields = (source, targetCollection, runtime) => {
396
- if (typeof source === "string") {
397
- const references = runtime?.collections?.[source]?.references;
398
- return [
399
- ...references?.[targetCollection] || [],
400
- ...references?.["*"] || []
401
- ];
402
- }
403
- return collectTopLevelReferenceFields(source.schema, targetCollection);
404
- };
405
- const targetReferenceCandidates = (doc) => {
406
- const values = [
407
- doc.ref,
408
- doc.id,
409
- doc._canonicalKey,
410
- doc._path,
411
- doc._path ? doc.path : void 0,
412
- doc._path ? doc.canonicalPath : void 0
413
- ].filter((value) => typeof value === "string" && value.length > 0).flatMap((value) => [value, normalizeReferenceValue(value)]).filter(Boolean);
414
- return Array.from(new Set(values));
415
- };
416
- const backlinkWhere = (fields, candidates) => {
417
- const clauses = fields.map((field) => ({
418
- [field]: { $in: candidates }
419
- }));
420
- return clauses.length ? { $or: clauses } : void 0;
421
- };
422
- const createMissingBacklinkFieldsError = (sourceCollection, targetCollection) => new Error(
423
- `Cannot infer backlink fields from "${sourceCollection}" to "${targetCollection}". Declare fields.relation('${targetCollection}') / fields.relations('${targetCollection}') in ${sourceCollection}.schema, or pass fields explicitly.`
424
- );
425
19
  export async function backlinks(context, targetHandle, options) {
426
- const targetCollection = ensureCollectionName(targetHandle);
427
- const target = await one(context, targetHandle, {
428
- by: options.by,
429
- ...options.locale ? { locale: options.locale } : {},
430
- ...options.fallback !== void 0 ? { fallback: options.fallback } : {}
431
- });
432
- if (!target) {
433
- return [];
434
- }
435
- const candidates = targetReferenceCandidates(target);
436
- if (!candidates.length) {
437
- return [];
438
- }
439
- const sources = backlinkSources(options.from);
440
- const results = await Promise.all(sources.map(async (source) => {
441
- const sourceName = ensureCollectionName(source);
442
- const fields = [
443
- .../* @__PURE__ */ new Set([
444
- ...resolveExplicitBacklinkFields(options.fields, sourceName),
445
- ...inferBacklinkFields(source, targetCollection, context.runtime)
446
- ])
447
- ];
448
- if (!fields.length) {
449
- throw createMissingBacklinkFieldsError(sourceName, targetCollection);
450
- }
451
- const where = backlinkWhere(fields, candidates);
452
- if (!where) {
453
- return [];
454
- }
455
- return await many(context, source, {
456
- where,
457
- sort: options.sort,
458
- limit: options.limit,
459
- skip: options.skip,
460
- ...options.locale ? { locale: options.locale } : {},
461
- ...options.fallback !== void 0 ? { fallback: options.fallback } : {},
462
- select: options.select,
463
- populate: options.populate
464
- });
465
- }));
466
- return results.flat();
20
+ return resolveBacklinks(context, one, many, targetHandle, options);
467
21
  }
468
22
  export async function variants(context, handle, options) {
469
- const collection = ensureCollectionName(handle);
470
- const runtime = context.runtime;
471
- const collectionI18n = runtime?.collections?.[collection]?.i18n;
472
- const collectionLocales = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.locales : void 0;
473
- const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
474
- const locales = collectionLocales?.length ? collectionLocales : runtime?.locales || [];
475
- const defaultLocale = collectionDefault || runtime?.defaultLocale;
476
- const requestedLocales = options.locales?.length ? options.locales : locales;
477
- if (!requestedLocales.length) {
478
- return [];
479
- }
480
- const seed = await one(context, handle, {
481
- by: options.by,
482
- locale: options.locale || defaultLocale,
483
- fallback: true
484
- });
485
- if (!seed) return [];
486
- const variantPaths = seed._variantPaths || {};
487
- const sourceLocale = seed.locale || defaultLocale || "";
488
- return requestedLocales.map((locale) => {
489
- const variantPath = variantPaths[locale];
490
- if (variantPath) {
491
- return {
492
- locale,
493
- path: seed.localePaths?.[locale]?.path || variantPath,
494
- translated: true
495
- };
496
- }
497
- return {
498
- locale,
499
- path: seed.path,
500
- translated: false,
501
- fallback: sourceLocale
502
- };
503
- });
23
+ return resolveVariants(context, one, handle, options);
504
24
  }
505
25
  export async function tree(context, handle, options = {}) {
506
- const collection = ensureCollectionName(handle);
507
- const runtime = context.runtime;
508
- const fallback = resolveFallback(options.fallback, collection, runtime);
509
- const params = compileQueryParams({
510
- collection,
511
- where: options.where,
512
- sort: options.sort,
513
- locale: options.locale,
514
- fallback,
515
- select: navigationSelectFields(options.fields),
516
- exact: options.fallback === void 0 ? false : void 0
517
- });
518
- const response = await context.transport("navigation", params);
519
- const list = Array.isArray(response) ? response : Array.isArray(response?.result) ? response.result : [];
520
- return list;
26
+ return resolveTree(context, handle, options);
521
27
  }
522
28
  export async function neighbors(context, handle, options) {
523
- const collection = ensureCollectionName(handle);
524
- const runtime = context.runtime;
525
- const seed = await one(context, handle, {
526
- by: options.by,
527
- locale: options.locale,
528
- fallback: options.fallback ?? true
529
- });
530
- if (!seed) return { prev: null, next: null };
531
- const fullTree = await tree(context, handle, {
532
- locale: options.locale,
533
- fallback: options.fallback,
534
- fields: options.fields
535
- });
536
- const flat = [];
537
- const walk = (nodes) => {
538
- for (const node of nodes) {
539
- const n = node;
540
- if (n.path || n._path) {
541
- flat.push({ path: n.path || n._path || "", item: node });
542
- }
543
- if (Array.isArray(n.children)) walk(n.children);
544
- }
545
- };
546
- walk(fullTree);
547
- const targetPath = seed.path;
548
- const idx = flat.findIndex((entry) => entry.path === targetPath);
549
- if (idx === -1 && (isCollectionRouteRoot(targetPath, collection, runtime) || isNavigationRootPath(targetPath, flat))) {
550
- return {
551
- prev: null,
552
- next: flat[0]?.item ?? null
553
- };
554
- }
555
- if (idx === -1) return { prev: null, next: null };
556
- return {
557
- prev: flat[idx - 1]?.item ?? null,
558
- next: flat[idx + 1]?.item ?? null
559
- };
29
+ return resolveNeighbors(context, one, tree, handle, options);
560
30
  }
@@ -0,0 +1 @@
1
+ export * from './variants.js'
@@ -0,0 +1,11 @@
1
+ import type { ParsedContent } from '../../types/content';
2
+ import type { ContentCollectionHandle } from '../../types/config';
3
+ import type { ContentVariant, LocalizedContentDocument, OneOptions, VariantsOptions } from '../../types/query';
4
+ import type { ContentQueryContext } from './context';
5
+ type OneResolver = <H extends ContentCollectionHandle | string>(context: ContentQueryContext, handle: H, options: OneOptions<H>) => Promise<LocalizedContentDocument<ParsedContent> | null>;
6
+ export declare function resolveVariants<H extends ContentCollectionHandle | string>(context: ContentQueryContext, one: OneResolver, handle: H, options: VariantsOptions<H>): Promise<Array<ContentVariant<H extends {
7
+ __schema: {
8
+ _output: infer O;
9
+ };
10
+ } ? O & ParsedContent : ParsedContent>>>;
11
+ export {};
@@ -0,0 +1,36 @@
1
+ import { ensureCollectionName } from "./handles.js";
2
+ import { collectionDefaultLocale, collectionLocales } from "./locale-options.js";
3
+ export async function resolveVariants(context, one, handle, options) {
4
+ const collection = ensureCollectionName(handle);
5
+ const runtime = context.runtime;
6
+ const locales = collectionLocales(collection, runtime);
7
+ const defaultLocale = collectionDefaultLocale(collection, runtime);
8
+ const requestedLocales = options.locales?.length ? options.locales : locales;
9
+ if (!requestedLocales.length) {
10
+ return [];
11
+ }
12
+ const seed = await one(context, handle, {
13
+ by: options.by,
14
+ locale: options.locale || defaultLocale,
15
+ fallback: true
16
+ });
17
+ if (!seed) return [];
18
+ const variantPaths = seed._variantPaths || {};
19
+ const sourceLocale = seed.locale || defaultLocale || "";
20
+ return requestedLocales.map((locale) => {
21
+ const variantPath = variantPaths[locale];
22
+ if (variantPath) {
23
+ return {
24
+ locale,
25
+ path: seed.localePaths[locale]?.path || variantPath,
26
+ translated: true
27
+ };
28
+ }
29
+ return {
30
+ locale,
31
+ path: seed.path,
32
+ translated: false,
33
+ fallback: sourceLocale
34
+ };
35
+ });
36
+ }
@@ -0,0 +1 @@
1
+ export * from './agent-http.js'
@@ -0,0 +1,7 @@
1
+ import type { H3Event } from 'h3';
2
+ export declare const appendResponseHeader: (event: H3Event, name: string, value: string) => void;
3
+ export declare const addVaryHeader: (event: H3Event, value: string) => void;
4
+ export declare const acceptsMarkdown: (event: H3Event) => boolean;
5
+ export declare const setAgentMarkdownHeaders: (event: H3Event, options?: {
6
+ noindex?: boolean;
7
+ }) => void;
@@ -0,0 +1,36 @@
1
+ import { getHeader, setHeader } from "h3";
2
+ export const appendResponseHeader = (event, name, value) => {
3
+ const current = event.node.res.getHeader(name);
4
+ const existing = Array.isArray(current) ? current.filter(Boolean).join(", ") : typeof current === "number" ? String(current) : typeof current === "string" ? current : "";
5
+ setHeader(event, name, existing ? `${existing}, ${value}` : value);
6
+ };
7
+ export const addVaryHeader = (event, value) => {
8
+ const current = event.node.res.getHeader("vary");
9
+ const entries = new Set(
10
+ (typeof current === "string" ? current : Array.isArray(current) ? current.join(",") : "").split(",").map((entry) => entry.trim().toLowerCase()).filter(Boolean)
11
+ );
12
+ entries.add(value.toLowerCase());
13
+ setHeader(event, "vary", Array.from(entries).join(", "));
14
+ };
15
+ const parseAcceptPart = (part) => {
16
+ const [type = "", ...params] = part.split(";").map((value) => value.trim());
17
+ const qParam = params.find((param) => param.toLowerCase().startsWith("q="));
18
+ const q = qParam ? Number(qParam.slice(2)) : 1;
19
+ return {
20
+ type: type.toLowerCase(),
21
+ q: Number.isFinite(q) ? q : 0
22
+ };
23
+ };
24
+ export const acceptsMarkdown = (event) => {
25
+ const accept = getHeader(event, "accept");
26
+ if (!accept) return false;
27
+ const entries = accept.split(",").map(parseAcceptPart).filter((entry) => entry.q > 0);
28
+ const markdownQ = entries.filter((entry) => entry.type === "text/markdown").reduce((max, entry) => Math.max(max, entry.q), 0);
29
+ if (!markdownQ) return false;
30
+ const htmlQ = entries.filter((entry) => entry.type === "text/html" || entry.type === "application/xhtml+xml").reduce((max, entry) => Math.max(max, entry.q), 0);
31
+ return markdownQ >= htmlQ;
32
+ };
33
+ export const setAgentMarkdownHeaders = (event, options = {}) => {
34
+ setHeader(event, "content-type", "text/markdown; charset=utf-8");
35
+ if (options.noindex) setHeader(event, "x-robots-tag", "noindex");
36
+ };
@@ -0,0 +1 @@
1
+ export * from './agent-markdown.js'