# Electric Cloud CLI

Command-line interface for [Electric Cloud](https://dashboard.electric-sql.cloud) — manage workspaces, projects, environments, and services from the terminal.

## Installation

```bash
npm install -g @electric-sql/cli
```

Or run directly with `npx`:

```bash
npx @electric-sql/cli --help
```

## Quick Start

```bash
# Log in via browser
electric auth login

# List your workspaces
electric workspaces list

# Create a project
electric projects create --name "my-app"

# Provision a Postgres sync service
electric services create postgres \
  --environment env_abc \
  --database-url "postgresql://postgres:password@localhost:64323/electric" \
  --region us-east-1
  --wait
```

## Authentication

The CLI supports three authentication methods, checked in this order:

### 1. `--token` flag

Pass a token directly for one-off commands or scripts:

```bash
electric projects list --token sv_live_...
```

### 2. `ELECTRIC_API_TOKEN` environment variable

Set a token in your environment for CI/CD pipelines:

```bash
export ELECTRIC_API_TOKEN=sv_live_...
electric projects list
```

### 3. Browser login

For interactive use, log in via OAuth:

```bash
electric auth login
```

This opens the Electric Cloud dashboard in your browser. After authenticating, your session is stored locally at `~/.config/electric/auth.json` and is valid for 7 days.

### Creating API tokens

Tokens are created with specific scopes that control what they can access:

```bash
electric auth token create \
  --name "ci-deploy" \
  --scopes v2:services:read,v2:services:write
```

The token value is displayed once at creation and cannot be retrieved again.

Available scopes: `v2:projects:read`, `v2:projects:write`, `v2:environments:read`, `v2:environments:write`, `v2:services:read`, `v2:services:write`, `v2:services:secrets`, `v2:tokens:read`, `v2:tokens:write`.

## Commands

Run `electric --help` for the full command list, or `electric <command> --help` for details on any command.

```
electric [--json] [--token <token>]
├── auth
│   ├── login                      Log in via browser OAuth
│   ├── logout                     Clear stored credentials
│   ├── whoami                     Show current auth context
│   └── token
│       ├── create                 Create an API token
│       ├── list                   List tokens in a workspace
│       └── revoke <token-id>     Revoke a token
├── workspaces
│   ├── list                       List accessible workspaces
│   └── get <workspace-id>        Get workspace details
├── projects
│   ├── list                       List projects
│   ├── create                     Create a project
│   ├── get <project-id>          Get project details
│   ├── update <project-id>       Rename a project
│   └── delete <project-id>       Delete a project
├── environments
│   ├── list                       List environments in a project
│   ├── create                     Create an environment
│   ├── get <environment-id>      Get environment details
│   ├── update <environment-id>   Rename an environment
│   └── delete <environment-id>   Delete an environment
├── services
│   ├── list                       List services in an environment
│   ├── get <service-id>          Get service details
│   ├── update <service-id>       Rename a service
│   ├── delete <service-id>       Delete a service
│   ├── get-secret <service-id>   Get service credentials
│   └── create
│       ├── postgres               Create a Postgres sync service
│       ├── streams                Create a durable streams service
│       └── proxy                  Create a proxy service
├── durable-streams
│   ├── export                     Export every stream to a tar.gz archive
│   └── import                     Recreate streams from an archive
└── claimable
    ├── create                     Provision a Postgres database with Sync
    ├── status <claim-id>         Check provisioning status
    └── claim <claim-id>          Claim a provisioned service into your workspace
```

### Global flags

| Flag | Description |
|------|-------------|
| `--json` | Output as JSON (for scripting and CI) |
| `--token <token>` | Use this API token for authentication |
| `--help` | Show help for any command |
| `--version` | Show CLI version |

## Common Workflows

### Provision a Postgres sync service

```bash
electric projects create --name "my-app"
electric environments create --project proj_abc --name "staging"
electric services create postgres \
  --environment env_abc \
  --database-url "postgresql://user:pass@host:5432/db" \
  --region us-east-1
```

### Fetch service credentials

```bash
electric services get-secret svc_abc
```

### Back up and restore Durable Streams

Export every stream in a service using its base URL and read token:

```bash
electric durable-streams export \
  --service-url https://api.example.com/v1/stream/service-id \
  --read-token "$SERVICE_JWT" \
  --output ./service-backup
```

The export command follows every stream-list page and reads each stream through
its current tail. It leaves `./service-backup` in place and creates
`./service-backup.tar.gz` alongside it. Each stream is represented by two files:
a URL-encoded `<stream-path>.bin` containing the raw data and a matching
`<stream-path>.json` containing content type, expiry, user metadata, closed
state, offsets, sizes, and export provenance. JSON stream pages are joined into
one valid JSON array in the `.bin` file.

Restore the archive to any Durable Streams-compatible server, repeating
`--header` for whatever authentication or routing headers that server needs:

```bash
electric durable-streams import \
  --archive ./service-backup.tar.gz \
  --server-url https://target.example.com/v1/stream/target-service-id \
  --header "Authorization: Bearer $TARGET_TOKEN" \
  --header "X-Tenant: tenant-id"
```

The import command validates archive paths, file pairs, metadata, and byte
counts before issuing requests. It restores the stream body, content type,
absolute expiry (or TTL), user metadata, and closed state, and refuses to
overwrite a stream that already exists.

### Per-PR environments

```bash
# Create
ENV_ID=$(electric environments create \
  --project "$PROJECT_ID" --name "pr-$PR_NUMBER" \
  --json | jq -r '.id')

electric services create postgres \
  --environment "$ENV_ID" \
  --database-url "$DATABASE_URL" \
  --region us-east-1

# Tear down
electric environments delete "$ENV_ID" --force
```

### Token management

```bash
electric auth token create --name "deploy-bot" --scopes v2:services:read,v2:services:write
electric auth token list
electric auth token revoke tok_abc --force
```

## JSON Output

All commands support `--json` for machine-readable output:

```bash
electric projects list --json
```

Errors in JSON mode are written to stderr:

```json
{ "error": "NOT_FOUND", "message": "Service not found", "exitCode": 3 }
```

Destructive commands (`delete`, `revoke`) require `--force` when using `--json` since there is no interactive prompt.

## Environment Variables

| Variable | Description |
|----------|-------------|
| `ELECTRIC_API_TOKEN` | API token for authentication |
| `ELECTRIC_WORKSPACE_ID` | Default workspace ID |
| `ELECTRIC_API_URL` | Override API base URL |

## Workspace Resolution

Commands that need a workspace resolve it automatically:

1. `--workspace` flag (if provided)
2. `ELECTRIC_WORKSPACE_ID` env var
3. API token → uses the token's bound workspace
4. User JWT with one workspace → auto-selected
5. Multiple workspaces → error with guidance

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | General error (network, unexpected API error) |
| 2 | Authentication error (missing/invalid credentials) |
| 3 | Resource not found |
| 4 | Validation error (bad input, missing `--force`) |
| 5 | Conflict (resource state prevents the operation) |

## License

[Apache-2.0](../../LICENSE)
