Metadata-Version: 2.4
Name: okfile
Version: 2.10.0
Summary: Python CLI for uploading files and publishing static sites to OkFile
License-Expression: Apache-2.0
Project-URL: Homepage, https://www.okfile.com
Project-URL: Repository, https://github.com/okfilecom/okfile
Project-URL: Issues, https://github.com/okfilecom/okfile/issues
Keywords: okfile,upload,publish,cli,cloudflare,r2
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: cryptography>=46.0.0
Dynamic: license-file

# OkFile

Agent-first file upload and publish service built on Cloudflare Pages Functions, R2, and D1.

- Website: `https://www.okfile.com`
- Repository: `https://github.com/okfilecom/okfile`
- License: `Apache-2.0`

## Python CLI

CLI 2.10.0 supports persistent recovery, checksum, cancellation, sequential uploads and managed automatic updates. Install with `python -m pip install --upgrade okfile==2.10.0`, then run `python -m okfile_cli upgrade` once to create the fixed launcher. See [automatic updates](docs/CLI_UPDATES.md) and [CLI recovery](docs/CLI_RESUMABLE_UPLOADS.md). Older servers retain their existing upload flow.

On a server advertising resumable extensions, transient retries reuse the same upload ID and transfer only missing parts or bytes. Upload state is saved in the user's OkFile configuration directory. Interactive reruns ask whether to continue a matching unfinished upload; scripts resume automatically. Ctrl+C pauses and retains state. Changed files cannot resume the old task.

```sh
okfile upload ./report.bin --resume --server http://localhost:8080
okfile upload ./report.bin --restart --server http://localhost:8080
okfile upload ./report.bin --mode sequential --checksum sha256 --server http://localhost:8080
okfile cancel ./report.bin --server http://localhost:8080
```

The published Python package name is `okfile`.

Install the latest release from PyPI:

```bash
py -3 -m pip install okfile
okfile --version
```

Install a pinned version when you need reproducible environments:

```bash
py -3 -m pip install okfile==2.1.4
```

Upgrade to the latest release:

```bash
py -3 -m pip install --upgrade okfile
```

Fallback wheel install:

```bash
py -3 -m pip install "https://okfile.pckee.com/downloads/okfile-2.1.1-py3-none-any.whl"
```

If `okfile` is not on `PATH` yet, use one of these repo-local fallbacks first:

```bash
py -3 -m pip install -e .
okfile --version
```

```bash
py -3 -m okfile_cli --version
py -3 -m okfile_cli publish ./my-site/
```

Do not use `py -m okfile`. The published package exposes the `okfile` console command, while the module entrypoint is `okfile_cli`.

- PyPI: `https://pypi.org/project/okfile/`
- CLI skill doc: `./SKILL.md`

Common CLI examples:

```bash
okfile upload photo.jpg
okfile upload video.mp4 --multipart-concurrency 3
okfile upload video.mp4 --stream
okfile upload video.mp4 --stream --stream-account-id <account_id> --stream-token <token>
okfile upload photo.jpg --retries 5 --retry-delay 3
okfile upload archive.zip --multipart-concurrency 6 --max-downloads 10
okfile upload photo.jpg --expires-at 2026-12-31T23:59:59Z
okfile publish ./my-site/
okfile publish ./my-site/ --retries 5 --retry-delay 2
okfile publish ./my-site/ --state-file .okfile-state.json
okfile publish ./my-site/ --fail-fast
okfile publish ./my-site/ --expires-at 2026-12-31T23:59:59Z
okfile status a3k7m92x
okfile status <stream_video_id> --stream
okfile config --key okf_xxxxx
```

Help examples:

```bash
okfile upload --help
okfile publish --help
okfile status --help
```

Notes:

