@zerct/zerct 0.1.8 → 0.1.10

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.
package/README.md CHANGED
@@ -22,7 +22,8 @@ From a full-stack repo root, the same deploy command discovers nested
22
22
 
23
23
  Agents can also inspect API capabilities, account identity, usage, account
24
24
  activity, apps, complete app overviews, deploys, builds, app/deploy/build logs,
25
- env metadata, custom domains, and billing portal links through the same CLI.
25
+ env metadata, custom domains, domain verification, and billing portal links
26
+ through the same CLI.
26
27
 
27
28
  On first deploy, the CLI opens browser login, waits for GitHub or Google, stores
28
29
  the Zerct session in the OS credential store when available, and continues the
package/bin/zerct.js CHANGED
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSy
4
4
  import { homedir } from 'node:os'
5
5
  import path from 'node:path'
6
6
 
7
- const VERSION = '0.1.8'
7
+ const VERSION = '0.1.10'
8
8
  const DEFAULT_API_URL = 'https://api.zerct.com'
9
9
  const ARCHIVE_LIMIT_BYTES = 48 * 1024 * 1024
10
10
  const SESSION_DIR = '.zerct'
@@ -82,6 +82,7 @@ Usage:
82
82
  zerct env delete --app <app_id> KEY [--api <url>] [--json]
83
83
  zerct domains list --app <app_id> [--api <url>] [--json]
84
84
  zerct domains add --app <app_id> <domain> [--api <url>] [--json]
85
+ zerct domains verify --app <app_id> <domain> [--api <url>] [--json]
85
86
  zerct domains delete --app <app_id> <domain> [--api <url>] [--json]
86
87
  zerct billing [portal] [--api <url>] [--json]
87
88
 
@@ -447,12 +448,14 @@ async function deploy(projectDir, cli) {
447
448
  throw agentError('invalid_database_target', 'Static frontends cannot attach managed Postgres directly.', 'Deploy a Rust backend with managed Postgres and call it from the frontend.', cli.json)
448
449
  }
449
450
  const token = await readOrLoginToken(project.dir, cli)
451
+ await preflightDeployLimits([project], cli, token, cli.database)
450
452
  const result = await deployProject(project.dir, cli, token, cli.database)
451
453
  printDeployResult(result, cli)
452
454
  return
453
455
  }
454
456
 
455
457
  const token = await readOrLoginToken(projectDir, cli)
458
+ await preflightDeployLimits(projects, cli, token, cli.database)
456
459
  const results = []
457
460
  if (!cli.json) {
458
461
  console.log(`deploying ${projects.length} projects`)
@@ -474,6 +477,50 @@ async function deploy(projectDir, cli) {
474
477
  printWorkspaceDeployResults(projectDir, results, cli)
475
478
  }
476
479
 
480
+ async function preflightDeployLimits(projects, cli, token, databaseRequested) {
481
+ const [usageResponse, appsResponse] = await Promise.all([
482
+ apiRequest(cli, 'GET', '/v1/usage', token, null),
483
+ apiRequest(cli, 'GET', '/v1/apps', token, null)
484
+ ])
485
+ const usage = usageResponse?.usage || {}
486
+ const limits = usageResponse?.limits || {}
487
+ const apps = Array.isArray(appsResponse?.apps) ? appsResponse.apps : []
488
+ const existingApps = new Map(apps.map((app) => [app.name, app]))
489
+ let newProjects = 0
490
+ let newDatabases = 0
491
+
492
+ for (const project of projects) {
493
+ if (!project.name || project.kind === 'unknown') {
494
+ continue
495
+ }
496
+ const existing = existingApps.get(project.name)
497
+ if (!existing) {
498
+ newProjects += 1
499
+ }
500
+ if (databaseRequested && project.kind === 'rust_backend' && !existing?.databaseStorageMib) {
501
+ newDatabases += 1
502
+ }
503
+ }
504
+
505
+ if (newProjects > 0 && Number(usage.appCount) + newProjects > Number(limits.projects)) {
506
+ throw agentError(
507
+ 'payment_required',
508
+ `Project limit reached: ${usage.appCount}/${limits.projects} projects are already used.`,
509
+ 'Redeploy an existing app by reusing its `name` in zerct.toml, or run `npx @zerct/zerct billing` to open Stripe Checkout before creating another project.',
510
+ cli.json
511
+ )
512
+ }
513
+
514
+ if (newDatabases > 0 && Number(usage.databaseCount) + newDatabases > Number(limits.managedDatabases)) {
515
+ throw agentError(
516
+ 'payment_required',
517
+ `Managed Postgres limit reached: ${usage.databaseCount}/${limits.managedDatabases} databases are already used.`,
518
+ 'Redeploy an app that already has managed Postgres, deploy without `--database`, or run `npx @zerct/zerct billing` to open Stripe Checkout.',
519
+ cli.json
520
+ )
521
+ }
522
+ }
523
+
477
524
  async function deployProject(projectDir, cli, token, wantsDatabase) {
478
525
  const report = runDoctor(projectDir)
479
526
  if (!report.ok) {
@@ -681,13 +728,18 @@ async function domainsCommand(cli) {
681
728
  printJsonOrPretty(cli, response)
682
729
  return
683
730
  }
731
+ if (action === 'verify') {
732
+ const response = await apiRequest(cli, 'POST', `/v1/apps/${encodeURIComponent(app)}/domains/${encodeURIComponent(domain)}/verify`, token, null)
733
+ printJsonOrPretty(cli, response)
734
+ return
735
+ }
684
736
  if (action === 'delete') {
685
737
  const response = await apiRequest(cli, 'DELETE', `/v1/apps/${encodeURIComponent(app)}/domains/${encodeURIComponent(domain)}`, token, null)
686
738
  printJsonOrPretty(cli, response)
687
739
  return
688
740
  }
689
741
 
690
- throw agentError('unknown_command', 'Unknown domains command.', 'Use `domains list`, `domains add`, or `domains delete`.', cli.json)
742
+ throw agentError('unknown_command', 'Unknown domains command.', 'Use `domains list`, `domains add`, `domains verify`, or `domains delete`.', cli.json)
691
743
  }
692
744
 
693
745
  async function billing(cli) {
@@ -1283,9 +1335,9 @@ function deployProjectInfo(dir, rootDir) {
1283
1335
  const relative = path.relative(rootDir, dir).replace(/\\/gu, '/') || '.'
1284
1336
  try {
1285
1337
  const config = parseZerctToml(readFileSync(path.join(dir, 'zerct.toml'), 'utf8'), dir)
1286
- return { dir, relative, kind: config.kind }
1338
+ return { dir, relative, name: config.name || '', kind: config.kind }
1287
1339
  } catch (_error) {
1288
- return { dir, relative, kind: 'unknown' }
1340
+ return { dir, relative, name: '', kind: 'unknown' }
1289
1341
  }
1290
1342
  }
1291
1343
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerct/zerct",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Deploy Rust backends and static frontends to Zerct.",
5
5
  "type": "module",
6
6
  "bin": {