import { type BookingRequirementId, type BookingSessionId, type DeclaredMimeType, type DetectedMimeType, type EntitlementId, type FileChecksumSha256, type MediaAssetId, type NonEmptyArray, type OriginalFilename, type PositiveByteCount, type PositiveSeconds, type ProductId, type Result, type SafeDownloadFilename, type StoragePath, type SiteScopedStoragePath, type SiteId, type SiteFontId, type StorageBucketName, type UserId, type UtcIsoDateTimeString } from '@riverbankcms/core';
export type FileAssetId = MediaAssetId;
export type FileKind = {
    readonly tag: 'image';
    readonly family: 'raster';
    readonly format: ImageFileFormat;
} | {
    readonly tag: 'video';
    readonly format: VideoFileFormat;
} | {
    readonly tag: 'audio';
    readonly format: AudioFileFormat;
} | {
    readonly tag: 'document';
    readonly format: DocumentFileFormat;
} | {
    readonly tag: 'spreadsheet';
    readonly format: SpreadsheetFileFormat;
} | {
    readonly tag: 'font';
    readonly format: FontFileFormat;
} | {
    readonly tag: 'archive';
    readonly format: ArchiveFileFormat;
};
export type ImageFileFormat = 'jpeg' | 'png' | 'webp' | 'gif' | 'avif' | 'heic' | 'heif' | 'svg';
export type VideoFileFormat = 'mp4' | 'webm' | 'mov';
export type AudioFileFormat = 'mpeg' | 'mp4' | 'wav' | 'ogg' | 'webm' | 'flac';
export type DocumentFileFormat = 'pdf' | 'docx' | 'txt' | 'rtf';
export type SpreadsheetFileFormat = 'csv';
export type FontFileFormat = 'woff2';
export type ArchiveFileFormat = 'zip';
export type RenderableFileKind = Extract<FileKind, {
    readonly tag: 'image' | 'video' | 'audio';
}>;
export type RenderableFileKindTag = RenderableFileKind['tag'];
export type FileKindTag = FileKind['tag'];
export declare const IMAGE_FILE_FORMATS: readonly ["jpeg", "png", "webp", "gif", "avif", "heic", "heif", "svg"];
export declare const VIDEO_FILE_FORMATS: readonly ["mp4", "webm", "mov"];
export declare const AUDIO_FILE_FORMATS: readonly ["mpeg", "mp4", "wav", "ogg", "webm", "flac"];
export declare const DOCUMENT_FILE_FORMATS: readonly ["pdf", "docx", "txt", "rtf"];
export declare const SPREADSHEET_FILE_FORMATS: readonly ["csv"];
export declare const FONT_FILE_FORMATS: readonly ["woff2"];
export declare const ARCHIVE_FILE_FORMATS: readonly ["zip"];
export declare const FILE_KIND_TAGS: readonly ["image", "video", "audio", "document", "spreadsheet", "font", "archive"];
export declare const RENDERABLE_FILE_KIND_TAGS: readonly ["image", "video", "audio"];
export type FileUse = {
    readonly tag: 'media-library';
    readonly renderUse: RenderableFileKindTag;
} | {
    readonly tag: 'content-download';
} | {
    readonly tag: 'digital-product-file';
    readonly fulfillmentVisibility: 'entitled-customer';
} | {
    readonly tag: 'workflow-input';
    readonly workflowKind: WorkflowInputKind;
} | {
    readonly tag: 'booking-evidence';
    readonly requirementId: BookingRequirementId;
} | {
    readonly tag: 'site-brand-asset';
    readonly brandUse: SiteBrandAssetUse;
} | {
    readonly tag: 'site-font-file';
    readonly fontId: SiteFontId;
} | {
    readonly tag: 'temporary-ingestion';
    readonly ingestionKind: TemporaryIngestionKind;
};
export type FileUseTag = FileUse['tag'];
export type WorkflowInputKind = 'audio-enrichment' | 'generic-file-processing';
export type SiteBrandAssetUse = 'logo' | 'social-image';
export type TemporaryIngestionKind = 'backup-zip' | 'newsletter-csv' | 'instagram-zip';
export declare const FILE_USE_TAGS: readonly ["media-library", "content-download", "digital-product-file", "workflow-input", "booking-evidence", "site-brand-asset", "site-font-file", "temporary-ingestion"];
export declare const WORKFLOW_INPUT_KINDS: readonly ["audio-enrichment", "generic-file-processing"];
export declare const SITE_BRAND_ASSET_USES: readonly ["logo", "social-image"];
export declare const TEMPORARY_INGESTION_KINDS: readonly ["backup-zip", "newsletter-csv", "instagram-zip"];
export type UploadIntent = {
    readonly tag: 'media-library';
    readonly allowedRenderUses: NonEmptyArray<RenderableFileKindTag>;
    readonly triggerWorkflow?: MediaLibraryTriggerWorkflow;
} | {
    readonly tag: 'content-download';
} | {
    readonly tag: 'digital-product-file';
    readonly productId: ProductId;
} | {
    readonly tag: 'booking-evidence';
    readonly requirementId: BookingRequirementId;
    readonly sessionId: BookingSessionId;
} | {
    readonly tag: 'site-brand-asset';
    readonly brandUse: SiteBrandAssetUse;
} | {
    readonly tag: 'site-font-file';
    readonly fontFamilyId: SiteFontId;
} | {
    readonly tag: 'temporary-ingestion';
    readonly ingestionKind: TemporaryIngestionKind;
};
export type UploadIntentTag = UploadIntent['tag'];
export type MediaLibraryTriggerWorkflow = Extract<WorkflowInputKind, 'audio-enrichment'>;
export declare const UPLOAD_INTENT_TAGS: readonly ["media-library", "content-download", "digital-product-file", "booking-evidence", "site-brand-asset", "site-font-file", "temporary-ingestion"];
export declare const MEDIA_LIBRARY_TRIGGER_WORKFLOWS: readonly ["audio-enrichment"];
export type FileActor = {
    readonly tag: 'dashboard-user';
    readonly userId: UserId;
    readonly siteId: SiteId;
} | {
    readonly tag: 'sdk-management';
    readonly keyId: string;
    readonly siteId: SiteId;
} | {
    readonly tag: 'public-visitor';
} | {
    readonly tag: 'portal-customer';
    readonly entitlementId?: EntitlementId;
} | {
    readonly tag: 'booking-session';
    readonly sessionId: BookingSessionId;
} | {
    readonly tag: 'system-worker';
    readonly siteId: SiteId;
};
export type FileActorTag = FileActor['tag'];
export declare const FILE_ACTOR_TAGS: readonly ["dashboard-user", "sdk-management", "public-visitor", "portal-customer", "booking-session", "system-worker"];
export type StorageClass = 'public-site' | 'private-site' | 'temporary';
export declare const STORAGE_CLASSES: readonly ["public-site", "private-site", "temporary"];
export type FileKindRule = {
    readonly tag: 'any-renderable';
    readonly renderUse: RenderableFileKindTag;
} | {
    readonly tag: 'exact-kind';
    readonly kind: FileKind;
} | {
    readonly tag: 'kind-tag';
    readonly kindTag: FileKindTag;
};
export type FileKindRuleTag = FileKindRule['tag'];
export declare const FILE_KIND_RULE_TAGS: readonly ["any-renderable", "exact-kind", "kind-tag"];
export type UploadPolicy = {
    readonly intent: UploadIntent;
    readonly allowedKinds: NonEmptyArray<FileKindRule>;
    readonly allowedUses: NonEmptyArray<FileUseTag>;
    readonly maxBytes: PositiveByteCount;
    readonly storageClass: StorageClass;
    readonly finalizeMode: {
        readonly tag: UploadPolicyFinalizeModeTag;
    };
    readonly detection: UploadPolicyDetection;
    readonly postProcess: {
        readonly tag: UploadPolicyPostProcessTag;
    };
};
export type UploadPolicyFinalizeModeTag = 'durable-file-asset' | 'context-private-attachment' | 'process-and-discard-source';
export type UploadPolicyPostProcessTag = 'none' | 'image-metadata' | 'video-metadata-and-poster' | 'audio-metadata' | 'font-metadata' | 'archive-import' | 'csv-import';
export declare const UPLOAD_POLICY_FINALIZE_MODE_TAGS: readonly ["durable-file-asset", "context-private-attachment", "process-and-discard-source"];
export declare const UPLOAD_POLICY_POST_PROCESS_TAGS: readonly ["none", "image-metadata", "video-metadata-and-poster", "audio-metadata", "font-metadata", "archive-import", "csv-import"];
export type UploadPolicyDetection = {
    readonly tag: 'server-detected-kind-required';
};
export type UploadPolicyDetectionTag = UploadPolicyDetection['tag'];
export declare const UPLOAD_POLICY_DETECTION_TAGS: readonly ["server-detected-kind-required"];
export type AccessPolicy = {
    readonly tag: 'public-read';
} | {
    readonly tag: 'site-editor-read';
    readonly siteId: SiteId;
} | {
    readonly tag: 'signed-public-render';
    readonly expiresInSeconds: PositiveSeconds;
} | {
    readonly tag: 'entitled-customer-read';
    readonly scope: EntitledCustomerAccessScope;
    readonly expiresInSeconds?: PositiveSeconds;
} | {
    readonly tag: 'booking-session-read';
    readonly sessionId: BookingSessionId;
    readonly expiresInSeconds?: PositiveSeconds;
} | {
    readonly tag: 'management-api-read';
};
export type EntitledCustomerAccessScope = {
    readonly tag: 'any-entitled-customer';
} | {
    readonly tag: 'specific-entitlement';
    readonly entitlementId: EntitlementId;
};
export type FileAccessGrant = {
    readonly tag: 'public-url';
} | {
    readonly tag: 'signed-url';
    readonly expiresInSeconds: PositiveSeconds;
} | {
    readonly tag: 'internal-read';
};
export type FileAccessDeniedReason = 'site-editor-required' | 'site-mismatch' | 'portal-customer-required' | 'entitlement-required' | 'entitlement-mismatch' | 'booking-session-required' | 'booking-session-mismatch' | 'management-api-required';
export type AccessPolicyTag = AccessPolicy['tag'];
export declare const ACCESS_POLICY_TAGS: readonly ["public-read", "site-editor-read", "signed-public-render", "entitled-customer-read", "booking-session-read", "management-api-read"];
export type UploadSessionState = {
    readonly tag: 'pending';
    readonly expiresAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'uploaded';
    readonly expiresAt: UtcIsoDateTimeString;
    readonly uploadedAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'finalizing';
    readonly expiresAt: UtcIsoDateTimeString;
    readonly uploadedAt: UtcIsoDateTimeString;
    readonly startedAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'finalized';
    readonly assetId: FileAssetId;
    readonly expiresAt: UtcIsoDateTimeString;
    readonly uploadedAt: UtcIsoDateTimeString;
    readonly startedAt: UtcIsoDateTimeString;
    readonly finalizedAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'rejected';
    readonly expiresAt: UtcIsoDateTimeString;
    readonly reason: UploadRejectionReason;
    readonly rejectedAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'expired';
    readonly expiresAt: UtcIsoDateTimeString;
    readonly expiredAt: UtcIsoDateTimeString;
} | {
    readonly tag: 'cleaned-up';
    readonly expiresAt: UtcIsoDateTimeString;
    readonly cleanedUpAt: UtcIsoDateTimeString;
};
export type UploadSessionStateTag = UploadSessionState['tag'];
export declare const UPLOAD_SESSION_STATE_TAGS: readonly ["pending", "uploaded", "finalizing", "finalized", "rejected", "expired", "cleaned-up"];
export type ExpirableUploadSessionState = Extract<UploadSessionState, {
    readonly tag: 'pending' | 'uploaded' | 'finalizing';
}>;
export type CleanupReadyUploadSessionState = Extract<UploadSessionState, {
    readonly tag: 'expired' | 'rejected';
}>;
/**
 * Total transition for session states that are allowed to become expired.
 */
