@lupinum/ginko-content 0.1.2 → 0.1.4
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/README.md +18 -4
- package/compatibility.json +1 -1
- package/dist/cli.mjs +317 -294
- package/dist/cms-import/index.js +5 -1
- package/dist/config.d.mts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/core/cache-hints.d.ts +9 -1
- package/dist/core/content/collection.js +1 -1
- package/dist/core/content/path.js +1 -1
- package/dist/core/errors.js +5 -1
- package/dist/core/provider-errors +1 -0
- package/dist/core/provider-errors.d.ts +10 -0
- package/dist/core/provider-errors.js +27 -0
- package/dist/core/query/execute.js +12 -3
- package/dist/core/query/filter.js +2 -2
- package/dist/core/query/lower.js +5 -4
- package/dist/features/navigation/build.js +14 -6
- package/dist/features/navigation/canonical.js +1 -1
- package/dist/features/sitemap/query.js +2 -2
- package/dist/integrations/nitro/ingest.d.ts +3 -3
- package/dist/integrations/nitro/ingest.js +3 -3
- package/dist/integrations/nitro/storage.js +3 -1
- package/dist/module.d.mts +151 -526
- package/dist/module.json +1 -1
- package/dist/module.mjs +1083 -730
- package/dist/parsers/csv.js +4 -3
- package/dist/parsers/index.d.ts +2 -5
- package/dist/parsers/index.js +2 -2
- package/dist/parsers/markdown-plugins.d.ts +1 -0
- package/dist/parsers/markdown-plugins.js +83 -1
- package/dist/parsers/markdown.js +1 -1
- package/dist/public/client.d.ts +3 -2
- package/dist/public/client.js +2 -2
- package/dist/public/provider-errors.d.ts +2 -1
- package/dist/public/provider-errors.js +1 -18
- package/dist/public/provider.d.ts +3 -10
- package/dist/public/server.d.ts +6 -1
- package/dist/public/server.js +33 -0
- package/dist/runtime/agent-paths +1 -0
- package/dist/runtime/agent-paths.d.ts +6 -0
- package/dist/runtime/agent-paths.js +41 -0
- package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +1 -1
- package/dist/runtime/app/composables/head.d.ts +3 -0
- package/dist/runtime/app/composables/head.js +2 -1
- package/dist/runtime/app/composables/hot-reload +1 -0
- package/dist/runtime/app/composables/hot-reload.d.ts +5 -0
- package/dist/runtime/app/composables/hot-reload.js +15 -0
- package/dist/runtime/app/composables/locale-context.d.ts +1 -1
- package/dist/runtime/app/composables/locale-context.js +2 -1
- package/dist/runtime/app/composables/locale.js +2 -2
- package/dist/runtime/app/composables/search.js +10 -6
- package/dist/runtime/app/composables/use-content-document +1 -0
- package/dist/runtime/app/composables/use-content-document.d.ts +29 -0
- package/dist/runtime/app/composables/use-content-document.js +44 -0
- package/dist/runtime/app/composables/use-content-list +1 -0
- package/dist/runtime/app/composables/use-content-list.d.ts +43 -0
- package/dist/runtime/app/composables/use-content-list.js +98 -0
- package/dist/runtime/app/composables/use-content-navigation +1 -0
- package/dist/runtime/app/composables/use-content-navigation.d.ts +40 -0
- package/dist/runtime/app/composables/use-content-navigation.js +102 -0
- package/dist/runtime/app/composables/use-content-page +1 -0
- package/dist/runtime/app/composables/use-content-page.d.ts +47 -0
- package/dist/runtime/app/composables/use-content-page.js +142 -0
- package/dist/runtime/app/composables/use-content-shared +1 -0
- package/dist/runtime/app/composables/use-content-shared.d.ts +13 -0
- package/dist/runtime/app/composables/use-content-shared.js +29 -0
- package/dist/runtime/app/composables/use-content.d.ts +11 -206
- package/dist/runtime/app/composables/use-content.js +4 -377
- package/dist/runtime/app/plugins/hot-reload +1 -0
- package/dist/runtime/app/plugins/hot-reload.js +6 -0
- package/dist/runtime/query/backlinks +1 -0
- package/dist/runtime/query/backlinks.d.ts +8 -0
- package/dist/runtime/query/backlinks.js +90 -0
- package/dist/runtime/query/context +1 -0
- package/dist/runtime/query/context.d.ts +20 -0
- package/dist/runtime/query/context.js +0 -0
- package/dist/runtime/query/documents +1 -0
- package/dist/runtime/query/documents.d.ts +6 -0
- package/dist/runtime/query/documents.js +98 -0
- package/dist/runtime/query/errors +1 -0
- package/dist/runtime/query/errors.d.ts +1 -0
- package/dist/runtime/query/errors.js +4 -0
- package/dist/runtime/query/handles +1 -0
- package/dist/runtime/query/handles.d.ts +2 -0
- package/dist/runtime/query/handles.js +7 -0
- package/dist/runtime/query/locale-options +1 -0
- package/dist/runtime/query/locale-options.d.ts +5 -0
- package/dist/runtime/query/locale-options.js +14 -0
- package/dist/runtime/query/localized-docs +1 -0
- package/dist/runtime/query/localized-docs.d.ts +17 -0
- package/dist/runtime/query/localized-docs.js +44 -0
- package/dist/runtime/query/navigation +1 -0
- package/dist/runtime/query/navigation.d.ts +22 -0
- package/dist/runtime/query/navigation.js +73 -0
- package/dist/runtime/query/pagination +1 -0
- package/dist/runtime/query/pagination.d.ts +7 -0
- package/dist/runtime/query/pagination.js +78 -0
- package/dist/runtime/query/populate +1 -0
- package/dist/runtime/query/populate.d.ts +9 -0
- package/dist/runtime/query/populate.js +106 -0
- package/dist/runtime/query/responses +1 -0
- package/dist/runtime/query/responses.d.ts +10 -0
- package/dist/runtime/query/responses.js +47 -0
- package/dist/runtime/query/unified.d.ts +4 -20
- package/dist/runtime/query/unified.js +14 -544
- package/dist/runtime/query/variants +1 -0
- package/dist/runtime/query/variants.d.ts +11 -0
- package/dist/runtime/query/variants.js +36 -0
- package/dist/runtime/server/agent-http +1 -0
- package/dist/runtime/server/agent-http.d.ts +7 -0
- package/dist/runtime/server/agent-http.js +36 -0
- package/dist/runtime/server/agent-markdown +1 -0
- package/dist/runtime/server/agent-markdown.d.ts +83 -0
- package/dist/runtime/server/agent-markdown.js +449 -0
- package/dist/runtime/server/agent-site +1 -0
- package/dist/runtime/server/agent-site.d.ts +38 -0
- package/dist/runtime/server/agent-site.js +272 -0
- package/dist/runtime/server/api/agent-llms +1 -0
- package/dist/runtime/server/api/agent-llms-full +1 -0
- package/dist/runtime/server/api/agent-llms-full.d.ts +2 -0
- package/dist/runtime/server/api/agent-llms-full.js +13 -0
- package/dist/runtime/server/api/agent-llms.d.ts +2 -0
- package/dist/runtime/server/api/agent-llms.js +14 -0
- package/dist/runtime/server/api/agent-raw +1 -0
- package/dist/runtime/server/api/agent-raw.d.ts +2 -0
- package/dist/runtime/server/api/agent-raw.js +17 -0
- package/dist/runtime/server/api/locales.d.ts +2 -2
- package/dist/runtime/server/api/locales.js +4 -2
- package/dist/runtime/server/api/navigation.d.ts +1 -1
- package/dist/runtime/server/api/query.d.ts +1 -1
- package/dist/runtime/server/api/query.js +4 -1
- package/dist/runtime/server/api/revalidate.js +2 -2
- package/dist/runtime/server/api/site-data.d.ts +1 -1
- package/dist/runtime/server/collection-helpers.js +2 -1
- package/dist/runtime/server/middleware/agent-link-headers +1 -0
- package/dist/runtime/server/middleware/agent-link-headers.d.ts +2 -0
- package/dist/runtime/server/middleware/agent-link-headers.js +41 -0
- package/dist/runtime/server/middleware/agent-markdown +1 -0
- package/dist/runtime/server/middleware/agent-markdown.d.ts +2 -0
- package/dist/runtime/server/middleware/agent-markdown.js +43 -0
- package/dist/runtime/server/plugins/sitemap.js +1 -0
- package/dist/runtime/server/provider-query.d.ts +8 -5
- package/dist/runtime/server/provider-query.js +50 -8
- package/dist/runtime/server/provider-result.d.ts +19 -2
- package/dist/runtime/server/providers/filesystem.js +4 -1
- package/dist/runtime/server/providers/index.d.ts +3 -1
- package/dist/runtime/server/providers/index.js +2 -2
- package/dist/runtime/server/query-api.js +2 -1
- package/dist/runtime/server/query-executor.d.ts +3 -2
- package/dist/runtime/server/query-executor.js +13 -5
- package/dist/runtime/server/search.js +1 -1
- package/dist/runtime/server/sitemap-provider.js +40 -1
- package/dist/runtime/server/sitemap.js +3 -2
- package/dist/runtime/transformers/component-resolver.js +2 -1
- package/dist/runtime/utils/content-components.d.ts +0 -5
- package/dist/storage/content.d.ts +2 -9
- package/dist/storage/references.d.ts +1 -8
- package/dist/storage/references.js +9 -4
- package/dist/testing/provider-contract.js +3 -4
- package/dist/testing/provider-fixture.d.ts +3 -1
- package/dist/testing/provider-fixture.js +27 -14
- package/dist/types/config.d.ts +77 -0
- package/dist/types/config.js +23 -0
- package/dist/types/module.d.ts +15 -5
- package/dist/types/query-parts/collections +1 -0
- package/dist/types/query-parts/collections.d.ts +15 -0
- package/dist/types/query-parts/collections.js +0 -0
- package/dist/types/query-parts/public +1 -0
- package/dist/types/query-parts/public.d.ts +202 -0
- package/dist/types/query-parts/public.js +0 -0
- package/dist/types/query-parts/results +1 -0
- package/dist/types/query-parts/results.d.ts +95 -0
- package/dist/types/query-parts/results.js +0 -0
- package/dist/types/query-parts/transport +1 -0
- package/dist/types/query-parts/transport.d.ts +103 -0
- package/dist/types/query-parts/transport.js +0 -0
- package/dist/types/query.d.ts +4 -870
- package/dist/types/query.js +4 -0
- package/dist/types/runtime.d.ts +2 -2
- package/dist/types/virtual.d.ts +54 -0
- package/dist/types.d.mts +2 -2
- package/dist/web-types.json +1 -1
- package/package.json +5 -5
- package/dist/runtime/app/composables/web-socket +0 -1
- package/dist/runtime/app/composables/web-socket.d.ts +0 -3
- package/dist/runtime/app/composables/web-socket.js +0 -65
- package/dist/runtime/app/plugins/ws +0 -1
- package/dist/runtime/app/plugins/ws.js +0 -7
- /package/dist/runtime/app/plugins/{ws.d.ts → hot-reload.d.ts} +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { normalizeReferenceValue } from "../../core/references/resolve";
|
|
2
|
+
import { collectTopLevelReferenceFields } from "../../core/references/schema";
|
|
3
|
+
import { ensureCollectionName } from "./handles.js";
|
|
4
|
+
const backlinkSources = (value) => Array.isArray(value) ? [...value] : [value];
|
|
5
|
+
const isBacklinkFieldMap = (value) => {
|
|
6
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
7
|
+
};
|
|
8
|
+
const resolveExplicitBacklinkFields = (fields, sourceName) => {
|
|
9
|
+
if (Array.isArray(fields)) {
|
|
10
|
+
return fields.filter((field) => typeof field === "string" && field.length > 0);
|
|
11
|
+
}
|
|
12
|
+
if (!isBacklinkFieldMap(fields)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const sourceFields = fields?.[sourceName];
|
|
16
|
+
return Array.isArray(sourceFields) ? sourceFields.filter((field) => typeof field === "string" && field.length > 0) : [];
|
|
17
|
+
};
|
|
18
|
+
const inferBacklinkFields = (source, targetCollection, runtime) => {
|
|
19
|
+
if (typeof source === "string") {
|
|
20
|
+
const references = runtime?.collections?.[source]?.references;
|
|
21
|
+
return [
|
|
22
|
+
...references?.[targetCollection] || [],
|
|
23
|
+
...references?.["*"] || []
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
return collectTopLevelReferenceFields(source.schema, targetCollection);
|
|
27
|
+
};
|
|
28
|
+
const targetReferenceCandidates = (doc) => {
|
|
29
|
+
const values = [
|
|
30
|
+
doc.ref,
|
|
31
|
+
doc.id,
|
|
32
|
+
doc._canonicalKey,
|
|
33
|
+
doc._path,
|
|
34
|
+
doc._path ? doc.path : void 0,
|
|
35
|
+
doc._path ? doc.canonicalPath : void 0
|
|
36
|
+
].filter((value) => typeof value === "string" && value.length > 0).flatMap((value) => [value, normalizeReferenceValue(value)]).filter(Boolean);
|
|
37
|
+
return Array.from(new Set(values));
|
|
38
|
+
};
|
|
39
|
+
const backlinkWhere = (fields, candidates) => {
|
|
40
|
+
const clauses = fields.map((field) => ({
|
|
41
|
+
[field]: { $in: candidates }
|
|
42
|
+
}));
|
|
43
|
+
return clauses.length ? { $or: clauses } : void 0;
|
|
44
|
+
};
|
|
45
|
+
const createMissingBacklinkFieldsError = (sourceCollection, targetCollection) => new Error(
|
|
46
|
+
`Cannot infer backlink fields from "${sourceCollection}" to "${targetCollection}". Declare fields.relation('${targetCollection}') / fields.relations('${targetCollection}') in ${sourceCollection}.schema, or pass fields explicitly.`
|
|
47
|
+
);
|
|
48
|
+
export async function resolveBacklinks(context, one, many, targetHandle, options) {
|
|
49
|
+
const targetCollection = ensureCollectionName(targetHandle);
|
|
50
|
+
const target = await one(context, targetHandle, {
|
|
51
|
+
by: options.by,
|
|
52
|
+
...options.locale ? { locale: options.locale } : {},
|
|
53
|
+
...options.fallback !== void 0 ? { fallback: options.fallback } : {}
|
|
54
|
+
});
|
|
55
|
+
if (!target) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const candidates = targetReferenceCandidates(target);
|
|
59
|
+
if (!candidates.length) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
const sources = backlinkSources(options.from);
|
|
63
|
+
const results = await Promise.all(sources.map(async (source) => {
|
|
64
|
+
const sourceName = ensureCollectionName(source);
|
|
65
|
+
const fields = [
|
|
66
|
+
.../* @__PURE__ */ new Set([
|
|
67
|
+
...resolveExplicitBacklinkFields(options.fields, sourceName),
|
|
68
|
+
...inferBacklinkFields(source, targetCollection, context.runtime)
|
|
69
|
+
])
|
|
70
|
+
];
|
|
71
|
+
if (!fields.length) {
|
|
72
|
+
throw createMissingBacklinkFieldsError(sourceName, targetCollection);
|
|
73
|
+
}
|
|
74
|
+
const where = backlinkWhere(fields, candidates);
|
|
75
|
+
if (!where) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
return await many(context, source, {
|
|
79
|
+
where,
|
|
80
|
+
sort: options.sort,
|
|
81
|
+
limit: options.limit,
|
|
82
|
+
skip: options.skip,
|
|
83
|
+
...options.locale ? { locale: options.locale } : {},
|
|
84
|
+
...options.fallback !== void 0 ? { fallback: options.fallback } : {},
|
|
85
|
+
select: options.select,
|
|
86
|
+
populate: options.populate
|
|
87
|
+
});
|
|
88
|
+
}));
|
|
89
|
+
return results.flat();
|
|
90
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './context.js'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { NavItem } from '../../types/content';
|
|
2
|
+
import type { ContentQueryResponse } from '../../types/api';
|
|
3
|
+
import type { ContentQueryBuilderParams } from '../../types/query';
|
|
4
|
+
export interface RuntimeContentConfig {
|
|
5
|
+
locales?: string[];
|
|
6
|
+
defaultLocale?: string;
|
|
7
|
+
collections?: Record<string, {
|
|
8
|
+
i18n?: boolean | {
|
|
9
|
+
locales?: string[];
|
|
10
|
+
defaultLocale?: string;
|
|
11
|
+
};
|
|
12
|
+
route?: string | Record<string, string>;
|
|
13
|
+
references?: Record<string, string[]>;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export type ContentQueryEndpoint = 'query' | 'navigation';
|
|
17
|
+
export interface ContentQueryContext {
|
|
18
|
+
runtime: RuntimeContentConfig;
|
|
19
|
+
transport: <T>(endpoint: ContentQueryEndpoint, params: ContentQueryBuilderParams) => Promise<ContentQueryResponse<T> | T | T[] | NavItem[] | null>;
|
|
20
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './documents.js'
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ContentCollectionHandle } from '../../types/config';
|
|
2
|
+
import type { DocumentFromHandle, LocalizedDoc, ManyOptions, OneOptions, PopulateFromOptions, PopulateSpec, PopulatedDocument, ResolveOneOptions, ResolveOneResult } from '../../types/query';
|
|
3
|
+
import type { ContentQueryContext } from './context';
|
|
4
|
+
export declare function resolveDocument<const H extends ContentCollectionHandle | string, O extends ResolveOneOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, one: typeof resolveDocumentOnly, handle: H, options: O): Promise<ResolveOneResult<PopulatedDocument<DocumentFromHandle<H>, PopulateFromOptions<O>>>>;
|
|
5
|
+
export declare function resolveDocumentOnly<const H extends ContentCollectionHandle | string, O extends OneOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, handle: H, options: O): Promise<LocalizedDoc<PopulatedDocument<DocumentFromHandle<H>, PopulateFromOptions<O>>> | null>;
|
|
6
|
+
export declare function resolveManyDocuments<const H extends ContentCollectionHandle | string, O extends ManyOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, one: typeof resolveDocumentOnly, handle: H, options?: O): Promise<Array<LocalizedDoc<PopulatedDocument<DocumentFromHandle<H>, PopulateFromOptions<O>>>>>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { compileQueryParams } from "../../core/query/filter";
|
|
2
|
+
import { isNotFoundError } from "./errors.js";
|
|
3
|
+
import { ensureCollectionName } from "./handles.js";
|
|
4
|
+
import { decorateLocalizedDocument } from "./localized-docs.js";
|
|
5
|
+
import { resolveFallback } from "./locale-options.js";
|
|
6
|
+
import { populateDocument, selectWithPopulate, validatePopulateSpec } from "./populate.js";
|
|
7
|
+
import { unwrapListResponse, unwrapOneResponse } from "./responses.js";
|
|
8
|
+
const explainResolution = (collection, requestedBy, normalizedBy, requestedLocale, requestedFallback, doc) => {
|
|
9
|
+
const resolvedLocale = doc?.resolved?.locale || doc?.locale;
|
|
10
|
+
return {
|
|
11
|
+
requested: {
|
|
12
|
+
collection,
|
|
13
|
+
by: requestedBy,
|
|
14
|
+
...requestedLocale ? { locale: requestedLocale } : {},
|
|
15
|
+
...requestedFallback !== void 0 ? { fallback: requestedFallback } : {}
|
|
16
|
+
},
|
|
17
|
+
normalized: {
|
|
18
|
+
by: normalizedBy
|
|
19
|
+
},
|
|
20
|
+
matched: {
|
|
21
|
+
found: Boolean(doc),
|
|
22
|
+
collection,
|
|
23
|
+
...doc?.path ? { path: doc.path } : {},
|
|
24
|
+
...doc?.canonicalPath ? { canonicalPath: doc.canonicalPath } : {},
|
|
25
|
+
...doc?.ref ? { ref: doc.ref } : {},
|
|
26
|
+
...resolvedLocale ? { locale: resolvedLocale } : {}
|
|
27
|
+
},
|
|
28
|
+
fallback: {
|
|
29
|
+
used: Boolean(requestedLocale && resolvedLocale && requestedLocale !== resolvedLocale),
|
|
30
|
+
...requestedLocale && resolvedLocale && requestedLocale !== resolvedLocale ? { locale: resolvedLocale } : {}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export async function resolveDocument(context, one, handle, options) {
|
|
35
|
+
const collection = ensureCollectionName(handle);
|
|
36
|
+
const runtime = context.runtime;
|
|
37
|
+
validatePopulateSpec(handle, collection, runtime, options.populate);
|
|
38
|
+
const by = options.by;
|
|
39
|
+
const fallback = resolveFallback(options.fallback, collection, runtime);
|
|
40
|
+
const params = compileQueryParams({
|
|
41
|
+
collection,
|
|
42
|
+
by,
|
|
43
|
+
locale: options.locale,
|
|
44
|
+
fallback,
|
|
45
|
+
select: selectWithPopulate(options.select, options.populate)
|
|
46
|
+
});
|
|
47
|
+
params.first = true;
|
|
48
|
+
let response;
|
|
49
|
+
try {
|
|
50
|
+
response = await context.transport("query", params);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (isNotFoundError(error)) {
|
|
53
|
+
const explain2 = explainResolution(collection, options.by, by, options.locale, options.fallback, null);
|
|
54
|
+
return { doc: null, explain: explain2 };
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
const unwrapped = unwrapOneResponse(response);
|
|
59
|
+
const doc = Array.isArray(unwrapped) ? unwrapped[0] ?? null : unwrapped ?? null;
|
|
60
|
+
const decorated = decorateLocalizedDocument(doc, collection, runtime, options.locale);
|
|
61
|
+
const populated = decorated ? await populateDocument(context, one, decorated, options.populate, options.locale, options.fallback) : null;
|
|
62
|
+
const explain = explainResolution(collection, options.by, by, options.locale, options.fallback, decorated);
|
|
63
|
+
return {
|
|
64
|
+
doc: populated,
|
|
65
|
+
explain
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export async function resolveDocumentOnly(context, handle, options) {
|
|
69
|
+
const result = await resolveDocument(context, resolveDocumentOnly, handle, options);
|
|
70
|
+
return result.doc;
|
|
71
|
+
}
|
|
72
|
+
export async function resolveManyDocuments(context, one, handle, options = {}) {
|
|
73
|
+
const collection = ensureCollectionName(handle);
|
|
74
|
+
const runtime = context.runtime;
|
|
75
|
+
validatePopulateSpec(handle, collection, runtime, options.populate);
|
|
76
|
+
const fallback = resolveFallback(options.fallback, collection, runtime);
|
|
77
|
+
const params = compileQueryParams({
|
|
78
|
+
collection,
|
|
79
|
+
where: options.where,
|
|
80
|
+
sort: options.sort,
|
|
81
|
+
limit: options.limit,
|
|
82
|
+
skip: options.skip,
|
|
83
|
+
locale: options.locale,
|
|
84
|
+
fallback,
|
|
85
|
+
select: selectWithPopulate(options.select, options.populate)
|
|
86
|
+
});
|
|
87
|
+
let response;
|
|
88
|
+
try {
|
|
89
|
+
response = await context.transport("query", params);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (isNotFoundError(error)) return [];
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
const list = unwrapListResponse(response);
|
|
95
|
+
const decorated = list.map((doc) => decorateLocalizedDocument(doc, collection, runtime, options.locale)).filter((doc) => Boolean(doc));
|
|
96
|
+
const populated = await Promise.all(decorated.map((doc) => populateDocument(context, one, doc, options.populate, options.locale, options.fallback)));
|
|
97
|
+
return populated;
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './errors.js'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isNotFoundError: (error: unknown) => boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './handles.js'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const ensureCollectionName = (handle) => {
|
|
2
|
+
if (typeof handle === "string") return handle;
|
|
3
|
+
if (!handle || typeof handle !== "object" || typeof handle.name !== "string") {
|
|
4
|
+
throw new TypeError("query API: expected a string collection name or a collection handle from defineContentConfig({ collections }). Use useContentPage('docs') or config.collections.docs.");
|
|
5
|
+
}
|
|
6
|
+
return handle.name;
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './locale-options.js'
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LocaleFallback } from '../../types/query';
|
|
2
|
+
import type { RuntimeContentConfig } from './context';
|
|
3
|
+
export declare const collectionDefaultLocale: (collection: string, runtime: RuntimeContentConfig | undefined) => string | undefined;
|
|
4
|
+
export declare const collectionLocales: (collection: string, runtime: RuntimeContentConfig | undefined) => string[];
|
|
5
|
+
export declare const resolveFallback: (fallback: LocaleFallback | undefined, collection: string, runtime: RuntimeContentConfig | undefined) => Exclude<LocaleFallback, "default"> | undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const collectionDefaultLocale = (collection, runtime) => {
|
|
2
|
+
const collectionI18n = runtime?.collections?.[collection]?.i18n;
|
|
3
|
+
const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
|
|
4
|
+
return collectionDefault || runtime?.defaultLocale;
|
|
5
|
+
};
|
|
6
|
+
export const collectionLocales = (collection, runtime) => {
|
|
7
|
+
const collectionI18n = runtime?.collections?.[collection]?.i18n;
|
|
8
|
+
const collectionLocales2 = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.locales : void 0;
|
|
9
|
+
return collectionLocales2?.length ? collectionLocales2 : runtime?.locales || [];
|
|
10
|
+
};
|
|
11
|
+
export const resolveFallback = (fallback, collection, runtime) => {
|
|
12
|
+
if (fallback !== "default") return fallback;
|
|
13
|
+
return collectionDefaultLocale(collection, runtime);
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './localized-docs.js'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ParsedContent } from '../../types/content';
|
|
2
|
+
import type { LocalizedDoc } from '../../types/query';
|
|
3
|
+
import type { RuntimeContentConfig } from './context';
|
|
4
|
+
/**
|
|
5
|
+
* Decorate a raw parsed document with route metadata and locale paths.
|
|
6
|
+
*
|
|
7
|
+
* `localizePageResult` already attaches `path`, `canonicalPath`, `locale`,
|
|
8
|
+
* `defaultLocale`, `variants`, and `localePaths`. This helper additionally
|
|
9
|
+
* fills non-translated locales with fallback paths so app switchers can render
|
|
10
|
+
* all configured languages without another query.
|
|
11
|
+
*/
|
|
12
|
+
export declare const decorateLocalizedDocument: <T extends ParsedContent & Record<string, unknown>>(doc: T | null, collection: string, runtime: RuntimeContentConfig | undefined, requestedLocale?: string) => LocalizedDoc<T> | null;
|
|
13
|
+
export declare const isCollectionRouteRoot: (path: string, collection: string, runtime: RuntimeContentConfig | undefined) => boolean;
|
|
14
|
+
export declare const isNavigationRootPath: (path: string, flat: Array<{
|
|
15
|
+
path: string;
|
|
16
|
+
item: unknown;
|
|
17
|
+
}>) => boolean;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { decorateLocalePathsWithFallbacks, localizePageResult } from "../../features/localization/results";
|
|
2
|
+
import { normalizeContentPath, normalizeRouteMounts } from "../../features/localization/path";
|
|
3
|
+
const collectionLocaleConfig = (collection, runtime) => {
|
|
4
|
+
const collectionConfig = runtime?.collections?.[collection];
|
|
5
|
+
const collectionI18n = collectionConfig?.i18n;
|
|
6
|
+
const collectionLocales = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.locales : void 0;
|
|
7
|
+
const collectionDefault = collectionI18n && typeof collectionI18n === "object" ? collectionI18n.defaultLocale : void 0;
|
|
8
|
+
const locales = collectionLocales?.length ? collectionLocales : runtime?.locales?.length ? runtime.locales : [];
|
|
9
|
+
const defaultLocale = collectionDefault || runtime?.defaultLocale;
|
|
10
|
+
const routeMounts = normalizeRouteMounts(collectionConfig?.route, locales, defaultLocale);
|
|
11
|
+
return {
|
|
12
|
+
locales,
|
|
13
|
+
defaultLocale,
|
|
14
|
+
routeMounts,
|
|
15
|
+
hasLocaleConfig: Boolean(locales.length || defaultLocale)
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export const decorateLocalizedDocument = (doc, collection, runtime, requestedLocale) => {
|
|
19
|
+
if (!doc) return null;
|
|
20
|
+
const { locales, defaultLocale, routeMounts, hasLocaleConfig } = collectionLocaleConfig(collection, runtime);
|
|
21
|
+
const page = hasLocaleConfig ? doc : {
|
|
22
|
+
...doc,
|
|
23
|
+
_locale: "",
|
|
24
|
+
_resolvedLocale: void 0,
|
|
25
|
+
_requestedLocale: void 0,
|
|
26
|
+
_variantPaths: void 0,
|
|
27
|
+
_availableLocales: []
|
|
28
|
+
};
|
|
29
|
+
const result = localizePageResult(page, hasLocaleConfig ? requestedLocale : void 0, defaultLocale, locales, routeMounts);
|
|
30
|
+
const fallbackLocale = doc._resolvedLocale || requestedLocale || defaultLocale;
|
|
31
|
+
result.localePaths = decorateLocalePathsWithFallbacks(result.localePaths, locales, fallbackLocale, defaultLocale, routeMounts);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
const collectionRouteRoots = (collection, runtime) => {
|
|
35
|
+
const { routeMounts } = collectionLocaleConfig(collection, runtime);
|
|
36
|
+
return new Set(Object.values(routeMounts || {}).map((value) => normalizeContentPath(value)));
|
|
37
|
+
};
|
|
38
|
+
export const isCollectionRouteRoot = (path, collection, runtime) => collectionRouteRoots(collection, runtime).has(normalizeContentPath(path));
|
|
39
|
+
const isAncestorRoutePath = (path, childPath) => {
|
|
40
|
+
const normalized = normalizeContentPath(path);
|
|
41
|
+
const child = normalizeContentPath(childPath);
|
|
42
|
+
return normalized === "/" ? child !== "/" : child.startsWith(`${normalized}/`);
|
|
43
|
+
};
|
|
44
|
+
export const isNavigationRootPath = (path, flat) => Boolean(flat[0]?.path && isAncestorRoutePath(path, flat[0].path));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './navigation.js'
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ParsedContent } from '../../types/content';
|
|
2
|
+
import type { ContentCollectionHandle } from '../../types/config';
|
|
3
|
+
import type { ContentTreeItem, LocalizedContentDocument, NeighborsOptions, NeighborsResult, OneOptions, TreeOptions } from '../../types/query';
|
|
4
|
+
import type { ContentQueryContext } from './context';
|
|
5
|
+
export declare const navigationSelectFields: (fields?: ReadonlyArray<string> | undefined) => string[];
|
|
6
|
+
type OneResolver = <H extends ContentCollectionHandle | string>(context: ContentQueryContext, handle: H, options: OneOptions<H>) => Promise<LocalizedContentDocument<ParsedContent> | null>;
|
|
7
|
+
type TreeResolver = <H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, options?: Omit<TreeOptions<H>, 'fields'> & {
|
|
8
|
+
fields?: Fields;
|
|
9
|
+
}) => Promise<unknown[]>;
|
|
10
|
+
export declare function resolveTree<H extends ContentCollectionHandle | string, Fields extends ReadonlyArray<string> | undefined = undefined>(context: ContentQueryContext, handle: H, options?: Omit<TreeOptions<H>, 'fields'> & {
|
|
11
|
+
fields?: Fields;
|
|
12
|
+
}): Promise<ContentTreeItem<H extends {
|
|
13
|
+
__schema: {
|
|
14
|
+
_output: infer O;
|
|
15
|
+
};
|
|
16
|
+
} ? O & ParsedContent : ParsedContent, Fields>[]>;
|
|
17
|
+
export declare function resolveNeighbors<H extends ContentCollectionHandle | string>(context: ContentQueryContext, one: OneResolver, tree: TreeResolver, handle: H, options: NeighborsOptions<H>): Promise<NeighborsResult<H extends {
|
|
18
|
+
__schema: {
|
|
19
|
+
_output: infer O;
|
|
20
|
+
};
|
|
21
|
+
} ? O & ParsedContent : ParsedContent>>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { compileQueryParams } from "../../core/query/filter";
|
|
2
|
+
import { ensureCollectionName } from "./handles.js";
|
|
3
|
+
import { isCollectionRouteRoot, isNavigationRootPath } from "./localized-docs.js";
|
|
4
|
+
import { resolveFallback } from "./locale-options.js";
|
|
5
|
+
const NAVIGATION_INTERNAL_FIELDS = [
|
|
6
|
+
"_id",
|
|
7
|
+
"_path",
|
|
8
|
+
"_file",
|
|
9
|
+
"_canonicalKey",
|
|
10
|
+
"_locale",
|
|
11
|
+
"_draft",
|
|
12
|
+
"navigation",
|
|
13
|
+
"title"
|
|
14
|
+
];
|
|
15
|
+
export const navigationSelectFields = (fields = []) => [
|
|
16
|
+
.../* @__PURE__ */ new Set([...NAVIGATION_INTERNAL_FIELDS, ...fields])
|
|
17
|
+
];
|
|
18
|
+
export async function resolveTree(context, handle, options = {}) {
|
|
19
|
+
const collection = ensureCollectionName(handle);
|
|
20
|
+
const runtime = context.runtime;
|
|
21
|
+
const fallback = resolveFallback(options.fallback, collection, runtime);
|
|
22
|
+
const params = compileQueryParams({
|
|
23
|
+
collection,
|
|
24
|
+
where: options.where,
|
|
25
|
+
sort: options.sort,
|
|
26
|
+
locale: options.locale,
|
|
27
|
+
fallback,
|
|
28
|
+
select: navigationSelectFields(options.fields),
|
|
29
|
+
exact: options.fallback === void 0 ? false : void 0
|
|
30
|
+
});
|
|
31
|
+
const response = await context.transport("navigation", params);
|
|
32
|
+
const list = Array.isArray(response) ? response : Array.isArray(response?.result) ? response.result : [];
|
|
33
|
+
return list;
|
|
34
|
+
}
|
|
35
|
+
export async function resolveNeighbors(context, one, tree, handle, options) {
|
|
36
|
+
const collection = ensureCollectionName(handle);
|
|
37
|
+
const runtime = context.runtime;
|
|
38
|
+
const seed = await one(context, handle, {
|
|
39
|
+
by: options.by,
|
|
40
|
+
locale: options.locale,
|
|
41
|
+
fallback: options.fallback ?? true
|
|
42
|
+
});
|
|
43
|
+
if (!seed) return { prev: null, next: null };
|
|
44
|
+
const fullTree = await tree(context, handle, {
|
|
45
|
+
locale: options.locale,
|
|
46
|
+
fallback: options.fallback,
|
|
47
|
+
fields: options.fields
|
|
48
|
+
});
|
|
49
|
+
const flat = [];
|
|
50
|
+
const walk = (nodes) => {
|
|
51
|
+
for (const node of nodes) {
|
|
52
|
+
const n = node;
|
|
53
|
+
if (n.path || n._path) {
|
|
54
|
+
flat.push({ path: n.path || n._path || "", item: node });
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(n.children)) walk(n.children);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
walk(fullTree);
|
|
60
|
+
const targetPath = seed.path;
|
|
61
|
+
const idx = flat.findIndex((entry) => entry.path === targetPath);
|
|
62
|
+
if (idx === -1 && (isCollectionRouteRoot(targetPath, collection, runtime) || isNavigationRootPath(targetPath, flat))) {
|
|
63
|
+
return {
|
|
64
|
+
prev: null,
|
|
65
|
+
next: flat[0]?.item ?? null
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (idx === -1) return { prev: null, next: null };
|
|
69
|
+
return {
|
|
70
|
+
prev: flat[idx - 1]?.item ?? null,
|
|
71
|
+
next: flat[idx + 1]?.item ?? null
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './pagination.js'
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ParsedContent } from '../../types/content';
|
|
2
|
+
import type { ContentCollectionHandle } from '../../types/config';
|
|
3
|
+
import type { DocumentFromHandle, LocalizedDoc, OneOptions, PaginationOptions, PaginationResult, PopulateFromOptions, PopulateSpec, PopulatedDocument } from '../../types/query';
|
|
4
|
+
import type { ContentQueryContext } from './context';
|
|
5
|
+
type OneResolver = <H extends ContentCollectionHandle | string>(context: ContentQueryContext, handle: H, options: OneOptions<H>) => Promise<LocalizedDoc<ParsedContent> | null>;
|
|
6
|
+
export declare function resolvePagination<const H extends ContentCollectionHandle | string, O extends PaginationOptions<H, PopulateSpec | undefined>>(context: ContentQueryContext, one: OneResolver, handle: H, options: O): Promise<PaginationResult<PopulatedDocument<DocumentFromHandle<H>, PopulateFromOptions<O>>>>;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { compileQueryParams } from "../../core/query/filter";
|
|
2
|
+
import { decorateLocalizedDocument } from "./localized-docs.js";
|
|
3
|
+
import { ensureCollectionName } from "./handles.js";
|
|
4
|
+
import { resolveFallback } from "./locale-options.js";
|
|
5
|
+
import { populateDocument, selectWithPopulate, validatePopulateSpec } from "./populate.js";
|
|
6
|
+
import { MAX_PUBLIC_QUERY_LIMIT, MAX_PUBLIC_QUERY_SKIP } from "./public-limits.js";
|
|
7
|
+
import { unwrapCountResponse, unwrapFindResponse } from "./responses.js";
|
|
8
|
+
import { isNotFoundError } from "./errors.js";
|
|
9
|
+
const normalizePositiveInteger = (value, fallback) => {
|
|
10
|
+
const number = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
11
|
+
return Math.max(1, number);
|
|
12
|
+
};
|
|
13
|
+
export async function resolvePagination(context, one, handle, options) {
|
|
14
|
+
const collection = ensureCollectionName(handle);
|
|
15
|
+
const runtime = context.runtime;
|
|
16
|
+
validatePopulateSpec(handle, collection, runtime, options.populate);
|
|
17
|
+
const requestedPage = normalizePositiveInteger(options.page, 1);
|
|
18
|
+
const limit = Math.min(normalizePositiveInteger(options.limit, 10), MAX_PUBLIC_QUERY_LIMIT);
|
|
19
|
+
const skip = Math.min((requestedPage - 1) * limit, MAX_PUBLIC_QUERY_SKIP);
|
|
20
|
+
const page = Math.floor(skip / limit) + 1;
|
|
21
|
+
const fallback = resolveFallback(options.fallback, collection, runtime);
|
|
22
|
+
const params = compileQueryParams({
|
|
23
|
+
collection,
|
|
24
|
+
where: options.where,
|
|
25
|
+
sort: options.sort,
|
|
26
|
+
limit,
|
|
27
|
+
skip,
|
|
28
|
+
locale: options.locale,
|
|
29
|
+
fallback,
|
|
30
|
+
select: selectWithPopulate(options.select, options.populate)
|
|
31
|
+
});
|
|
32
|
+
const countParams = compileQueryParams({
|
|
33
|
+
collection,
|
|
34
|
+
where: options.where,
|
|
35
|
+
locale: options.locale,
|
|
36
|
+
fallback
|
|
37
|
+
});
|
|
38
|
+
countParams.count = true;
|
|
39
|
+
let response;
|
|
40
|
+
try {
|
|
41
|
+
response = await context.transport("query", params);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (isNotFoundError(error)) {
|
|
44
|
+
return {
|
|
45
|
+
data: [],
|
|
46
|
+
page,
|
|
47
|
+
limit,
|
|
48
|
+
total: 0,
|
|
49
|
+
pageCount: 0,
|
|
50
|
+
hasNext: false,
|
|
51
|
+
hasPrev: page > 1,
|
|
52
|
+
nextPage: null,
|
|
53
|
+
prevPage: page > 1 ? page - 1 : null
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
const envelope = unwrapFindResponse(response);
|
|
59
|
+
let total = envelope.total;
|
|
60
|
+
if (!envelope.hasTotal) {
|
|
61
|
+
const countResponse = await context.transport("query", countParams);
|
|
62
|
+
total = unwrapCountResponse(countResponse) ?? envelope.total;
|
|
63
|
+
}
|
|
64
|
+
const decorated = envelope.result.map((doc) => decorateLocalizedDocument(doc, collection, runtime, options.locale)).filter((doc) => Boolean(doc));
|
|
65
|
+
const populated = await Promise.all(decorated.map((doc) => populateDocument(context, one, doc, options.populate, options.locale, options.fallback)));
|
|
66
|
+
const pageCount = total > 0 ? Math.ceil(total / limit) : 0;
|
|
67
|
+
return {
|
|
68
|
+
data: populated,
|
|
69
|
+
page,
|
|
70
|
+
limit,
|
|
71
|
+
total,
|
|
72
|
+
pageCount,
|
|
73
|
+
hasNext: page < pageCount,
|
|
74
|
+
hasPrev: page > 1,
|
|
75
|
+
nextPage: page < pageCount ? page + 1 : null,
|
|
76
|
+
prevPage: page > 1 ? page - 1 : null
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './populate.js'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ParsedContent } from '../../types/content';
|
|
2
|
+
import type { ContentCollectionHandle } from '../../types/config';
|
|
3
|
+
import type { LocaleFallback, LocalizedDoc, OneOptions, PopulateSpec, PopulatedDocument } from '../../types/query';
|
|
4
|
+
import type { ContentQueryContext, RuntimeContentConfig } from './context';
|
|
5
|
+
export declare const validatePopulateSpec: (source: ContentCollectionHandle | string, sourceCollection: string, runtime: RuntimeContentConfig | undefined, populate: PopulateSpec | undefined) => void;
|
|
6
|
+
type PopulateReferenceResolver = (context: ContentQueryContext, target: ContentCollectionHandle | string, options: OneOptions<ContentCollectionHandle | string>) => Promise<unknown>;
|
|
7
|
+
export declare const populateDocument: <T extends ParsedContent, P extends PopulateSpec | undefined>(context: ContentQueryContext, resolveReference: PopulateReferenceResolver, doc: LocalizedDoc<T>, populate: P, locale: string | undefined, fallback: LocaleFallback | undefined) => Promise<LocalizedDoc<PopulatedDocument<T, P>>>;
|
|
8
|
+
export declare const selectWithPopulate: (select: ReadonlyArray<string> | undefined, populate: PopulateSpec | undefined) => string[] | undefined;
|
|
9
|
+
export {};
|