@bison-lab/payload-core 3.14.0 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"access-B3LglN2J.mjs","names":["isAccessArgs"],"sources":["../src/features/types.ts","../src/features/matrix.ts","../src/roles/types.ts","../src/roles/matrix.ts","../src/roles/access.ts","../src/features/access.ts"],"sourcesContent":["export const FEATURES_SLUG = \"features\";\n\nexport const FEATURE_GROUPS = [\"pages\", \"media\", \"theme\", \"users\"] as const;\n\nexport type FeatureGroupId = (typeof FEATURE_GROUPS)[number];\n\nexport const FEATURE_GROUP_LABELS: Record<FeatureGroupId, string> = {\n pages: \"Pages\",\n media: \"Media\",\n theme: \"Theme\",\n users: \"Users\",\n};\n\nexport const PACKAGE_FEATURE_SLUGS = [\n \"content\",\n \"publish\",\n \"api-tab\",\n \"media\",\n \"theme-colors\",\n \"theme-typography\",\n \"theme-appearance\",\n \"theme-identity\",\n \"brand-assets\",\n \"users\",\n \"roles\",\n] as const;\n\nexport type PackageFeatureSlug = (typeof PACKAGE_FEATURE_SLUGS)[number];\n\nexport interface PackageFeature {\n slug: PackageFeatureSlug;\n label: string;\n group: FeatureGroupId;\n defaultReleased: boolean;\n}\n\n/**\n * Package catalogue. Features itself is not a row — that screen is\n * Developer-only in code. Empty Global falls back to these defaults.\n */\nexport const PACKAGE_FEATURES: readonly PackageFeature[] = [\n { slug: \"content\", label: \"Content\", group: \"pages\", defaultReleased: true },\n { slug: \"publish\", label: \"Publish\", group: \"pages\", defaultReleased: true },\n { slug: \"api-tab\", label: \"API tab\", group: \"pages\", defaultReleased: false },\n { slug: \"media\", label: \"Media\", group: \"media\", defaultReleased: true },\n { slug: \"theme-colors\", label: \"Colors\", group: \"theme\", defaultReleased: true },\n { slug: \"theme-typography\", label: \"Typography\", group: \"theme\", defaultReleased: true },\n { slug: \"theme-appearance\", label: \"Appearance\", group: \"theme\", defaultReleased: true },\n { slug: \"theme-identity\", label: \"Identity\", group: \"theme\", defaultReleased: true },\n { slug: \"brand-assets\", label: \"Brand assets\", group: \"theme\", defaultReleased: true },\n { slug: \"users\", label: \"Users\", group: \"users\", defaultReleased: true },\n { slug: \"roles\", label: \"Roles\", group: \"users\", defaultReleased: true },\n];\n\n/** A site-only row. Other sites never see this slug. */\nexport interface FeatureExtra {\n slug: string;\n label: string;\n group?: FeatureGroupId;\n defaultReleased?: boolean;\n}\n\nexport interface FeatureRow {\n id?: string | null;\n slug: string;\n label?: string | null;\n group?: string | null;\n released: boolean;\n}\n\nexport interface FeaturesDoc {\n features?: FeatureRow[] | null;\n}\n\nexport function isFeatureGroupId(value: unknown): value is FeatureGroupId {\n return typeof value === \"string\" && (FEATURE_GROUPS as readonly string[]).includes(value);\n}\n\nexport function isPackageFeatureSlug(value: unknown): value is PackageFeatureSlug {\n return typeof value === \"string\" && (PACKAGE_FEATURE_SLUGS as readonly string[]).includes(value);\n}\n\nexport function isFeatureSlug(value: unknown): value is string {\n return typeof value === \"string\" && /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(value);\n}\n\n/** @deprecated Locks are gone; the release switch is the valve. */\nexport function isLockedFeature(_slug: string, _locked?: boolean | null): boolean {\n return false;\n}\n","import {\n FEATURE_GROUP_LABELS,\n isFeatureGroupId,\n isFeatureSlug,\n PACKAGE_FEATURES,\n type FeatureExtra,\n type FeatureGroupId,\n type FeatureRow,\n type PackageFeature,\n} from \"./types\";\n\nexport const MISSING_PACKAGE_FEATURES_MESSAGE =\n \"Features must include Content, Publish, API tab, Media, Theme screens, Brand assets, Users, and Roles.\";\n\nexport interface FeatureCatalogueEntry {\n slug: string;\n label: string;\n group: FeatureGroupId;\n defaultReleased: boolean;\n}\n\nexport function featureCatalogue(extras: readonly FeatureExtra[] = []): FeatureCatalogueEntry[] {\n return [\n ...PACKAGE_FEATURES.map((feature) => ({ ...feature })),\n ...extras.map((extra) => ({\n slug: extra.slug,\n label: extra.label,\n group: extra.group ?? \"users\",\n defaultReleased: extra.defaultReleased ?? false,\n })),\n ];\n}\n\nexport function defaultFeaturesFieldValue(extras: readonly FeatureExtra[] = []): FeatureRow[] {\n return featureCatalogue(extras).map((feature) => ({\n id: feature.slug,\n slug: feature.slug,\n label: feature.label,\n group: feature.group,\n released: feature.defaultReleased,\n }));\n}\n\nexport function stampFeatureCatalogue(\n value: unknown,\n extras: readonly FeatureExtra[] = [],\n): FeatureRow[] {\n const bySlug = new Map(featureCatalogue(extras).map((feature) => [feature.slug, feature]));\n if (!Array.isArray(value)) return defaultFeaturesFieldValue(extras);\n return value.flatMap((item) => {\n if (!item || typeof item !== \"object\") return [];\n const slug = \"slug\" in item && typeof item.slug === \"string\" ? item.slug : \"\";\n const feature = bySlug.get(slug);\n if (!feature) return [];\n return [\n {\n id: feature.slug,\n slug: feature.slug,\n label: feature.label,\n group: feature.group,\n released: Boolean(\"released\" in item && item.released),\n },\n ];\n });\n}\n\nexport function parseFeaturesMatrix(\n value: unknown,\n): { ok: true; rows: FeatureRow[] } | { ok: false; message: string } {\n if (!Array.isArray(value) || value.length === 0) {\n return { ok: false, message: MISSING_PACKAGE_FEATURES_MESSAGE };\n }\n\n const rows: FeatureRow[] = [];\n const seen = new Set<string>();\n\n for (const item of value) {\n if (!item || typeof item !== \"object\") continue;\n const slug = \"slug\" in item ? item.slug : undefined;\n if (!isFeatureSlug(slug) || seen.has(slug)) continue;\n seen.add(slug);\n const pack = PACKAGE_FEATURES.find((feature) => feature.slug === slug);\n const label =\n \"label\" in item && typeof item.label === \"string\"\n ? item.label\n : (pack?.label ?? slug);\n const group =\n \"group\" in item && isFeatureGroupId(item.group) ? item.group : (pack?.group ?? \"users\");\n rows.push({\n id: slug,\n slug,\n label,\n group,\n released: Boolean(\"released\" in item && item.released),\n });\n }\n\n if (PACKAGE_FEATURES.some((feature) => !seen.has(feature.slug))) {\n return { ok: false, message: MISSING_PACKAGE_FEATURES_MESSAGE };\n }\n return { ok: true, rows };\n}\n\nexport function validateFeaturesMatrix(\n value: unknown,\n extras: readonly FeatureExtra[] = [],\n): true | string {\n const parsed = parseFeaturesMatrix(value);\n if (!parsed.ok) return parsed.message;\n const allowed = new Set(featureCatalogue(extras).map((feature) => feature.slug));\n if (parsed.rows.some((row) => !allowed.has(row.slug))) return MISSING_PACKAGE_FEATURES_MESSAGE;\n return true;\n}\n\nexport function featureGroupLabel(group: string): string {\n return isFeatureGroupId(group) ? FEATURE_GROUP_LABELS[group] : group;\n}\n\nexport function packageFeatureLabel(slug: string, extras: readonly FeatureExtra[] = []): string {\n const pack = PACKAGE_FEATURES.find((feature) => feature.slug === slug);\n if (pack) return pack.label;\n const extra = extras.find((feature) => feature.slug === slug);\n return extra?.label ?? slug;\n}\n\nexport function isGroupOnlySlug(slug: string): boolean {\n return isFeatureGroupId(slug) && !PACKAGE_FEATURES.some((feature) => feature.slug === slug);\n}\n\nexport type { PackageFeature };\n","/**\n * The Roles Global a site's generated types will describe. Optional and\n * nullable, no index signature: a generated Global is assignable to this,\n * never the reverse.\n */\n\nexport const ROLES = [\"developer\", \"admin\", \"designer\", \"author\"] as const;\n\nexport type Role = (typeof ROLES)[number];\n\nexport const ROLE_LABELS: Record<Role, string> = {\n developer: \"Developer\",\n admin: \"Admin\",\n designer: \"Designer\",\n author: \"Author\",\n};\n\n/** Capability aliases over feature grants. Brand is any Theme-group leaf. */\nexport const CAPABILITIES = [\"content\", \"brand\", \"publish\", \"users\"] as const;\n\nexport type Capability = (typeof CAPABILITIES)[number];\n\nexport const THEME_FEATURE_SLUGS = [\n \"theme-colors\",\n \"theme-typography\",\n \"theme-appearance\",\n \"theme-identity\",\n \"brand-assets\",\n] as const;\n\nexport const CAPABILITY_FEATURES: Record<Capability, readonly string[]> = {\n content: [\"content\"],\n publish: [\"publish\"],\n users: [\"users\"],\n brand: THEME_FEATURE_SLUGS,\n};\n\nexport const DEFAULT_ROLE_GRANTS: Record<Role, readonly string[]> = {\n developer: [],\n admin: [\"content\", \"publish\", \"media\", \"users\", \"roles\"],\n designer: [\n \"content\",\n \"media\",\n ...THEME_FEATURE_SLUGS,\n \"users\",\n \"roles\",\n ],\n author: [\"content\", \"media\"],\n};\n\n/**\n * A site-defined row passed into `createRoles({ extras })`. The slug is the\n * stored key; the label is what Settings → Roles and Users show.\n */\nexport interface RoleExtra {\n role: string;\n label: string;\n grants?: readonly string[];\n}\n\nexport interface RoleRow {\n id?: string | null;\n role: string;\n label?: string | null;\n grants: string[];\n}\n\nexport interface RolesDoc {\n roles?: RoleRow[] | null;\n}\n\n/**\n * `req.user` as Payload hands it over. Structural so this module never\n * imports a site's generated `User`. `roles` is optional because a row\n * that predates the field must come back powerless.\n */\nexport type MaybeUser = { id?: string | number; roles?: readonly string[] | null } | null | undefined;\n\nexport function isRole(value: unknown): value is Role {\n return typeof value === \"string\" && (ROLES as readonly string[]).includes(value);\n}\n\n/** Lowercase slug from a letters-and-spaces name: `designer`, `the-designer`. */\nexport function isRoleSlug(value: unknown): value is string {\n return typeof value === \"string\" && /^[a-z]+(-[a-z]+)*$/.test(value);\n}\n\n/** Display name: letters and single spaces only. `The Greatest Designer`. */\nexport function isRoleName(value: unknown): value is string {\n return typeof value === \"string\" && /^[A-Za-z]+(?: [A-Za-z]+)*$/.test(value.trim());\n}\n\n/** Strip digits and punctuation as the name is typed. Trailing space stays. */\nexport function sanitizeRoleNameInput(value: string): string {\n return value.replace(/[^A-Za-z ]/g, \"\").replace(/ {2,}/g, \" \");\n}\n\n/** Name → stored key. `The Greatest Designer` → `the-greatest-designer`. */\nexport function slugifyRoleName(value: unknown): string {\n if (typeof value !== \"string\") return \"\";\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nexport function roleLabel(role: string, label?: string | null): string {\n const trimmed = typeof label === \"string\" ? label.trim() : \"\";\n if (trimmed) return trimmed;\n return isRole(role) ? ROLE_LABELS[role] : role;\n}\n\nexport function defaultGrantsForRole(role: string, extraGrants?: readonly string[]): string[] {\n if (isRole(role)) return [...DEFAULT_ROLE_GRANTS[role]];\n return extraGrants ? [...extraGrants] : [];\n}\n","import { packageFeatureLabel } from \"../features/matrix\";\nimport { isFeatureSlug } from \"../features/types\";\nimport {\n CAPABILITY_FEATURES,\n defaultGrantsForRole,\n isRole,\n isRoleName,\n isRoleSlug,\n ROLE_LABELS,\n roleLabel,\n ROLES,\n slugifyRoleName,\n THEME_FEATURE_SLUGS,\n type Capability,\n type RoleExtra,\n type RoleRow,\n} from \"./types\";\n\nexport const ROLES_SLUG = \"roles\";\n\nexport const ROLES_GLOBAL_DESCRIPTION = \"Who may do what. Drag to change rank.\";\n\nexport const ROLES_FIELD_DESCRIPTION =\n \"Drag to change rank. Ticks are features released on Features. Developer has the whole catalogue.\"\n\n/**\n * Default rank and grants. Developer is implicit (empty grants). Brand\n * screens default to Designer. The API tab is not granted until released.\n */\nexport const DEFAULT_ROLE_MATRIX: readonly RoleRow[] = ROLES.map((role) => ({\n role,\n grants: defaultGrantsForRole(role),\n}));\n\nexport const DEVELOPER_DESCRIPTION =\n \"Everything, including features not released for assignment.\";\n\nexport const LAST_USERS_TICK_MESSAGE =\n \"Keep Users granted on at least one of Admin or Developer.\";\n\nexport const MISSING_SEED_ROLES_MESSAGE = \"Roles must include Developer, Admin, Designer, and Author.\";\n\nexport const DUPLICATE_ROLE_SLUG_MESSAGE = \"Each role needs a unique slug.\";\n\nexport const DUPLICATE_ROLE_NAME_MESSAGE = \"Each role needs a unique name.\";\n\nexport const INVALID_ROLE_NAME_MESSAGE = \"Use letters and spaces only.\";\n\nfunction uniqueSlugs(values: readonly unknown[]): string[] {\n const slugs: string[] = [];\n for (const value of values) {\n if (typeof value === \"string\" && isFeatureSlug(value) && !slugs.includes(value)) slugs.push(value);\n }\n return slugs;\n}\n\n/** Read stored grants, or rebuild them from the old capability ticks. */\nexport function grantsFromStoredRole(item: object): string[] {\n if (\"grants\" in item && Array.isArray(item.grants)) return uniqueSlugs(item.grants);\n const grants: string[] = [];\n if (\"content\" in item && item.content) {\n grants.push(\"content\", \"media\");\n }\n if (\"publish\" in item && item.publish) grants.push(\"publish\");\n if (\"users\" in item && item.users) grants.push(\"users\", \"roles\");\n if (\"brand\" in item && item.brand) grants.push(...THEME_FEATURE_SLUGS);\n return uniqueSlugs(grants);\n}\n\nexport function seedRoleRows(extras: readonly RoleExtra[] = []): RoleRow[] {\n return [\n ...DEFAULT_ROLE_MATRIX.map((row) => ({\n ...row,\n grants: [...row.grants],\n label: isRole(row.role) ? ROLE_LABELS[row.role] : row.role,\n })),\n ...extras.map((extra) => ({\n role: extra.role,\n label: extra.label,\n grants: extra.grants ? [...extra.grants] : [],\n })),\n ];\n}\n\nexport function defaultRolesFieldValue(extras: readonly RoleExtra[] = []): RoleRow[] {\n return seedRoleRows(extras).map((row) => ({ id: row.role, ...row }));\n}\n\nfunction readRoleRow(item: object): RoleRow | { error: string } {\n const role = \"role\" in item ? item.role : undefined;\n if (typeof role !== \"string\" || role.trim() === \"\") return { error: DUPLICATE_ROLE_SLUG_MESSAGE };\n if (!isRoleSlug(role)) return { error: DUPLICATE_ROLE_SLUG_MESSAGE };\n const label = \"label\" in item && typeof item.label === \"string\" ? item.label : undefined;\n return {\n id: role,\n role,\n label: roleLabel(role, label),\n grants: grantsFromStoredRole(item),\n };\n}\n\nexport function parseRolesMatrix(\n value: unknown,\n): { ok: true; rows: RoleRow[] } | { ok: false; message: string } {\n if (!Array.isArray(value)) {\n return { ok: false, message: MISSING_SEED_ROLES_MESSAGE };\n }\n\n const rows: RoleRow[] = [];\n const seen = new Set<string>();\n for (const item of value) {\n if (!item || typeof item !== \"object\") continue;\n // An Add Role row starts with no slug. Skip it so form-state can\n // build the fields; the slug field still refuses an empty save.\n const role = \"role\" in item ? item.role : undefined;\n if (typeof role !== \"string\" || role.trim() === \"\") continue;\n const parsed = readRoleRow(item);\n if (\"error\" in parsed) return { ok: false, message: parsed.error };\n if (seen.has(parsed.role)) return { ok: false, message: DUPLICATE_ROLE_SLUG_MESSAGE };\n seen.add(parsed.role);\n rows.push(parsed);\n }\n\n if (ROLES.some((role) => !seen.has(role))) {\n return { ok: false, message: MISSING_SEED_ROLES_MESSAGE };\n }\n return { ok: true, rows };\n}\n\nexport function roleHasGrant(row: RoleRow, slug: string): boolean {\n if (row.role === \"developer\") return true;\n return row.grants.includes(slug);\n}\n\nexport function roleHasCapability(row: RoleRow, capability: Capability): boolean {\n if (row.role === \"developer\") return true;\n return CAPABILITY_FEATURES[capability].some((slug) => row.grants.includes(slug));\n}\n\n/**\n * Mint a slug from the name only when the row has none yet. An existing\n * key — seed or custom — stays put so a rename cannot orphan users.\n */\nexport function applyRoleSlugsFromNames(value: unknown): unknown {\n if (!Array.isArray(value)) return value;\n return value.map((item) => {\n if (!item || typeof item !== \"object\") return item;\n const row = item as RoleRow;\n if (isRoleSlug(row.role)) return item;\n const slug = slugifyRoleName(row.label);\n return isRoleSlug(slug) ? { ...row, role: slug } : item;\n });\n}\n\nfunction hasDuplicateRoleNames(value: unknown): boolean {\n if (!Array.isArray(value)) return false;\n const seen = new Set<string>();\n for (const item of value) {\n if (!item || typeof item !== \"object\") continue;\n const role = \"role\" in item && typeof item.role === \"string\" ? item.role : \"\";\n const raw = \"label\" in item && typeof item.label === \"string\" ? item.label : \"\";\n const name = raw.trim() || (isRole(role) ? ROLE_LABELS[role] : \"\");\n if (!name) continue;\n const key = name.toLowerCase();\n if (seen.has(key)) return true;\n seen.add(key);\n }\n return false;\n}\n\nfunction hasInvalidRoleName(value: unknown): boolean {\n if (!Array.isArray(value)) return false;\n for (const item of value) {\n if (!item || typeof item !== \"object\") continue;\n const label = \"label\" in item && typeof item.label === \"string\" ? item.label.trim() : \"\";\n if (!label) continue;\n if (!isRoleName(label)) return true;\n }\n return false;\n}\n\nexport function validateRolesMatrix(value: unknown): true | string {\n if (hasDuplicateRoleNames(value)) return DUPLICATE_ROLE_NAME_MESSAGE;\n if (hasInvalidRoleName(value)) return INVALID_ROLE_NAME_MESSAGE;\n const parsed = parseRolesMatrix(applyRoleSlugsFromNames(value));\n if (!parsed.ok) return parsed.message;\n return true;\n}\n\n/**\n * Developer is exclusive. Admin does not swallow Designer: both store.\n * Unknown slugs (dropped catalogue keys such as `approver`) fall away unless\n * they appear on the matrix.\n */\nexport function normalizeStoredRoles(\n value: unknown,\n matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX,\n): string[] {\n if (!Array.isArray(value)) return [];\n const allowed = new Set(matrix.map((row) => row.role));\n const roles = [...new Set(value.filter((entry): entry is string => typeof entry === \"string\" && allowed.has(entry)))];\n if (roles.includes(\"developer\")) return [\"developer\"];\n return roles;\n}\n\nexport function roleSelectOptions(matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX) {\n return matrix.map((row) => ({ label: roleLabel(row.role, row.label), value: row.role }));\n}\n\n/** Grant copy only. Developer names the unreleased catalogue; nothing about MCP or seed. */\nexport function roleDescription(role: string, matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX): string {\n if (role === \"developer\") return DEVELOPER_DESCRIPTION;\n const row = matrix.find((entry) => entry.role === role);\n if (!row) return \"No capabilities\";\n const ticks = row.grants.map((slug) => packageFeatureLabel(slug));\n return ticks.join(\", \") || \"No capabilities\";\n}\n\n/**\n * Seed grants and package labels come back; extra rows stay as they are.\n */\nexport function resetRolesMatrix(current: unknown): RoleRow[] {\n const extras: RoleRow[] = [];\n if (Array.isArray(current)) {\n for (const item of current) {\n if (!item || typeof item !== \"object\") continue;\n const parsed = readRoleRow(item);\n if (\"error\" in parsed || isRole(parsed.role)) continue;\n extras.push(parsed);\n }\n }\n return [...defaultRolesFieldValue(), ...extras];\n}\n","import type { Access, PayloadRequest } from \"payload\";\n\nimport { DEFAULT_ROLE_MATRIX, parseRolesMatrix, roleHasCapability, roleHasGrant, ROLES_SLUG, seedRoleRows } from \"./matrix\";\nimport { type Capability, type MaybeUser, type RoleExtra, type RoleRow } from \"./types\";\n\nexport type { MaybeUser } from \"./types\";\n\ntype AccessArgs = {\n req: {\n user?: MaybeUser;\n payload?: Pick<NonNullable<PayloadRequest[\"payload\"]>, \"findGlobal\">;\n };\n};\n\ntype CapabilityPredicate = {\n (user: MaybeUser, matrix?: readonly RoleRow[]): boolean;\n (args: AccessArgs): boolean | Promise<boolean>;\n};\n\nfunction isAccessArgs(value: unknown): value is AccessArgs {\n return typeof value === \"object\" && value !== null && \"req\" in value;\n}\n\nexport function storedRoles(user: MaybeUser): readonly string[] {\n return Array.isArray(user?.roles) ? user.roles : [];\n}\n\nexport function hasRole(user: MaybeUser, role: string): boolean {\n return storedRoles(user).includes(role);\n}\n\n/** Not a tick. True only when `developer` is stored on the row. */\nexport function isDeveloper(user: MaybeUser): boolean {\n return hasRole(user, \"developer\");\n}\n\nexport function hasCapability(\n user: MaybeUser,\n capability: Capability,\n matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX,\n): boolean {\n if (isDeveloper(user)) return true;\n return storedRoles(user).some((role) => {\n const row = matrix.find((entry) => entry.role === role);\n return row ? roleHasCapability(row, capability) : false;\n });\n}\n\nexport function hasGrant(\n user: MaybeUser,\n slug: string,\n matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX,\n): boolean {\n if (isDeveloper(user)) return true;\n return storedRoles(user).some((role) => {\n const row = matrix.find((entry) => entry.role === role);\n return row ? roleHasGrant(row, slug) : false;\n });\n}\n\n/**\n * Reads the saved Roles Global, falling back to the seed when the row is\n * empty, missing, or unreadable. Always override-access so a Designer\n * evaluating Theme does not have to read Settings → Roles.\n */\nexport async function getRolesMatrix(\n req: AccessArgs[\"req\"] = {},\n extras: readonly RoleExtra[] = [],\n): Promise<RoleRow[]> {\n const fallback = seedRoleRows(extras);\n const findGlobal = req.payload?.findGlobal;\n if (typeof findGlobal !== \"function\") return fallback;\n try {\n const doc = await findGlobal({\n slug: ROLES_SLUG,\n overrideAccess: true,\n req: req as PayloadRequest,\n });\n const parsed = parseRolesMatrix(doc && typeof doc === \"object\" && \"roles\" in doc ? doc.roles : undefined);\n return parsed.ok ? parsed.rows : fallback;\n } catch {\n return fallback;\n }\n}\n\nfunction capabilityPredicate(capability: Capability): CapabilityPredicate {\n function predicate(\n userOrArgs: MaybeUser | AccessArgs,\n matrix?: readonly RoleRow[],\n ): boolean | Promise<boolean> {\n if (isAccessArgs(userOrArgs)) {\n const user = userOrArgs.req.user as MaybeUser;\n if (matrix) return hasCapability(user, capability, matrix);\n return getRolesMatrix(userOrArgs.req).then((rows) => hasCapability(user, capability, rows));\n }\n return hasCapability(userOrArgs, capability, matrix ?? DEFAULT_ROLE_MATRIX);\n }\n return predicate as CapabilityPredicate;\n}\n\nexport const canManageContent = capabilityPredicate(\"content\");\nexport const canManageBrand = capabilityPredicate(\"brand\");\nexport const canPublish = capabilityPredicate(\"publish\");\n\n/** Users grant on any held role (Developer is implicit). */\nexport const isAdmin = capabilityPredicate(\"users\");\n\n/** This role id currently has the Users grant, or is Developer. */\nexport function isPrivilegedRole(\n role: unknown,\n matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX,\n): boolean {\n if (typeof role !== \"string\") return false;\n if (role === \"developer\") return true;\n const row = matrix.find((entry) => entry.role === role);\n return row ? roleHasGrant(row, \"users\") : false;\n}\n\nexport function isAuthenticated(user: MaybeUser): boolean;\nexport function isAuthenticated(args: AccessArgs): boolean;\nexport function isAuthenticated(userOrArgs: MaybeUser | AccessArgs): boolean {\n if (isAccessArgs(userOrArgs)) return Boolean(userOrArgs.req.user);\n return Boolean(userOrArgs);\n}\n\nexport const isAdminOrSelf: Access = async ({ req }) => {\n if (!req.user) return false;\n if (await isAdmin({ req })) return true;\n return { id: { equals: req.user.id } };\n};\n\nexport const authenticatedOrPublished: Access = ({ req: { user } }) => {\n if (isAuthenticated(user as MaybeUser)) return true;\n return { _status: { equals: \"published\" } };\n};\n\n/**\n * API tab condition. Unreleased (the default) is Developer only.\n * After Features releases it, whoever holds the grant sees it.\n */\nexport function isDeveloperTab({ req }: AccessArgs): boolean | Promise<boolean> {\n if (isDeveloper(req.user as MaybeUser)) return true;\n if (!req.payload) return false;\n // Dynamic import avoids a cycle: features/access reads this module.\n return import(\"../features/access\").then(({ canUseFeature }) => canUseFeature(\"api-tab\")({ req }));\n}\n","import type { PayloadRequest } from \"payload\";\n\nimport { getRolesMatrix, hasGrant, isDeveloper, type MaybeUser } from \"../roles/access\";\nimport { DEFAULT_ROLE_MATRIX } from \"../roles/matrix\";\nimport type { RoleRow } from \"../roles/types\";\nimport { defaultFeaturesFieldValue, isGroupOnlySlug, parseFeaturesMatrix } from \"./matrix\";\nimport { FEATURES_SLUG, type FeatureRow } from \"./types\";\n\ntype AccessArgs = {\n req: {\n user?: MaybeUser;\n payload?: Pick<NonNullable<PayloadRequest[\"payload\"]>, \"findGlobal\">;\n };\n};\n\ntype FeaturePredicate = {\n (user: MaybeUser, features?: readonly FeatureRow[] | null, roles?: readonly RoleRow[]): boolean;\n (args: AccessArgs): boolean | Promise<boolean>;\n};\n\nfunction isAccessArgs(value: unknown): value is AccessArgs {\n return typeof value === \"object\" && value !== null && \"req\" in value;\n}\n\nfunction grantedOnReleased(\n user: MaybeUser,\n slug: string,\n row: FeatureRow,\n matrix: readonly RoleRow[],\n): boolean {\n if (!row.released) return false;\n return hasGrant(user, slug, matrix);\n}\n\n/**\n * True when the feature is released and a held role is granted it.\n * Developer is always allowed. An empty Global falls back to catalogue\n * defaults. A group slug (`pages`, `theme`) is true when any child is.\n */\nexport function hasFeature(\n user: MaybeUser,\n slug: string,\n features: readonly FeatureRow[] | null = null,\n matrix: readonly RoleRow[] = DEFAULT_ROLE_MATRIX,\n): boolean {\n if (isDeveloper(user)) return true;\n if (!user) return false;\n const rows = features && features.length > 0 ? features : defaultFeaturesFieldValue();\n const leaf = rows.find((entry) => entry.slug === slug);\n if (leaf) return grantedOnReleased(user, slug, leaf, matrix);\n if (!isGroupOnlySlug(slug)) return false;\n return rows.some((entry) => entry.group === slug && grantedOnReleased(user, entry.slug, entry, matrix));\n}\n\n/**\n * Reads the saved Features Global. `null` means empty or unreadable — callers\n * fall back to catalogue defaults. Always override-access.\n */\nexport async function getFeaturesMatrix(req: AccessArgs[\"req\"] = {}): Promise<FeatureRow[] | null> {\n const findGlobal = req.payload?.findGlobal;\n if (typeof findGlobal !== \"function\") return null;\n try {\n const doc = await findGlobal({\n slug: FEATURES_SLUG,\n overrideAccess: true,\n req: req as PayloadRequest,\n });\n const parsed = parseFeaturesMatrix(\n doc && typeof doc === \"object\" && \"features\" in doc ? doc.features : undefined,\n );\n return parsed.ok ? parsed.rows : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Access / nav helper for one catalogue slug. Sync against a passed grid;\n * async when given `req` so it can read both Globals.\n */\nexport function canUseFeature(slug: string): FeaturePredicate {\n function predicate(\n userOrArgs: MaybeUser | AccessArgs,\n features?: readonly FeatureRow[] | null,\n roles?: readonly RoleRow[],\n ): boolean | Promise<boolean> {\n if (isAccessArgs(userOrArgs)) {\n const user = userOrArgs.req.user as MaybeUser;\n if (features !== undefined) return hasFeature(user, slug, features, roles ?? DEFAULT_ROLE_MATRIX);\n return Promise.all([getFeaturesMatrix(userOrArgs.req), getRolesMatrix(userOrArgs.req)]).then(\n ([grid, matrix]) => hasFeature(user, slug, grid, matrix),\n );\n }\n return hasFeature(userOrArgs, slug, features ?? null, roles ?? DEFAULT_ROLE_MATRIX);\n }\n return predicate as FeaturePredicate;\n}\n\n/** `admin.hidden`: hide when the login cannot use the feature. */\nexport function hideUnlessFeature(slug: string) {\n return (args: { user?: MaybeUser; req?: AccessArgs[\"req\"] }) => {\n const user = args.user;\n if (args.req) {\n const result = canUseFeature(slug)({ req: { ...args.req, user } });\n if (result instanceof Promise) return result.then((ok) => !ok);\n return !result;\n }\n return !canUseFeature(slug)(user ?? null);\n };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"identity-Dwyq8519.mjs","names":[],"sources":["../src/theme/fields.ts","../src/theme/map.ts","../src/theme/types.ts","../src/theme/library.ts","../src/theme/color-tokens.ts","../src/theme/looks.ts","../src/theme/look-field.ts","../src/theme/identity.ts"],"sourcesContent":["import type { ThemeConfig } from \"@bison-lab/tokens\";\n\nimport type { EditableTheme } from \"./types\";\n\nexport const THEME_COLOR_FIELD = \"@bison-lab/payload-core/admin#ColorField\";\nexport const THEME_COLOR_SCALE_FIELD = \"@bison-lab/payload-core/admin#ColorScaleField\";\nexport const THEME_LIBRARY_FIELD = \"@bison-lab/payload-core/admin#LibraryField\";\nexport const THEME_FONT_FIELD = \"@bison-lab/payload-core/admin#FontField\";\nexport const THEME_PAIRING_FIELD = \"@bison-lab/payload-core/admin#PairingField\";\nexport const THEME_APPEARANCE_FIELD = \"@bison-lab/payload-core/admin#AppearanceField\";\nexport const THEME_GREY_SCALE_FIELD = \"@bison-lab/payload-core/admin#GreyScaleField\";\nexport const THEME_CONTRAST_REPORT = \"@bison-lab/payload-core/admin#ContrastReport\";\nexport const THEME_SECTION_HEADING = \"@bison-lab/payload-core/admin#SectionHeading\";\nexport const THEME_PUBLISH_FIELD = \"@bison-lab/payload-core/admin#PublishChild\";\nexport const THEME_SAVE_BUTTON = \"@bison-lab/payload-core/admin#HiddenSaveButton\";\nexport const THEME_DOCUMENT_CONTROLS = \"@bison-lab/payload-core/admin#ThemeDocumentControls\";\nexport const THEME_IDENTITY_FALLBACK = \"@bison-lab/payload-core/admin#IdentityFallback\";\nexport const LOOK_FIELD = \"@bison-lab/payload-core/admin#LookField\";\n\n/**\n * Document path for each editable `ThemeConfig` key. Locked with `satisfies`\n * so a new config field without a Theme field (or the reverse) fails at\n * compile time. `darkSelector` and `fontWeights` are seed-only.\n */\nexport const THEME_FIELD_PATHS = {\n brandPrimary: \"colors.brand.primary.hex\",\n brandSecondary: \"colors.brand.secondary.hex\",\n brandAccent: \"colors.brand.accent.hex\",\n brandHighlight: \"colors.brand.highlight.hex\",\n brandSuccess: \"colors.brand.success.hex\",\n brandDestructive: \"colors.brand.destructive.hex\",\n greyScale: \"colors.greyScale\",\n defaultTheme: \"appearance.defaultTheme\",\n radius: \"appearance.radius\",\n shadow: \"appearance.shadow\",\n motion: \"appearance.motion\",\n density: \"appearance.density\",\n fontBody: \"typography.body\",\n fontHeading: \"typography.heading\",\n} as const satisfies Record<keyof EditableTheme, string>;\n\nexport type ThemeFieldPath = (typeof THEME_FIELD_PATHS)[keyof typeof THEME_FIELD_PATHS];\n\n/** Empty select value for heading: same family as body. */\nexport const SAME_AS_BODY = \"\";\n\nexport function headingSelectValue(heading: ThemeConfig[\"fontHeading\"]): string {\n return heading ?? SAME_AS_BODY;\n}\n","import {\n createColorScale,\n DESTRUCTIVE_SCALE_HEX,\n generateColorScale,\n isThemeHex,\n SHADE_STEPS,\n type ColorScale,\n type ColorScaleInclude,\n type ColorScaleState,\n type ShadeStep,\n type ThemeConfig,\n} from \"@bison-lab/tokens\";\n\nimport { SAME_AS_BODY } from \"./fields\";\nimport type { ThemeColorDoc, ThemeDoc } from \"./types\";\n\nfunction pick<T>(value: T | null | undefined, fallback: T): T {\n return value == null ? fallback : value;\n}\n\nfunction headingFromDoc(\n heading: string | null | undefined,\n seed: ThemeConfig[\"fontHeading\"],\n): string | null {\n if (heading === undefined) return seed;\n if (heading === null || heading === SAME_AS_BODY) return null;\n return heading;\n}\n\nfunction hexFromColor(value: ThemeColorDoc | string | null | undefined, fallback: string): string {\n if (typeof value === \"string\") return value || fallback;\n return pick(value?.hex, fallback);\n}\n\nexport function colorDocFromHex(hex: string, sourceStep: ShadeStep = 500): ThemeColorDoc {\n return colorDocFromState(createColorScale(hex, sourceStep));\n}\n\nexport function colorDocFromState(state: ColorScaleState): ThemeColorDoc {\n return {\n hex: state.hex,\n sourceStep: state.sourceStep,\n scale: state.scale,\n stale: state.stale,\n include: Array.isArray(state.include) ? \"custom\" : state.include,\n includedSteps: Array.isArray(state.include) ? [...state.include] : undefined,\n };\n}\n\nexport function stateFromColorDoc(\n doc: ThemeColorDoc | null | undefined,\n fallbackHex = \"#000000\",\n): ColorScaleState {\n const hex = isThemeHex(doc?.hex) ? doc.hex : fallbackHex;\n const sourceStep = (Number(doc?.sourceStep) || 500) as ShadeStep;\n const include = includeFromDoc(doc, sourceStep);\n const scale =\n doc?.scale && typeof doc.scale === \"object\" ? (doc.scale as ColorScale) : generateColorScale(hex, sourceStep);\n return { hex, sourceStep, scale, stale: Boolean(doc?.stale), include };\n}\n\nfunction includeFromDoc(doc: ThemeColorDoc | null | undefined, sourceStep: ShadeStep): ColorScaleInclude {\n if (doc?.include === \"source\") return \"source\";\n if (doc?.include === \"custom\" && Array.isArray(doc.includedSteps)) {\n const steps = doc.includedSteps.map(Number).filter((step): step is ShadeStep => SHADE_STEPS.includes(step as ShadeStep));\n if (!steps.includes(sourceStep)) steps.push(sourceStep);\n return steps;\n }\n return \"all\";\n}\n\n/**\n * Nested Theme document → flat `ThemeConfig`. Null or missing editor\n * fields take the seed; `darkSelector` and `fontWeights` always come from\n * the seed. Reads the BIS-87 groups and the pre-BIS-87 flat fields.\n */\nexport function themeConfigFromDoc(doc: ThemeDoc | null | undefined, seed: ThemeConfig): ThemeConfig {\n const brand = doc?.colors?.brand ?? doc?.brand;\n const typography = doc?.typography ?? doc?.fonts;\n const appearance = doc?.appearance;\n return {\n brandPrimary: hexFromColor(brand?.primary, seed.brandPrimary),\n brandSecondary: hexFromColor(brand?.secondary, seed.brandSecondary),\n brandAccent: hexFromColor(brand?.accent, seed.brandAccent),\n brandHighlight: hexFromColor(brand?.highlight, seed.brandHighlight),\n brandSuccess: hexFromColor(brand?.success, seed.brandSuccess),\n brandDestructive:\n hexFromColor(brand?.destructive, seed.brandDestructive ?? DESTRUCTIVE_SCALE_HEX) ||\n seed.brandDestructive ||\n DESTRUCTIVE_SCALE_HEX,\n greyScale: pick(doc?.colors?.greyScale ?? doc?.greyScale, seed.greyScale),\n radius: pick(appearance?.radius ?? doc?.radius, seed.radius),\n shadow: pick(appearance?.shadow ?? doc?.shadow, seed.shadow),\n motion: pick(appearance?.motion ?? doc?.motion, seed.motion),\n density: pick(appearance?.density ?? doc?.density, seed.density),\n defaultTheme: pick(appearance?.defaultTheme ?? doc?.defaultTheme, seed.defaultTheme),\n fontBody: pick(typography?.body, seed.fontBody),\n fontHeading: headingFromDoc(typography?.heading, seed.fontHeading),\n darkSelector: seed.darkSelector,\n fontWeights: seed.fontWeights,\n };\n}\n\n/** The document `seedTheme` writes so a fresh Global matches the seed config. */\nexport function docFromConfig(config: ThemeConfig, destructive?: string): ThemeDoc {\n const destructiveHex = destructive ?? config.brandDestructive ?? DESTRUCTIVE_SCALE_HEX;\n return {\n colors: {\n brand: {\n primary: colorDocFromHex(config.brandPrimary),\n secondary: colorDocFromHex(config.brandSecondary),\n accent: colorDocFromHex(config.brandAccent),\n highlight: colorDocFromHex(config.brandHighlight),\n success: colorDocFromHex(config.brandSuccess),\n destructive: colorDocFromHex(destructiveHex),\n },\n library: [],\n greyScale: config.greyScale,\n },\n typography: {\n body: config.fontBody,\n heading: config.fontHeading,\n },\n appearance: {\n defaultTheme: config.defaultTheme,\n radius: config.radius,\n shadow: config.shadow,\n motion: config.motion,\n density: config.density,\n },\n };\n}\n\nexport function validateThemeHex(value: unknown): true | string {\n if (!isThemeHex(value)) return \"Enter a six-digit hex colour like #1e3a5f\";\n return true;\n}\n\nexport function validateSourceIncluded(\n value: unknown,\n { siblingData }: { siblingData?: { sourceStep?: unknown; include?: unknown } },\n): true | string {\n const include = siblingData?.include;\n if (include === \"all\" || include === \"source\") return true;\n const source = Number(siblingData?.sourceStep);\n const steps = Array.isArray(value) ? value.map(Number) : [];\n if (!SHADE_STEPS.includes(source as ShadeStep)) return true;\n if (!steps.includes(source)) return \"The source step cannot be excluded\";\n return true;\n}\n","import type { Access } from \"payload\";\nimport type { FontEntry } from \"@bison-lab/fonts\";\nimport type { ColorScale, ColorScaleInclude, ShadeStep, ThemeConfig } from \"@bison-lab/tokens\";\n\nimport type { ResolvedThemeIdentity, ThemeIdentityFallback } from \"./identity\";\n\n/**\n * The Theme document a site's generated types will describe. Optional and\n * nullable, no index signature: a generated Global is assignable to this,\n * never the reverse.\n *\n * Legacy flat `brand.*` hexes, `fonts`, and preset fields at the root stay\n * readable so `getPublishedTheme` still maps a pre-BIS-87 row.\n */\nexport interface ThemeColorDoc {\n hex?: string | null;\n sourceStep?: ShadeStep | string | null;\n scale?: ColorScale | null;\n stale?: boolean | null;\n include?: ColorScaleInclude | \"custom\" | null;\n includedSteps?: ShadeStep[] | string[] | null;\n}\n\nexport interface ThemeLibraryColorDoc extends ThemeColorDoc {\n key?: string | null;\n label?: string | null;\n}\n\nexport interface ThemeDoc {\n colors?: {\n brand?: {\n primary?: ThemeColorDoc | string | null;\n secondary?: ThemeColorDoc | string | null;\n accent?: ThemeColorDoc | string | null;\n highlight?: ThemeColorDoc | string | null;\n success?: ThemeColorDoc | string | null;\n destructive?: ThemeColorDoc | string | null;\n } | null;\n library?: ThemeLibraryColorDoc[] | null;\n greyScale?: ThemeConfig[\"greyScale\"] | null;\n } | null;\n typography?: {\n body?: string | null;\n heading?: string | null;\n } | null;\n appearance?: {\n defaultTheme?: ThemeConfig[\"defaultTheme\"] | null;\n radius?: ThemeConfig[\"radius\"] | null;\n shadow?: ThemeConfig[\"shadow\"] | null;\n motion?: ThemeConfig[\"motion\"] | null;\n density?: ThemeConfig[\"density\"] | null;\n } | null;\n /** @deprecated Pre-BIS-87 flat brand hexes. */\n brand?: {\n primary?: ThemeColorDoc | string | null;\n secondary?: ThemeColorDoc | string | null;\n accent?: ThemeColorDoc | string | null;\n highlight?: ThemeColorDoc | string | null;\n success?: ThemeColorDoc | string | null;\n destructive?: ThemeColorDoc | string | null;\n } | null;\n /** @deprecated Pre-BIS-87; now `colors.greyScale`. */\n greyScale?: ThemeConfig[\"greyScale\"] | null;\n /** @deprecated Pre-BIS-87; now `appearance.*`. */\n radius?: ThemeConfig[\"radius\"] | null;\n shadow?: ThemeConfig[\"shadow\"] | null;\n motion?: ThemeConfig[\"motion\"] | null;\n density?: ThemeConfig[\"density\"] | null;\n defaultTheme?: ThemeConfig[\"defaultTheme\"] | null;\n /** @deprecated Pre-BIS-87; now `typography`. */\n fonts?: {\n body?: string | null;\n heading?: string | null;\n } | null;\n logo?: number | string | ThemeUploadDoc | null;\n favicon?: number | string | ThemeUploadDoc | null;\n logoMark?: number | string | ThemeUploadDoc | null;\n}\n\nexport interface ThemeUploadDoc {\n id?: number | string | null;\n url?: string | null;\n alt?: string | null;\n}\n\n/**\n * What an editor can change. `darkSelector` and `fontWeights` stay on the\n * seed — they mean nothing in the admin — and `themeConfigFromDoc` puts\n * them back.\n */\nexport type EditableTheme = Omit<ThemeConfig, \"darkSelector\" | \"fontWeights\">;\n\nexport interface CreateThemeOptions {\n /**\n * Required, no default. Pass `canManageBrand` as `update` (and typically\n * `isAuthenticated` as `read`). Theme does not read the Roles Global.\n */\n access: { read: Access; update: Access };\n /** The site's `bison.config.json`. Every field's `defaultValue`, and the fallback `getPublishedTheme` returns. */\n seed: ThemeConfig;\n /**\n * Destructive seed hex. Falls back to `seed.brandDestructive`, then\n * the library's `DESTRUCTIVE_SCALE_HEX` (`#ef4444`).\n */\n destructive?: string;\n /** Default: the whole catalogue. */\n fonts?: readonly FontEntry[];\n /** Where the site's `serveFont` route answers, for the picker's specimens. Default `\"/fonts\"`. */\n fontsBaseUrl?: string;\n /** Fill + automatic label target. Default `7`. Warnings never block save. */\n contrastTarget?: number;\n /**\n * @deprecated Theme has no preview pane (SPI-56 canceled). Kept so a\n * site that still passes it does not fail to boot.\n */\n previewPath?: string;\n /**\n * Adds the Identity page (logo, favicon, mobile-menu mark) when given.\n * Pass `BRAND_ASSETS_SLUG` (or the slug you gave `createBrandAssets`).\n * Save on that page writes only those uploads onto the stored Theme row.\n */\n logo?: { collection: string };\n /**\n * Fallback art when logo, favicon, or mobile-menu mark is empty. The\n * site passes today's files; `--color-primary-mark` is not a Theme field.\n */\n identity?: { fallback?: ThemeIdentityFallback };\n /** Fires from `afterChange` on every save — Theme has no draft mode. */\n onPublish?: (theme: ThemeConfig, doc: ThemeDoc) => void | Promise<void>;\n /**\n * Slugs that store `lookField` / `colorTokenField` values. Colors\n * Delete scans these (drafts included) before dropping a custom row.\n * Omit or pass empty: every additional color is unused and deletes\n * immediately. A new look surface is added here, not copied into a\n * site helper — site adopt names the slugs (SPI-93).\n */\n colorUsages?: {\n collections?: string[];\n globals?: string[];\n };\n}\n\nexport interface ThemeHeadOptions {\n fontsBaseUrl?: string;\n attribute?: \"class\" | \"data-theme\";\n identity?: ResolvedThemeIdentity;\n /**\n * Custom Colors rows. `themeHead` emits their 50–950 variables and\n * `[data-look]` bindings so a picker key paints without a package bump.\n */\n library?: ThemeLibraryColorDoc[] | null;\n}\n\nexport interface ThemeHead {\n css: string;\n preloads: { href: string; type: \"font/woff2\" }[];\n identity?: ResolvedThemeIdentity;\n}\n\nexport const THEME_SLUG = \"theme\";\nexport const THEME_COLORS_SLUG = \"theme-colors\";\nexport const THEME_TYPOGRAPHY_SLUG = \"theme-typography\";\nexport const THEME_APPEARANCE_SLUG = \"theme-appearance\";\nexport const THEME_IDENTITY_SLUG = \"theme-identity\";\n\nexport const SYSTEM_COLOR_KEYS = [\n \"primary\",\n \"secondary\",\n \"accent\",\n \"highlight\",\n \"success\",\n \"destructive\",\n] as const;\n\nexport type SystemColorKey = (typeof SYSTEM_COLOR_KEYS)[number];\n","import { SHADE_STEPS, type ShadeStep } from \"@bison-lab/tokens\";\n\nimport { SYSTEM_COLOR_KEYS, type ThemeDoc, type ThemeLibraryColorDoc } from \"./types\";\n\n/**\n * Payload's array form state stores the row count (`0`, `2`, …), not the\n * rows. A custom Field that treats that number as the list will throw\n * `rows.filter is not a function` on an empty Theme library.\n */\nexport function asLibraryRows(value: unknown): ThemeLibraryColorDoc[] {\n return Array.isArray(value) ? value : [];\n}\n\nconst STEP_SET = new Set<number>(SHADE_STEPS);\n\n/**\n * Page editors pick `coral-400`, never a raw hex. Rewrite every use of\n * `fromKey` onto `toKey` at the same step: `coral-400` → `highlight-400`.\n * A bare key (`coral`) becomes `toKey`. Anything else is left alone.\n */\nexport function rewriteColorToken(token: string, fromKey: string, toKey: string): string {\n if (token === fromKey) return toKey;\n const dash = token.lastIndexOf(\"-\");\n if (dash <= 0) return token;\n const key = token.slice(0, dash);\n const step = Number(token.slice(dash + 1));\n if (key !== fromKey || !STEP_SET.has(step)) return token;\n return `${toKey}-${step as ShadeStep}`;\n}\n\nexport function themeColorKeys(doc: ThemeDoc | null | undefined): string[] {\n const custom = asLibraryRows(doc?.colors?.library)\n .map((row) => row.key?.trim())\n .filter((key): key is string => Boolean(key));\n return [...SYSTEM_COLOR_KEYS, ...custom];\n}\n\n/**\n * Remove a custom color. Unused: omit `replacement` and the row is gone.\n * In use: pass another system or custom key; the caller rewrites page\n * tokens with `rewriteColorToken`. After this, no library row still\n * has `key`.\n */\nexport function deleteLibraryColor(doc: ThemeDoc, key: string, replacement?: string): ThemeDoc {\n const library = [...asLibraryRows(doc.colors?.library)];\n const index = library.findIndex((row) => row.key === key);\n if (index === -1) {\n throw new Error(`No custom color named ${JSON.stringify(key)}`);\n }\n library.splice(index, 1);\n const next: ThemeDoc = {\n ...doc,\n colors: { ...doc.colors, library },\n };\n if (replacement !== undefined) {\n if (replacement === key) {\n throw new Error(\"Replacement must be a different color\");\n }\n if (!themeColorKeys(next).includes(replacement)) {\n throw new Error(`Replacement ${JSON.stringify(replacement)} is not a system or remaining custom color`);\n }\n }\n return next;\n}\n","import { rewriteColorToken } from \"./library\";\n\nexport interface ColorTokenHit {\n path: string;\n token: string;\n}\n\n/**\n * A string `rewriteColorToken` would change: `coral`, `coral-400`.\n * `#FF5A2D` and `coral-ish` are not tokens.\n */\nexport function isColorToken(value: string, key: string): boolean {\n return rewriteColorToken(value, key, `\\0${key}`) !== value;\n}\n\nexport function findColorTokens(value: unknown, key: string): ColorTokenHit[] {\n const hits: ColorTokenHit[] = [];\n walk(value, \"\", (path, token) => {\n if (isColorToken(token, key)) hits.push({ path, token });\n });\n return hits;\n}\n\nexport function rewriteColorTokens<T>(value: T, fromKey: string, toKey: string): T {\n return rewriteValue(value, fromKey, toKey) as T;\n}\n\nfunction rewriteValue(value: unknown, fromKey: string, toKey: string): unknown {\n if (typeof value === \"string\") return rewriteColorToken(value, fromKey, toKey);\n if (Array.isArray(value)) return value.map((item) => rewriteValue(item, fromKey, toKey));\n if (value && typeof value === \"object\") {\n const next: Record<string, unknown> = {};\n for (const [name, child] of Object.entries(value)) {\n next[name] = rewriteValue(child, fromKey, toKey);\n }\n return next;\n }\n return value;\n}\n\nfunction walk(value: unknown, path: string, visit: (path: string, token: string) => void): void {\n if (typeof value === \"string\") {\n visit(path, value);\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => walk(item, join(path, String(index)), visit));\n return;\n }\n if (value && typeof value === \"object\") {\n for (const [name, child] of Object.entries(value)) {\n walk(child, join(path, name), visit);\n }\n }\n}\n\nfunction join(path: string, segment: string): string {\n return path ? `${path}.${segment}` : segment;\n}\n","import { includedShadeSteps, type ShadeStep } from \"@bison-lab/tokens\";\n\nimport { stateFromColorDoc } from \"./map\";\nimport { THEME_SLUG, type ThemeColorDoc, type ThemeDoc, type ThemeLibraryColorDoc } from \"./types\";\n\n/**\n * System colors Color Settings offers as page-editor fills. Success and\n * Destructive stay off this list — they are theme chrome only.\n */\nexport const PAGE_EDITOR_SYSTEM_KEYS = [\"primary\", \"secondary\", \"accent\", \"highlight\"] as const;\n\nexport type PageEditorSystemKey = (typeof PAGE_EDITOR_SYSTEM_KEYS)[number];\n\nexport interface LookOption {\n label: string;\n value: string;\n}\n\nconst SYSTEM_LABELS: Record<PageEditorSystemKey, string> = {\n primary: \"Primary\",\n secondary: \"Secondary\",\n accent: \"Accent\",\n highlight: \"Highlight\",\n};\n\nfunction brandColor(doc: ThemeDoc | null | undefined, key: PageEditorSystemKey): ThemeColorDoc | null {\n const brand = doc?.colors?.brand ?? doc?.brand;\n const value = brand?.[key];\n if (typeof value === \"string\" || value == null) return value == null ? null : { hex: value };\n return value;\n}\n\nexport function themeLibraryFromDoc(doc: ThemeDoc | null | undefined): ThemeLibraryColorDoc[] {\n return Array.isArray(doc?.colors?.library) ? doc.colors.library : [];\n}\n\nfunction libraryRows(doc: ThemeDoc | null | undefined): ThemeLibraryColorDoc[] {\n return themeLibraryFromDoc(doc);\n}\n\nfunction titleCase(key: string): string {\n return key.charAt(0).toUpperCase() + key.slice(1);\n}\n\nfunction stepsFor(color: ThemeColorDoc | null | undefined, fallbackHex: string): ShadeStep[] {\n return includedShadeSteps(stateFromColorDoc(color, fallbackHex));\n}\n\n/**\n * Family keys a `lookField()` may offer: the page-editor system scales\n * plus every custom color on Colors. Adding Coral on Theme makes `coral`\n * appear here with no `@bison-lab/*` release.\n */\nexport function pageEditorLooks(doc: ThemeDoc | null | undefined): LookOption[] {\n const system = PAGE_EDITOR_SYSTEM_KEYS.map((value) => ({\n label: SYSTEM_LABELS[value],\n value,\n }));\n const custom = libraryRows(doc)\n .map((row) => {\n const value = row.key?.trim();\n if (!value) return null;\n return { label: row.label?.trim() || titleCase(value), value };\n })\n .filter((option): option is LookOption => option !== null);\n return [...system, ...custom];\n}\n\n/**\n * Included steps as `coral-400`. Excluded steps do not appear. System\n * scales with no stored include list offer the full 50–950 ramp.\n */\nexport function pageEditorTokens(doc: ThemeDoc | null | undefined): LookOption[] {\n const tokens: LookOption[] = [];\n for (const key of PAGE_EDITOR_SYSTEM_KEYS) {\n const label = SYSTEM_LABELS[key];\n for (const step of stepsFor(brandColor(doc, key), \"#000000\")) {\n tokens.push({ label: `${label} ${step}`, value: `${key}-${step}` });\n }\n }\n for (const row of libraryRows(doc)) {\n const key = row.key?.trim();\n if (!key) continue;\n const label = row.label?.trim() || titleCase(key);\n for (const step of stepsFor(row, row.hex ?? \"#000000\")) {\n tokens.push({ label: `${label} ${step}`, value: `${key}-${step}` });\n }\n }\n return tokens;\n}\n\nexport async function themeDocFromRequest(req: {\n payload?: {\n findGlobal?: (args: {\n slug: string;\n depth?: number;\n overrideAccess?: boolean;\n }) => Promise<ThemeDoc | null | undefined>;\n };\n}): Promise<ThemeDoc | null> {\n try {\n const doc = await req.payload?.findGlobal?.({\n slug: THEME_SLUG,\n depth: 0,\n overrideAccess: true,\n });\n return doc ?? null;\n } catch {\n return null;\n }\n}\n","import type { StaticLabel, TextField, TextFieldSingleValidation } from \"payload\";\n\nimport { LOOK_FIELD } from \"./fields\";\nimport { pageEditorLooks, pageEditorTokens, themeDocFromRequest } from \"./looks\";\n\nexport interface LookFieldOptions {\n name?: string;\n label?: StaticLabel;\n required?: boolean;\n admin?: TextField[\"admin\"];\n validate?: TextFieldSingleValidation;\n}\n\nexport type LookFieldMode = \"look\" | \"token\";\n\nexport const validateLook: TextFieldSingleValidation = async (value, { req }) => {\n if (value == null || value === \"\") return true;\n if (typeof value !== \"string\") return \"Pick a look from Theme → Colors\";\n const doc = await themeDocFromRequest(req);\n if (pageEditorLooks(doc).some((look) => look.value === value)) return true;\n return \"Pick a look from Theme → Colors\";\n};\n\nexport const validateColorToken: TextFieldSingleValidation = async (value, { req }) => {\n if (value == null || value === \"\") return true;\n if (typeof value !== \"string\") return \"Pick an included step from Theme → Colors\";\n const doc = await themeDocFromRequest(req);\n if (pageEditorTokens(doc).some((token) => token.value === value)) return true;\n return \"Pick an included step from Theme → Colors\";\n};\n\nfunction pickerField(\n defaults: { name: string; label: string; mode: LookFieldMode; validate: TextFieldSingleValidation },\n overrides: LookFieldOptions,\n): TextField {\n const { name = defaults.name, label = defaults.label, admin, required, validate = defaults.validate } = overrides;\n return {\n name,\n type: \"text\",\n label,\n required,\n validate,\n admin: {\n ...admin,\n components: { Field: LOOK_FIELD, ...admin?.components },\n custom: { mode: defaults.mode, ...admin?.custom },\n },\n };\n}\n\n/**\n * A picker any collection or global can offer. Options come from the\n * published Theme at request time: page-editor system scales plus custom\n * Colors. Payload select options are a static list, so this is a text\n * field with an admin picker — adding Coral does not need a schema change.\n */\nexport function lookField(overrides: LookFieldOptions = {}): TextField {\n return pickerField({ name: \"look\", label: \"Look\", mode: \"look\", validate: validateLook }, overrides);\n}\n\n/**\n * Included steps as `coral-400`. Excluded steps do not appear.\n */\nexport function colorTokenField(overrides: LookFieldOptions = {}): TextField {\n return pickerField(\n { name: \"color\", label: \"Color\", mode: \"token\", validate: validateColorToken },\n overrides,\n );\n}\n","import type { ThemeDoc, ThemeUploadDoc } from \"./types\";\n\nexport interface ThemeIdentityAsset {\n url: string;\n alt: string;\n}\n\nexport interface ThemeIdentityFallback {\n lockup?: ThemeIdentityAsset;\n mark?: ThemeIdentityAsset;\n favicon?: ThemeIdentityAsset;\n}\n\nexport interface ResolvedThemeIdentity {\n lockup: ThemeIdentityAsset | null;\n mark: ThemeIdentityAsset | null;\n favicon: ThemeIdentityAsset | null;\n}\n\nfunction fromUpload(value: ThemeDoc[\"logo\"], fallback?: ThemeIdentityAsset): ThemeIdentityAsset | null {\n if (value && typeof value === \"object\") {\n const upload = value as ThemeUploadDoc;\n if (upload.url) {\n return { url: upload.url, alt: upload.alt ?? fallback?.alt ?? \"\" };\n }\n }\n return fallback ?? null;\n}\n\n/**\n * Uploaded logo, favicon, and mobile-menu mark, or the fallback the site\n * passed into `createTheme`. Empty fields keep the fallback;\n * `--color-primary-mark` is not a Theme field.\n */\nexport function resolveThemeIdentity(\n doc: ThemeDoc | null | undefined,\n fallback?: ThemeIdentityFallback,\n): ResolvedThemeIdentity {\n return {\n lockup: fromUpload(doc?.logo, fallback?.lockup),\n mark: fromUpload(doc?.logoMark, fallback?.mark),\n favicon: fromUpload(doc?.favicon, fallback?.favicon),\n };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"looks-Xs6v5vYU.d.mts","names":[],"sources":["../src/theme/identity.ts","../src/theme/types.ts","../src/theme/library.ts","../src/theme/color-tokens.ts","../src/theme/look-field.ts","../src/theme/looks.ts"],"mappings":"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"}