export declare function expireUploadSessionState(state: ExpirableUploadSessionState, at: UtcIsoDateTimeString): Extract<UploadSessionState, {
    readonly tag: 'expired';
}>;
/**
 * Total transition for session states whose staged object can be cleaned up.
 */
export declare function cleanUpUploadSessionState(state: CleanupReadyUploadSessionState, at: UtcIsoDateTimeString): Extract<UploadSessionState, {
    readonly tag: 'cleaned-up';
}>;
export type UploadRejectionReason = 'kind-not-allowed' | 'file-too-large' | 'mime-mismatch' | 'storage-path-not-owned' | 'upload-session-expired' | 'storage-object-missing';
export declare const UPLOAD_REJECTION_REASONS: readonly ["kind-not-allowed", "file-too-large", "mime-mismatch", "storage-path-not-owned", "upload-session-expired", "storage-object-missing"];
export type FileUsageReference = {
    readonly tag: 'page-block';
    readonly label: string;
    readonly pageId?: string;
} | {
    readonly tag: 'product-download';
    readonly productId: ProductId;
    readonly label: string;
} | {
    readonly tag: 'workflow-processing';
    readonly label: string;
} | {
    readonly tag: 'derived-asset';
    readonly assetId: FileAssetId;
    readonly label: string;
};
export type FileAssetLifecycle = {
    readonly tag: 'active';
} | {
    readonly tag: 'pending-delete';
    readonly blockedBy: readonly FileUsageReference[];
} | {
    readonly tag: 'deleted';
    readonly deletedAt: UtcIsoDateTimeString;
    readonly deletedBy: UserId;
};
export type FileDerivative = {
    readonly tag: 'image-variant';
    readonly derivativeAssetId: FileAssetId;
    readonly variantKey?: string;
} | {
    readonly tag: 'video-poster';
    readonly derivativeAssetId: FileAssetId;
} | {
    readonly tag: 'audio-waveform';
    readonly derivativeAssetId: FileAssetId;
};
export type FileDerivativeTag = FileDerivative['tag'];
export declare const FILE_DERIVATIVE_TAGS: readonly ["image-variant", "video-poster", "audio-waveform"];
export type FileAssetSource = {
    readonly tag: 'direct-upload';
} | {
    readonly tag: 'instagram-import';
} | {
    readonly tag: 'system-generated';
    readonly originAssetId: FileAssetId;
    readonly derivativeKind: FileDerivative['tag'];
};
export type FileAssetMetadata = {
    readonly tag: 'image-metadata';
    readonly width?: number;
    readonly height?: number;
    readonly altText?: string;
    readonly caption?: string;
    readonly exif?: Record<string, unknown>;
} | {
    readonly tag: 'video-metadata';
    readonly width?: number;
    readonly height?: number;
    readonly durationSeconds?: number;
    readonly posterAssetId?: FileAssetId;
    readonly caption?: string;
} | {
    readonly tag: 'audio-metadata';
    readonly durationSeconds?: number;
    readonly caption?: string;
} | {
    readonly tag: 'file-metadata';
    readonly title?: string;
};
export type FileAsset = {
    readonly id: FileAssetId;
    readonly siteId: SiteId;
    readonly storageBucket: StorageBucketName;
    readonly storagePath: StoragePath | SiteScopedStoragePath;
    readonly filename: OriginalFilename;
    readonly safeDownloadFilename?: SafeDownloadFilename;
    readonly mimeType: DeclaredMimeType;
    readonly kind: FileKind;
    readonly uses: NonEmptyArray<FileUse>;
    readonly storageClass: StorageClass;
    readonly accessPolicy: AccessPolicy;
    readonly lifecycle: FileAssetLifecycle;
    readonly source: FileAssetSource;
    readonly bytes?: PositiveByteCount;
    readonly checksumSha256?: FileChecksumSha256;
    readonly createdBy?: UserId;
    readonly createdAt: UtcIsoDateTimeString;
    readonly updatedAt: UtcIsoDateTimeString;
    readonly derivatives: readonly FileDerivative[];
    readonly metadata: FileAssetMetadata;
};
declare const validatedFileAssetBrand: unique symbol;
declare const activeValidatedFileAssetBrand: unique symbol;
/**
 * File asset whose intrinsic fields agree with each other: MIME/kind, uses/kind,
 * metadata/kind, video poster metadata/derivatives, and storage/access policy.
 * This does not prove the asset is active; use `ActiveValidatedFileAsset` when
 * callers need an asset that can be rendered, downloaded, or inserted as active.
 */
