@danubedata/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 (54) hide show
  1. package/README.md +138 -0
  2. package/bin/danube +2 -0
  3. package/dist/commands/deploy.d.ts +4 -0
  4. package/dist/commands/deploy.js +72 -0
  5. package/dist/commands/deploy.js.map +1 -0
  6. package/dist/commands/deployments.d.ts +2 -0
  7. package/dist/commands/deployments.js +52 -0
  8. package/dist/commands/deployments.js.map +1 -0
  9. package/dist/commands/domains.d.ts +2 -0
  10. package/dist/commands/domains.js +89 -0
  11. package/dist/commands/domains.js.map +1 -0
  12. package/dist/commands/link.d.ts +2 -0
  13. package/dist/commands/link.js +58 -0
  14. package/dist/commands/link.js.map +1 -0
  15. package/dist/commands/login.d.ts +2 -0
  16. package/dist/commands/login.js +50 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/logout.d.ts +2 -0
  19. package/dist/commands/logout.js +10 -0
  20. package/dist/commands/logout.js.map +1 -0
  21. package/dist/commands/whoami.d.ts +2 -0
  22. package/dist/commands/whoami.js +16 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +81 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/api-client.d.ts +11 -0
  28. package/dist/lib/api-client.js +63 -0
  29. package/dist/lib/api-client.js.map +1 -0
  30. package/dist/lib/config.d.ts +9 -0
  31. package/dist/lib/config.js +38 -0
  32. package/dist/lib/config.js.map +1 -0
  33. package/dist/lib/errors.d.ts +11 -0
  34. package/dist/lib/errors.js +23 -0
  35. package/dist/lib/errors.js.map +1 -0
  36. package/dist/lib/output.d.ts +4 -0
  37. package/dist/lib/output.js +36 -0
  38. package/dist/lib/output.js.map +1 -0
  39. package/dist/lib/packager.d.ts +5 -0
  40. package/dist/lib/packager.js +85 -0
  41. package/dist/lib/packager.js.map +1 -0
  42. package/dist/lib/project.d.ts +13 -0
  43. package/dist/lib/project.js +39 -0
  44. package/dist/lib/project.js.map +1 -0
  45. package/dist/lib/sleep.d.ts +1 -0
  46. package/dist/lib/sleep.js +4 -0
  47. package/dist/lib/sleep.js.map +1 -0
  48. package/dist/lib/version.d.ts +9 -0
  49. package/dist/lib/version.js +80 -0
  50. package/dist/lib/version.js.map +1 -0
  51. package/dist/types/api.d.ts +89 -0
  52. package/dist/types/api.js +2 -0
  53. package/dist/types/api.js.map +1 -0
  54. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # @danubedata/cli
