exifcleaner-web/src/infrastructure/wasm/format_strategy.ts
forgejo_admin d9e763b76e
All checks were successful
CI / Lint, Typecheck & Unit Tests (push) Successful in 32s
CI / Smoke build (VITE_ENABLE_FFMPEG_FALLBACK=false) (push) Successful in 45s
CI / E2E (Standalone single-file) (push) Successful in 1m35s
CI / E2E (Web) (push) Successful in 3m23s
feat(zip): generic ZIP support with recursive inner-file cleaning (#184) (#188)
2026-05-22 20:32:03 +04:00

68 lines
2.8 KiB
TypeScript

import type { Result } from "../../common";
import type {
ArchiveEntryResult,
ExifError,
MetadataDocument,
MetadataEntry,
StripOptions,
} from "../../domain";
export type { StripOptions };
export type { ArchiveEntryResult, ArchiveEntryStatus } from "../../domain";
export interface StripResult {
readonly bytes: Uint8Array;
// Walker-derived MetadataEntry records for things ExifTool's read path
// can't see — Office ZIP entries (comments, embeddings, customXml),
// PDF annotations, embedded files, etc. Prepended to
// MetadataDocument.before by WasmProcessor.buildDiffDocumentForEntry,
// where they naturally classify as "removed" in the diff (not in
// `after`). Source labels are granular ("Office Comments", "PDF
// Annotations", etc.) and distinct from ExifTool's "Office" / "PDF"
// groups so they render as their own sections in the two-pane view.
// JPEG/PNG/MP4/fallback always return [] — ExifTool's dump covers them.
readonly walkerEntries: readonly MetadataEntry[];
// Full before/after metadata snapshot from ExifTool. Populated by
// WasmProcessor (not the strategy) after a successful strip, via
// ExifToolDiffStrategy. Strategies themselves return null here.
readonly diffDocument: MetadataDocument | null;
// Non-fatal per-file warnings emitted by the strategy. Surfaced as
// an inline disclosure on the FileRow. Reserved for future use:
// the originally-planned encrypted-entry passthrough messages
// would have populated this, but v1 refuses encrypted archives
// outright (spec §3) so no current strategy emits warnings. Kept
// optional + threaded through so adding the byte-level walker
// follow-up doesn't require touching every reducer + the WebApi
// surface again.
readonly warnings?: readonly string[];
// Recursive tree of inner entries for archive formats. Currently only
// ZipStrategy populates this. UI: src/web/components/file-list/ZipExpansion.tsx
// renders the tree; per-leaf diffs are lazy-loaded via
// WasmProcessor.buildArchiveLeafDiff. See
// docs/superpowers/specs/2026-05-22-issue-184-zip-support-design.md.
readonly archiveEntries?: readonly ArchiveEntryResult[];
}
export interface FormatStrategy {
/**
* Returns the lowercase set of file extensions this strategy handles
* (each starting with a dot, e.g. ".docx").
*/
readonly extensions: ReadonlySet<string>;
/**
* Optional magic-byte check to confirm the file content matches the
* declared extension. Returns true if confirmed, false to decline.
* If absent, extension match alone is sufficient.
*/
readonly verifyMagicBytes?: (args: { bytes: Uint8Array }) => boolean;
/**
* Strips metadata from the file bytes and returns the cleaned bytes.
* Pure function — no I/O, no globals.
*/
strip(args: {
bytes: Uint8Array;
options: StripOptions;
}): Promise<Result<StripResult, ExifError>>;
}