init commit for iPAL-kit plugin

This commit is contained in:
2026-07-18 20:30:23 +02:00
parent 10638127a9
commit 5733a9c8bf
119 changed files with 6892 additions and 411 deletions
@@ -0,0 +1,93 @@
import type { BasePayload, SanitizedConfig } from 'payload'
import { getPayload } from 'payload'
import { cache } from 'react'
import type { ContentOption, ResolvedRoute } from '../content/index.js'
import { resolveRoute as resolveRouteRaw } from '../content/index.js'
type CreateContentHelpersArgs = {
/**
* The client's payload config promise (the default export of payload.config).
* Passed in because the plugin never imports the client's config directly.
*/
config: Promise<SanitizedConfig> | SanitizedConfig
/** Archive-backed collections, same value as the plugin option. */
content?: ContentOption
/** Pages collection slug. Defaults to 'pages'. */
pagesSlug?: string
/** SiteSettings global slug. Defaults to 'site-settings'. */
settingsSlug?: string
}
/**
* Bundles the per-request data helpers a frontend needs — the same cached
* wrappers every project was writing by hand (getPayload, settings, locale
* list, route resolution).
*
* Everything is wrapped in React `cache()`, so within one request a value is
* fetched once no matter how many times it's asked for — which matters because
* Next runs generateMetadata and the page component separately, and both hit
* these. Crucially the Payload instance is cached *here*, once, so every helper
* shares it; that's why this is a factory and not loose functions importing a
* shared module.
*
* ```ts
* // src/lib/content.ts
* import { createContentHelpers } from 'ipal-kit'
* import config from '@/payload.config'
* import { contentConfig } from '@/content.config'
*
* export const { getCachedPayload, getSettings, getConfiguredLocales, resolveRoute } =
* createContentHelpers({ config, content: contentConfig })
* ```
*/
export function createContentHelpers({
config,
content,
pagesSlug = 'pages',
settingsSlug = 'site-settings',
}: CreateContentHelpersArgs) {
const getCachedPayload = cache(async (): Promise<BasePayload> =>
getPayload({ config: await config }),
)
const getConfiguredLocales = cache(async (): Promise<string[]> => {
const c = await config
return c.localization ? c.localization.locales.map((l) => l.code) : []
})
const getSettings = cache(async (locale: string) => {
const payload = await getCachedPayload()
return payload.findGlobal({ slug: settingsSlug as never, depth: 2, locale: locale as never })
})
/**
* Resolves a URL to a page / archive / entry. Pass `withEntries` on the page
* component (it needs the listing); omit it for metadata (it doesn't, and the
* query would be wasted).
*/
const resolveRoute = cache(
async (
locale: string,
segments: string[] | undefined,
page: number,
withEntries = false,
): Promise<null | ResolvedRoute> => {
const payload = await getCachedPayload()
return resolveRouteRaw({
content,
locale,
page,
pagesSlug,
payload,
segments,
settingsSlug,
withEntries,
})
},
)
return { getCachedPayload, getConfiguredLocales, getSettings, resolveRoute }
}
+1
View File
@@ -0,0 +1 @@
export { createContentHelpers } from './createContentHelpers.js'