diff --git a/packages/cms/core/package.json b/packages/cms/core/package.json index c3b70cba4..f172e9864 100644 --- a/packages/cms/core/package.json +++ b/packages/cms/core/package.json @@ -13,9 +13,12 @@ ".": "./src/index.ts" }, "devDependencies": { + "@kit/cms-types": "workspace:^", "@kit/eslint-config": "workspace:*", + "@kit/keystatic": "workspace:^", "@kit/prettier-config": "workspace:*", "@kit/tsconfig": "workspace:*", + "@kit/wordpress": "workspace:^", "@types/node": "^22.5.2" }, "eslintConfig": { diff --git a/packages/cms/core/src/content-renderer.tsx b/packages/cms/core/src/content-renderer.tsx index 5ada07531..e8dfdbe38 100644 --- a/packages/cms/core/src/content-renderer.tsx +++ b/packages/cms/core/src/content-renderer.tsx @@ -1,4 +1,4 @@ -import type { CmsType } from './cms.type'; +import type { CmsType } from '@kit/cms-types'; const CMS_CLIENT = process.env.CMS_CLIENT as CmsType; @@ -11,21 +11,32 @@ export async function ContentRenderer({ content, type = CMS_CLIENT, }: ContentRendererProps) { + const Renderer = await getContentRenderer(type); + + return Renderer ? : null; +} + +/** + * Gets the content renderer for the specified CMS client. + * + * @param {CmsType} type - The type of CMS client. + */ +async function getContentRenderer(type: CmsType) { switch (type) { case 'keystatic': { const { KeystaticContentRenderer } = await import( - '../../keystatic/src/content-renderer' + '@kit/keystatic/renderer' ); - return ; + return KeystaticContentRenderer; } case 'wordpress': { const { WordpressContentRenderer } = await import( - '../../wordpress/src/content-renderer' + '@kit/wordpress/renderer' ); - return ; + return WordpressContentRenderer; } default: { diff --git a/packages/cms/core/src/create-cms-client.ts b/packages/cms/core/src/create-cms-client.ts index 77b307224..0f824903c 100644 --- a/packages/cms/core/src/create-cms-client.ts +++ b/packages/cms/core/src/create-cms-client.ts @@ -1,5 +1,9 @@ -import { CmsClient } from './cms-client'; -import { CmsType } from './cms.type'; +import { CmsClient, CmsType } from '@kit/cms-types'; + +/** + * The type of CMS client to use. + */ +const CMS_CLIENT = process.env.CMS_CLIENT as CmsType; /** * Creates a CMS client based on the specified type. @@ -9,61 +13,32 @@ import { CmsType } from './cms.type'; * @throws {Error} If the specified CMS type is unknown. */ export async function createCmsClient( - type: CmsType = process.env.CMS_CLIENT as CmsType, + type: CmsType = CMS_CLIENT, ): Promise { return cmsClientFactory(type); } -async function cmsClientFactory(type: CmsType) { +/** + * Creates a CMS client based on the specified type. + * + * @param {CmsType} type - The type of CMS client to create. + * @returns {Promise} A Promise that resolves to the created CMS client. + */ +async function cmsClientFactory(type: CmsType): Promise { switch (type) { - case 'wordpress': - return getWordpressClient(); + case 'wordpress': { + const { createWordpressClient } = await import('@kit/wordpress'); - case 'keystatic': - return getKeystaticClient(); + return createWordpressClient(); + } + + case 'keystatic': { + const { createKeystaticClient } = await import('@kit/keystatic'); + + return createKeystaticClient(); + } default: throw new Error(`Unknown CMS type`); } } - -async function getWordpressClient() { - const { createWordpressClient } = await import( - '../../wordpress/src/wp-client' - ); - - return createWordpressClient(); -} - -async function getKeystaticClient() { - if ( - process.env.NEXT_RUNTIME === 'nodejs' || - process.env.KEYSTATIC_STORAGE_KIND !== 'local' - ) { - const { createKeystaticClient } = await import( - '../../keystatic/src/keystatic-client' - ); - - return createKeystaticClient(); - } - - console.error( - `[CMS] Keystatic client using "Local" mode is only available in Node.js runtime. Please choose a different CMS client. Returning a mock client instead of throwing an error.`, - ); - - return mockCMSClient() as unknown as CmsClient; -} - -function mockCMSClient() { - return { - getContentItems() { - return Promise.resolve({ - items: [], - total: 0, - }); - }, - getContentItemBySlug() { - return Promise.resolve(undefined); - }, - }; -} diff --git a/packages/cms/core/src/index.ts b/packages/cms/core/src/index.ts index 3f75ccf29..3963ccfae 100644 --- a/packages/cms/core/src/index.ts +++ b/packages/cms/core/src/index.ts @@ -1,4 +1,6 @@ -export * from './cms-client'; +import { Cms } from '@kit/cms-types'; + export * from './create-cms-client'; -export * from './cms.type'; export * from './content-renderer'; + +export type { Cms }; diff --git a/packages/cms/keystatic/package.json b/packages/cms/keystatic/package.json index 8b268aec4..1729d1dab 100644 --- a/packages/cms/keystatic/package.json +++ b/packages/cms/keystatic/package.json @@ -11,6 +11,7 @@ "prettier": "@kit/prettier-config", "exports": { ".": "./src/index.ts", + "./renderer": "./src/content-renderer.tsx", "./admin": "./src/keystatic-admin.tsx", "./route-handler": "./src/keystatic-route-handler.ts" }, @@ -20,7 +21,7 @@ "@markdoc/markdoc": "^0.4.0" }, "devDependencies": { - "@kit/cms": "workspace:^", + "@kit/cms-types": "workspace:^", "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", "@kit/tsconfig": "workspace:*", diff --git a/packages/cms/keystatic/src/create-keystatic-cms.ts b/packages/cms/keystatic/src/create-keystatic-cms.ts new file mode 100644 index 000000000..f8b626e3d --- /dev/null +++ b/packages/cms/keystatic/src/create-keystatic-cms.ts @@ -0,0 +1,37 @@ +import { CmsClient } from '@kit/cms-types'; + +/** + * Creates a new Keystatic client instance. + */ +export async function createKeystaticClient() { + if ( + process.env.NEXT_RUNTIME === 'nodejs' || + process.env.KEYSTATIC_STORAGE_KIND !== 'local' + ) { + const { createKeystaticClient: createClient } = await import( + './keystatic-client' + ); + + return createClient(); + } + + console.error( + `[CMS] Keystatic client using "Local" mode is only available in Node.js runtime. Please choose a different CMS client. Returning a mock client instead of throwing an error.`, + ); + + return mockCMSClient() as unknown as CmsClient; +} + +function mockCMSClient() { + return { + getContentItems() { + return Promise.resolve({ + items: [], + total: 0, + }); + }, + getContentItemBySlug() { + return Promise.resolve(undefined); + }, + }; +} diff --git a/packages/cms/keystatic/src/create-reader.ts b/packages/cms/keystatic/src/create-reader.ts index 1f4cffa6f..c65e00a87 100644 --- a/packages/cms/keystatic/src/create-reader.ts +++ b/packages/cms/keystatic/src/create-reader.ts @@ -1,18 +1,22 @@ import { z } from 'zod'; +import { keyStaticConfig } from './keystatic.config'; + +/** + * The kind of storage to use for the Keystatic reader. + */ const STORAGE_KIND = process.env.KEYSTATIC_STORAGE_KIND ?? 'local'; /** - * Create a KeyStatic reader based on the storage kind. + * Creates a new Keystatic reader instance. */ export async function createKeystaticReader() { switch (STORAGE_KIND) { case 'local': { if (process.env.NEXT_RUNTIME === 'nodejs') { - const { default: config } = await import('./keystatic.config'); const { createReader } = await import('@keystatic/core/reader'); - return createReader(process.cwd(), config); + return createReader(process.cwd(), keyStaticConfig); } else { // we should never get here but the compiler requires the check // to ensure we don't parse the package at build time @@ -22,11 +26,11 @@ export async function createKeystaticReader() { case 'github': case 'cloud': { - const { default: config } = await import('./keystatic.config'); - const githubConfig = z .object({ - token: z.string(), + token: z.string({ + description: 'The GitHub token to use for authentication.', + }), repo: z.custom<`${string}/${string}`>(), pathPrefix: z.string().optional(), }) @@ -40,7 +44,7 @@ export async function createKeystaticReader() { '@keystatic/core/reader/github' ); - return createGitHubReader(config, githubConfig); + return createGitHubReader(keyStaticConfig, githubConfig); } default: diff --git a/packages/cms/keystatic/src/index.ts b/packages/cms/keystatic/src/index.ts index a08c2867d..394dadc58 100644 --- a/packages/cms/keystatic/src/index.ts +++ b/packages/cms/keystatic/src/index.ts @@ -1,3 +1 @@ -export * from './keystatic-client'; -export * from './content-renderer'; -export * from './keystatic.config'; +export * from './create-keystatic-cms'; \ No newline at end of file diff --git a/packages/cms/keystatic/src/keystatic-admin.tsx b/packages/cms/keystatic/src/keystatic-admin.tsx index 39b23d171..d8b7a2e7f 100644 --- a/packages/cms/keystatic/src/keystatic-admin.tsx +++ b/packages/cms/keystatic/src/keystatic-admin.tsx @@ -2,6 +2,6 @@ import { makePage } from '@keystatic/next/ui/app'; -import config from './keystatic.config'; +import { keyStaticConfig } from './keystatic.config'; -export default makePage(config); +export default makePage(keyStaticConfig); diff --git a/packages/cms/keystatic/src/keystatic-client.ts b/packages/cms/keystatic/src/keystatic-client.ts index bab46f055..27bb399e3 100644 --- a/packages/cms/keystatic/src/keystatic-client.ts +++ b/packages/cms/keystatic/src/keystatic-client.ts @@ -1,6 +1,6 @@ import React from 'react'; -import { Cms, CmsClient } from '@kit/cms'; +import { Cms, CmsClient } from '@kit/cms-types'; import { createKeystaticReader } from './create-reader'; import { diff --git a/packages/cms/keystatic/src/keystatic-route-handler.ts b/packages/cms/keystatic/src/keystatic-route-handler.ts index 081b1075e..d748415ef 100644 --- a/packages/cms/keystatic/src/keystatic-route-handler.ts +++ b/packages/cms/keystatic/src/keystatic-route-handler.ts @@ -1,9 +1,9 @@ import { makeRouteHandler } from '@keystatic/next/route-handler'; -import config from './keystatic.config'; +import { keyStaticConfig } from './keystatic.config'; const handlers = makeRouteHandler({ - config, + config: keyStaticConfig, }); /** diff --git a/packages/cms/keystatic/src/keystatic.config.ts b/packages/cms/keystatic/src/keystatic.config.ts index 9716262df..2d208285c 100644 --- a/packages/cms/keystatic/src/keystatic.config.ts +++ b/packages/cms/keystatic/src/keystatic.config.ts @@ -43,12 +43,10 @@ const storage = z.union([local, cloud, github]).parse({ pathPrefix: process.env.KEYSTATIC_PATH_PREFIX, }); -const keyStaticConfig = createKeyStaticConfig( +export const keyStaticConfig = createKeyStaticConfig( process.env.NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH ?? '', ); -export default keyStaticConfig; - function getContentField() { return fields.markdoc({ label: 'Content', diff --git a/packages/cms/types/README.md b/packages/cms/types/README.md new file mode 100644 index 000000000..9f552a43e --- /dev/null +++ b/packages/cms/types/README.md @@ -0,0 +1,3 @@ +# CMS - @kit/cms + +CMS abstraction layer for the Makerkit framework. \ No newline at end of file diff --git a/packages/cms/types/package.json b/packages/cms/types/package.json new file mode 100644 index 000000000..6ed01784c --- /dev/null +++ b/packages/cms/types/package.json @@ -0,0 +1,34 @@ +{ + "name": "@kit/cms-types", + "private": true, + "version": "0.1.0", + "scripts": { + "clean": "git clean -xdf .turbo node_modules", + "format": "prettier --check \"**/*.{ts,tsx}\"", + "lint": "eslint .", + "typecheck": "tsc --noEmit" + }, + "prettier": "@kit/prettier-config", + "exports": { + ".": "./src/index.ts" + }, + "devDependencies": { + "@kit/eslint-config": "workspace:*", + "@kit/prettier-config": "workspace:*", + "@kit/tsconfig": "workspace:*" + }, + "eslintConfig": { + "root": true, + "extends": [ + "@kit/eslint-config/base", + "@kit/eslint-config/react" + ] + }, + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + } +} \ No newline at end of file diff --git a/packages/cms/core/src/cms-client.ts b/packages/cms/types/src/cms-client.ts similarity index 100% rename from packages/cms/core/src/cms-client.ts rename to packages/cms/types/src/cms-client.ts diff --git a/packages/cms/core/src/cms.type.ts b/packages/cms/types/src/cms.type.ts similarity index 100% rename from packages/cms/core/src/cms.type.ts rename to packages/cms/types/src/cms.type.ts diff --git a/packages/cms/types/src/index.ts b/packages/cms/types/src/index.ts new file mode 100644 index 000000000..e24881f8d --- /dev/null +++ b/packages/cms/types/src/index.ts @@ -0,0 +1,2 @@ +export * from './cms-client'; +export * from './cms.type'; \ No newline at end of file diff --git a/packages/cms/types/tsconfig.json b/packages/cms/types/tsconfig.json new file mode 100644 index 000000000..c92857ed3 --- /dev/null +++ b/packages/cms/types/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@kit/tsconfig/base.json", + "compilerOptions": { + "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" + }, + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/packages/cms/wordpress/package.json b/packages/cms/wordpress/package.json index 773ec4afb..6bbe3f490 100644 --- a/packages/cms/wordpress/package.json +++ b/packages/cms/wordpress/package.json @@ -11,15 +11,17 @@ }, "prettier": "@kit/prettier-config", "exports": { - ".": "./src/index.ts" + ".": "./src/index.ts", + "./renderer": "./src/content-renderer.tsx" }, "devDependencies": { - "@kit/cms": "workspace:^", + "@kit/cms-types": "workspace:^", "@kit/eslint-config": "workspace:*", "@kit/prettier-config": "workspace:*", "@kit/tsconfig": "workspace:*", "@kit/ui": "workspace:^", "@types/node": "^22.5.2", + "@types/react": "^18.3.5", "wp-types": "^4.66.1" }, "eslintConfig": { diff --git a/packages/cms/wordpress/src/content-renderer.tsx b/packages/cms/wordpress/src/content-renderer.tsx index 7e4578e7f..fd905a567 100644 --- a/packages/cms/wordpress/src/content-renderer.tsx +++ b/packages/cms/wordpress/src/content-renderer.tsx @@ -1,3 +1,5 @@ +import React from 'react'; + export function WordpressContentRenderer(props: { content: unknown }) { return
; } diff --git a/packages/cms/wordpress/src/index.ts b/packages/cms/wordpress/src/index.ts index a7fab7906..3f535eac4 100644 --- a/packages/cms/wordpress/src/index.ts +++ b/packages/cms/wordpress/src/index.ts @@ -1 +1 @@ -export * from './wp-client'; +export * from './wp-client'; \ No newline at end of file diff --git a/packages/cms/wordpress/src/wp-client.ts b/packages/cms/wordpress/src/wp-client.ts index 775a599b7..60a7d191e 100644 --- a/packages/cms/wordpress/src/wp-client.ts +++ b/packages/cms/wordpress/src/wp-client.ts @@ -5,10 +5,16 @@ import type { WP_REST_API_Tag, } from 'wp-types'; -import { Cms, CmsClient } from '@kit/cms'; +import { Cms, CmsClient } from '@kit/cms-types'; import GetTagsOptions = Cms.GetTagsOptions; +/** + * Creates a new WordpressClient instance. + * + * @param {string} apiUrl - The URL of the Wordpress API. + * @returns {WordpressClient} A new WordpressClient instance. + */ export function createWordpressClient( apiUrl = process.env.WORDPRESS_API_URL as string, ) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e09d8117..a1dbd27e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -420,15 +420,24 @@ importers: packages/cms/core: devDependencies: + '@kit/cms-types': + specifier: workspace:^ + version: link:../types '@kit/eslint-config': specifier: workspace:* version: link:../../../tooling/eslint + '@kit/keystatic': + specifier: workspace:^ + version: link:../keystatic '@kit/prettier-config': specifier: workspace:* version: link:../../../tooling/prettier '@kit/tsconfig': specifier: workspace:* version: link:../../../tooling/typescript + '@kit/wordpress': + specifier: workspace:^ + version: link:../wordpress '@types/node': specifier: ^22.5.2 version: 22.5.2 @@ -445,9 +454,9 @@ importers: specifier: ^0.4.0 version: 0.4.0(@types/react@18.3.5)(react@18.3.1) devDependencies: - '@kit/cms': + '@kit/cms-types': specifier: workspace:^ - version: link:../core + version: link:../types '@kit/eslint-config': specifier: workspace:* version: link:../../../tooling/eslint @@ -473,11 +482,23 @@ importers: specifier: ^3.23.8 version: 3.23.8 + packages/cms/types: + devDependencies: + '@kit/eslint-config': + specifier: workspace:* + version: link:../../../tooling/eslint + '@kit/prettier-config': + specifier: workspace:* + version: link:../../../tooling/prettier + '@kit/tsconfig': + specifier: workspace:* + version: link:../../../tooling/typescript + packages/cms/wordpress: devDependencies: - '@kit/cms': + '@kit/cms-types': specifier: workspace:^ - version: link:../core + version: link:../types '@kit/eslint-config': specifier: workspace:* version: link:../../../tooling/eslint @@ -493,6 +514,9 @@ importers: '@types/node': specifier: ^22.5.2 version: 22.5.2 + '@types/react': + specifier: ^18.3.5 + version: 18.3.5 wp-types: specifier: ^4.66.1 version: 4.66.1