@pushto/cli 0.0.9 → 0.1.1

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 (43) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +2 -1
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +32 -10
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/domain.d.ts.map +1 -1
  9. package/dist/commands/domain.js +25 -14
  10. package/dist/commands/domain.js.map +1 -1
  11. package/dist/commands/env.d.ts.map +1 -1
  12. package/dist/commands/env.js +43 -1
  13. package/dist/commands/env.js.map +1 -1
  14. package/dist/commands/upgrade.d.ts +2 -0
  15. package/dist/commands/upgrade.d.ts.map +1 -0
  16. package/dist/commands/upgrade.js +19 -0
  17. package/dist/commands/upgrade.js.map +1 -0
  18. package/dist/commands/whoami.d.ts +2 -0
  19. package/dist/commands/whoami.d.ts.map +1 -0
  20. package/dist/commands/whoami.js +35 -0
  21. package/dist/commands/whoami.js.map +1 -0
  22. package/dist/index.d.ts +0 -1
  23. package/dist/index.js +19 -2
  24. package/dist/index.js.map +1 -1
  25. package/package.json +5 -2
  26. package/.turbo/turbo-build.log +0 -4
  27. package/bin/pushto.js +0 -2
  28. package/src/commands/deploy.ts +0 -135
  29. package/src/commands/doctor.ts +0 -160
  30. package/src/commands/domain.ts +0 -54
  31. package/src/commands/env.ts +0 -129
  32. package/src/commands/init.ts +0 -66
  33. package/src/commands/login.ts +0 -97
  34. package/src/commands/logs.ts +0 -24
  35. package/src/commands/open.ts +0 -27
  36. package/src/commands/rollback.ts +0 -43
  37. package/src/commands/status.ts +0 -59
  38. package/src/index.ts +0 -88
  39. package/src/lib/api.ts +0 -25
  40. package/src/lib/config.ts +0 -30
  41. package/src/lib/resolve-slug.ts +0 -23
  42. package/src/lib/safe-json.ts +0 -15
  43. package/tsconfig.json +0 -18
