# How Ego‑Lite Handles File Uploads and Downloads: CDP‑Based Implementation Explained

> Discover how Ego-Lite handles file uploads and downloads using CDP-based Playwright helpers in ego-browser. Learn about the direct Chrome DevTools Protocol implementation.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: deep-dive
- Published: 2026-08-25

---

**Ego‑Lite implements file uploads and downloads through Playwright‑style helpers in the `ego-browser` package, using the Chrome DevTools Protocol (CDP) directly via the [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) and [`src/driver/downloads.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/downloads.ts) modules.**

The `citrolabs/ego-lite` library provides lightweight browser automation with a focus on CDP‑native operations. File handling follows the Playwright API surface while operating at the protocol level, eliminating heavy dependency chains. This article examines the complete upload and download workflow as implemented in the source code.

## File Upload Architecture

### The setInputFiles Helper

The primary entry point for uploads is `page.setInputFiles()`, exported from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) and implemented in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts). This method populates a file input element with one or more files without simulated user interaction.

```typescript
// Re-export from helpers.ts (lines 99-100)
export const setInputFiles = driverFiles.setInputFiles;

```

### CDP Implementation Details

The `setInputFiles(selector, path)` implementation in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) performs three coordinated steps:

1. **Path normalization** – Converts the `path` argument to an array of absolute file paths
2. **Element resolution** – Uses `withHandle()` to obtain the DOM element's `objectId` and current CDP session ID
3. **Protocol invocation** – Calls `DOM.setFileInputFiles` with the file list and element reference

```javascript
// Upload multiple files to a file input element
await page.setInputFiles('#file-input', [
  '/absolute/path/to/file1.txt',
  '/absolute/path/to/file2.jpg',
]);

```

The operation returns `Promise<void>` — no value is returned because the upload modifies page state as a side effect. The CDP command `DOM.setFileInputFiles` is a Chromium‑native operation that directly populates the input's `files` property.

## File Download Handling

### Event‑Based Download Capture

Downloads are captured through `page.waitForEvent('download')`, which delegates to [`src/driver/downloads.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/downloads.ts). The implementation currently supports only the `"download"` event; other event names throw descriptive errors.

### Download Workflow Stages

The [`downloads.ts`](https://github.com/citrolabs/ego-lite/blob/main/downloads.ts) driver implements a multi‑stage download pipeline:

**Stage 1: Environment Preparation**

- Creates a unique temporary directory under `os.tmpdir()` with naming pattern: `{pid}-{timestamp}-{randomSuffix}`
- Invokes `ensureSession()` to guarantee an active CDP session
- Configures download behavior via `setDownloadBehavior()` using `Browser.setDownloadBehavior` (preferred) or `Page.setDownloadBehavior` (fallback)

**Stage 2: Event Listening**

Two CDP events are monitored simultaneously:

- `Page.downloadWillBegin` – Captures the download `guid` and `suggestedFilename`
- `Page.downloadProgress` – Filters by `guid`, watching for `"completed"` or `"canceled"` state

**Stage 3: Completion Handling**

Upon successful completion, a facade object provides four methods:

| Method | Return Type | Description |
|--------|-------------|-------------|
| `suggestedFilename()` | `string` | Filename proposed by the browser |
| `url()` | `string` | Source URL of the download |
| `path()` | `Promise<string>` | Absolute path in temporary directory |
| `saveAs(targetPath)` | `Promise<void>` | Copies file to permanent location |

If the download is canceled, the operation throws an error including the filename.

### Timeout Configuration

Both event listeners respect the `timeout` option, defaulting to `state.defaultTimeout` when unspecified.

```javascript
// Wait for download with custom timeout
const download = await page.waitForEvent('download', { timeout: 30_000 });
console.log('Downloading:', download.suggestedFilename());

// Move to permanent storage
await download.saveAs('/my/downloads/' + download.suggestedFilename());

```

## Key Source Files and Responsibilities

Understanding the module structure clarifies where specific behaviors originate:

- **[`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts)** – Core upload implementation using `DOM.setFileInputFiles`
- **[`src/driver/downloads.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/downloads.ts)** – Complete download lifecycle: temp directory management, behavior configuration, event listening, and facade object creation
- **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** – Public API surface re-exporting driver functions as `page.*` methods
- **[`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts)** – Low‑level `cdp()` wrapper used by both drivers for protocol commands
- **[`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts)** – Provides `ensureSession()` and `waitForBrowserEvent()` infrastructure essential for download operations

## Summary

- **File uploads** in Ego‑Lite use CDP's `DOM.setFileInputFiles` via [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts), accepting absolute paths and operating directly on element `objectId`s
- **File downloads** require configuring browser download behavior, creating temporary directories, and listening for `Page.downloadWillBegin` and `Page.downloadProgress` events
- The **facade pattern** for downloads provides Playwright‑compatible methods (`suggestedFilename()`, `saveAs()`, etc.) while managing temporary file cleanup implicitly
- All operations are **promise‑based** with configurable timeouts consistent with Ego‑Lite's global timeout state
- The **CDP abstraction layer** in [`cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/cdp-eval.ts) and session management in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) enable these features without external browser control dependencies

## Frequently Asked Questions

### How does Ego‑Lite handle multiple file uploads?

The `setInputFiles` method normalizes any path argument to an array, then passes the complete list to CDP's `DOM.setFileInputFiles` command. The browser's native file input mechanism accepts multiple paths simultaneously, populating the input's `files` FileList in order.

### Where are downloaded files stored before saveAs() is called?

Downloads are written to a uniquely‑named temporary directory created under the OS temp folder (`os.tmpdir()`). The directory name incorporates process PID, timestamp, and random suffix to prevent collisions. The `path()` method on the download object resolves to this temporary location.

### What happens if a download is canceled or fails?

The `Page.downloadProgress` event watcher detects `state: "canceled"` and throws an error containing the filename. Successful completion requires `state: "completed"`; no partial file handling is implemented—canceled downloads remain in the temporary directory until system cleanup.

### Can I use waitForEvent for events other than "download"?

Currently no. The [`src/driver/downloads.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/downloads.ts) implementation explicitly validates the event name and throws `'Unsupported event: ${event}'` for any value other than `"download"`. This matches Ego‑Lite's scoped feature set focused on file operations rather than general event coverage.