Refactor route handlers and CMS clients
Refactored the route handlers to use a new `enhanceRouteHandler` function for better control over request handlers and user authentication. CMS clients are now created using factory functions for better encapsulation and control over instance creation. Renamed `client.ts` in 'keystatic' to `keystatic-client.ts`.
This commit is contained in:
174
packages/cms/keystatic/src/keystatic-client.ts
Normal file
174
packages/cms/keystatic/src/keystatic-client.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { Cms, CmsClient } from '@kit/cms';
|
||||
|
||||
import { createKeystaticReader } from './create-reader';
|
||||
import { PostEntryProps } from './keystatic.config';
|
||||
|
||||
export function createKeystaticClient() {
|
||||
return new KeystaticClient();
|
||||
}
|
||||
|
||||
class KeystaticClient implements CmsClient {
|
||||
async getContentItems(options: Cms.GetContentItemsOptions) {
|
||||
const reader = await createKeystaticReader();
|
||||
|
||||
const collection =
|
||||
options.collection as keyof (typeof reader)['collections'];
|
||||
|
||||
if (!reader.collections[collection]) {
|
||||
throw new Error(`Collection ${collection} not found`);
|
||||
}
|
||||
|
||||
const docs = await reader.collections[collection].all();
|
||||
|
||||
const startOffset = options?.offset ?? 0;
|
||||
const endOffset = startOffset + (options?.limit ?? 10);
|
||||
|
||||
const filtered = docs
|
||||
.filter((item) => {
|
||||
const categoryMatch = options?.categories?.length
|
||||
? options.categories.find((category) =>
|
||||
item.entry.categories.includes(category),
|
||||
)
|
||||
: true;
|
||||
|
||||
if (!categoryMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.language) {
|
||||
if (item.entry.language && item.entry.language !== options.language) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const tagMatch = options?.tags?.length
|
||||
? options.tags.find((tag) => item.entry.tags.includes(tag))
|
||||
: true;
|
||||
|
||||
if (!tagMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const direction = options.sortDirection ?? 'asc';
|
||||
const sortBy = options.sortBy ?? 'publishedAt';
|
||||
|
||||
const transform = (value: string | number | undefined | null) => {
|
||||
if (typeof value === 'string') {
|
||||
return new Date(value).getTime();
|
||||
}
|
||||
|
||||
return value ?? 0;
|
||||
};
|
||||
|
||||
const left = transform(a.entry[sortBy]);
|
||||
const right = transform(b.entry[sortBy]);
|
||||
|
||||
if (direction === 'asc') {
|
||||
return left - right;
|
||||
}
|
||||
|
||||
return right - left;
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
filtered.slice(startOffset, endOffset).map(async (item) => {
|
||||
const children = docs.filter((item) => item.entry.parent === item.slug);
|
||||
|
||||
return this.mapPost(item, children);
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
total: filtered.length,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
async getContentItemBySlug(params: { slug: string; collection: string }) {
|
||||
const reader = await createKeystaticReader();
|
||||
|
||||
const collection =
|
||||
params.collection as keyof (typeof reader)['collections'];
|
||||
|
||||
if (!reader.collections[collection]) {
|
||||
throw new Error(`Collection ${collection} not found`);
|
||||
}
|
||||
|
||||
const doc = await reader.collections[collection].read(params.slug);
|
||||
|
||||
if (!doc) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const allPosts = await reader.collections[collection].all();
|
||||
|
||||
const children = allPosts.filter(
|
||||
(item) => item.entry.parent === params.slug,
|
||||
);
|
||||
|
||||
return this.mapPost({ entry: doc, slug: params.slug }, children);
|
||||
}
|
||||
|
||||
async getCategories() {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
async getTags() {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
async getTagBySlug() {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async getCategoryBySlug() {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private async mapPost<
|
||||
Type extends {
|
||||
entry: PostEntryProps;
|
||||
slug: string;
|
||||
},
|
||||
>(item: Type, children: Type[] = []): Promise<Cms.ContentItem> {
|
||||
const publishedAt = item.entry.publishedAt
|
||||
? new Date(item.entry.publishedAt)
|
||||
: new Date();
|
||||
|
||||
const content = await item.entry.content();
|
||||
|
||||
return {
|
||||
id: item.slug,
|
||||
title: item.entry.title,
|
||||
url: item.slug,
|
||||
slug: item.slug,
|
||||
description: item.entry.description,
|
||||
publishedAt: publishedAt.toISOString(),
|
||||
content,
|
||||
image: item.entry.image ?? undefined,
|
||||
categories:
|
||||
item.entry.categories.map((item) => {
|
||||
return {
|
||||
id: item,
|
||||
name: item,
|
||||
slug: item,
|
||||
};
|
||||
}) ?? [],
|
||||
tags: item.entry.tags.map((item) => {
|
||||
return {
|
||||
id: item,
|
||||
name: item,
|
||||
slug: item,
|
||||
};
|
||||
}),
|
||||
parentId: item.entry.parent ?? undefined,
|
||||
order: item.entry.order ?? 1,
|
||||
children: await Promise.all(
|
||||
children.map(async (child) => this.mapPost(child, [])),
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user