2
+
3
+ Deploy static sites to [DanubeData](https://danubedata.ro) from the terminal.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @danubedata/cli
9
+ ```
10
+
11
+ Requires Node.js 18 or later.
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Authenticate with your API token
17
+ danube login
18
+
19
+ # Link your project to a static site
20
+ danube pages link
21
+
22
+ # Deploy the current directory
23
+ danube pages deploy
24
+ ```
25
+
26
+ ## Authentication
27
+
28
+ Generate an API token from your [DanubeData dashboard](https://danubedata.ro) and authenticate:
29
+
30
+ ```bash
31
+ danube login
32
+ ```
33
+
34
+ You can also pass the token directly:
35
+
36
+ ```bash
37
+ danube login --token <your-token>
38
+ ```
39
+
40
+ Or set the `DANUBE_TOKEN` environment variable for CI/CD:
41
+
42
+ ```bash
43
+ export DANUBE_TOKEN=your-token
44
+ danube pages deploy
45
+ ```
46
+
47
+ ## Commands
48
+
49
+ ### `danube login`
50
+
51
+ Authenticate with DanubeData. Prompts for an API token or accepts `--token <token>`.
52
+
53
+ ### `danube logout`
54
+
55
+ Remove stored authentication credentials.
56
+
57
+ ### `danube whoami`
58
+
59
+ Show the currently authenticated user and their teams.
60
+
61
+ ### `danube pages link`
62
+
63
+ Link the current directory to a DanubeData static site. Prompts you to select a team and site (or create a new one). Writes configuration to `.danube/project.json`.
64
+
65
+ ### `danube pages deploy`
66
+
67
+ Deploy your site to DanubeData.
68
+
69
+ ```bash
70
+ danube pages deploy # Deploy current directory
71
+ danube pages deploy --dir dist # Deploy a specific directory
72
+ danube pages deploy --no-wait # Don't wait for build to complete
73
+ ```
74
+
75
+ The command packages your files into a ZIP archive, uploads them, and polls the build status until deployment is live.
76
+
77
+ ### `danube pages deployments ls`
78
+
79
+ List all deployments for the linked site. Shows revision, status, trigger method, and timestamps.
80
+
81
+ ### `danube pages deployments rollback <revision>`
82
+
83
+ Activate a previous deployment by revision number.
84
+
85
+ ```bash
86
+ danube pages deployments rollback 3
87
+ ```
88
+
89
+ ### `danube pages domains ls`
90
+
91
+ List all domains configured for the linked site.
92
+
93
+ ### `danube pages domains add <domain>`
94
+
95
+ Add a custom domain. Returns DNS verification instructions if required.
96
+
97
+ ### `danube pages domains remove <domain>`
98
+
99
+ Remove a custom domain.
100
+
101
+ ### `danube pages domains verify <domain>`
102
+
103
+ Trigger DNS verification for a custom domain.
104
+
105
+ ## Configuration
106
+
107
+ ### Project Configuration
108
+
109
+ Running `danube pages link` creates a `.danube/project.json` file in your project directory. This file is required for all `pages` subcommands.
110
+
111
+ ### `danube.json`
112
+
113
+ You can optionally create a `danube.json` file in your project root to configure deployments:
114
+
115
+ ```json
116
+ {
117
+ "outputDir": "dist",
118
+ "ignore": ["*.map", "test/**"]
119
+ }
120
+ ```
121
+
122
+ - **`outputDir`** - Directory to deploy (overridden by `--dir` flag)
123
+ - **`ignore`** - Additional file patterns to exclude from deployment
124
+
125
+ Files matching `.gitignore` patterns are automatically excluded, along with `.git`, `node_modules`, and `.danube` directories.
126
+
127
+ ## Environment Variables
128
+
129
+ | Variable | Description |
130
+ |---|---|
131
+ | `DANUBE_TOKEN` | API token (alternative to `danube login`) |
132
+ | `DANUBE_API_BASE` | Override the API base URL |
133
+ | `CI` | Suppresses update notifications |
134
+ | `DANUBE_NO_UPDATE_CHECK` | Suppresses update notifications |
135
+
136
+ ## License
137
+
138
+ MIT
package/bin/danube ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/index.js');
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ export declare const POLL_INTERVAL = 2000;
3
+ export declare const POLL_TIMEOUT: number;
4
+ export declare const deployCommand: Command;
@@ -0,0 +1,72 @@
1
+ import { Command } from 'commander';
2
+ import { resolve } from 'node:path';
3
+ import { access } from 'node:fs/promises';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import { ApiClient } from '../lib/api-client.js';
7
+ import { readProjectConfig, readDanubeJson } from '../lib/project.js';
8
+ import { NotLinkedError } from '../lib/errors.js';
9
+ import { packageDirectory } from '../lib/packager.js';
10
+ import { formatBytes, statusColor } from '../lib/output.js';
11
+ import { sleep } from '../lib/sleep.js';
12
+ export const POLL_INTERVAL = 2000;
13
+ export const POLL_TIMEOUT = 5 * 60 * 1000;
14
+ export const deployCommand = new Command('deploy')
15
+ .description('Deploy your site to DanubeData')
16
+ .option('--dir <directory>', 'Directory to deploy (overrides danube.json)')
17
+ .option('--no-wait', 'Skip waiting for deployment to complete')
18
+ .action(async (opts) => {
19
+ const project = await readProjectConfig();
20
+ if (!project)
21
+ throw new NotLinkedError();
22
+ const api = await ApiClient.create();
23
+ const danubeJson = await readDanubeJson();
24
+ // Resolve deploy directory
25
+ const deployDir = resolve(opts.dir || danubeJson?.outputDir || '.');
26
+ // Verify directory exists
27
+ try {
28
+ await access(deployDir);
29
+ }
30
+ catch {
31
+ console.error(chalk.red(`Directory not found: ${deployDir}`));
32
+ process.exit(1);
33
+ }
34
+ // Package files
35
+ const packSpinner = ora('Packaging files...').start();
36
+ const { buffer, fileCount } = await packageDirectory(deployDir, danubeJson?.ignore);
37
+ packSpinner.succeed(`Packaged ${fileCount} files (${formatBytes(buffer.length)})`);
38
+ // Upload
39
+ const uploadSpinner = ora('Uploading...').start();
40
+ const deployRes = await api.upload(`/api/v1/static-sites/${project.siteId}/deploy`, buffer, 'deploy.zip');
41
+ uploadSpinner.succeed('Uploaded');
42
+ if (!opts.wait) {
43
+ console.log(chalk.green(`\nDeployment started. Status: ${deployRes.status}`));
44
+ return;
45
+ }
46
+ // Poll build status
47
+ const pollSpinner = ora('Building...').start();
48
+ const startTime = Date.now();
49
+ while (Date.now() - startTime < POLL_TIMEOUT) {
50
+ await sleep(POLL_INTERVAL);
51
+ const buildRes = await api.get(`/api/v1/static-sites/${project.siteId}/builds/latest`);
52
+ const build = buildRes.data;
53
+ if (!build)
54
+ continue;
55
+ pollSpinner.text = `Status: ${build.status}...`;
56
+ if (build.status === 'succeeded') {
57
+ pollSpinner.succeed(`Deployed! Build #${build.build_number} ${statusColor('succeeded')}`);
58
+ const domain = project.defaultDomain || `${project.siteName}.pages.danubedata.ro`;
59
+ console.log(chalk.green(`\nLive at: ${chalk.bold(`https://${domain}`)}`));
60
+ return;
61
+ }
62
+ if (build.status === 'failed' || build.status === 'cancelled') {
63
+ pollSpinner.fail(`Deployment failed`);
64
+ if (build.error_message) {
65
+ console.error(chalk.red(build.error_message));
66
+ }
67
+ process.exit(1);
68
+ }
69
+ }
70
+ pollSpinner.warn('Timed out waiting for deployment. Check status with `danube deployments ls`.');
71
+ });
72
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const deploymentsCommand: Command;
@@ -0,0 +1,52 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { ApiClient } from '../lib/api-client.js';
5
+ import { readProjectConfig } from '../lib/project.js';
6
+ import { NotLinkedError } from '../lib/errors.js';
7
+ import { formatTable, statusColor, formatDate } from '../lib/output.js';
8
+ const lsCommand = new Command('ls')
9
+ .description('List deployments')
10
+ .action(async () => {
11
+ const project = await readProjectConfig();
12
+ if (!project)
13
+ throw new NotLinkedError();
14
+ const api = await ApiClient.create();
15
+ const res = await api.get(`/api/v1/static-sites/${project.siteId}/deployments`);
16
+ if (res.data.length === 0) {
17
+ console.log('No deployments yet.');
18
+ return;
19
+ }
20
+ const rows = res.data.map(d => [
21
+ `#${d.revision_number}`,
22
+ statusColor(d.status) + (d.is_current ? chalk.cyan(' (current)') : ''),
23
+ d.trigger_type,
24
+ d.deployed_at ? formatDate(d.deployed_at) : '-',
25
+ formatDate(d.created_at),
26
+ ]);
27
+ console.log(formatTable(['REVISION', 'STATUS', 'TRIGGER', 'DEPLOYED', 'CREATED'], rows));
28
+ });
29
+ const rollbackCommand = new Command('rollback')
30
+ .description('Activate a previous deployment')
31
+ .argument('<revision>', 'Deployment revision number')
32
+ .action(async (revision) => {
33
+ const project = await readProjectConfig();
34
+ if (!project)
35
+ throw new NotLinkedError();
36
+ const api = await ApiClient.create();
37
+ // Find deployment by revision
38
+ const deploymentsRes = await api.get(`/api/v1/static-sites/${project.siteId}/deployments`);
39
+ const deployment = deploymentsRes.data.find(d => d.revision_number === Number(revision));
40
+ if (!deployment) {
41
+ console.error(chalk.red(`Deployment revision ${revision} not found.`));
42
+ process.exit(1);
43
+ }
44
+ const spinner = ora(`Rolling back to revision ${revision}...`).start();
45
+ await api.post(`/api/v1/static-sites/${project.siteId}/deployments/${deployment.id}/activate`);
46
+ spinner.succeed(`Rolled back to revision ${revision}`);
47
+ });
48
+ export const deploymentsCommand = new Command('deployments')
49
+ .description('Manage deployments')
50
+ .addCommand(lsCommand)
51
+ .addCommand(rollbackCommand);
52
+ //# sourceMappingURL=deployments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployments.js","sourceRoot":"","sources":["../../src/commands/deployments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const domainsCommand: Command;
@@ -0,0 +1,89 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { ApiClient } from '../lib/api-client.js';
5
+ import { readProjectConfig } from '../lib/project.js';
6
+ import { NotLinkedError } from '../lib/errors.js';
7
+ import { formatTable, statusColor } from '../lib/output.js';
8
+ const lsCommand = new Command('ls')
9
+ .description('List domains')
10
+ .action(async () => {
11
+ const project = await readProjectConfig();
12
+ if (!project)
13
+ throw new NotLinkedError();
14
+ const api = await ApiClient.create();
15
+ const res = await api.get(`/api/v1/static-sites/${project.siteId}/domains`);
16
+ if (res.data.length === 0) {
17
+ console.log('No domains configured.');
18
+ return;
19
+ }
20
+ const rows = res.data.map(d => [
21
+ d.domain,
22
+ d.type,
23
+ statusColor(d.status),
24
+ d.verified_at || '-',
25
+ ]);
26
+ console.log(formatTable(['DOMAIN', 'TYPE', 'STATUS', 'VERIFIED'], rows));
27
+ });
28
+ const addCommand = new Command('add')
29
+ .description('Add a custom domain')
30
+ .argument('<domain>', 'Domain name to add')
31
+ .action(async (domain) => {
32
+ const project = await readProjectConfig();
33
+ if (!project)
34
+ throw new NotLinkedError();
35
+ const api = await ApiClient.create();
36
+ const spinner = ora(`Adding ${domain}...`).start();
37
+ const res = await api.post(`/api/v1/static-sites/${project.siteId}/domains`, { domain });
38
+ spinner.succeed(`Added ${chalk.bold(domain)}`);
39
+ if (res.data.verification_record) {
40
+ console.log(`\nAdd a CNAME record to verify ownership:`);
41
+ console.log(chalk.cyan(` ${res.data.verification_record}`));
42
+ console.log(`\nThen run: ${chalk.bold(`danube pages domains verify ${domain}`)}`);
43
+ }
44
+ });
45
+ const removeCommand = new Command('remove')
46
+ .description('Remove a custom domain')
47
+ .argument('<domain>', 'Domain name to remove')
48
+ .action(async (domain) => {
49
+ const project = await readProjectConfig();
50
+ if (!project)
51
+ throw new NotLinkedError();
52
+ const api = await ApiClient.create();
53
+ // Find domain by name
54
+ const domainsRes = await api.get(`/api/v1/static-sites/${project.siteId}/domains`);
55
+ const domainObj = domainsRes.data.find(d => d.domain === domain);
56
+ if (!domainObj) {
57
+ console.error(chalk.red(`Domain ${domain} not found.`));
58
+ process.exit(1);
59
+ }
60
+ const spinner = ora(`Removing ${domain}...`).start();
61
+ await api.delete(`/api/v1/static-sites/${project.siteId}/domains/${domainObj.id}`);
62
+ spinner.succeed(`Removed ${domain}`);
63
+ });
64
+ const verifyCommand = new Command('verify')
65
+ .description('Verify a custom domain')
66
+ .argument('<domain>', 'Domain name to verify')
67
+ .action(async (domain) => {
68
+ const project = await readProjectConfig();
69
+ if (!project)
70
+ throw new NotLinkedError();
71
+ const api = await ApiClient.create();
72
+ // Find domain by name
73
+ const domainsRes = await api.get(`/api/v1/static-sites/${project.siteId}/domains`);
74
+ const domainObj = domainsRes.data.find(d => d.domain === domain);
75
+ if (!domainObj) {
76
+ console.error(chalk.red(`Domain ${domain} not found.`));
77
+ process.exit(1);
78
+ }
79
+ const spinner = ora(`Verifying ${domain}...`).start();
80
+ await api.post(`/api/v1/static-sites/${project.siteId}/domains/${domainObj.id}/verify`);
81
+ spinner.succeed(`Verification started for ${chalk.bold(domain)}`);
82
+ });
83
+ export const domainsCommand = new Command('domains')
84
+ .description('Manage custom domains')
85
+ .addCommand(lsCommand)
86
+ .addCommand(addCommand)
87
+ .addCommand(removeCommand)
88
+ .addCommand(verifyCommand);
89
+ //# sourceMappingURL=domains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.js","sourceRoot":"","sources":["../../src/commands/domains.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const linkCommand: Command;
@@ -0,0 +1,58 @@
1
+ import { Command } from 'commander';
2
+ import { select, input } from '@inquirer/prompts';
3
+ import chalk from 'chalk';
4
+ import { ApiClient } from '../lib/api-client.js';
5
+ import { writeProjectConfig } from '../lib/project.js';
6
+ export const linkCommand = new Command('link')
7
+ .description('Link current directory to a DanubeData static site')
8
+ .action(async () => {
9
+ const api = await ApiClient.create();
10
+ // 1. Fetch teams
11
+ const teamsRes = await api.get('/api/v1/user/teams');
12
+ const teams = teamsRes.data;
13
+ let teamId;
14
+ if (teams.length === 1) {
15
+ teamId = teams[0].id;
16
+ console.log(`Team: ${chalk.bold(teams[0].name)}`);
17
+ }
18
+ else {
19
+ teamId = await select({
20
+ message: 'Select a team:',
21
+ choices: teams.map(t => ({ name: t.name, value: t.id })),
22
+ });
23
+ }
24
+ // 2. Fetch existing sites
25
+ const sitesRes = await api.get(`/api/v1/teams/${teamId}/static-sites`);
26
+ const CREATE_NEW = -1;
27
+ const choices = [
28
+ ...sitesRes.data.map(s => ({ name: `${s.name} (${s.default_domain})`, value: s.id })),
29
+ { name: chalk.cyan('+ Create new site'), value: CREATE_NEW },
30
+ ];
31
+ const siteChoice = await select({
32
+ message: 'Select a site to link:',
33
+ choices,
34
+ });
35
+ let site;
36
+ if (siteChoice === CREATE_NEW) {
37
+ const name = await input({
38
+ message: 'Site name:',
39
+ validate: (v) => v.trim().length > 0 || 'Name is required',
40
+ });
41
+ const res = await api.post(`/api/v1/teams/${teamId}/static-sites`, { name: name.trim() });
42
+ site = res.data;
43
+ console.log(chalk.green(`Created site: ${site.name}`));
44
+ }
45
+ else {
46
+ site = sitesRes.data.find(s => s.id === siteChoice);
47
+ }
48
+ // 3. Write project config
49
+ await writeProjectConfig({
50
+ siteId: site.id,
51
+ teamId: teamId,
52
+ siteName: site.name,
53
+ defaultDomain: site.default_domain,
54
+ });
55
+ console.log(chalk.green(`\nLinked to ${chalk.bold(site.name)} (${site.default_domain})`));
56
+ console.log(`Config saved to ${chalk.dim('.danube/project.json')}`);
57
+ });
58
+ //# sourceMappingURL=link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.js","sourceRoot":"","sources":["../../src/commands/link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const loginCommand: Command;
@@ -0,0 +1,50 @@
1
+ import { Command } from 'commander';
2
+ import { password } from '@inquirer/prompts';
3
+ import chalk from 'chalk';
4
+ import { writeConfig, getApiBase } from '../lib/config.js';
5
+ import { ApiError } from '../lib/errors.js';
6
+ export const loginCommand = new Command('login')
7
+ .description('Authenticate with DanubeData')
8
+ .option('--token <token>', 'API token (or paste interactively)')
9
+ .action(async (opts) => {
10
+ let token = opts.token;
11
+ if (!token) {
12
+ console.log(chalk.bold('Log in to DanubeData\n'));
13
+ console.log(`Create an API token at: ${chalk.cyan(`${getApiBase()}/user/api-tokens`)}\n`);
14
+ token = await password({
15
+ message: 'Paste your API token:',
16
+ mask: '*',
17
+ });
18
+ }
19
+ if (!token?.trim()) {
20
+ console.error(chalk.red('No token provided.'));
21
+ process.exit(1);
22
+ }
23
+ token = token.trim();
24
+ // Validate token by calling /api/user
25
+ try {
26
+ const res = await fetch(`${getApiBase()}/api/user`, {
27
+ headers: {
28
+ 'Accept': 'application/json',
29
+ 'Authorization': `Bearer ${token}`,
30
+ },
31
+ });
32
+ if (!res.ok) {
33
+ if (res.status === 401) {
34
+ console.error(chalk.red('Invalid token.'));
35
+ process.exit(1);
36
+ }
37
+ throw new ApiError(res.status, `Validation failed with status ${res.status}`);
38
+ }
39
+ const user = (await res.json());
40
+ await writeConfig({ token, apiBase: getApiBase() });
41
+ console.log(chalk.green(`\nAuthenticated as ${chalk.bold(user.name)} (${user.email})`));
42
+ }
43
+ catch (err) {
44
+ if (err instanceof ApiError)
45
+ throw err;
46
+ console.error(chalk.red('Failed to connect to DanubeData API.'));
47
+ process.exit(1);
48
+ }
49
+ });
50
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,8BAA8B,CAAC;KAC3C,MAAM,CAAC,iBAAiB,EAAE,oCAAoC,CAAC;KAC/D,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;IACzC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IAEvB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAE1F,KAAK,GAAG,MAAM,QAAQ,CAAC;YACrB,OAAO,EAAE,uBAAuB;YAChC,IAAI,EAAE,GAAG;SACV,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAErB,sCAAsC;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,EAAE,WAAW,EAAE;YAClD,OAAO,EAAE;gBACP,QAAQ,EAAE,kBAAkB;gBAC5B,eAAe,EAAE,UAAU,KAAK,EAAE;aACnC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,iCAAiC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAS,CAAC;QACxC,MAAM,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QAEpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sBAAsB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ;YAAE,MAAM,GAAG,CAAC;QACvC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const logoutCommand: Command;
@@ -0,0 +1,10 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { deleteConfig } from '../lib/config.js';
4
+ export const logoutCommand = new Command('logout')
5
+ .description('Remove stored authentication')
6
+ .action(async () => {
7
+ await deleteConfig();
8
+ console.log(chalk.green('Logged out.'));
9
+ });
10
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,8BAA8B,CAAC;KAC3C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,YAAY,EAAE,CAAC;IACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const whoamiCommand: Command;
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { ApiClient } from '../lib/api-client.js';
4
+ export const whoamiCommand = new Command('whoami')
5
+ .description('Show current authenticated user')
6
+ .action(async () => {
7
+ const api = await ApiClient.create();
8
+ const [user, teams] = await Promise.all([
9
+ api.get('/api/user'),
10
+ api.get('/api/v1/user/teams'),
11
+ ]);
12
+ console.log(chalk.bold(user.name));
13
+ console.log(`Email: ${user.email}`);
14
+ console.log(`Teams: ${teams.data.map(t => t.name).join(', ')}`);
15
+ });
16
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGjD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IAErC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACtC,GAAG,CAAC,GAAG,CAAO,WAAW,CAAC;QAC1B,GAAG,CAAC,GAAG,CAAgB,oBAAoB,CAAC;KAC7C,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,81 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { loginCommand } from './commands/login.js';
4
+ import { logoutCommand } from './commands/logout.js';
5
+ import { whoamiCommand } from './commands/whoami.js';
6
+ import { linkCommand } from './commands/link.js';
7
+ import { deployCommand } from './commands/deploy.js';
8
+ import { deploymentsCommand } from './commands/deployments.js';
9
+ import { domainsCommand } from './commands/domains.js';
10
+ import { NotAuthenticatedError, NotLinkedError, ApiError } from './lib/errors.js';
11
+ import { getCurrentVersion, checkForUpdate, printUpdateNotification } from './lib/version.js';
12
+ const program = new Command()
13
+ .name('danube')
14
+ .description('DanubeData CLI')
15
+ .version(getCurrentVersion());
16
+ program.addCommand(loginCommand);
17
+ program.addCommand(logoutCommand);
18
+ program.addCommand(whoamiCommand);
19
+ const pagesCommand = new Command('pages')
20
+ .description('Manage static sites');
21
+ pagesCommand.addCommand(linkCommand);
22
+ pagesCommand.addCommand(deployCommand);
23
+ pagesCommand.addCommand(deploymentsCommand);
24
+ pagesCommand.addCommand(domainsCommand);
25
+ program.addCommand(pagesCommand);
26
+ // Global error handler
27
+ program.hook('postAction', () => { });
28
+ process.on('unhandledRejection', (err) => {
29
+ if (err instanceof NotAuthenticatedError) {
30
+ console.error(chalk.red(err.message));
31
+ process.exit(1);
32
+ }
33
+ if (err instanceof NotLinkedError) {
34
+ console.error(chalk.red(err.message));
35
+ process.exit(1);
36
+ }
37
+ if (err instanceof ApiError) {
38
+ console.error(chalk.red(`API Error (${err.statusCode}): ${err.message}`));
39
+ if (err.errors) {
40
+ for (const [field, messages] of Object.entries(err.errors)) {
41
+ for (const msg of messages) {
42
+ console.error(chalk.red(` ${field}: ${msg}`));
43
+ }
44
+ }
45
+ }
46
+ process.exit(1);
47
+ }
48
+ if (err instanceof Error) {
49
+ console.error(chalk.red(err.message));
50
+ process.exit(1);
51
+ }
52
+ console.error(chalk.red('An unexpected error occurred.'));
53
+ process.exit(1);
54
+ });
55
+ program.parseAsync()
56
+ .then(async () => {
57
+ const result = await checkForUpdate();
58
+ if (result?.updateAvailable) {
59
+ printUpdateNotification(result.current, result.latest);
60
+ }
61
+ })
62
+ .catch((err) => {
63
+ if (err instanceof NotAuthenticatedError || err instanceof NotLinkedError) {
64
+ console.error(chalk.red(err.message));
65
+ process.exit(1);
66
+ }
67
+ if (err instanceof ApiError) {
68
+ console.error(chalk.red(`API Error (${err.statusCode}): ${err.message}`));
69
+ if (err.errors) {
70
+ for (const [field, messages] of Object.entries(err.errors)) {
71
+ for (const msg of messages) {
72
+ console.error(chalk.red(` ${field}: ${msg}`));
73
+ }
74
+ }
75
+ }
76
+ process.exit(1);
77
+ }
78
+ console.error(chalk.red(err instanceof Error ? err.message : 'An unexpected error occurred.'));
79
+ process.exit(1);
80
+ });
81
+ //# sourceMappingURL=index.js.map