import type { FilesPlugin } from "../index.js"; /** * What {@link contentType} does when the type it sniffs from the bytes disagrees * with the type the caller declared (or that the key's extension implies). * * - `"correct"` (the default) — overwrite the stored `Content-Type` with the * sniffed one, so the object is always stored as what it actually *is*. A * mislabeled file still lands, but under its true type. * - `"reject"` — throw, so a mislabeled upload never reaches the adapter. The * security-hardening choice: a `.png` whose bytes are HTML is refused outright. * * A declared type of `application/octet-stream` (i.e. no real claim) is treated * as "unset" rather than a contradiction — the sniffed type fills it in under * both modes. */ export type OnMismatch = "correct" | "reject"; /** * What {@link contentType} does when the bytes match no known signature, so the * type can't be positively identified. * * - `"trust"` (the default) — keep the declared/inferred type. Sniffing only * overrides types it's sure about, so an unrecognized but legitimate body * (`.csv`, `.docx`, arbitrary binary) keeps its declared type untouched. * - `"reject"` — throw. A strict allowlist-by-signature posture: nothing lands * unless its bytes are recognized. */ export type OnUnknown = "trust" | "reject"; export interface ContentTypeOptions { /** * How to reconcile a sniffed type that disagrees with the declared one. * Defaults to `"correct"`. See {@link OnMismatch}. */ onMismatch?: OnMismatch; /** * What to do when the bytes match no known signature. Defaults to `"trust"`. * See {@link OnUnknown}. */ onUnknown?: OnUnknown; } /** * Identify the MIME type of a body from its leading bytes, or `undefined` when * the bytes match no known signature. Checks binary magic numbers (images, PDF) * first, then falls back to a text scan for HTML/SVG/XML. Exported so callers * can sniff outside the plugin; only the first {@link SNIFF_BYTES} bytes matter. */ export declare const detectContentType: (bytes: Uint8Array) => string | undefined; /** * A security guard that decides an upload's `Content-Type` from its **bytes**, * not the client's claim. It magic-byte-sniffs the body on `upload` and either * corrects the stored type to match (the default) or rejects a mismatch — so a * `.png` that's really HTML/SVG can't be stored under an image type and later * served inline. * * Recognizes the common images, PDF, and — the security-relevant part — HTML, * SVG, and XML, which have no fixed magic bytes and so are caught by a leading * text scan. Bodies it can't identify are left as-declared by default (see * {@link OnUnknown}). * * Unlike `compression()` / `encryption()`, it writes no metadata and only needs * the **first 512 bytes**, so it never buffers the whole body: known-length * bodies are peeked in place with no copy, and streams stay streaming (only the * prefix is read, then replayed). Reads, `url()`, `copy`, and `move` pass * straight through — there's nothing to undo. * * Place it **first**, before any body-transforming plugin, so it sniffs the * caller's original bytes: `plugins: [contentType(), compression(), encryption(key)]`. * * `signedUploadUrl()` hands upload capability to a client that writes directly, * bypassing the sniff, so it **fails closed** and throws. * * @param options `onMismatch` (`"correct"` default, or `"reject"`) and * `onUnknown` (`"trust"` default, or `"reject"`). * @example * ```ts * import { createFiles } from "files-sdk"; * import { s3 } from "files-sdk/s3"; * import { contentType } from "files-sdk/content-type"; * * const files = createFiles({ * adapter: s3({ bucket: "uploads" }), * plugins: [contentType({ onMismatch: "reject" })], * }); * * await files.upload("avatar.png", pngBytes); // ok — bytes are a PNG * await files.upload("avatar.png", htmlBytes); // throws — bytes are HTML * ``` */ export declare const contentType: (options?: ContentTypeOptions) => FilesPlugin; //# sourceMappingURL=index.d.ts.map