export type ValidatedFileAsset = FileAsset & {
    readonly [validatedFileAssetBrand]: true;
};
export type ActiveFileAsset = FileAsset & {
    readonly lifecycle: {
        readonly tag: 'active';
    };
};
export type ActiveValidatedFileAsset = ValidatedFileAsset & ActiveFileAsset & {
    readonly [activeValidatedFileAssetBrand]: true;
};
export type DurableFileAsset = FileAsset & {
    readonly storagePath: SiteScopedStoragePath;
    readonly storageClass: Exclude<StorageClass, 'temporary'>;
};
export type ActiveValidatedDurableFileAsset = ActiveValidatedFileAsset & DurableFileAsset;
export type StorageAccessMismatchReason = 'public-access-requires-public-storage' | 'private-signed-access-requires-private-storage' | 'management-api-access-requires-temporary-storage' | 'site-editor-access-requires-durable-storage';
export type FileStorageAccessMismatch = {
    readonly tag: 'storage-access-mismatch';
    readonly reason: StorageAccessMismatchReason;
    readonly storageClass: StorageClass;
};
export type FileAssetValidationError = {
    readonly tag: 'unsupported-mime-type';
    readonly mimeType: DeclaredMimeType;
} | {
    readonly tag: 'mime-kind-mismatch';
    readonly mimeType: DeclaredMimeType;
    readonly classifiedKind: FileKind;
    readonly assetKind: FileKind;
} | {
    readonly tag: 'file-use-kind-mismatch';
    readonly use: FileUse;
    readonly kind: FileKind;
} | {
    readonly tag: 'metadata-kind-mismatch';
    readonly metadata: FileAssetMetadata;
    readonly kind: FileKind;
} | {
    readonly tag: 'video-poster-derivative-mismatch';
    readonly metadataPosterAssetId?: FileAssetId;
    readonly derivativePosterAssetId?: FileAssetId;
} | FileStorageAccessMismatch;
export type ActiveFileAssetValidationError = FileAssetValidationError | {
    readonly tag: 'file-not-active';
    readonly lifecycle: Exclude<FileAssetLifecycle, {
        readonly tag: 'active';
    }>;
};
export type UploadPolicyError = 'actor-not-allowed-for-intent';
export type MimeTypeClassificationError = 'unsupported-mime-type';
export type FileChecksumSha256Error = 'invalid-sha256-checksum';
export type SafeDownloadFilenameError = 'empty-download-filename' | 'unsafe-download-filename' | 'download-filename-too-long';
export declare const FILE_SIZE_LIMITS: {
    readonly audio: PositiveByteCount;
    readonly rawVideoBeforeCompression: PositiveByteCount;
    readonly publicDownload: PositiveByteCount;
    readonly digitalProductFile: PositiveByteCount;
    readonly siteBrandAsset: PositiveByteCount;
    readonly image: PositiveByteCount;
    readonly font: PositiveByteCount;
    readonly newsletterCsv: PositiveByteCount;
    readonly backupZip: PositiveByteCount;
    readonly instagramZip: PositiveByteCount;
    readonly bookingEvidence: PositiveByteCount;
};
export declare const DEFAULT_PRIVATE_FILE_SIGNED_URL_EXPIRY_SECONDS: PositiveSeconds;
export declare const MAX_SAFE_DOWNLOAD_FILENAME_LENGTH = 180;
export declare function asPositiveByteCount(value: number): Result<PositiveByteCount, 'not-positive-byte-count'>;
export declare function asPositiveSeconds(value: number): Result<PositiveSeconds, 'not-positive-seconds'>;
export declare function asFileChecksumSha256(value: string): Result<FileChecksumSha256, FileChecksumSha256Error>;
export declare function asSafeDownloadFilename(value: string): Result<SafeDownloadFilename, SafeDownloadFilenameError>;
export declare function deriveUploadPolicy(actor: FileActor, intent: UploadIntent): Result<UploadPolicy, UploadPolicyError>;
export declare function classifyKnownMimeType(mimeType: string | DeclaredMimeType | DetectedMimeType | undefined | null): Result<FileKind, MimeTypeClassificationError>;
export declare function isMimeTypeAllowedForPolicy(mimeType: string | DeclaredMimeType | DetectedMimeType | undefined | null, policy: UploadPolicy): boolean;
export declare function isFileKindAllowed(kind: FileKind, policy: UploadPolicy): boolean;
export declare function isFileUseAllowed(requestedUse: FileUse, allowedUses: NonEmptyArray<FileUse>): boolean;
export declare function validateFileAsset(asset: FileAsset): Result<ValidatedFileAsset, FileAssetValidationError>;
export declare function validateActiveFileAsset(asset: FileAsset): Result<ActiveValidatedFileAsset, ActiveFileAssetValidationError>;
export declare function assertFileAccessPolicyStorageClass(policy: AccessPolicy, storageClass: StorageClass): Result<void, FileStorageAccessMismatch>;
export declare function areFileKindsEqual(left: FileKind, right: FileKind): boolean;
export declare function areFileUsesEqual(left: FileUse, right: FileUse): boolean;
/**
 * Order-insensitive multiset comparison for file-use lists.
 * Duplicate uses are significant so corrupted `[A, A, B]` and `[A, B, B]` lists do not compare equal.
 */
