@zerct/zerct 0.1.10 → 0.1.12
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 +4 -0
- package/bin/zerct.js +62 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,10 @@ on `0.0.0.0:$PORT` and expose the configured health endpoint.
|
|
|
20
20
|
From a full-stack repo root, the same deploy command discovers nested
|
|
21
21
|
`zerct.toml` files and deploys the whole workspace in one command.
|
|
22
22
|
|
|
23
|
+
Managed Postgres apps receive `DATABASE_URL`, `ZERCT_DATABASE_URL`, and
|
|
24
|
+
`ZERCT_DATABASE_CONNECTION_LIMIT`. Use that limit as the max size for your
|
|
25
|
+
database pool.
|
|
26
|
+
|
|
23
27
|
Agents can also inspect API capabilities, account identity, usage, account
|
|
24
28
|
activity, apps, complete app overviews, deploys, builds, app/deploy/build logs,
|
|
25
29
|
env metadata, custom domains, domain verification, and billing portal links
|
package/bin/zerct.js
CHANGED
|
@@ -4,9 +4,10 @@ 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.
|
|
7
|
+
const VERSION = '0.1.12'
|
|
8
8
|
const DEFAULT_API_URL = 'https://api.zerct.com'
|
|
9
9
|
const ARCHIVE_LIMIT_BYTES = 48 * 1024 * 1024
|
|
10
|
+
const DEFAULT_DEPLOY_WAIT_TIMEOUT_SECONDS = 900
|
|
10
11
|
const SESSION_DIR = '.zerct'
|
|
11
12
|
const SESSION_FILE = 'session-token'
|
|
12
13
|
const SESSION_SERVICE = 'com.zerct.cli'
|
|
@@ -64,7 +65,7 @@ Usage:
|
|
|
64
65
|
zerct install [path]
|
|
65
66
|
zerct doctor [path] [--json]
|
|
66
67
|
zerct login [--token <token>] [--api <url>]
|
|
67
|
-
zerct deploy [path] [--database] [--api <url>] [--json]
|
|
68
|
+
zerct deploy [path] [--database] [--wait] [--wait-timeout <seconds>] [--api <url>] [--json]
|
|
68
69
|
zerct capabilities [--api <url>] [--json]
|
|
69
70
|
zerct me [--api <url>] [--json]
|
|
70
71
|
zerct usage [--api <url>] [--json]
|
|
@@ -184,8 +185,10 @@ function parseArgs(argv) {
|
|
|
184
185
|
limit: '',
|
|
185
186
|
cursor: '',
|
|
186
187
|
token: '',
|
|
188
|
+
waitTimeoutSeconds: DEFAULT_DEPLOY_WAIT_TIMEOUT_SECONDS,
|
|
187
189
|
json: false,
|
|
188
190
|
database: false,
|
|
191
|
+
wait: false,
|
|
189
192
|
help: false,
|
|
190
193
|
version: false
|
|
191
194
|
}
|
|
@@ -203,6 +206,11 @@ function parseArgs(argv) {
|
|
|
203
206
|
cli.database = true
|
|
204
207
|
} else if (arg === '--no-database') {
|
|
205
208
|
cli.database = false
|
|
209
|
+
} else if (arg === '--wait') {
|
|
210
|
+
cli.wait = true
|
|
211
|
+
} else if (arg === '--wait-timeout') {
|
|
212
|
+
cli.waitTimeoutSeconds = parsePositiveInteger(requireValue(argv, index, '--wait-timeout'), '--wait-timeout')
|
|
213
|
+
index += 1
|
|
206
214
|
} else if (arg === '--api') {
|
|
207
215
|
cli.apiUrl = requireValue(argv, index, '--api')
|
|
208
216
|
index += 1
|
|
@@ -238,6 +246,14 @@ function parseArgs(argv) {
|
|
|
238
246
|
return cli
|
|
239
247
|
}
|
|
240
248
|
|
|
249
|
+
function parsePositiveInteger(value, name) {
|
|
250
|
+
const parsed = Number.parseInt(value, 10)
|
|
251
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
252
|
+
throw agentError('invalid_argument', `${name} must be a positive integer.`, `Pass ${name} as seconds, for example ${name} 900.`, false)
|
|
253
|
+
}
|
|
254
|
+
return parsed
|
|
255
|
+
}
|
|
256
|
+
|
|
241
257
|
function requireValue(argv, index, name) {
|
|
242
258
|
const value = argv[index + 1]
|
|
243
259
|
if (!value || value.startsWith('--')) {
|
|
@@ -450,6 +466,9 @@ async function deploy(projectDir, cli) {
|
|
|
450
466
|
const token = await readOrLoginToken(project.dir, cli)
|
|
451
467
|
await preflightDeployLimits([project], cli, token, cli.database)
|
|
452
468
|
const result = await deployProject(project.dir, cli, token, cli.database)
|
|
469
|
+
if (cli.wait) {
|
|
470
|
+
result.final_build = await waitForBuild(cli, token, result.build_job.id)
|
|
471
|
+
}
|
|
453
472
|
printDeployResult(result, cli)
|
|
454
473
|
return
|
|
455
474
|
}
|
|
@@ -474,6 +493,10 @@ async function deploy(projectDir, cli) {
|
|
|
474
493
|
}
|
|
475
494
|
}
|
|
476
495
|
|
|
496
|
+
if (cli.wait) {
|
|
497
|
+
await waitForWorkspaceBuilds(cli, token, results)
|
|
498
|
+
}
|
|
499
|
+
|
|
477
500
|
printWorkspaceDeployResults(projectDir, results, cli)
|
|
478
501
|
}
|
|
479
502
|
|
|
@@ -561,7 +584,8 @@ function printWorkspaceDeployResults(projectDir, results, cli) {
|
|
|
561
584
|
kind: result.project.kind,
|
|
562
585
|
wants_database: result.wantsDatabase,
|
|
563
586
|
app: result.response.app,
|
|
564
|
-
build_job: result.response.build_job
|
|
587
|
+
build_job: result.response.build_job,
|
|
588
|
+
final_build: result.finalBuild || null
|
|
565
589
|
}))
|
|
566
590
|
}, null, 2))
|
|
567
591
|
return
|
|
@@ -573,6 +597,41 @@ function printWorkspaceDeployResults(projectDir, results, cli) {
|
|
|
573
597
|
}
|
|
574
598
|
}
|
|
575
599
|
|
|
600
|
+
async function waitForWorkspaceBuilds(cli, token, results) {
|
|
601
|
+
await Promise.all(results.map(async (result) => {
|
|
602
|
+
result.finalBuild = await waitForBuild(cli, token, result.response.build_job.id)
|
|
603
|
+
}))
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async function waitForBuild(cli, token, buildId) {
|
|
607
|
+
const deadline = Date.now() + cli.waitTimeoutSeconds * 1000
|
|
608
|
+
let lastStatus = ''
|
|
609
|
+
|
|
610
|
+
while (Date.now() <= deadline) {
|
|
611
|
+
const response = await apiRequest(cli, 'GET', `/v1/builds/${encodeURIComponent(buildId)}`, token, null)
|
|
612
|
+
const build = response.build
|
|
613
|
+
if (!build?.status) {
|
|
614
|
+
throw agentError('build_status_unavailable', 'Build status is unavailable.', `Retry with \`npx @zerct/zerct logs --build ${buildId}\`.`, cli.json)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (build.status !== lastStatus) {
|
|
618
|
+
progress(cli, `build ${build.id} ${build.status}`)
|
|
619
|
+
lastStatus = build.status
|
|
620
|
+
}
|
|
621
|
+
if (['succeeded', 'failed', 'canceled'].includes(build.status)) {
|
|
622
|
+
return build
|
|
623
|
+
}
|
|
624
|
+
await sleep(3000)
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
throw agentError(
|
|
628
|
+
'build_wait_timeout',
|
|
629
|
+
`Timed out waiting for build ${buildId}.`,
|
|
630
|
+
`Run \`npx @zerct/zerct logs --build ${buildId}\` to continue watching.`,
|
|
631
|
+
cli.json
|
|
632
|
+
)
|
|
633
|
+
}
|
|
634
|
+
|
|
576
635
|
async function logs(cli) {
|
|
577
636
|
const token = await readOrLoginToken(process.cwd(), cli)
|
|
578
637
|
const page = pageQuery(cli)
|