import { TrackedChangeAddress } from '../types/address.js'; import { StoryLocator } from '../types/story.types.js'; import { TrackChangeNavigationTarget } from '../types/track-changes.types.js'; /** Identifier for the engine adapter that produced the opaque payload. */ export type DiffEngineId = 'superdoc-v2'; /** Declares which document components are included in a snapshot or diff. */ export interface DiffCoverage { body: true; comments: boolean; styles: boolean; numbering: boolean; headerFooters: boolean; } /** Versioned, fingerprinted snapshot of a document's diffable state. */ export interface DiffSnapshot { version: 'sd-diff-snapshot/v1' | 'sd-diff-snapshot/v2'; engine: DiffEngineId; fingerprint: string; coverage: DiffCoverage; /** Opaque engine-owned snapshot data. Do not inspect or modify. */ payload: Record; } /** Coarse change summary for a diff payload. */ export interface DiffSummary { hasChanges: boolean; changedComponents: Array<'body' | 'comments' | 'styles' | 'numbering' | 'headerFooters' | 'parts'>; body: { hasChanges: boolean; }; comments: { hasChanges: boolean; }; styles: { hasChanges: boolean; }; numbering: { hasChanges: boolean; }; headerFooters: { hasChanges: boolean; }; parts: { hasChanges: boolean; }; } /** Stable reason code for a compare-time apply blocker. */ export type DiffApplyEligibilityBlockerCode = 'family-apply-lane-unavailable' | 'header-footer-physical-lifecycle-unsafe' | 'header-footer-tracked-lifecycle-unsupported' | 'comment-replay-unsafe' | 'comment-anchor-marker-semantics-unsafe' | 'styles-replay-unsafe' | 'numbering-replay-unsafe' | 'definition-replay-tracked-unsupported' | 'package-graph-tracked-unsupported' | 'section-reference-replay-unsafe' | 'structural-paragraph-unsupported'; /** A known reason that the complete diff cannot be applied in one change mode. */ export interface DiffApplyEligibilityBlocker { code: DiffApplyEligibilityBlockerCode; message: string; families?: string[]; } /** Compare-time apply posture for one change mode. */ export interface DiffApplyModeEligibility { status: 'candidate' | 'blocked'; blockers: DiffApplyEligibilityBlocker[]; } /** Compare-time apply posture for each supported change mode. */ export interface DiffApplyEligibility { direct: DiffApplyModeEligibility; tracked: DiffApplyModeEligibility; } /** Versioned diff payload describing changes from a base to a target document. */ export interface DiffPayload { version: 'sd-diff-payload/v1' | 'sd-diff-payload/v2'; engine: DiffEngineId; baseFingerprint: string; targetFingerprint: string; coverage: DiffCoverage; summary: DiffSummary; /** Known compare-time blockers by apply mode. Candidate status is not a live apply guarantee. */ applyEligibility?: DiffApplyEligibility; /** Exhaustive changed OPC parts from the two source-complete snapshots. */ partChanges?: DiffPartChange[]; /** Opaque engine-owned diff data. Do not inspect or modify. */ payload: Record; } export interface DiffPartChange { partUri: string; kind: 'added' | 'removed' | 'modified'; beforeFingerprint: string | null; afterFingerprint: string | null; } export interface DiffApplyReviewItem { id: string; story: StoryLocator; address: TrackedChangeAddress; navigationTarget?: TrackChangeNavigationTarget; } export type DiffApplyOperationReceipt = { operationId: string; disposition: 'review-created'; reviewItems: [DiffApplyReviewItem, ...DiffApplyReviewItem[]]; } | { operationId: string; disposition: 'applied-directly'; reviewItems: []; }; export interface DiffApplyResult { appliedOperations: number; operationReceipts: DiffApplyOperationReceipt[]; baseFingerprint: string; targetFingerprint: string; coverage: DiffCoverage; summary: DiffSummary; diagnostics: string[]; /** Style definitions applied directly; these changes remain when body revisions are rejected. */ styleChanges?: { changeMode: 'direct'; partUris: string[]; }; } /** Input for `diff.compare`. */ export interface DiffCompareInput { targetSnapshot: DiffSnapshot; /** Assess tracked eligibility with explicit consent to apply style definitions directly. */ styleChangeMode?: 'direct'; } /** Input for `diff.apply`. */ export interface DiffApplyInput { diff: DiffPayload; /** Apply target style definitions directly, even when body changes are tracked. */ styleChangeMode?: 'direct'; } /** How body content changes are applied. */ export type DiffChangeMode = 'direct' | 'tracked'; /** Options for `diff.apply`. Omitted `changeMode` applies story content directly. */ export interface DiffApplyOptions { changeMode?: DiffChangeMode; /** Requires the current document revision; a mismatch fails before any diff operation applies. */ expectedRevision?: string; }