import type { Field, GlobalConfig } from 'payload' import { isAdmin } from '../../modules/access/index.js' import { analyticsFields } from './fields/analytics.js' import { smtpFields } from './fields/smtp.js' import { turnstileFields } from './fields/turnstile.js' type BuildSiteIntegrationsArgs = { /** Extra fields injected by the client project */ additionalFields?: Field[] } /** * Builds the SiteIntegrations global. * * Holds third-party service credentials. Access is enforced at the global * level — the whole global requires an authenticated user — so secrets stay * out of anonymous API responses while remaining editable in the admin panel * and readable via the server-side Local API. (Field-level read:false was * avoided because it also hides fields from the admin UI, making them * impossible to enter.) * * Unnamed tabs keep data flat (siteIntegrations.ga4MeasurementId). * * Note: R2 storage credentials are NOT here — storage is infrastructure and * binds at boot, so its config lives in .env (R2_BUCKET, R2_ENDPOINT, ...), * consumed by buildR2Storage. See docs/storage.md. */ export function buildSiteIntegrations({ additionalFields, }: BuildSiteIntegrationsArgs = {}): GlobalConfig { return { slug: 'site-integrations', access: { // Admin-only — secrets live here. Anonymous and non-admin users get // nothing through the API; admins read/edit in the panel and via Local API. read: ({ req: { user } }) => isAdmin(user), update: ({ req: { user } }) => isAdmin(user), }, admin: { group: 'Settings', }, fields: [ { type: 'tabs', tabs: [ { fields: analyticsFields, label: 'Analytics' }, { fields: turnstileFields, label: 'Turnstile' }, { fields: smtpFields, label: 'SMTP' }, ...(additionalFields?.length ? [{ fields: additionalFields, label: 'Custom' }] : []), ], }, ], label: 'Site Integrations', } }