# UploadOptions

```ts
type UploadOptions = {
  compress?:   | boolean
     | CompressOptions;
  contentType?: string;
  fileName?: string;
  presets?: RequestablePreset[];
  sha256?: string;
  timeoutMs?: number;
  video?: UploadVideoOptions;
};
```

Defined in: packages/sdk/src/index.ts:1013

## Properties

### compress?

```ts
optional compress?: 
  | boolean
  | CompressOptions;
```

Defined in: packages/sdk/src/index.ts:1048

Client-side compression before upload. Saves user bandwidth — typical
5–10× reduction for raw phone photos. Browser-only; in Node/Bun this
silently no-ops with a console.warn and the raw bytes upload as-is.

  - `true`             → use SDK `DEFAULT_COMPRESSION_OPTIONS` (webapp-tuned)
  - `CompressOptions`  → merge over defaults
  - `false` / omit     → no compression (current default behavior)

Implementation is lazy-imported from `@nitida/sdk/web` so callers
that never set `compress` don't pay the compressorjs + heic2any
bundle cost. Skipped for non-image MIMEs (video, PDF) regardless of
this option — those go to the upload pipeline raw.

#### See

 - [CompressOptions](/api/nitida/sdk/type-aliases/compressoptions/)
 - https://nitida.gofuture.space/guides/advanced/ — client-side compression

***

### contentType?

```ts
optional contentType?: string;
```

Defined in: packages/sdk/src/index.ts:1028

MIME type of the bytes. **Only needed for a `Uint8Array` input** — a `File`/`Blob`
already carries its `.type`. Raw bytes have no inherent MIME, so without this (and
without an extension on `fileName` to infer from) they upload as
`application/octet-stream`, which the server classifies as `kind:"other"` —
meaning NO image/video variants are generated and `regenerate()` is unsupported.
Resolution order for the effective MIME: `Blob.type` → `contentType` →
inferred from `fileName`'s extension → `application/octet-stream`.

  aq.upload(bytes, { fileName: "cover.webp" })                 // inferred → image/webp ✓
  aq.upload(bytes, { contentType: "image/webp" })             // explicit ✓
  aq.upload(bytes)                                             // octet-stream → kind:"other" ⚠

***

### fileName?

```ts
optional fileName?: string;
```

Defined in: packages/sdk/src/index.ts:1014

***

### presets?

```ts
optional presets?: RequestablePreset[];
```

Defined in: packages/sdk/src/index.ts:1077

Variant set to generate. **Defaults to `["original"]`** —
if you omit this option, only the raw bytes land on the CDN
under the `o` path. Pass an explicit array to request more.

Image presets (`thumb` 256 · `sm` 640 · `md` 1280 · `lg` 1920 ·
`xl` 3840 · `original`):
  - `["original"]` (default) → just the raw bytes. Right call for
    logos / SVGs / anything you'll resize browser-side or via
    `aq.assets.regenerate(id, { presets: ["thumb"] })` later.
  - `["thumb","sm","md","lg"]` → the classic responsive ladder.
  - `["thumb","sm","md","lg","xl"]` → add 4K.

Video presets (`poster`, `video`, `aiproxy`): omit `aiproxy` if
the tenant doesn't need the low-res transcode for AI captioning.

No upscaling. Each size preset is a **ceiling**; a 1080×720 source
asked for `xl` (3840) yields a 1080×720 xl variant, not a stretched
3840-wide image.

Idempotent: you can always add missing variants later via
`aq.assets.regenerate(id, { presets: [...] })`. The platform
stores the source so regeneration doesn't require re-uploading.

[RequestablePreset](/api/nitida/sdk/type-aliases/requestablepreset/), not [VariantPreset](/api/nitida/sdk/type-aliases/variantpreset/). `hls` and `mp3` are
produced FOR you — the ladder when a video transcodes, the mp3 alongside
any audio original — and asking for either is a 400.

***

### sha256?

```ts
optional sha256?: string;
```

Defined in: packages/sdk/src/index.ts:1030

Computed sha256 of bytes. Skip to compute locally with WebCrypto (browser only).

***

### timeoutMs?

```ts
optional timeoutMs?: number;
```

Defined in: packages/sdk/src/index.ts:1089

Max time to wait for the asset to transition to `ready` (or `failed`)
after dispatch. Default `5 * 60_000` (5 min). Bump higher for large
videos / HLS transcodes — processing time scales with input size,
and with how much other work the platform is doing at that moment.

Throws `Error("waitReady timeout for <id>")` if the deadline passes
without the asset transitioning. The asset row stays in aquienpz
(status="processing") and the next byHash lookup will return it once
processing completes; the caller can resume with their own poll.

***

### video?

```ts
optional video?: UploadVideoOptions;
```

Defined in: packages/sdk/src/index.ts:1101

VIDEO-only delivery knobs forwarded into `/assets/process`. See
[UploadVideoOptions](/api/nitida/sdk/type-aliases/uploadvideooptions/). Ignored for non-video uploads.

  // A delivery-ready reel: skip the unused HLS ladder + skip re-encode.
  await aq.upload(mp4Bytes, {
    fileName: "reel.mp4",
    presets: ["poster", "video"],
    video: { hls: false, passthrough: true },
  });