@@ -1,160 +0,0 @@
1
- import chalk from 'chalk';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { getToken } from '../lib/config.js';
5
- import { resolveSlug } from '../lib/resolve-slug.js';
6
- import { api } from '../lib/api.js';
7
-
8
- interface Check {
9
- name: string;
10
- status: 'pass' | 'warn' | 'fail';
11
- message: string;
12
- }
13
-
14
- export const doctor = async (): Promise<void> => {
15
- console.log(chalk.green('> pushto doctor\n'));
16
-
17
- const checks: Check[] = [];
18
- const cwd = process.cwd();
19
-
20
- // 1. Auth check
21
- const token = getToken();
22
- checks.push(token
23
- ? { name: 'auth', status: 'pass', message: 'logged in' }
24
- : { name: 'auth', status: 'fail', message: 'not logged in. run pushto login' },
25
- );
26
-
27
- // 2. Project linked
28
- const slug = resolveSlug();
29
- checks.push(slug
30
- ? { name: 'project', status: 'pass', message: `linked to ${slug}` }
31
- : { name: 'project', status: 'fail', message: 'no .pushto file. run pushto init <name>' },
32
- );
33
-
34
- // 3. Package.json exists
35
- const pkgPath = path.join(cwd, 'package.json');
36
- const hasPkg = fs.existsSync(pkgPath);
37
- checks.push(hasPkg
38
- ? { name: 'package.json', status: 'pass', message: 'found' }
39
- : { name: 'package.json', status: 'warn', message: 'not found. static site? that works too.' },
40
- );
41
-
42
- // 4. Framework detection
43
- if (hasPkg) {
44
- try {
45
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
46
- const deps = { ...pkg.dependencies, ...pkg.devDependencies };
47
- const framework =
48
- deps['next'] ? 'Next.js' :
49
- deps['react'] ? 'React' :
50
- deps['vue'] ? 'Vue' :
51
- deps['svelte'] ? 'Svelte' :
52
- deps['@sveltejs/kit'] ? 'SvelteKit' :
53
- deps['astro'] ? 'Astro' :
54
- deps['nuxt'] ? 'Nuxt' :
55
- deps['express'] ? 'Express' :
56
- deps['fastify'] ? 'Fastify' :
57
- deps['hono'] ? 'Hono' :
58
- null;
59
-
60
- checks.push(framework
61
- ? { name: 'framework', status: 'pass', message: `detected ${framework}` }
62
- : { name: 'framework', status: 'warn', message: 'no known framework detected. nixpacks will figure it out.' },
63
- );
64
-
65
- // 5. Build script
66
- const hasBuild = pkg.scripts?.build;
67
- checks.push(hasBuild
68
- ? { name: 'build script', status: 'pass', message: `"${hasBuild}"` }
69
- : { name: 'build script', status: 'warn', message: 'no build script. might be fine for static sites.' },
70
- );
71
-
72
- // 6. Node version
73
- const nodeVersion = pkg.engines?.node;
74
- if (nodeVersion) {
75
- checks.push({ name: 'node version', status: 'pass', message: nodeVersion });
76
- }
77
- } catch {
78
- checks.push({ name: 'package.json', status: 'warn', message: 'could not parse package.json' });
79
- }
80
- }
81
-
82
- // 7. .gitignore check
83
- const gitignorePath = path.join(cwd, '.gitignore');
84
- if (fs.existsSync(gitignorePath)) {
85
- const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
86
- if (!gitignore.includes('node_modules')) {
87
- checks.push({ name: '.gitignore', status: 'warn', message: 'node_modules not in .gitignore. deploy will be slow.' });
88
- }
89
- if (!gitignore.includes('.env')) {
90
- checks.push({ name: '.gitignore', status: 'warn', message: '.env not in .gitignore. secrets might leak.' });
91
- }
92
- if (!gitignore.includes('.pushto')) {
93
- checks.push({ name: '.gitignore', status: 'warn', message: '.pushto not in .gitignore. add it.' });
94
- }
95
- }
96
-
97
- // 8. Env vars check (if project linked and authed)
98
- if (token && slug) {
99
- try {
100
- const res = await api(`/cli/projects/${slug}`);
101
- if (res.ok) {
102
- checks.push({ name: 'api', status: 'pass', message: 'pushto.host reachable' });
103
- } else {
104
- checks.push({ name: 'api', status: 'fail', message: 'project not found on pushto.host' });
105
- }
106
- } catch {
107
- checks.push({ name: 'api', status: 'fail', message: 'cannot reach pushto.host' });
108
- }
109
- }
110
-
111
- // 9. Large files check
112
- const largeFiles: string[] = [];
113
- const checkDir = (dir: string, depth = 0) => {
114
- if (depth > 3) return;
115
- try {
116
- const entries = fs.readdirSync(dir, { withFileTypes: true });
117
- for (const entry of entries) {
118
- if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.next') continue;
119
- const full = path.join(dir, entry.name);
120
- if (entry.isFile()) {
121
- const stat = fs.statSync(full);
122
- if (stat.size > 10 * 1024 * 1024) {
123
- largeFiles.push(`${entry.name} (${Math.round(stat.size / 1024 / 1024)}MB)`);
124
- }
125
- } else if (entry.isDirectory()) {
126
- checkDir(full, depth + 1);
127
- }
128
- }
129
- } catch { /* permission error, skip */ }
130
- };
131
- checkDir(cwd);
132
-
133
- if (largeFiles.length > 0) {
134
- checks.push({ name: 'large files', status: 'warn', message: `found: ${largeFiles.join(', ')}. will slow deploy.` });
135
- }
136
-
137
- // Print results
138
- console.log();
139
- for (const check of checks) {
140
- const icon = check.status === 'pass' ? chalk.green('✓')
141
- : check.status === 'warn' ? chalk.yellow('⚠')
142
- : chalk.red('✗');
143
- const color = check.status === 'pass' ? chalk.dim
144
- : check.status === 'warn' ? chalk.yellow
145
- : chalk.red;
146
- console.log(` ${icon} ${chalk.dim(check.name.padEnd(16))} ${color(check.message)}`);
147
- }
148
-
149
- const fails = checks.filter((c) => c.status === 'fail');
150
- const warns = checks.filter((c) => c.status === 'warn');
151
-
152
- console.log();
153
- if (fails.length > 0) {
154
- console.log(chalk.red(` ${fails.length} issue${fails.length > 1 ? 's' : ''} to fix before deploying.`));
155
- } else if (warns.length > 0) {
156
- console.log(chalk.yellow(` ${warns.length} warning${warns.length > 1 ? 's' : ''}. probably fine. deploy when ready.`));
157
- } else {
158
- console.log(chalk.green(' all good. run pushto to deploy.'));
159
- }
160
- };
@@ -1,54 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getToken } from '../lib/config.js';
3
- import { resolveSlug } from '../lib/resolve-slug.js';
4
-
5
- export const domain = async (action: string, domainName?: string): Promise<void> => {
6
- const token = getToken();
7
- if (!token) {
8
- console.log(chalk.red('> not logged in.'));
9
- process.exit(1);
10
- }
11
-
12
- const slug = resolveSlug();
13
- if (!slug) {
14
- console.log(chalk.red('> no project here. run pushto init first.'));
15
- process.exit(1);
16
- }
17
-
18
- if (action === 'add') {
19
- if (!domainName) {
20
- console.log(chalk.red('> usage: pushto domain add yourdomain.com'));
21
- process.exit(1);
22
- }
23
-
24
- console.log(chalk.green(`> setting up ${domainName} for ${slug}\n`));
25
- console.log(chalk.dim(' add this DNS record at your domain provider:\n'));
26
- console.log(` ${chalk.cyan('Type')} ${chalk.cyan('Name')} ${chalk.cyan('Value')}`);
27
- console.log(` CNAME @ ${slug}.pushto.host`);
28
- console.log();
29
- console.log(chalk.dim(' or if your provider doesn\'t support CNAME on root:\n'));
30
- console.log(` A @ 76.76.21.21`);
31
- console.log();
32
-
33
- // TODO: when Cloudflare DNS API is wired, this will:
34
- // 1. Register the domain in our system
35
- // 2. Provision SSL via Let's Encrypt
36
- // 3. Poll DNS until verified
37
- // 4. Update the project's customDomain field
38
-
39
- console.log(chalk.yellow(' auto-verification coming soon.'));
40
- console.log(chalk.dim(' for now, add the domain in your dashboard too:'));
41
- console.log(chalk.cyan(` https://pushto.host/dashboard/projects/${slug}/settings`));
42
-
43
- } else if (action === 'remove' || action === 'rm') {
44
- console.log(chalk.green(`> removing custom domain from ${slug}`));
45
- console.log(chalk.yellow(' domain management coming soon via CLI.'));
46
- console.log(chalk.dim(' use the dashboard for now:'));
47
- console.log(chalk.cyan(` https://pushto.host/dashboard/projects/${slug}/settings`));
48
-
49
- } else {
50
- console.log(chalk.dim(' usage:'));
51
- console.log(chalk.cyan(' pushto domain add yourdomain.com'));
52
- console.log(chalk.cyan(' pushto domain remove'));
53
- }
54
- };
@@ -1,129 +0,0 @@
1
- import chalk from 'chalk';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { getToken } from '../lib/config.js';
5
- import { resolveSlug } from '../lib/resolve-slug.js';
6
- import { api } from '../lib/api.js';
7
- import { safeJson } from '../lib/safe-json.js';
8
-
9
- export const env = async (action: string, args: string[]): Promise<void> => {
10
- const token = getToken();
11
- if (!token) {
12
- console.log(chalk.red('> not logged in.'));
13
- console.log(chalk.dim(' run ') + chalk.cyan('pushto login') + chalk.dim(' first.'));
14
- process.exit(1);
15
- }
16
-
17
- const slug = resolveSlug();
18
- if (!slug) {
19
- console.log(chalk.red('> no project here. run pushto init first.'));
20
- process.exit(1);
21
- }
22
-
23
- if (action === 'set') {
24
- // pushto env set KEY=value
25
- const pair = args[0];
26
- if (!pair || !pair.includes('=')) {
27
- console.log(chalk.red('> usage: pushto env set KEY=value'));
28
- process.exit(1);
29
- }
30
-
31
- const eqIdx = pair.indexOf('=');
32
- const key = pair.slice(0, eqIdx);
33
- const value = pair.slice(eqIdx + 1);
34
-
35
- if (!key) {
36
- console.log(chalk.red('> key is empty.'));
37
- process.exit(1);
38
- }
39
-
40
- // Call the tRPC mutation via REST-like endpoint
41
- // We'll use a simple CLI API endpoint for this
42
- const res = await api(`/cli/projects/${slug}/env`, {
43
- method: 'POST',
44
- body: JSON.stringify({ key, value }),
45
- });
46
-
47
- if (!res.ok) {
48
- const data = (await safeJson<{ error?: string }>(res));
49
- console.log(chalk.red(`> ${data.error ?? 'failed to set env var.'}`));
50
- process.exit(1);
51
- }
52
-
53
- console.log(chalk.green(`> ${key} set.`));
54
-
55
- } else if (action === 'list' || action === 'ls') {
56
- // pushto env list
57
- const res = await api(`/cli/projects/${slug}/env`);
58
-
59
- if (!res.ok) {
60
- const data = (await safeJson<{ error?: string }>(res));
61
- console.log(chalk.red(`> ${data.error ?? 'failed to list env vars.'}`));
62
- process.exit(1);
63
- }
64
-
65
- const vars = await safeJson<{ key: string; value: string }[]>(res);
66
-
67
- if (vars.length === 0) {
68
- console.log(chalk.dim('> no env vars set.'));
69
- return;
70
- }
71
-
72
- console.log(chalk.green(`> ${slug} env vars\n`));
73
- for (const v of vars) {
74
- console.log(` ${chalk.cyan(v.key)}=${chalk.dim('••••••••')}`);
75
- }
76
- console.log(chalk.dim(`\n ${vars.length} variable${vars.length > 1 ? 's' : ''}`));
77
-
78
- } else if (action === 'pull') {
79
- // pushto env pull — download to .env
80
- const res = await api(`/cli/projects/${slug}/env`);
81
-
82
- if (!res.ok) {
83
- const data = (await safeJson<{ error?: string }>(res));
84
- console.log(chalk.red(`> ${data.error ?? 'failed to pull env vars.'}`));
85
- process.exit(1);
86
- }
87
-
88
- const vars = await safeJson<{ key: string; value: string }[]>(res);
89
-
90
- if (vars.length === 0) {
91
- console.log(chalk.dim('> no env vars to pull.'));
92
- return;
93
- }
94
-
95
- const envContent = vars.map((v) => `${v.key}=${v.value}`).join('\n') + '\n';
96
- const envPath = path.join(process.cwd(), '.env');
97
-
98
- fs.writeFileSync(envPath, envContent);
99
- console.log(chalk.green(`> pulled ${vars.length} var${vars.length > 1 ? 's' : ''} to .env`));
100
- console.log(chalk.dim(' make sure .env is in your .gitignore.'));
101
-
102
- } else if (action === 'rm' || action === 'remove' || action === 'delete') {
103
- const key = args[0];
104
- if (!key) {
105
- console.log(chalk.red('> usage: pushto env rm KEY'));
106
- process.exit(1);
107
- }
108
-
109
- const res = await api(`/cli/projects/${slug}/env`, {
110
- method: 'DELETE',
111
- body: JSON.stringify({ key }),
112
- });
113
-
114
- if (!res.ok) {
115
- const data = (await safeJson<{ error?: string }>(res));
116
- console.log(chalk.red(`> ${data.error ?? 'failed to delete env var.'}`));
117
- process.exit(1);
118
- }
119
-
120
- console.log(chalk.green(`> ${key} removed.`));
121
-
122
- } else {
123
- console.log(chalk.dim(' usage:'));
124
- console.log(chalk.cyan(' pushto env set KEY=value'));
125
- console.log(chalk.cyan(' pushto env list'));
126
- console.log(chalk.cyan(' pushto env pull'));
127
- console.log(chalk.cyan(' pushto env rm KEY'));
128
- }
129
- };
@@ -1,66 +0,0 @@
1
- import chalk from 'chalk';
2
- import ora from 'ora';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { getToken, setProjectSlug } from '../lib/config.js';
6
- import { api } from '../lib/api.js';
7
- import { safeJson } from '../lib/safe-json.js';
8
-
9
- export const init = async (name: string): Promise<void> => {
10
- const token = getToken();
11
- if (!token) {
12
- console.log(chalk.red('> not logged in.'));
13
- console.log(chalk.dim(' run ') + chalk.cyan('pushto login') + chalk.dim(' first.'));
14
- process.exit(1);
15
- }
16
-
17
- const slug = name
18
- .toLowerCase()
19
- .replace(/[^a-z0-9-]/g, '-')
20
- .replace(/-+/g, '-')
21
- .replace(/^-|-$/g, '');
22
-
23
- if (slug.length < 3) {
24
- console.log(chalk.red('> name too short. needs at least 3 characters.'));
25
- process.exit(1);
26
- }
27
-
28
- const spinner = ora('creating project...').start();
29
-
30
- try {
31
- const res = await api('/cli/projects', {
32
- method: 'POST',
33
- body: JSON.stringify({ name, slug }),
34
- });
35
-
36
- const data = await safeJson<{
37
- error?: string;
38
- project?: { id: string };
39
- message?: string;
40
- }>(res);
41
-
42
- if (!res.ok) {
43
- spinner.fail(chalk.red(`> ${data.error ?? 'something went wrong.'}`));
44
- process.exit(1);
45
- }
46
-
47
- // Write .pushto file in current directory
48
- const pushtoConfig = { slug, projectId: data.project?.id };
49
- fs.writeFileSync(
50
- path.join(process.cwd(), '.pushto'),
51
- JSON.stringify(pushtoConfig, null, 2) + '\n',
52
- );
53
-
54
- // Also store globally so bare `pushto` works from this dir
55
- setProjectSlug(slug);
56
-
57
- spinner.succeed(chalk.green(`> ${slug} is ready.`));
58
- console.log(chalk.dim(` ${data.message ?? 'project created.'}`));
59
- console.log();
60
- console.log(chalk.dim(' deploy anytime with just: ') + chalk.cyan('pushto'));
61
- console.log(chalk.dim(' your url will be: ') + chalk.cyan(`${slug}.pushto.host`));
62
- } catch (err) {
63
- spinner.fail(chalk.red('> could not reach pushto.host. check your internet.'));
64
- process.exit(1);
65
- }
66
- };
@@ -1,97 +0,0 @@
1
- import chalk from 'chalk';
2
- import http from 'node:http';
3
- import { execSync } from 'node:child_process';
4
- import { setToken, config } from '../lib/config.js';
5
- import { api } from '../lib/api.js';
6
-
7
- export const login = async (): Promise<void> => {
8
- const baseUrl = config.get('apiUrl');
9
-
10
- // Start a local server to receive the callback
11
- const server = http.createServer((req, res) => {
12
- // Handle CORS preflight
13
- if (req.method === 'OPTIONS') {
14
- res.writeHead(200, {
15
- 'Access-Control-Allow-Origin': baseUrl,
16
- 'Access-Control-Allow-Methods': 'POST, OPTIONS',
17
- 'Access-Control-Allow-Headers': 'Content-Type',
18
- });
19
- res.end();
20
- return;
21
- }
22
-
23
- if (req.method === 'POST' && req.url === '/callback') {
24
- let body = '';
25
- req.on('data', (chunk) => (body += chunk));
26
- req.on('end', async () => {
27
- res.writeHead(200, {
28
- 'Content-Type': 'application/json',
29
- 'Access-Control-Allow-Origin': baseUrl,
30
- });
31
- res.end(JSON.stringify({ ok: true }));
32
-
33
- try {
34
- const { access_token } = JSON.parse(body);
35
- if (!access_token) {
36
- console.log(chalk.red('\n> auth failed. no token received.'));
37
- process.exit(1);
38
- }
39
-
40
- setToken(access_token);
41
-
42
- // Verify the token
43
- const meRes = await api('/cli/me');
44
- if (meRes.ok) {
45
- const me = (await meRes.json()) as { email: string; tier: string };
46
- console.log(chalk.green(`\n> logged in as ${me.email}`));
47
- console.log(chalk.dim(` tier: ${me.tier.toLowerCase()}`));
48
- } else {
49
- console.log(chalk.green('\n> logged in.'));
50
- }
51
- } catch {
52
- console.log(chalk.green('\n> logged in.'));
53
- }
54
-
55
- server.close();
56
- process.exit(0);
57
- });
58
- return;
59
- }
60
-
61
- res.writeHead(404);
62
- res.end();
63
- });
64
-
65
- // Listen on a random available port
66
- server.listen(0, () => {
67
- const port = (server.address() as { port: number }).port;
68
- const authUrl = `${baseUrl}/cli/auth?port=${port}`;
69
-
70
- console.log(chalk.dim('> opening browser to log you in...'));
71
- console.log(chalk.dim(` if it doesn't open, go to: `) + chalk.cyan(authUrl));
72
-
73
- // Open browser
74
- const open = (url: string) => {
75
- const cmd =
76
- process.platform === 'darwin'
77
- ? `open "${url}"`
78
- : process.platform === 'win32'
79
- ? `start "${url}"`
80
- : `xdg-open "${url}"`;
81
- try {
82
- execSync(cmd, { stdio: 'ignore' });
83
- } catch {
84
- // User will see the URL in the console
85
- }
86
- };
87
-
88
- open(authUrl);
89
-
90
- // Timeout after 2 minutes
91
- setTimeout(() => {
92
- console.log(chalk.red('\n> login timed out. try again.'));
93
- server.close();
94
- process.exit(1);
95
- }, 120_000);
96
- });
97
- };
@@ -1,24 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getToken } from '../lib/config.js';
3
- import { resolveSlug } from '../lib/resolve-slug.js';
4
-
5
- export const logs = async (): Promise<void> => {
6
- const token = getToken();
7
- if (!token) {
8
- console.log(chalk.red('> not logged in.'));
9
- console.log(chalk.dim(' run ') + chalk.cyan('pushto login') + chalk.dim(' first.'));
10
- process.exit(1);
11
- }
12
-
13
- const slug = resolveSlug();
14
- if (!slug) {
15
- console.log(chalk.red('> no project here. run pushto init first.'));
16
- process.exit(1);
17
- }
18
-
19
- console.log(chalk.dim(`> streaming logs for ${slug}...`));
20
- console.log(chalk.dim(' (ctrl+c to stop)\n'));
21
-
22
- // TODO: Phase 3 — SSE connection to log stream API
23
- console.log(chalk.yellow('> log streaming coming soon. deploy first, then we\'ll show you everything.'));
24
- };
@@ -1,27 +0,0 @@
1
- import chalk from 'chalk';
2
- import { execSync } from 'node:child_process';
3
- import { resolveSlug } from '../lib/resolve-slug.js';
4
-
5
- export const open = async (): Promise<void> => {
6
- const slug = resolveSlug();
7
- if (!slug) {
8
- console.log(chalk.red('> no project here. run pushto init first.'));
9
- process.exit(1);
10
- }
11
-
12
- const url = `https://${slug}.pushto.host`;
13
- console.log(chalk.green(`> opening ${url}`));
14
-
15
- const cmd =
16
- process.platform === 'darwin'
17
- ? `open "${url}"`
18
- : process.platform === 'win32'
19
- ? `start "${url}"`
20
- : `xdg-open "${url}"`;
21
-
22
- try {
23
- execSync(cmd, { stdio: 'ignore' });
24
- } catch {
25
- console.log(chalk.dim(` couldn't open browser. go to: `) + chalk.cyan(url));
26
- }
27
- };
@@ -1,43 +0,0 @@
1
- import chalk from 'chalk';
2
- import ora from 'ora';
3
- import { getToken } from '../lib/config.js';
4
- import { resolveSlug } from '../lib/resolve-slug.js';
5
- import { api } from '../lib/api.js';
6
-
7
- export const rollback = async (version?: string): Promise<void> => {
8
- const token = getToken();
9
- if (!token) {
10
- console.log(chalk.red('> not logged in.'));
11
- process.exit(1);
12
- }
13
-
14
- const slug = resolveSlug();
15
- if (!slug) {
16
- console.log(chalk.red('> no project here. run pushto init first.'));
17
- process.exit(1);
18
- }
19
-
20
- const spinner = ora('rolling back...').start();
21
-
22
- try {
23
- // TODO: when build engine is live, this will call the rollback API
24
- // which restores the previous Fly Machine image
25
- spinner.info(chalk.yellow('> rollback is ready to wire up.'));
26
- console.log();
27
- console.log(chalk.dim(' when the build engine is live, this command will:'));
28
- console.log(chalk.dim(' 1. find the last working deployment'));
29
- console.log(chalk.dim(' 2. restore that container image'));
30
- console.log(chalk.dim(' 3. update DNS to point to it'));
31
- console.log(chalk.dim(' 4. mark the current deploy as rolled back'));
32
- console.log();
33
- if (version) {
34
- console.log(chalk.dim(` target version: v${version}`));
35
- } else {
36
- console.log(chalk.dim(' target: previous working deploy'));
37
- }
38
- console.log(chalk.dim(" you're early. this will work soon."));
39
- } catch {
40
- spinner.fail(chalk.red('> rollback failed.'));
41
- process.exit(1);
42
- }
43
- };
@@ -1,59 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getToken } from '../lib/config.js';
3
- import { api } from '../lib/api.js';
4
- import { resolveSlug } from '../lib/resolve-slug.js';
5
- import { safeJson } from '../lib/safe-json.js';
6
-
7
- const STATUS_COLORS: Record<string, (s: string) => string> = {
8
- CREATED: chalk.dim,
9
- BUILDING: chalk.yellow,
10
- DEPLOYING: chalk.yellow,
11
- LIVE: chalk.green,
12
- SLEEPING: chalk.cyan,
13
- FAILED: chalk.red,
14
- SUSPENDED: chalk.red,
15
- };
16
-
17
- export const status = async (): Promise<void> => {
18
- const token = getToken();
19
- if (!token) {
20
- console.log(chalk.red('> not logged in.'));
21
- console.log(chalk.dim(' run ') + chalk.cyan('pushto login') + chalk.dim(' first.'));
22
- process.exit(1);
23
- }
24
-
25
- const slug = resolveSlug();
26
- if (!slug) {
27
- console.log(chalk.red('> no project here.'));
28
- console.log(chalk.dim(' run ') + chalk.cyan('pushto init <name>') + chalk.dim(' first.'));
29
- process.exit(1);
30
- }
31
-
32
- try {
33
- const res = await api(`/cli/projects/${slug}`);
34
-
35
- if (!res.ok) {
36
- const data = await safeJson<{ error?: string }>(res);
37
- console.log(chalk.red(`> ${data.error ?? 'something went wrong.'}`));
38
- process.exit(1);
39
- }
40
-
41
- const project = await safeJson<{
42
- name: string;
43
- status: string;
44
- subdomain: string;
45
- customDomain?: string | null;
46
- }>(res);
47
- const colorFn = STATUS_COLORS[project.status] ?? chalk.dim;
48
-
49
- console.log(chalk.green(`> ${project.name}`));
50
- console.log(chalk.dim(' status: ') + colorFn(project.status.toLowerCase()));
51
- console.log(chalk.dim(' url: ') + chalk.cyan(`${project.subdomain}.pushto.host`));
52
- if (project.customDomain) {
53
- console.log(chalk.dim(' domain: ') + chalk.cyan(project.customDomain));
54
- }
55
- } catch {
56
- console.log(chalk.red('> could not reach pushto.host. check your internet.'));
57
- process.exit(1);
58
- }
59
- };