- `okfile upload` defaults to `--multipart-concurrency 3` for multipart uploads
- larger values can improve throughput for bigger files, but small files may not benefit
- `okfile upload` and `okfile publish` now retry failed file uploads by default with `--retries 3 --retry-delay 2`
- retry delay uses exponential backoff per file, so later retries wait longer than earlier ones
- `okfile publish` continues uploading other files after an individual file failure and reports a failed-file summary at the end
- `okfile publish` writes a local resume file by default at `<site>/.okfile-publish-state.json` and reuses already uploaded files on the next run when size and mtime still match
- the publish state file is deleted automatically after a fully successful site publish
- use `--fail-fast` when you want `publish` to stop immediately on the first file failure instead of collecting a failure summary
- `okfile upload --stream` sends video files to Cloudflare Stream with the tus resumable upload protocol; without Cloudflare credentials it uses OkFile hosted transcoding automatically
- `--stream` requires a Cloudflare account ID and API token with `Stream Write`; use command flags or `CLOUDFLARE_ACCOUNT_ID` plus `CLOUDFLARE_STREAM_API_TOKEN`
- `okfile status --stream <video_uid>` queries Cloudflare Stream video status and playback URLs
- `--max-downloads` only applies to OkFile file storage and cannot be combined with `--stream`
- `--expires-at` maps to Cloudflare Stream scheduled deletion when `--stream` is used

## MCP Server

`@okfilecom/okfile-mcp` is a Model Context Protocol server (stdio, Node 18+) exposing OkFile as agent tools: `okfile_upload_file`, `okfile_publish_site`, `okfile_upload_video_stream`, `okfile_get_status`, `okfile_get_limits`. Register it with one command in Claude Code (`claude mcp add okfile -- npx -y @okfilecom/okfile-mcp`), Claude Desktop, or Cursor; optional env vars `OKFILE_API_KEY`, `OKFILE_SERVER`, and `OKFILE_MCP_ROOT` (restricts which local paths may be published). The source lives in `mcp-server/`; a self-contained build is served at `https://www.okfile.com/okfile-mcp.mjs` (`node okfile-mcp.mjs`).

## What It Does

OkFile is designed for Agents, scripts, and lightweight manual upload use cases.

It supports:

- anonymous uploads
- authenticated uploads with user API keys
- video-to-streaming-media transcoding via hosted Cloudflare Stream (`okfile upload video.mp4 --stream` or `POST /api/stream/prepare`), returning watch/HLS/DASH playback URLs with no Cloudflare account required
- direct file URLs for download or embedding
- preview/playback URLs for image, video, and PDF
- anonymous single-file uploads up to `1GB`
- API Key uploads up to `1TB` per file
- temporary retention for anonymous uploads, with current default expiry at `24 hours`
- a default `10`-download cap on anonymous uploads (on the `/d/{id}` download route); override with `maxDownloads`, or authenticate for uncapped uploads
- multipart upload for larger authenticated files
- phase-1 site directory upload with nested subdirectories and per-site subdomain publish URLs
- automatic shared top-level directory stripping for folder-based site uploads
- directory listing fallback when a published site does not contain root `index.html`
- retrying only missing parts after incomplete multipart uploads
- email magic-link login and account management
- localized home, upload, and account pages

## Main User Flows

### 1. Anonymous Publish

1. `POST /api/upload/prepare`
2. `PUT uploadUrl` or each `parts[].uploadUrl`
3. `POST /api/upload/complete`
4. return `url` and optionally `playUrl`
5. current single-file limit is `1GB`, and uploaded files expire after `24 hours`

### 2. API Key Publish

1. request a magic link and log in
2. create an API key in `/account`
3. call `POST /api/upload/prepare` with `X-API-Key` header
4. upload file data to signed URLs
5. call `POST /api/upload/complete`
6. current single-file limit is `1TB` when a valid API key is used

### 3. Manual Upload

Users can also use:

- `/zh/upload/`
- `/en/upload/`

This path is kept as a fallback entry, while API integration remains the recommended flow.

### 4. Site Directory Publish

1. select a whole folder in `/zh/upload/` or `/en/upload/`
2. the uploader preserves nested relative paths
3. if every file sits under one shared top-level folder, that folder is stripped and treated as the site root
4. if the site contains root `index.html`, `/` renders that page
5. if root `index.html` does not exist, `/` renders a directory listing with file name, size, and upload time
6. image and video entries open inline, while other files use download links

## Architecture

### Runtime

