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

# API Reference

> Complete reference for upload(), UploadOptions, UploadResult, SegmentInput, and error codes.

## `upload(segments, manifest, options)`

Encrypts HLS segments in the browser and uploads them to S3 via presigned URLs.

**Parameters:**

| Parameter  | Type             | Description                                 |
| ---------- | ---------------- | ------------------------------------------- |
| `segments` | `SegmentInput[]` | Array of HLS segments to encrypt and upload |
| `manifest` | `string`         | The `.m3u8` manifest text                   |
| `options`  | `UploadOptions`  | Configuration for the upload                |

**Returns:** `Promise<Result<UploadResult, UploaderError>>`

## `UploadOptions`

```typescript theme={null}
interface UploadOptions {
  /** Unique identifier for this content (used for key derivation) */
  contentId: string

  /** Key server URL including the /keys path (e.g., "https://your-worker.workers.dev/keys") */
  keyServerUrl: string

  /** URL of the presign endpoint */
  presignUrl: string

  /** Returns a Bearer token for auth (called for key fetch and presign requests) */
  auth?: () => Promise<string>

  /** Called after each segment is uploaded */
  onProgress?: (progress: { completed: number; total: number }) => void

  /** AbortSignal to cancel the upload */
  signal?: AbortSignal

  /** Number of parallel uploads (default: 4) */
  concurrency?: number

  /** S3 key prefix (default: "content/<contentId>/") */
  prefix?: string
}
```

## `SegmentInput`

```typescript theme={null}
interface SegmentInput {
  /** Segment number (used for IV derivation) */
  index: number

  /** Raw .ts segment bytes (plaintext — will be encrypted) */
  data: Uint8Array

  /** Object key/path in storage (e.g., "seg-0.ts") */
  key: string
}
```

## `UploadResult`

```typescript theme={null}
interface UploadResult {
  /** URL of the uploaded (rewritten) manifest */
  manifestUrl: string

  /** URLs of uploaded encrypted segments, in order */
  segmentUrls: string[]

  /** Total number of segments uploaded */
  segmentCount: number
}
```

## `UploadProgress`

The `onProgress` callback receives:

```typescript theme={null}
{ completed: number; total: number }
```

| Field       | Type     | Description                        |
| ----------- | -------- | ---------------------------------- |
| `completed` | `number` | Number of segments uploaded so far |
| `total`     | `number` | Total number of segments           |

## `rewriteManifest(manifest, opts)`

Rewrites an HLS manifest to include `EXT-X-KEY` tags pointing to the key server and replaces segment URIs with uploaded URLs. This is called internally by `upload()` — you only need it directly for custom upload pipelines.

Exported from `@blindcast/storage`:

```typescript theme={null}
import { rewriteManifest } from "@blindcast/storage"
```

**Parameters:**

| Parameter  | Type          | Description                    |
| ---------- | ------------- | ------------------------------ |
| `manifest` | `string`      | Original `.m3u8` manifest text |
| `opts`     | `RewriteOpts` | Rewrite configuration          |

**Returns:** `Result<string, StorageError>` — the rewritten manifest text

```typescript theme={null}
interface RewriteOpts {
  /** Key server base URL — /keys/:contentId is appended automatically */
  keyServerUrl: string

  /** Content identifier (used in the EXT-X-KEY URI) */
  contentId: string

  /** Map original segment filenames → uploaded URLs */
  segmentUrlMap: Record<string, string>

  /** If set, insert new EXT-X-KEY every N segments (key rotation) */
  segmentsPerEpoch?: number
}
```

<Warning>
  `keyServerUrl` here is the **base server URL** (e.g., `https://your-worker.workers.dev`) — NOT the `/keys` path. The function appends `/keys/:contentId` automatically. This is different from the Player and Uploader SDKs, which expect the URL to include `/keys`.
</Warning>

## Error codes

| Code                   | Cause                                                                     |
| ---------------------- | ------------------------------------------------------------------------- |
| `KEY_FETCH_FAILED`     | Could not fetch content key from key server                               |
| `ENCRYPT_FAILED`       | Segment encryption failed                                                 |
| `PRESIGN_FAILED`       | Presign endpoint returned an error or non-200 status                      |
| `UPLOAD_FAILED`        | S3 upload failed (network error or rejected)                              |
| `MANIFEST_PARSE_ERROR` | The manifest text is not valid HLS                                        |
| `INVALID_INPUT`        | Segments array is empty, contentId is invalid, or segment data is missing |
| `ABORTED`              | Upload was cancelled via AbortSignal                                      |

See [Error Codes](/reference/error-codes) for all error codes across BlindCast.
