@zerodeploy/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +523 -0
  2. package/dist/cli.js +4954 -0
  3. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,523 @@
1
+ # ZeroDeploy CLI
2
+
3
+ Command-line interface for deploying static sites to ZeroDeploy.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # From the monorepo root
9
+ bun install
10
+
11
+ # Link CLI globally
12
+ cd apps/cli && bun link
13
+ ```
14
+
15
+ After linking, the `zerodeploy` command is available globally.
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # 1. Login with GitHub
21
+ zerodeploy login
22
+
23
+ # 2. Create an organization
24
+ zerodeploy org create "My Company"
25
+
26
+ # 3. Create a site
27
+ zerodeploy site create my-company "My Website"
28
+
29
+ # 4. Deploy your site
30
+ zerodeploy deploy my-website --org my-company --dir ./dist
31
+ ```
32
+
33
+ ## Commands
34
+
35
+ ### Authentication
36
+
37
+ #### `zerodeploy login`
38
+
39
+ Authenticate with GitHub OAuth. Opens browser for authentication and stores JWT token locally.
40
+
41
+ ```bash
42
+ zerodeploy login
43
+ ```
44
+
45
+ Token is stored at `~/.zerodeploy/token`.
46
+
47
+ #### `zerodeploy logout`
48
+
49
+ Clear stored authentication token.
50
+
51
+ ```bash
52
+ zerodeploy logout
53
+ ```
54
+
55
+ #### `zerodeploy whoami`
56
+
57
+ Display current logged-in user information.
58
+
59
+ ```bash
60
+ zerodeploy whoami
61
+ ```
62
+
63
+ Output:
64
+ ```
65
+ Logged in as:
66
+ Username: johndoe
67
+ User ID: 019b1234-5678-...
68
+ Admin: No
69
+ ```
70
+
71
+ ### Organizations
72
+
73
+ #### `zerodeploy org list`
74
+
75
+ List all organizations you own.
76
+
77
+ ```bash
78
+ zerodeploy org list
79
+ ```
80
+
81
+ Output:
82
+ ```
83
+ Organizations:
84
+ - My Company [paid] (id: 019b1234-...)
85
+ - Personal [paid] (id: 019b5678-...)
86
+ ```
87
+
88
+ #### `zerodeploy org create <name>`
89
+
90
+ Create a new organization. Slug is auto-generated from the name.
91
+
92
+ ```bash
93
+ zerodeploy org create "My Company"
94
+ ```
95
+
96
+ Output:
97
+ ```
98
+ Organization created: My Company
99
+ id: 019b1234-5678-...
100
+ ```
101
+
102
+ ### Sites
103
+
104
+ #### `zerodeploy site list <orgSlug>`
105
+
106
+ List all sites in an organization. Shows linked GitHub repositories if configured.
107
+
108
+ ```bash
109
+ zerodeploy site list my-company
110
+ ```
111
+
112
+ Output:
113
+ ```
114
+ Sites:
115
+ my-website My Website -> company/frontend
116
+ landing-page Landing Page
117
+ docs Documentation -> company/monorepo
118
+ ```
119
+
120
+ #### `zerodeploy site create <orgSlug> <name> [options]`
121
+
122
+ Create a new site in an organization. Slug is auto-generated from the name.
123
+
124
+ **Options:**
125
+ - `--repo <owner/repo>` - Link to a GitHub repository
126
+
127
+ ```bash
128
+ # Create a site
129
+ zerodeploy site create my-company "My Website"
130
+
131
+ # Create a site linked to a GitHub repo
132
+ zerodeploy site create my-company "Dashboard" --repo company/monorepo
133
+ ```
134
+
135
+ Output:
136
+ ```
137
+ Site created: Dashboard
138
+ ID: 019b1234-5678-...
139
+ Repo: company/monorepo
140
+ ```
141
+
142
+ #### `zerodeploy site link <orgSlug> <siteSlug> <repo>`
143
+
144
+ Link an existing site to a GitHub repository. One repository can be linked to multiple sites (monorepo support).
145
+
146
+ ```bash
147
+ zerodeploy site link my-company dashboard company/monorepo
148
+ ```
149
+
150
+ Output:
151
+ ```
152
+ Site "Dashboard" linked to company/monorepo
153
+ ```
154
+
155
+ #### `zerodeploy site unlink <orgSlug> <siteSlug>`
156
+
157
+ Remove the GitHub repository link from a site.
158
+
159
+ ```bash
160
+ zerodeploy site unlink my-company dashboard
161
+ ```
162
+
163
+ Output:
164
+ ```
165
+ Site "Dashboard" unlinked from GitHub repository
166
+ ```
167
+
168
+ #### GitHub Repository Linking
169
+
170
+ Sites can be linked to GitHub repositories to enable:
171
+ - Tracking which repo deploys to which site
172
+ - Future: Automatic PR preview comments
173
+ - Future: GitHub webhook integration
174
+
175
+ **Monorepo support:** One repository can be linked to multiple sites:
176
+
177
+ ```
178
+ company/monorepo
179
+ ├── apps/marketing → site: marketing
180
+ ├── apps/dashboard → site: dashboard
181
+ └── apps/docs → site: docs
182
+ ```
183
+
184
+ ### Deployment
185
+
186
+ #### `zerodeploy deploy <siteSlug> [options]`
187
+
188
+ Deploy a directory to a site. Uploads all files and makes the deployment live.
189
+
190
+ **Arguments:**
191
+ - `siteSlug` - The site slug to deploy to
192
+
193
+ **Options:**
194
+ - `--org <orgSlug>` - Organization slug (required)
195
+ - `--dir <directory>` - Directory to deploy (default: auto-detect)
196
+ - `--build` - Run build command before deploying
197
+ - `--no-build` - Skip build step (even if output dir doesn't exist)
198
+ - `--build-command <cmd>` - Override the build command
199
+ - `--install` - Run install command before building
200
+
201
+ **CI/CD Options:**
202
+ - `--pr <number>` - PR number (for GitHub Actions)
203
+ - `--pr-title <title>` - PR title
204
+ - `--commit <sha>` - Commit SHA
205
+ - `--commit-message <message>` - Commit message
206
+ - `--branch <branch>` - Branch name
207
+ - `--github-output` - Output deployment info in GitHub Actions format
208
+
209
+ ```bash
210
+ # Deploy specific directory
211
+ zerodeploy deploy my-website --org my-company --dir ./dist
212
+
213
+ # Auto-detect build directory (looks for dist/, build/, out/, public/)
214
+ zerodeploy deploy my-website --org my-company
215
+
216
+ # Build and deploy (auto-detects framework)
217
+ zerodeploy deploy my-website --org my-company --build
218
+
219
+ # Install, build, and deploy
220
+ zerodeploy deploy my-website --org my-company --install --build
221
+
222
+ # Custom build command
223
+ zerodeploy deploy my-website --org my-company --build-command "npm run build:prod"
224
+ ```
225
+
226
+ Output:
227
+ ```
228
+ Detected: Vite
229
+
230
+ Building...
231
+ > npm run build
232
+
233
+ Deploying: ./dist
234
+ Found 42 files (1.2 MB)
235
+ Created deployment: 019b1234-5678-...
236
+ Uploading files...
237
+ [100%] 42/42 files
238
+
239
+ Deployment successful!
240
+ URL: https://my-website_my-company.zerodeploy.app
241
+ Preview: https://019b1234_my-website_my-company.zerodeploy.app
242
+ ```
243
+
244
+ #### Preview Deployments
245
+
246
+ Each deployment gets a unique preview URL that remains accessible even after new deployments:
247
+
248
+ - **Production URL**: `https://site_org.zerodeploy.app` - Always serves the current deployment
249
+ - **Preview URL**: `https://{shortId}_site_org.zerodeploy.app` - Serves a specific deployment
250
+
251
+ Preview URLs use the first 8 characters of the deployment ID. This is useful for:
252
+ - Reviewing changes before promoting to production
253
+ - Sharing specific versions with stakeholders
254
+ - Rolling back by comparing different deployments
255
+ - PR preview deployments
256
+
257
+ #### GitHub Actions Integration
258
+
259
+ ZeroDeploy integrates with GitHub Actions for automated deployments and PR previews.
260
+
261
+ **Setup:**
262
+ 1. Generate a token: Run `zerodeploy login` and copy the token from `~/.zerodeploy/token`
263
+ 2. Add the token to your repository secrets as `ZERODEPLOY_TOKEN`
264
+ 3. Copy the workflow template to `.github/workflows/deploy.yml`
265
+
266
+ **Minimal workflow:**
267
+ ```yaml
268
+ name: Deploy
269
+ on:
270
+ push:
271
+ branches: [main]
272
+
273
+ jobs:
274
+ deploy:
275
+ runs-on: ubuntu-latest
276
+ steps:
277
+ - uses: actions/checkout@v4
278
+ - uses: oven-sh/setup-bun@v2
279
+ - run: bun install
280
+ - run: bun run build
281
+ - name: Deploy
282
+ env:
283
+ ZERODEPLOY_TOKEN: ${{ secrets.ZERODEPLOY_TOKEN }}
284
+ run: bunx zerodeploy deploy my-site --org my-org
285
+ ```
286
+
287
+ **PR Preview workflow:**
288
+ ```yaml
289
+ - name: Deploy PR Preview
290
+ if: github.event_name == 'pull_request'
291
+ env:
292
+ ZERODEPLOY_TOKEN: ${{ secrets.ZERODEPLOY_TOKEN }}
293
+ run: |
294
+ zerodeploy deploy my-site \
295
+ --org my-org \
296
+ --pr ${{ github.event.pull_request.number }} \
297
+ --pr-title "${{ github.event.pull_request.title }}" \
298
+ --commit ${{ github.sha }} \
299
+ --branch ${{ github.head_ref }} \
300
+ --github-output
301
+ ```
302
+
303
+ The `--github-output` flag exports deployment info as GitHub Actions outputs:
304
+ - `deployment_id` - The deployment ID
305
+ - `deployment_url` - The production URL
306
+ - `preview_url` - The unique preview URL
307
+
308
+ See `apps/cli/examples/github-actions/` for full workflow templates including PR comment automation
309
+
310
+ #### Framework Auto-Detection
311
+
312
+ The CLI automatically detects your framework from `package.json` and uses the appropriate build command and output directory:
313
+
314
+ | Framework | Detection | Build Command | Output Dir |
315
+ |-----------|-----------|---------------|------------|
316
+ | Vite | `vite` in deps | `npm run build` | `dist/` |
317
+ | Next.js | `next` in deps | `npm run build` | `out/` |
318
+ | Create React App | `react-scripts` in deps | `npm run build` | `build/` |
319
+ | Vue CLI | `@vue/cli-service` in deps | `npm run build` | `dist/` |
320
+ | Nuxt | `nuxt` in deps | `npm run build` | `dist/` |
321
+ | Astro | `astro` in deps | `npm run build` | `dist/` |
322
+ | SvelteKit | `@sveltejs/kit` in deps | `npm run build` | `build/` |
323
+ | Gatsby | `gatsby` in deps | `npm run build` | `public/` |
324
+ | Remix | `@remix-run/dev` in deps | `npm run build` | `public/build/` |
325
+ | Parcel | `parcel` in deps | `npm run build` | `dist/` |
326
+
327
+ **Auto-build behavior:**
328
+ - If a framework is detected but the output directory doesn't exist, the CLI automatically runs the build
329
+ - Use `--no-build` to skip the build step
330
+ - Use `--build-command` to override the detected build command
331
+
332
+ **Auto-detected directories (fallback):**
333
+ If no framework is detected, the CLI looks for common build output directories:
334
+ 1. `dist/` (Vite, Rollup)
335
+ 2. `build/` (Create React App)
336
+ 3. `out/` (Next.js static export)
337
+ 4. `public/` (static sites)
338
+
339
+ **Ignored files:**
340
+ The following are automatically excluded from deployments:
341
+ - `node_modules/`
342
+ - `.git/`
343
+ - `.env`, `.env.*` files
344
+ - Hidden files starting with `.`
345
+
346
+ #### `zerodeploy deploy list <siteSlug> --org <orgSlug>`
347
+
348
+ List all deployments for a site.
349
+
350
+ ```bash
351
+ zerodeploy deploy list my-website --org my-company
352
+ ```
353
+
354
+ Output:
355
+ ```
356
+ Deployments for my-company/my-website:
357
+
358
+ 019b1234 ready 12/14/2025, 9:00:00 PM <- current
359
+ 019b1230 ready 12/14/2025, 8:30:00 PM
360
+ 019b1220 ready 12/14/2025, 8:00:00 PM
361
+ ```
362
+
363
+ **Options:**
364
+ - `--org <orgSlug>` - Organization slug (required)
365
+ - `--limit <number>` - Number of deployments to show (default: 10)
366
+
367
+ #### `zerodeploy deploy rollback <deploymentId>`
368
+
369
+ Rollback to a previous deployment. Sets the specified deployment as the current live deployment.
370
+
371
+ ```bash
372
+ zerodeploy deploy rollback 019b1230-5678-...
373
+ ```
374
+
375
+ Output:
376
+ ```
377
+ Rolled back successfully
378
+ Deployment: 019b1230-5678-...
379
+ URL: https://my-website_my-company.zerodeploy.app
380
+ ```
381
+
382
+ ### Deploy Tokens
383
+
384
+ Deploy tokens allow CI/CD systems to authenticate with ZeroDeploy without using your personal JWT.
385
+
386
+ #### `zerodeploy token create <name> --org <org> --site <site>`
387
+
388
+ Create a new deploy token for a site.
389
+
390
+ ```bash
391
+ zerodeploy token create "GitHub Actions" --org my-company --site my-website
392
+ ```
393
+
394
+ Output:
395
+ ```
396
+ Deploy token created successfully!
397
+
398
+ Name: GitHub Actions
399
+ ID: 019b1234-5678-...
400
+
401
+ Token (save this - it will not be shown again):
402
+
403
+ abc123def456...
404
+
405
+ Usage in GitHub Actions:
406
+ Add this token as a repository secret named ZERODEPLOY_TOKEN
407
+ ```
408
+
409
+ **Options:**
410
+ - `--org <orgSlug>` - Organization slug (required)
411
+ - `--site <siteSlug>` - Site slug (required)
412
+
413
+ #### `zerodeploy token list --org <org> --site <site>`
414
+
415
+ List all deploy tokens for a site.
416
+
417
+ ```bash
418
+ zerodeploy token list --org my-company --site my-website
419
+ ```
420
+
421
+ Output:
422
+ ```
423
+ Deploy tokens for my-company/my-website:
424
+
425
+ 019b1234 GitHub Actions Created: 12/14/2025 Last used: 12/14/2025
426
+ 019b5678 CircleCI Created: 12/10/2025 Last used: Never
427
+ ```
428
+
429
+ #### `zerodeploy token delete <tokenId> --org <org> --site <site>`
430
+
431
+ Delete a deploy token. You can use the full ID or the first 8 characters.
432
+
433
+ ```bash
434
+ zerodeploy token delete 019b1234 --org my-company --site my-website
435
+ ```
436
+
437
+ ## Deployment Flow
438
+
439
+ 1. **Create deployment** - API creates a new deployment record with `uploading` status
440
+ 2. **Upload files** - CLI scans directory and uploads each file as base64 to R2
441
+ 3. **Finalize** - API marks deployment as `ready` and sets it as the current deployment
442
+ 4. **Live** - Site is immediately accessible at the deployment URL
443
+
444
+ ## Accessing Deployed Sites
445
+
446
+ After deployment, sites are accessible at:
447
+
448
+ **Local development:**
449
+ ```
450
+ http://localhost:8787/serve/<orgSlug>/<siteSlug>/
451
+ ```
452
+
453
+ **Production:**
454
+ ```
455
+ https://<siteSlug>_<orgSlug>.zerodeploy.app
456
+ ```
457
+
458
+ ### SPA Support
459
+
460
+ ZeroDeploy automatically handles SPA (Single Page Application) routing:
461
+ - Requests without file extensions fall back to `index.html`
462
+ - Enables client-side routing for React, Vue, Angular, etc.
463
+
464
+ ### Caching
465
+
466
+ Appropriate cache headers are set automatically:
467
+ - **HTML files**: `max-age=0, must-revalidate` (always check for updates)
468
+ - **Hashed assets** (e.g., `main.abc123.js`): `max-age=31536000, immutable` (1 year)
469
+ - **Other assets**: `max-age=3600, stale-while-revalidate=86400` (1 hour)
470
+
471
+ ## Configuration
472
+
473
+ ### Token Storage
474
+
475
+ Authentication token is stored at `~/.zerodeploy/token`.
476
+
477
+ For CI/CD, set the `ZERODEPLOY_TOKEN` environment variable instead. The environment variable takes precedence over the file-based token.
478
+
479
+ ### API URL
480
+
481
+ By default, CLI connects to production (`https://api.zerodeploy.dev`). To use a local development server, set the `ZERODEPLOY_API_URL` environment variable:
482
+
483
+ ```bash
484
+ # Point to local dev server
485
+ export ZERODEPLOY_API_URL=http://localhost:8787
486
+
487
+ # Or prefix individual commands
488
+ ZERODEPLOY_API_URL=http://localhost:8787 zerodeploy whoami
489
+ ```
490
+
491
+ Make sure your local API is running with `cd apps/api && bun run dev`.
492
+
493
+ ## Development
494
+
495
+ ```bash
496
+ # Run CLI in development
497
+ cd apps/cli
498
+ bun run src/index.ts <command>
499
+
500
+ # Run tests
501
+ bun test
502
+
503
+ # Run e2e tests (requires API running)
504
+ bun test test/e2e.test.ts
505
+ ```
506
+
507
+ ## Troubleshooting
508
+
509
+ ### "Not logged in"
510
+
511
+ Run `zerodeploy login` to authenticate.
512
+
513
+ ### "Org not found"
514
+
515
+ Ensure you're using the correct org slug (lowercase, hyphenated). Use `zerodeploy org list` to see your organizations.
516
+
517
+ ### "Site not found"
518
+
519
+ Ensure you're using the correct site slug and org slug. Use `zerodeploy site list <orgSlug>` to see sites.
520
+
521
+ ### "No build directory found"
522
+
523
+ Specify the directory explicitly with `--dir ./path/to/build` or ensure your project has a `dist/`, `build/`, `out/`, or `public/` directory.