- Cloudflare Pages Functions for routing and API handling
- Cloudflare Worker route for `*.ok26.org/*` site subdomains
- Cloudflare R2 for file storage
- Cloudflare D1 for auth and API key metadata
- Resend for email magic links

### Frontend

- static `index.html` for homepage
- static `upload.html` for manual upload
- server-side localization and SEO injection in `worker-app.js`

### Backend Responsibilities

- issue presigned R2 upload URLs
- complete multipart uploads
- activate public file routes
- resolve published site subdomains from request `Host`
- manage sessions, magic links, and API keys
- enforce anonymous and per-key quota limits

## Core Routes

### Pages

- `/zh/` and `/en/`: localized home pages
- `/zh/upload/` and `/en/upload/`: manual upload pages
- `/account`: redirects to localized account page
- `/zh/account/` and `/en/account/`: localized account pages
- `/admin`: admin console

### Upload APIs

- `POST /api/upload/prepare`
- `POST /api/upload/complete`
- `GET /api/upload/status/{id}`
- `POST /api/stream/prepare` and `GET /api/stream/status/{uid}` for hosted video-to-streaming transcoding
- authenticated automation should send `X-API-Key: okf_...`

Authenticated prepare example:

```bash
curl -X POST "https://www.okfile.com/api/upload/prepare" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: okf_..." \
  --data '{"filename":"photo.jpg","size":12345,"contentType":"image/jpeg"}'
```

### Auth APIs

- `POST /api/auth/request-link`
- `GET /auth/verify?token=...`
- `GET /api/account/me`
- `POST /api/account/api-keys`

### File URLs

- `/i/{id}`: direct file URL
- `/i/{id}?play=1`: preview/playback page
- `/d/{id}`: controlled download route

### Site URLs

- `https://{subdomain}.ok26.org/`: site root or directory listing
- `https://{subdomain}.ok26.org/path/to/file`: published site asset or document
- `https://{subdomain}.ok26.org/path/to/file?download=1`: force download for a site file

## Repository Layout

```text
.
|- worker-app.js                      # main Pages Function entry (re-exports src/router.js)
|- src/                               # worker implementation modules
|  |- router.js                       # route dispatch + scheduled handler
|  |- constants.js                    # shared constants and limits
|  |- utils.js                        # responses, ids, formatting, cookies, rate limiting
|  |- seo.js                          # robots/sitemap/SEO + localized static pages
|  |- policy.js                       # VIP tiers, size limits, expiry rules
|  |- db.js                           # D1 schema bootstrap / lazy migrations
|  |- storage.js                      # R2 presign, metadata, multipart, file serving
|  |- auth.js                         # users, sessions, magic links, API keys
|  |- account.js                      # account data + /api/account handlers
|  |- sites.js                        # site publish, releases, directory listing
|  |- uploads.js                      # upload prepare/quick/complete/status
|  |- admin.js                        # admin APIs + scheduled cleanup
|  |- pages-account.js                # account/login/admin console pages
|  |- pages-viewer.js                 # file viewer pages + raw/controlled downloads
|- index.html                         # homepage
|- upload.html                        # manual upload page
|- schema.sql                         # D1 schema
|- wrangler.toml                      # Cloudflare config
|- SKILL.md                           # root skill document
|- .trae/skills/okfile/SKILL.md       # Trae skill definition
|- okfile-upload-pitfalls.md          # upload pitfalls and debugging notes
```

## Local Development

Install dependencies:

```bash
npm install
```

Run local development:

```bash
npx wrangler pages dev .
```

Deploy to Cloudflare Pages:

```bash
npx wrangler pages deploy . --project-name okfile --branch main
```

## CI/CD

`.github/workflows/ci.yml` runs on every push and pull request:

- **test**: Python CLI unit tests (`tests/`) plus esbuild bundle checks for the main worker and the admin worker
- **deploy** (push to `main` only): deploys all three targets from the same commit Ã¢â‚¬â€ the Pages project (`www.okfile.com`), the sites worker (`*.ok26.org`), and the admin worker (`admin.okfile.com`) Ã¢â‚¬â€ then runs a post-deploy smoke check

