> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filerouter.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Supported Document Input Types and MIME Resolution

> FileRouter accepts URLs, file paths, Blob, ArrayBuffer, and streams. MIME types resolve by explicit type, filename extension, or octet-stream fallback.

FileRouter accepts your document in whatever form it naturally exists in your code — a URL you fetched, a file path on disk, a browser `File` object, raw bytes, or a streaming body from a network response. Before passing anything to a provider, FileRouter resolves the input once into a canonical, provider-safe form. This resolution step is what lets `compare()` run multiple providers concurrently without consuming a one-shot stream more than once.

## Accepted input types

You can pass any of the following as the first argument to `parse()` or `compare()`:

<CardGroup cols={2}>
  <Card title="HTTP URL" icon="link">
    A `string` starting with `http://` or `https://`, or a `URL` object. FileRouter validates the URL and passes it directly to the provider — the document is never downloaded into your runtime.
  </Card>

  <Card title="Local file path" icon="folder">
    A plain string file path (e.g. `"/tmp/report.pdf"`) or the explicit object `{ kind: "file", path: "/tmp/report.pdf" }`. FileRouter reads the file from disk into bytes.
  </Card>

  <Card title="File or Blob" icon="file">
    A browser or Node.js `File` or `Blob` instance. FileRouter preserves the filename and MIME type from the object when available.
  </Card>

  <Card title="ArrayBuffer or typed array" icon="square-binary">
    An `ArrayBuffer` or any `ArrayBufferView` (such as `Uint8Array`). Useful when you have already read bytes into memory.
  </Card>

  <Card title="ReadableStream" icon="wave-square">
    A web `ReadableStream<Uint8Array>`. FileRouter consumes the stream once and converts it to replayable bytes before dispatch.
  </Card>

  <Card title="Explicit bytes object" icon="code">
    The structured form `{ kind: "bytes", data, mimeType?, name? }` lets you supply bytes alongside explicit metadata when you already know the filename and MIME type.
  </Card>
</CardGroup>

The full `ParseInput` type from the SDK captures all of these forms:

```ts parse-input-type.ts theme={null}
import type { ParseInput } from "@file_router/sdk"

// All of these are valid ParseInput values:
const fromUrl: ParseInput = "https://example.com/report.pdf"
const fromFile: ParseInput = new File([bytes], "report.pdf", { type: "application/pdf" })
const fromBuffer: ParseInput = buffer // ArrayBuffer or ArrayBufferView
const fromStream: ParseInput = response.body // ReadableStream<Uint8Array>
const fromPath: ParseInput = { kind: "file", path: "/tmp/report.pdf" }
const withMetadata: ParseInput = {
  kind: "bytes",
  data: buffer,
  name: "report.pdf",
  mimeType: "application/pdf",
}
```

## How inputs are resolved

FileRouter resolves every input exactly **once** into one of two canonical, provider-safe representations before any provider call is made:

* **A validated HTTP URL** — used when your input is already an `http://` or `https://` URL. FileRouter validates the URL format and passes it directly to the provider. The file is never downloaded into your runtime.
* **Replayable bytes** — used for everything else. The input (file, buffer, stream, or path) is read into an in-memory `Blob` with a normalized filename and resolved MIME type.

<Info>
  The one-time resolution is critical for `compare()`. A `ReadableStream` can only be consumed once. FileRouter reads it into replayable bytes first, then fans the same bytes out to each provider concurrently — your stream is never partially consumed.
</Info>

## MIME type resolution

FileRouter resolves the MIME type of your document deterministically using the following priority order:

<Steps>
  <Step title="Explicit non-generic MIME type">
    If you supply a `mimeType` directly (via a `File`, `Blob`, or the `{ kind: "bytes" }` form) and it is a specific, non-generic type (not `application/octet-stream`), FileRouter uses it as-is.
  </Step>

  <Step title="Filename extension">
    If the explicit MIME type is absent or generic, FileRouter infers the type from the filename extension — for example, `.pdf` → `application/pdf`, `.docx` → `application/vnd.openxmlformats-officedocument.wordprocessingml.document`.
  </Step>

  <Step title="Fallback to octet-stream">
    If neither step produces a specific type, FileRouter falls back to `application/octet-stream` and lets the provider decide how to handle the bytes.
  </Step>
</Steps>

<Warning>
  MIME metadata is purely informational. It is attached to the resolved input and forwarded to the provider as a hint, but it does **not** select a provider, change the requested operation, or cause FileRouter itself to reject the document.
</Warning>

## Unknown file signatures

FileRouter does not reject a document simply because its binary signature is unrecognized. Text-based formats like CSV and Markdown have no reliable binary signature, and provider support for new formats evolves independently of FileRouter releases. If you send a `.csv` file, FileRouter resolves the MIME type from the extension and forwards it to your chosen provider.

<Note>
  You can check how FileRouter resolves the MIME type of any document locally — without sending it anywhere — using `inspectDocument()` from `@file_router/sdk/inspect`. This function reports the resolved type, the extension-derived type, the detected binary signature type, and whether they conflict.
</Note>

## Hosted uploads

When you use the hosted API (`FileRouterClient`), your document streams directly from the request body into private cloud storage. FileRouter never buffers the full file in memory during ingress.

<CardGroup cols={2}>
  <Card title="Upload limit" icon="weight-hanging">
    The hosted endpoint accepts files up to **100 MB**.
  </Card>

  <Card title="Streaming ingress" icon="arrow-right-to-bracket">
    Your file streams directly to storage — it is never parsed as multipart or accumulated in memory by FileRouter during upload.
  </Card>
</CardGroup>

<Warning>
  Files larger than 100 MB are not supported by the hosted upload endpoint. A future direct-upload session will lift this limit without changing the parsing contract. If you are testing locally with the hosted API, note that `localhost` URLs cannot be fetched by external providers — use a public development tunnel when testing hosted parses against local files.
</Warning>