export declare function areFileUseListsEqual(left: readonly FileUse[], right: readonly FileUse[]): boolean;
export declare function isFileUseCompatibleWithKind(use: FileUse, kind: FileKind): boolean;
export declare function areUploadIntentsEqual(left: UploadIntent, right: UploadIntent): boolean;
export declare function authorizeFileAccess(actor: FileActor, policy: AccessPolicy): Result<FileAccessGrant, FileAccessDeniedReason>;
export declare function transitionUploadSessionState(state: UploadSessionState, event: UploadSessionEvent): Result<UploadSessionState, UploadSessionTransitionError>;
export type UploadSessionEvent = {
    readonly tag: 'mark-uploaded';
    readonly at: UtcIsoDateTimeString;
} | {
    readonly tag: 'start-finalizing';
    readonly at: UtcIsoDateTimeString;
} | {
    readonly tag: 'finalize';
    readonly assetId: FileAssetId;
    readonly at: UtcIsoDateTimeString;
} | {
    readonly tag: 'reject';
    readonly reason: UploadRejectionReason;
    readonly at: UtcIsoDateTimeString;
} | {
    readonly tag: 'expire';
    readonly at: UtcIsoDateTimeString;
} | {
    readonly tag: 'clean-up';
    readonly at: UtcIsoDateTimeString;
};
export type UploadSessionTransitionError = 'invalid-transition' | 'terminal-state';
export {};