Required repository secrets (Settings Ã¢â€ â€™ Secrets and variables Ã¢â€ â€™ Actions):

- `CLOUDFLARE_API_TOKEN`: token with Pages Edit + Workers Scripts Edit + D1 Edit for the account
- `CLOUDFLARE_ACCOUNT_ID`: the Cloudflare account id

Deploying all three targets together prevents the Pages project and the classic workers (which share `worker-app.js`) from drifting apart.

## Configuration

Store secrets in Cloudflare, not in the repository.

### Secrets

- `R2_ACCESS_KEY_ID`
- `R2_SECRET_ACCESS_KEY`
- `RESEND_API_KEY`

### Plain-Text Vars

- `R2_ACCOUNT_ID`
- `RESEND_FROM_EMAIL`
- `ADMIN_EMAILS`

## Database

The D1 schema is defined in `schema.sql` and includes:

- `users`
- `magic_links`
- `sessions`
- `api_keys`
- `api_key_usage_windows`

## Upload Notes

See these repo docs for integration details:

- `SKILL.md`
- `SITE_UPLOAD_DESIGN.md`
- `.trae/skills/okfile/SKILL.md`
- `okfile-upload-pitfalls.md`

The pitfalls doc includes practical notes such as:

- Cloudflare requiring a normal `User-Agent` for some requests
- explicit `Content-Length` on R2 PUT
- multipart retry strategy
- large-file client recommendations on Windows

For site publishing:

- use root `index.html` when you want the subdomain root to render a page
- if you upload a single wrapper folder such as `my-site/...`, OkFile strips `my-site/` automatically
- if no root `index.html` exists, users land on a browsable directory listing instead of downloading an arbitrary file

## Articles

Published and outward-facing articles are archived in `docs/`:

- docs/README.md
- docs/devto-agent-delivery-publish-file-or-site-test-guide.md
- docs/aliyun-workbuddy-agent-file-site-publish-test-guide.md

## Contributing

Please read `CONTRIBUTING.md` before opening pull requests.

## Security

Please read `SECURITY.md` for reporting instructions and secret-handling rules.

## Changelog

See `CHANGELOG.md` for release notes tracked in-repo.

## License

Apache-2.0


Password-protected files: `okfile upload report.pdf --password` prompts privately; recipients enter the password when opening the link. See [password protection](docs/PASSWORD_PROTECTION.md). Requires a supporting server.

Download: `okfile download URL -o saved.bin` automatically resumes matching partial files. Protected links prompt privately, or accept `--password-env NAME`. See [download guide](docs/CLI_DOWNLOADS.md).

Private queues: `okfile queue create videos --mode shared --credentials-out videos.keys.json`. Work queues use claim/renew/release/ack with lease receipts. End-to-end encryption: upload with `--encrypt-password`, download with `--decrypt-password`; passwords are entered privately on the client and no key file is needed. See [command guide](docs/COMMAND_GUIDE.md), [queues](docs/QUEUES.md) and [encryption format](docs/ENCRYPTION.md).

## Completion email

Use `okfile upload FILE --notify-email you@example.com` or `okfile download URL --notify-email you@example.com`. Requires a valid API key or queue credential and server email configuration. Only successful commands notify; decryption must also succeed. Email queue failures warn without failing the completed transfer. See [notification documentation](docs/COMPLETION_NOTIFICATIONS.md).

## Email accounts from the CLI

Go servers with email login enabled support registration and account API key management entirely in the terminal:

```sh
okfile register you@example.com --server https://okfile.pckee.com
okfile login you@example.com
okfile whoami
okfile apikey list
okfile apikey create --name workstation --use
okfile apikey revoke key_ID
okfile logout
```

Enter the emailed verification code at the hidden prompt. Registration creates an account only after verification, signs in and saves a new API key. Repeated login reuses the active saved key. Keep the existing key when accessing its private queues: resource ownership remains per key. See [account commands](docs/CLI_ACCOUNTS.md).

## Task chat

Run `okfile chat` to upload, download, resume and manage your account using local Chinese task phrases. No AI Key is required. See [chat commands](docs/CLI_CHAT.md).
