import { OVERRIDE_SCHEMA_VERSION, THEME_OVERRIDE_EXTENSION_ID } from '../constants'; import type { Mode, Platform, Preset } from '../types'; import type { CatalogInputStrategy, CatalogRecipeStrategy } from './catalogAuthoring'; import type { overrideCatalogDefinitions } from './catalogDefinitions'; export type TokenPath = string; export type PrimitiveTokenPath = string; export type ConcreteTokenValue = string | number; export type DtcgTokenType = string; export type RuntimeMap = Readonly>; export interface TokenReference { readonly ref: PrimitiveTokenPath; } export interface LiteralValue { readonly value: ConcreteTokenValue; } export type SelectedValue = TokenReference | LiteralValue; export type LinkedSelection = | { readonly mode: 'linked'; readonly source: TokenReference; } | { readonly mode: 'unlinked'; readonly light: TokenReference; readonly dark: TokenReference; }; export interface InvariantSelection { readonly source: TokenReference; } type AuthoredInputDefinition = (typeof overrideCatalogDefinitions.inputs)[number]; type AuthoredSelectionDefinition = (typeof overrideCatalogDefinitions.selections)[number]; type InputValueFor = TDefinition['valueType'] extends | 'color-seed' | 'font-family' ? string : never; type SelectionValueFor = TDefinition['valueShape'] extends 'linked-reference' ? LinkedSelection : TDefinition['valueShape'] extends 'invariant-reference' ? InvariantSelection : never; export type InputId = AuthoredInputDefinition['id']; export type SelectionId = AuthoredSelectionDefinition['id']; export type ThemeInputs = { readonly [TDefinition in AuthoredInputDefinition as TDefinition['id']]?: InputValueFor; }; export type ThemeSelections = { readonly [TDefinition in AuthoredSelectionDefinition as TDefinition['id']]?: SelectionValueFor; }; export type ModeSpecificOverride = | { readonly light: SelectedValue; readonly dark?: SelectedValue; } | { readonly light?: SelectedValue; readonly dark: SelectedValue; }; export type TokenOverride = SelectedValue | ModeSpecificOverride; export type TokenOverrides = Readonly>; export interface ThemeOverride { readonly $extensions: { readonly [THEME_OVERRIDE_EXTENSION_ID]: { readonly schemaVersion: typeof OVERRIDE_SCHEMA_VERSION; readonly basePreset: Preset; }; readonly [extensionId: string]: unknown; }; readonly inputs?: ThemeInputs; readonly selections?: ThemeSelections; readonly overrides?: TokenOverrides; } export interface RawThemeOverrideEnvelope { readonly value: unknown; } export interface ParsedSection { readonly known: TKnown; readonly unknown: Readonly>; } export interface PreservedUnknownFields { readonly topLevel: Readonly>; readonly extensions: Readonly>; readonly inputs: Readonly>; readonly selections: Readonly>; readonly overrides: Readonly>; } export interface ParsedThemeOverride { readonly kind: 'parsed-theme-override'; readonly raw: Readonly>; readonly metadata: { readonly schemaVersion: '1.0.0'; readonly basePreset: Preset; }; readonly inputs: ParsedSection; readonly selections: ParsedSection; readonly overrides: ParsedSection; readonly preservedUnknown: PreservedUnknownFields; } export type OverrideLayer = 'preset' | 'input' | 'selection' | 'direct'; export interface TokenProvenance { readonly layer: OverrideLayer; readonly intentPath?: string; readonly sourceRef?: PrimitiveTokenPath; readonly inputId?: InputId; readonly selectionId?: SelectionId; readonly recipeId?: string; } export type OverrideDiagnosticSeverity = 'error' | 'warning'; export type OverrideDiagnosticPhase = 'parse' | 'intent' | 'expand' | 'rule' | 'adapter'; export type OverrideDiagnosticCode = | 'override.unsupported_schema_version' | 'override.legacy_shape' | 'override.invalid_metadata' | 'override.invalid_structure' | 'override.prototype_key' | 'override.unknown_input' | 'override.unknown_selection' | 'override.unknown_target' | 'override.invalid_value' | 'override.invalid_reference' | 'override.unresolved_reference' | 'override.literal_type_mismatch' | 'override.mode_policy_violation' | 'override.source_not_allowed' | 'override.rule_violation' | 'override.primitive_step_frozen' | 'override.adapter_write_failed'; export interface OverrideDiagnostic { readonly code: OverrideDiagnosticCode; readonly severity: OverrideDiagnosticSeverity; readonly phase: OverrideDiagnosticPhase; readonly message: string; readonly mode?: Mode; readonly intentPath?: string; readonly tokenPath?: TokenPath; readonly relatedTokenPaths?: readonly TokenPath[]; readonly ruleId?: string; readonly provenance?: TokenProvenance; readonly artifactRevision?: string; } export type ParseThemeOverrideResult = | { readonly valid: true; readonly parsed: ParsedThemeOverride; readonly diagnostics: readonly OverrideDiagnostic[]; } | { readonly valid: false; readonly diagnostics: readonly OverrideDiagnostic[]; }; export type ParseThemeOverride = (raw: unknown) => ParseThemeOverrideResult; export type PackageTokenExpression = | { readonly kind: 'reference'; readonly ref: PrimitiveTokenPath; } | { readonly kind: 'literal'; readonly value: ConcreteTokenValue; }; export interface PresetTokenExpression { readonly tokenPath: TokenPath; readonly type: DtcgTokenType; readonly mode: Mode | 'invariant'; readonly platform?: Platform; readonly expression: PackageTokenExpression; } export interface PresetExpressionData { readonly source: 'shipped-preset-json'; readonly byPreset: Readonly>; } export interface PrimitiveValueArtifact { readonly byPreset: Readonly< Record>> >; readonly types: Readonly>; } export type ModePolicy = 'invariant' | 'mode-capable'; export interface TargetMetadata { readonly tokenPath: TokenPath; readonly type: DtcgTokenType; readonly modePolicy: ModePolicy; readonly referenceEligible: boolean; readonly literalEligible: boolean; readonly availableIn: readonly Preset[]; readonly runtimePath: TokenPath; } export interface TargetMetadataCatalog { readonly targets: Readonly>; } export interface OverrideArtifactRevision { readonly id: string; readonly algorithm: 'sha256'; readonly components: { readonly presetData: string; readonly primitiveData: string; readonly targetMetadata: string; readonly runtimeMap: string; readonly inputs: string; readonly sourceSets: string; readonly recipes: string; readonly rules: string; readonly fonts: string; }; } export type InputStrategy = CatalogInputStrategy; export interface InputDefinition { readonly id: InputId; readonly valueType: 'color-seed' | 'font-family'; readonly executionPhase: 'primitive' | 'resolved'; readonly priority: number; readonly managedTargets: readonly TokenPath[]; readonly strategy: InputStrategy; } export interface SourceSetDefinition { readonly id: string; readonly references: readonly PrimitiveTokenPath[]; readonly excludesInputSeeds: boolean; } export type SelectionValueShape = 'linked-reference' | 'invariant-reference' | 'chart-palette'; export interface SelectionDefinition { readonly id: SelectionId; readonly sourceSetId?: string; readonly recipeId: string; readonly valueShape: SelectionValueShape; readonly modePolicy: ModePolicy; readonly priority: number; } export interface RecipeModeDefinition { readonly targets: Readonly>; } export type RecipeStrategy = CatalogRecipeStrategy; export interface RecipeDefinition { readonly id: string; readonly selectionId: SelectionId; readonly strategy: RecipeStrategy; readonly byPreset: Readonly< Record< Preset, { readonly light: RecipeModeDefinition; readonly dark: RecipeModeDefinition; } > >; readonly managedTargets: readonly TokenPath[]; readonly retiredTargets: readonly TokenPath[]; } export interface ManagedTargetDefinition { readonly tokenPath: TokenPath; readonly modePolicy: ModePolicy; readonly owner: | { readonly kind: 'preset-patch'; readonly preset: Preset; } | { readonly kind: 'input'; readonly inputId: InputId; } | { readonly kind: 'recipe'; readonly recipeId: string; readonly state: 'active' | 'retired'; }; } export interface OverrideCatalogQueries { readonly getInput: (id: string) => InputDefinition | undefined; readonly getSourceSet: (id: string) => SourceSetDefinition | undefined; readonly getSelection: (id: string) => SelectionDefinition | undefined; readonly getRecipe: (id: string) => RecipeDefinition | undefined; readonly listInputs: () => readonly InputDefinition[]; readonly listSelections: () => readonly SelectionDefinition[]; readonly listManagedTargets: () => readonly ManagedTargetDefinition[]; } export type RuleCalibrationStatus = 'approved' | 'provisional' | 'deferred'; interface RuleDefinitionBase { readonly id: string; readonly description: string; readonly severity: OverrideDiagnosticSeverity; readonly calibration: RuleCalibrationStatus; } export interface AllowedValuesRuleDefinition extends RuleDefinitionBase { readonly type: 'allowed-values'; readonly phase: 'intent'; readonly selectionId: SelectionId; readonly sourceSetId: string; } export interface ContrastRuleDefinition extends RuleDefinitionBase { readonly type: 'contrast'; readonly phase: 'resolved'; readonly source: TokenPath; readonly against: TokenPath; readonly minRatio: number; } export interface ProximityRuleDefinition extends RuleDefinitionBase { readonly type: 'proximity'; readonly phase: 'resolved'; readonly source: TokenPath; readonly against: TokenPath; readonly minDeltaE: number; } export interface DistinctSetRuleDefinition extends RuleDefinitionBase { readonly type: 'distinct-set'; readonly phase: 'resolved'; readonly targets: readonly TokenPath[]; readonly minDeltaE: number; } export type RuleDefinition = | AllowedValuesRuleDefinition | ContrastRuleDefinition | ProximityRuleDefinition | DistinctSetRuleDefinition; export interface ModeTokenState { readonly light: Readonly>; readonly dark: Readonly>; } export interface ExpandedThemeOverride { readonly basePreset: Preset; readonly platform: Platform; readonly resolved: ModeTokenState; readonly writes: ModeTokenState; readonly writtenKeys: { readonly light: readonly TokenPath[]; readonly dark: readonly TokenPath[]; }; readonly provenance: { readonly resolved: ModeTokenState; readonly writes: ModeTokenState; }; readonly diagnostics: readonly OverrideDiagnostic[]; readonly revision: OverrideArtifactRevision; } export type ExpandThemeOverrideResult = | { readonly valid: true; readonly expanded: ExpandedThemeOverride; } | { readonly valid: false; readonly diagnostics: readonly OverrideDiagnostic[]; readonly revision: OverrideArtifactRevision; }; export interface OverrideRuntimeData { readonly expressions: PresetExpressionData; readonly primitives: PrimitiveValueArtifact; readonly targets: TargetMetadataCatalog; readonly catalogs: OverrideCatalogQueries; readonly rules: readonly RuleDefinition[]; readonly revision: OverrideArtifactRevision; } export interface ExpandThemeOverrideRequest { readonly parsed: ParsedThemeOverride; readonly platform: Platform; readonly data: OverrideRuntimeData; } export type ExpandThemeOverrideWithData = ( request: ExpandThemeOverrideRequest, ) => ExpandThemeOverrideResult; export type ExpandThemeOverride = ( override: unknown, platform: Platform, ) => ExpandThemeOverrideResult; export interface RuleEvaluationContext { readonly parsed: ParsedThemeOverride; readonly expanded: ExpandedThemeOverride; } export interface CandidateEvaluationRequest { readonly parsed: ParsedThemeOverride; readonly platform: Platform; readonly selectionId: SelectionId; readonly candidate: unknown; } export interface CandidateEvaluationResult { readonly accepted: boolean; readonly diagnostics: readonly OverrideDiagnostic[]; readonly expanded?: ExpandedThemeOverride; } export interface RuleEvaluator { readonly evaluateIntent: ( rules: readonly RuleDefinition[], parsed: ParsedThemeOverride, ) => readonly OverrideDiagnostic[]; readonly evaluateResolved: ( rules: readonly RuleDefinition[], context: RuleEvaluationContext, ) => readonly OverrideDiagnostic[]; readonly evaluateCandidate: ( rules: readonly RuleDefinition[], request: CandidateEvaluationRequest, ) => CandidateEvaluationResult; } declare const writerOwnershipTokenBrand: unique symbol; export type ThemeOverrideWriterOwnershipToken = string & { readonly [writerOwnershipTokenBrand]: true; }; export interface ThemeOverrideSessionState { readonly everWrittenKeys: { readonly light: readonly TokenPath[]; readonly dark: readonly TokenPath[]; }; readonly platform: Platform; readonly lastArtifactRevision: string | null; readonly writerOwner: ThemeOverrideWriterOwnershipToken; } export interface CoverPlanRequest { readonly expanded: ExpandedThemeOverride; readonly state: ThemeOverrideSessionState; readonly staticManagedTargets: { readonly light: readonly TokenPath[]; readonly dark: readonly TokenPath[]; }; readonly writerOwner: ThemeOverrideWriterOwnershipToken; } export interface ThemeOverrideCoverPlan { readonly coverKeys: { readonly light: readonly TokenPath[]; readonly dark: readonly TokenPath[]; }; readonly writes: ModeTokenState; readonly nextState: ThemeOverrideSessionState; } export type PlanThemeOverrideCover = (request: CoverPlanRequest) => ThemeOverrideCoverPlan; export type UpdateCssVariables = (mode: Mode, variables: Readonly>) => void; export interface UniwindAdapterInput { readonly expanded: ExpandedThemeOverride; readonly runtimeMap: Readonly>; readonly writer: UpdateCssVariables; } export interface CoveringUniwindAdapterInput extends UniwindAdapterInput { readonly session: ThemeOverrideSessionState; readonly staticManagedTargets: { readonly light: readonly TokenPath[]; readonly dark: readonly TokenPath[]; }; readonly writerOwner: ThemeOverrideWriterOwnershipToken; } export type ToUniwindMaps = (input: Omit) => ModeTokenState; export type ApplyExpandedThemeOverride = (input: UniwindAdapterInput) => | { readonly applied: true; readonly revision: string; } | { readonly applied: false; readonly failure: AdapterWriteFailure; }; export interface MuiSemanticMapping { readonly tokenPath: TokenPath; readonly optionPath: string; readonly cssVariable: string; /** * Companion channel variable consumed by non-native-color MUI themes. * The bridge writes this as relative-color channel syntax so it follows * runtime Forge variable updates instead of retaining MUI's initial value. */ readonly channelCssVariable?: string; } export interface MuiAdapterInput { readonly expanded: ExpandedThemeOverride; readonly mappings: readonly MuiSemanticMapping[]; } export type ToMuiThemeOptions = (input: MuiAdapterInput) => Readonly>; export interface AdapterWriteFailure { readonly code: 'override.adapter_write_failed'; readonly mode: Mode; readonly artifactRevision: string; readonly cause: unknown; readonly recovery: 'reload-and-reapply'; } export type DraftProvenance = 'absent' | 'incoming' | 'touched' | 'cleared'; export interface EditorDraftField { readonly displayValue: TValue; readonly intentValue?: TValue; readonly provenance: DraftProvenance; } export type InputDraftRelationship = 'derived' | 'pinned'; export interface InputDraftField extends EditorDraftField { readonly relationship?: InputDraftRelationship; } export interface BaseInputDraft extends EditorDraftField { readonly relationship: InputDraftRelationship; } export interface ThemeOverrideEditorDraft { readonly loadState: 'empty' | 'parsed' | 'unsupported' | 'invalid'; readonly basePreset: EditorDraftField; readonly inputs: Readonly>; readonly selections: Readonly< Partial>> >; readonly overrides: Readonly>>; readonly preservedUnknown: PreservedUnknownFields; readonly diagnostics: readonly OverrideDiagnostic[]; readonly previewPlatform: Platform; readonly artifactRevision: string | null; } export type SerializeThemeOverrideDraftResult = | { readonly valid: true; readonly override: ThemeOverride; } | { readonly valid: false; readonly diagnostics: readonly OverrideDiagnostic[]; }; export type SerializeThemeOverrideDraft = ( draft: ThemeOverrideEditorDraft, ) => SerializeThemeOverrideDraftResult;