diff --git a/packages/cms/keystatic/src/create-reader.ts b/packages/cms/keystatic/src/create-reader.ts index c65e00a87..2bad6a653 100644 --- a/packages/cms/keystatic/src/create-reader.ts +++ b/packages/cms/keystatic/src/create-reader.ts @@ -1,18 +1,16 @@ import { z } from 'zod'; +import { KeystaticStorage } from './keystatic-storage'; import { keyStaticConfig } from './keystatic.config'; /** - * The kind of storage to use for the Keystatic reader. - */ -const STORAGE_KIND = process.env.KEYSTATIC_STORAGE_KIND ?? 'local'; - -/** - * Creates a new Keystatic reader instance. + * @name createKeystaticReader + * @description Creates a new Keystatic reader instance. */ export async function createKeystaticReader() { - switch (STORAGE_KIND) { + switch (KeystaticStorage.kind) { case 'local': { + // we need to import this dynamically to avoid parsing the package in edge environments if (process.env.NEXT_RUNTIME === 'nodejs') { const { createReader } = await import('@keystatic/core/reader'); @@ -26,28 +24,34 @@ export async function createKeystaticReader() { case 'github': case 'cloud': { - const githubConfig = z - .object({ - token: z.string({ - description: 'The GitHub token to use for authentication.', - }), - repo: z.custom<`${string}/${string}`>(), - pathPrefix: z.string().optional(), - }) - .parse({ - token: process.env.KEYSTATIC_GITHUB_TOKEN, - repo: process.env.KEYSTATIC_STORAGE_REPO, - pathPrefix: process.env.KEYSTATIC_PATH_PREFIX, - }); - const { createGitHubReader } = await import( '@keystatic/core/reader/github' ); - return createGitHubReader(keyStaticConfig, githubConfig); + return createGitHubReader( + keyStaticConfig, + getKeystaticGithubConfiguration(), + ); } default: throw new Error(`Unknown storage kind`); } } + +function getKeystaticGithubConfiguration() { + return z + .object({ + token: z.string({ + description: + 'The GitHub token to use for authentication. Please provide the value through the "KEYSTATIC_GITHUB_TOKEN" environment variable.', + }), + repo: z.custom<`${string}/${string}`>(), + pathPrefix: z.string().optional(), + }) + .parse({ + token: process.env.KEYSTATIC_GITHUB_TOKEN, + repo: process.env.KEYSTATIC_STORAGE_REPO, + pathPrefix: process.env.KEYSTATIC_PATH_PREFIX, + }); +} diff --git a/packages/cms/keystatic/src/keystatic-storage.ts b/packages/cms/keystatic/src/keystatic-storage.ts new file mode 100644 index 000000000..c79cdd862 --- /dev/null +++ b/packages/cms/keystatic/src/keystatic-storage.ts @@ -0,0 +1,67 @@ +import { CloudConfig, GitHubConfig, LocalConfig } from '@keystatic/core'; +import { z } from 'zod'; + +type ZodOutputFor = z.ZodType; + +/** + * @name STORAGE_KIND + * @description The kind of storage to use for the Keystatic reader. + * + * This can be provided through the `KEYSTATIC_STORAGE_KIND` environment variable or 'NEXT_PUBLIC_KEYSTATIC_STORAGE_KIND'. + * The previous environment variable `KEYSTATIC_STORAGE_KIND` is deprecated - as Keystatic may need this to be available in the client-side. + * + */ +const STORAGE_KIND = process.env.NEXT_PUBLIC_KEYSTATIC_STORAGE_KIND ?? + /* @deprecated */ + process.env.KEYSTATIC_STORAGE_KIND ?? + 'local'; + +const PROJECT = process.env.KEYSTATIC_STORAGE_PROJECT; +const REPO = process.env.KEYSTATIC_STORAGE_REPO; +const BRANCH_PREFIX = process.env.KEYSTATIC_STORAGE_BRANCH_PREFIX; +const PATH_PREFIX = process.env.KEYSTATIC_PATH_PREFIX; + +/** + * @name local + * @description The configuration for the local storage. + */ +const local = z.object({ + kind: z.literal('local'), +}) satisfies ZodOutputFor; + +/** + * @name cloud + * @description The configuration for the cloud storage. + */ +const cloud = z.object({ + kind: z.literal('cloud'), + project: z.string({ + description: `The Keystatic Cloud project. Please provide the value through the "KEYSTATIC_STORAGE_PROJECT" environment variable.`, + }).min(1), + branchPrefix: z.string().optional(), + pathPrefix: z.string().optional(), +}) satisfies ZodOutputFor; + +/** + * @name github + * @description The configuration for the GitHub storage. + */ +const github = z.object({ + kind: z.literal('github'), + repo: z.custom<`${string}/${string}`>(), + branchPrefix: z.string().optional(), + pathPrefix: z.string().optional(), +}) satisfies ZodOutputFor; + +/** + * @name KeystaticStorage + * @description The configuration for the Keystatic storage. This is used to determine where the content is stored. + * This configuration is validated through Zod to ensure that the configuration is correct. + */ +export const KeystaticStorage = z.union([local, cloud, github]).parse({ + kind: STORAGE_KIND, + project: PROJECT, + repo: REPO, + branchPrefix: BRANCH_PREFIX, + pathPrefix: PATH_PREFIX, +}); \ No newline at end of file diff --git a/packages/cms/keystatic/src/keystatic.config.ts b/packages/cms/keystatic/src/keystatic.config.ts index 2d208285c..4a570c00c 100644 --- a/packages/cms/keystatic/src/keystatic.config.ts +++ b/packages/cms/keystatic/src/keystatic.config.ts @@ -1,47 +1,7 @@ -import { - CloudConfig, - GitHubConfig, - LocalConfig, - collection, - config, - fields, -} from '@keystatic/core'; +import { collection, config, fields } from '@keystatic/core'; import { Entry } from '@keystatic/core/reader'; -import { z } from 'zod'; -type ZodOutputFor = z.ZodType; - -const local = z.object({ - kind: z.literal('local'), -}) satisfies ZodOutputFor; - -const cloud = z.object({ - kind: z.literal('cloud'), - project: z.string().min(1), - branchPrefix: z.string().optional(), - pathPrefix: z.string().optional(), -}) satisfies ZodOutputFor; - -const github = z.object({ - kind: z.literal('github'), - repo: z.custom<`${string}/${string}`>(), - branchPrefix: z.string().optional(), - pathPrefix: z.string().optional(), - githubToken: z.string({ - description: - 'The GitHub token to use for authentication with the GitHub API', - required_error: 'Please provide a GitHub token', - }), -}) satisfies ZodOutputFor; - -const storage = z.union([local, cloud, github]).parse({ - kind: process.env.KEYSTATIC_STORAGE_KIND ?? 'local', - project: process.env.KEYSTATIC_STORAGE_PROJECT, - repo: process.env.KEYSTATIC_STORAGE_REPO, - branchPrefix: process.env.KEYSTATIC_STORAGE_BRANCH_PREFIX, - githubToken: process.env.KEYSTATIC_GITHUB_TOKEN, - pathPrefix: process.env.KEYSTATIC_PATH_PREFIX, -}); +import { KeystaticStorage } from './keystatic-storage'; export const keyStaticConfig = createKeyStaticConfig( process.env.NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH ?? '', @@ -85,13 +45,13 @@ function createKeyStaticConfig(path = '') { } const cloud = { - project: storage.kind === 'cloud' ? storage.project : '', + project: KeystaticStorage.kind === 'cloud' ? KeystaticStorage.project : '', }; const collections = getKeystaticCollections(path); return config({ - storage, + storage: KeystaticStorage, cloud, collections, });