/** * attachments.ts — W2.2 slice 4: file-attachment helpers for @oxpulse/chat-widget. * * Ported and extended from web/src/lib/chat/attachments/attachments.ts. * Widget package is standalone — no runtime import from web/. * * Supports images, audio, and generic files (up to 50 MB SDK cap). * All validation is pure — no DOM access — so tests run under jsdom without stubs. */ /** Whitelist of accepted image MIME types. */ export declare const ALLOWED_IMAGE_MIMES: ReadonlySet; /** Whitelist of accepted audio MIME types. */ export declare const ALLOWED_AUDIO_MIMES: ReadonlySet; /** 50 MB — matches SDK MAX_ATTACHMENT_BYTES cap. */ export declare const MAX_FILE_SIZE: number; /** Max image dimensions before rejection (sanity check only — compress handles downscale). */ export declare const MAX_IMAGE_DIMENSION = 8192; /** Reply-snapshot text used when the target is image-only. */ export declare const IMAGE_REPLY_SNAPSHOT = "\uD83D\uDCF7 Image"; /** Reply-snapshot text used when the target is a voice-only message. */ export declare const VOICE_REPLY_SNAPSHOT = "\uD83C\uDFA4 Voice message"; /** Result of validating a file blob against the widget policy. */ export type ValidateResult = { readonly ok: true; } | { readonly ok: false; readonly reason: string; }; /** * Sanitize a filename — return basename only (post-last path separator). * CM4: single-pass ../ replace left "....//etc" intact; basename-only approach * eliminates all path traversal by discarding everything before the last / or \. */ export declare function sanitizeFilename(name: string): string; /** * Validate a file against the widget attachment policy. * Pure — takes only the fields it needs so tests can pass plain objects. * * Allowed MIME types: images (ALLOWED_IMAGE_MIMES), audio (ALLOWED_AUDIO_MIMES), application/pdf. * Size cap: MAX_FILE_SIZE (50 MB). */ export declare function validate(file: { readonly type: string; readonly size: number; readonly name?: string; }): ValidateResult; /** Metadata shape for attachment rendering in message bubbles. */ export interface AttachmentMeta { id: string; url: string; mime: string; filename: string; sizeBytes: number; width?: number; height?: number; durationMs?: number; /** Waveform peaks for audio attachments (float[0,1], ≤ MAX_VOICE_PEAKS). * Absent on non-voice attachments and legacy envelopes → flat fallback. */ peaks?: number[]; } export declare function isSafeAttachmentUrl(url: string): boolean; /** Result of client-side image compression. */ export interface CompressionResult { blob: Blob; dataUrl: string; width: number; height: number; originalBytes: number; compressedBytes: number; /** true → output ≥ input; original blob returned as-is */ reused: boolean; encodingMime: string; } /** Compute target dimensions preserving aspect ratio. No upscale. Pure / testable. */ export declare function computeResizedDimensions(srcWidth: number, srcHeight: number, maxLongEdge: number): { width: number; height: number; }; /** * Compress an image blob to WebP (fallback: JPEG) at up to 1920px long edge. * Requires browser globals: createImageBitmap, HTMLCanvasElement. * Throws Error("decode-failed") if the source cannot be decoded. */ export declare function compress(source: Blob, opts?: { maxLongEdge?: number; quality?: number; }): Promise; /** * Generate a thumbnail data URL from an image blob (max 64px long edge). * Returns null if browser lacks canvas support. */ /** @internal Not part of the package's public API surface; not re-exported from index.ts. Kept exported for cross-file use within the package. */ export declare function thumbnail(source: Blob, maxLongEdge?: number): Promise; /** Attachment shape for replyBodySnapshotForMessage (duck-typed). * Supports both the legacy `kind` discriminator and widget AttachmentMeta's `mime`. */ interface AttachmentRef { readonly kind?: string; readonly mime?: string; } /** * Compute the body excerpt to use for a reply-snapshot. * Ported from web/src/lib/chat/attachments/attachments.ts. * Widget extension: also inspects `mime` for AttachmentMeta rows that lack `kind`. */ export declare function replyBodySnapshotForMessage(msg: { readonly body: string; readonly attachments?: ReadonlyArray; }): string; export {}; //# sourceMappingURL=attachments.d.ts.map