Metadata-Version: 2.5
Name: beamcode
Version: 1.2.0
Summary: Beamcode — encrypted file transfer, plus optional same-Wi‑Fi Nearby (WebRTC). Same product as beamcode.vjyas.online.
Project-URL: Homepage, https://beamcode.vjyas.online
Project-URL: Documentation, https://beamcode.vjyas.online/how
Project-URL: Repository, https://github.com/jyoshnavi/QRFileTransfer
Author: Beamcode
License-Expression: MIT
Keywords: aes-gcm,beamcode,cli,encryption,file-transfer,qr,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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 :: Communications :: File Sharing
Classifier: Topic :: Security :: Cryptography
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: cryptography>=42
Requires-Dist: httpx>=0.27
Requires-Dist: pyperclip>=1.8
Requires-Dist: qrcode>=7.4
Requires-Dist: rich>=13.7
Provides-Extra: dev
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: nearby
Requires-Dist: aiortc>=1.9; extra == 'nearby'
Description-Content-Type: text/markdown

# Beamcode for Python

**Encrypted file transfer over the internet** — same product as
[beamcode.vjyas.online](https://beamcode.vjyas.online).

```bash
pip install beamcode
```

You encrypt files on your machine, upload ciphertext, and share a link (or QR).
Anyone with the link can download on **any network** — no accounts, no shared Wi‑Fi.

---

## How Beamcode works

```text
  You (sender)                         Receiver (any device)
  ────────────                         ─────────────────────
  1. Pick files / URLs
  2. Encrypt locally (AES-256-GCM)
  3. Upload ciphertext  ──►  Beamcode cloud
  4. Get share_url (+ optional QR)
       │
       └── copy / chat / email  ──►  5. Open link
                                     6. Decrypt locally
                                     7. Save files
```

| Term | What it means |
|------|----------------|
| **share_url** | Link to copy. Includes encryption key in `#k=…` |
| **compact** | Short `bc:id:key` string — denser for QR codes |
| **pair code** | Short check code (e.g. `N26NSM`) to confirm the key by phone |
| **Downloads** | How many times the **full package** can be downloaded |
| **Password** | Optional extra lock (receiver must pass the same password) |
| **TTL** | How long the beam lives before it expires |
| **E2E encrypted** | Server never sees plaintext |

On the web UI, **"1/10 package downloads used"** means the beam allows 10
downloads and 1 was used. In this Python package the default is **1** download.

---

## Install & check

```bash
pip install beamcode
pip install "beamcode[nearby]"   # optional: same-Wi‑Fi Nearby (WebRTC)
beamcode doctor          # crypto + API health (+ nearby extra if installed)
beamcode --help
```

Requires **Python 3.10+**.

---

## Quick start (recommended)

Progress is a **single automatic bar** — you do **not** need `on_progress`.

```python
from beamcode import send_files, receive

result = send_files(
    ["./video.mp4", "https://example.com/doc.pdf"],
    ttl="1h",
    max_downloads=1,
)

print(result.share_url)   # give this to the receiver

paths = receive(result.share_url, out_dir="./inbox")
print(paths)
```

With password:

```python
result = send_files(
    ["./secret.pdf"],
    ttl="24h",
    max_downloads=3,
    password="my-secret-pw",   # 10–128 characters
)

paths = receive(
    result.share_url,
    out_dir="./inbox",
    password="my-secret-pw",   # required if sender set one
)
```

Nearby (same Wi‑Fi, no cloud file storage) — interoperable with the web QR:

```python
from beamcode import send_nearby, receive

# Sender: keep this running while the other device scans
def show(result):
    print(result.share_url)

result = send_nearby(["./video.mp4"], on_ready=show)
# Receiver: phone/web scan, or
paths = receive(result.share_url, out_dir="./inbox")
```

```bash
pip install "beamcode[nearby]"
beamcode send ./report.pdf --nearby          # keep running; scan the QR
beamcode receive "https://beamcode.vjyas.online/n/…#t=…" --out ./inbox
```

---

## Features

| Feature | Details |
|---------|---------|
| Any filetype | PDF, video, zip, JSON, binaries — treated as opaque bytes |
| Multi-file | Several paths in one beam, or `zip=True` to bundle |
| Remote URL attach | Pass `https://…` — Beamcode fetches then encrypts |
| Auto progress | One bar for send and receive (terminal + notebooks) |
| Large files | Disk-backed encrypt/upload up to server max (~2 GB) |
| Multipart resume | Failed large uploads can resume from checkpoint |
| Password | Optional download gate (10–128 chars) |
| Download limit | `max_downloads` (SDK default **1**) |
| TTL | `15m` / `1h` / `24h` / `7d` |
| Room PIN | `generate_pin=True` → 8-digit PIN for `/join` |
| Presence | Optional `--watch` / presence tokens in share URL |
| Revoke / extend / bump | Manage a live beam after send |
| Web compatible | Links open in the Beamcode web app and vice versa |
| **Nearby (optional extra)** | Same-Wi‑Fi WebRTC; file bytes never hit R2. `pip install "beamcode[nearby]"` |

---

## SDK reference

### `send_files(sources, **options) → ShareResult`

Encrypt and upload one or more **local paths** and/or **http(s) URLs**.

```python
from beamcode import send_files

result = send_files(
    ["./a.pdf", "./clip.mp4", "https://example.com/doc.pdf"],
    ttl="1h",
    max_downloads=1,
    password=None,
    zip=False,
    generate_pin=False,
    auto_delete_on_exhaust=False,
    allow_private_urls=False,
    api_url=None,
    turnstile_token=None,
    resume=True,
    show_progress=None,
    on_progress=None,
)
```

#### Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `sources` | list of paths / URLs | *required* | Local files and/or `http(s)` URLs to attach |
| `ttl` | `"15m"`\|`"1h"`\|`"24h"`\|`"7d"` or seconds | `"1h"` | Link lifetime |
| `max_downloads` | `int` | `1` | Max full package downloads (web often defaults to 10) |
| `password` | `str` \| `None` | `None` | Optional; **10–128 chars**; receiver must pass it |
| `zip` | `bool` | `False` | Bundle multiple files into one zip before encrypt |
| `generate_pin` | `bool` | `False` | Issue 8-digit room PIN for same-room `/join` |
| `auto_delete_on_exhaust` | `bool` | `False` | Delete storage after last download slot is used |
| `allow_private_urls` | `bool` | `False` | Allow fetching localhost / private IPs (advanced) |
| `api_url` | `str` \| `None` | production | Override API (`BEAMCODE_API_URL` also works) |
| `turnstile_token` | `str` \| `None` | env / `None` | CAPTCHA token if API enables Turnstile |
| `resume` | `bool` | `True` | Resume multipart uploads from checkpoint |
| `show_progress` | `bool` \| `None` | auto | `True`/`False` force bar; `None` = auto |
| `on_progress` | callback \| `None` | `None` | Custom callback; alone replaces auto UI |
| `client` | `BeamcodeClient` \| `None` | new client | Reuse an existing client |

#### `ShareResult` fields

| Field | Description |
|-------|-------------|
| `share_url` | **Primary** — copy and share this |
| `compact` | `bc:id:key` for dense QR |
| `pair_code` | Short human check code |
| `id` | Transfer id |
| `revoke_token` | Needed to revoke / extend / bump |
| `presence_token` | Embedded in share URL as `p=` |
| `public_url` | Public path without secrets |
| `expires_at` | Unix ms expiry |
| `pin` | Room PIN if `generate_pin=True` |
| `filenames` | Names included in the beam |
| `max_downloads` | Download limit for this beam |
| `password_protected` | `True` if a password was set |

---

### `receive(payload, **options) → list[Path]`

Download and decrypt a beam.

```python
from beamcode import receive

paths = receive(
    "https://beamcode.vjyas.online/d/…#k=…",
    out_dir="./inbox",
    password=None,           # required if sender set password
    encryption_key=None,     # only if key missing from URL
    api_url=None,
    show_progress=None,
    on_progress=None,
)
```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `payload` | `str` | *required* | `share_url`, `bc:id:key`, or id (+ key) |
| `out_dir` | path | `"."` | Folder to write files |
| `password` | `str` \| `None` | `None` | Must match sender password if set |
| `encryption_key` | `str` \| `None` | from URL | If fragment/`bc:` has no key |
| `api_url` | `str` \| `None` | production | Override API |
| `show_progress` | `bool` \| `None` | auto | Single progress bar |
| `on_progress` | callback \| `None` | `None` | Custom progress only |
| `client` | `BeamcodeClient` \| `None` | new | Reuse client |

Accepted payload forms:

- Full URL: `https://beamcode.vjyas.online/d/{id}#k=…&p=…`
- Compact: `bc:{id}:{key}` or `bc:{id}:{key}:{presence}`
- Nearby: `https://beamcode.vjyas.online/n/{id}#t=…` or `bn:{id}:{joinToken}`
- Bare id + `encryption_key=`

---

### `send_nearby(sources, **options) → NearbyShareResult`

Same-Wi‑Fi device-to-device beam. **File bytes never go to R2.** Works with the web Nearby QR.

```python
from beamcode import send_nearby, receive

def show(result):
    print(result.share_url)  # scan this while send_nearby is still running

result = send_nearby(["./clip.mp4"], on_ready=show)  # Ctrl+C to stop
paths = receive(result.share_url, out_dir="./inbox")
```

Requires `pip install "beamcode[nearby]"` (`aiortc`). Keep the sender process running while the other device scans.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `sources` | paths | *required* | Local files only (not URLs) |
| `timeout` | `float` | `45 * 60` | Seconds to keep serving after the QR is ready |
| `until_first` | `bool` | `False` | Return after the first successful delivery |
| `on_ready` | callback \| `None` | `None` | Called with `NearbyShareResult` as soon as the URL exists |
| `on_status` | callback \| `None` | `None` | Human-readable status lines |
| `show_progress` | `bool` \| `None` | auto | Same progress rules as `send_files` |
| `on_progress` | callback \| `None` | `None` | Custom progress only |
| `api_url` | `str` \| `None` | production | Override API |
| `turnstile_token` | `str` \| `None` | env / `None` | CAPTCHA token if API enables Turnstile |
| `wait` | `bool` | `True` | If `False`, create the session and return without hosting |
| `client` | `BeamcodeClient` \| `None` | new | Reuse client |

#### `NearbyShareResult` fields

| Field | Description |
|-------|-------------|
| `share_url` | **Primary** — scan or `beamcode receive` this (`/n/…#t=…`) |
| `compact` | `bn:id:joinToken` for dense QR |
| `join_token` | Session secret (also in `#t=`) |
| `id` | Nearby session id |
| `public_url` | Public path without the token |
| `expires_at` | Unix ms expiry |
| `filenames` | Names included in the beam |
| `delivered` | How many devices finished receiving (after `wait`) |

---

### `BeamcodeClient` (low-level)

For custom apps that need direct API control:

```python
from beamcode import BeamcodeClient

with BeamcodeClient() as client:          # or BeamcodeClient("https://…")
    print(client.health())
    print(client.get_limits())
    # create_transfer / upload_file / upload_multipart_file /
    # complete_transfer / get_download_ticket / revoke_transfer /
    # extend_transfer / bump_downloads / lookup_pin / get_presence …
```

---

### Progress behaviour

| Call style | What you see |
|------------|----------------|
| `send_files([...])` | One automatic bar |
| `send_nearby([...])` | One automatic bar (session + send) |
| `receive(url)` | One automatic bar |
| `show_progress=False` | Silent |
| `on_progress=fn` only | Your callback only (no auto bar) |
| `show_progress=True, on_progress=fn` | Bar **and** callback |

Env kill-switch: `BEAMCODE_NO_PROGRESS=1`.

---

## CLI reference

```bash
beamcode send PATH_OR_URL [PATH_OR_URL...] [OPTIONS]
beamcode send PATH --nearby
beamcode receive PAYLOAD [--out DIR] [--password …] [--key …]
beamcode join PIN --key KEY [--out DIR]
beamcode revoke ID --token REVOKE_TOKEN
beamcode extend ID --token REVOKE_TOKEN --add-sec SECONDS
beamcode bump ID --token REVOKE_TOKEN [--add N | --max N]
beamcode limits
beamcode doctor
```

### `beamcode send` options

| Flag | Default | Description |
|------|---------|-------------|
| `--ttl` | `1h` | `15m` / `1h` / `24h` / `7d` |
| `--downloads` | `1` | Max package downloads |
| `--password` | off | Download password (10–128 chars) |
| `--zip` | off | Zip multiple sources |
| `--pin` | off | Issue room PIN |
| `--auto-delete` | off | Purge after last download |
| `--api-url` | production | Custom API |
| `--turnstile-token` | env | CAPTCHA when required |
| `--nearby` | off | Same-Wi‑Fi Nearby (needs `pip install "beamcode[nearby]"`) |
| `--no-resume` | off | Disable multipart resume |
| `--no-qr` | off | Skip ASCII QR |
| `--no-clipboard` | off | Don’t copy share_url |
| `--json` | off | Machine-readable result |
| `--watch` | off | Print open/download receipts |
| `--allow-private-urls` | off | Fetch private IPs |

Examples:

```bash
beamcode send ./report.pdf
beamcode send ./report.pdf --nearby
beamcode send ./a.mp4 ./b.pdf --downloads 5 --password 'my-secret-pw' --ttl 24h
beamcode send https://example.com/whitepaper.pdf ./notes.txt --zip
beamcode receive "https://beamcode.vjyas.online/d/…#k=…" --out ./inbox
beamcode receive "…" --password 'my-secret-pw'
```

---

## Environment variables

| Variable | Purpose |
|----------|---------|
| `BEAMCODE_API_URL` | API base (default `https://beamcode.vjyas.online`) |
| `BEAMCODE_TURNSTILE_TOKEN` | Turnstile token when CAPTCHA is enabled |
| `BEAMCODE_CHECKPOINT_DIR` | Multipart resume checkpoint folder |
| `BEAMCODE_NO_PROGRESS` | `1` / `true` → hide auto progress bar |

---

## Security notes

- Encryption is **required**. The key lives in `#k=` / `bc:` — treat `share_url` like a secret.
- Password is an **extra** gate on download, not a replacement for the key.
- Nearby (`--nearby` / `send_nearby`) sends **file bytes on the local network only**. The API stores filenames/sizes and WebRTC signaling, not the file. Treat `#t=` / `bn:` like a secret while the sender is running.
- Remote fetch blocks private/loopback hosts by default (SSRF protection, including redirects).
- Large-file path uses disk streaming (≈1 MiB crypto window), not full-file RAM.

---

## Development

```bash
cd python
pip install -e ".[dev]"
pytest
beamcode doctor
```

## Publish to PyPI

Tag-driven via GitHub Actions (`.github/workflows/python-package.yml`).

1. [PyPI Trusted Publishing](https://pypi.org/manage/account/publishing/) — workflow `python-package.yml`, **Environment blank**
2. `git tag py-v1.2.0 && git push origin py-v1.2.0`

## License

MIT — same as the Beamcode monorepo.
