dbdiagram 0.1.2 → 0.2.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.
- package/dist/actions/auth/auth-login.action.js +8 -19
- package/dist/actions/auth/auth-logout.action.js +11 -3
- package/dist/actions/auth/auth-status.action.js +7 -13
- package/dist/actions/build/build-document.action.js +19 -43
- package/dist/actions/delete.action.js +8 -15
- package/dist/actions/list/list-document.action.js +13 -19
- package/dist/actions/list/list.action.js +12 -19
- package/dist/actions/pull.action.js +8 -17
- package/dist/actions/push.action.js +10 -24
- package/dist/actions/tokens/token-delete.action.js +8 -14
- package/dist/actions/tokens/token-generate.action.js +7 -12
- package/dist/actions/tokens/token-list.action.js +10 -17
- package/dist/commands/auth/auth-logout.command.js +1 -0
- package/dist/constants/cli-error.constant.js +81 -0
- package/dist/errors/cli.error.js +9 -0
- package/dist/errors/portal-api.error.js +1 -0
- package/dist/utils/cli-error.util.js +46 -0
- package/dist/utils/date.util.js +4 -0
- package/dist/utils/output.util.js +35 -4
- package/package.json +2 -2
- package/dist/constants/auth-message.constant.js +0 -1
- package/dist/errors/portal-error-codes.js +0 -23
- package/dist/utils/portal-error.util.js +0 -18
- package/dist/utils/table.util.js +0 -10
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import { spinner
|
|
2
|
+
import { spinner } from '@clack/prompts';
|
|
3
3
|
import open from 'open';
|
|
4
4
|
import { storeCredential } from '../../config/credential-manager.js';
|
|
5
5
|
import { PORTAL_LOGIN_CONFIGS, PORTAL_URLS } from '../../config.js';
|
|
6
|
-
import { initAuthClient
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[PORTAL_AUTH_ERROR_CODES.loginCancelled]: 'Login cancelled.',
|
|
10
|
-
[PORTAL_AUTH_ERROR_CODES.stateMismatch]: 'Authentication failed: security validation error.',
|
|
11
|
-
[PORTAL_AUTH_ERROR_CODES.exchangeFailed]: 'Authentication failed: could not exchange token.',
|
|
12
|
-
[PORTAL_AUTH_ERROR_CODES.invalidCallback]: 'Authentication failed: invalid callback received.',
|
|
13
|
-
[PORTAL_AUTH_ERROR_CODES.loopbackServerError]: 'Authentication failed: could not start local server.',
|
|
14
|
-
[PORTAL_AUTH_ERROR_CODES.unknownError]: 'Authentication failed: an unexpected error occurred.',
|
|
15
|
-
};
|
|
6
|
+
import { initAuthClient } from '../../libs/portal/index.js';
|
|
7
|
+
import { toCliError } from '../../utils/cli-error.util.js';
|
|
8
|
+
import { displayError } from '../../utils/output.util.js';
|
|
16
9
|
export async function loginAction() {
|
|
10
|
+
const s = spinner();
|
|
17
11
|
try {
|
|
18
12
|
const authClient = await initAuthClient({
|
|
19
13
|
loginUrl: PORTAL_URLS.loginUrl,
|
|
@@ -25,7 +19,6 @@ export async function loginAction() {
|
|
|
25
19
|
error: path.join(import.meta.dirname, '../../assets/callback-error.html'),
|
|
26
20
|
},
|
|
27
21
|
});
|
|
28
|
-
const s = spinner();
|
|
29
22
|
await open(authClient.getLoginUrl());
|
|
30
23
|
s.start('Waiting for browser login...');
|
|
31
24
|
const { accessToken } = await authClient.obtainTokens();
|
|
@@ -33,12 +26,8 @@ export async function loginAction() {
|
|
|
33
26
|
s.stop('Login successful. Credentials saved.');
|
|
34
27
|
}
|
|
35
28
|
catch (error) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
process.exitCode = 1;
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
throw error;
|
|
29
|
+
s.stop();
|
|
30
|
+
displayError(toCliError(error), 'plain');
|
|
31
|
+
process.exitCode = 1;
|
|
43
32
|
}
|
|
44
33
|
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { log } from '@clack/prompts';
|
|
2
2
|
import { clearCredential } from '../../config/credential-manager.js';
|
|
3
|
-
|
|
3
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
4
|
+
import { AUTH_LOGOUT_FAILED } from '../../constants/cli-error.constant.js';
|
|
5
|
+
import { displayError, getOutputFormat, printJson } from '../../utils/output.util.js';
|
|
6
|
+
export async function logoutAction(options = {}) {
|
|
4
7
|
try {
|
|
5
8
|
clearCredential();
|
|
6
|
-
|
|
9
|
+
if (options.json) {
|
|
10
|
+
printJson({ success: true });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
log.success('Logout successful.');
|
|
14
|
+
}
|
|
7
15
|
}
|
|
8
16
|
catch (error) {
|
|
9
17
|
const message = error instanceof Error ? error.message : String(error);
|
|
10
|
-
|
|
18
|
+
displayError(new CliError(AUTH_LOGOUT_FAILED, message), getOutputFormat(options.json));
|
|
11
19
|
process.exitCode = 1;
|
|
12
20
|
}
|
|
13
21
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spinner } from '@clack/prompts';
|
|
2
2
|
import { getCredential } from '../../config/credential-manager.js';
|
|
3
|
-
import {
|
|
3
|
+
import { AUTH_NOT_LOGGED_IN } from '../../constants/cli-error.constant.js';
|
|
4
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
4
5
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
5
|
-
import {
|
|
6
|
-
import { printJson } from '../../utils/output.util.js';
|
|
6
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
7
|
+
import { displayError, getOutputFormat, printJson } from '../../utils/output.util.js';
|
|
7
8
|
export async function statusAction(options = {}) {
|
|
8
9
|
const credential = getCredential();
|
|
9
10
|
if (!credential) {
|
|
10
|
-
log.warn(NOT_LOGGED_IN_MESSAGE);
|
|
11
11
|
process.exitCode = 1;
|
|
12
|
-
return;
|
|
12
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(options.json));
|
|
13
13
|
}
|
|
14
14
|
const s = spinner();
|
|
15
15
|
s.start('Checking login status...');
|
|
@@ -26,13 +26,7 @@ export async function statusAction(options = {}) {
|
|
|
26
26
|
}
|
|
27
27
|
catch (error) {
|
|
28
28
|
s.stop('Failed to check login status.');
|
|
29
|
-
|
|
30
|
-
log.error(getPortalApiErrorMessage(error));
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
-
log.error(message);
|
|
35
|
-
}
|
|
29
|
+
displayError(toCliError(error), getOutputFormat(options.json));
|
|
36
30
|
process.exitCode = 1;
|
|
37
31
|
}
|
|
38
32
|
}
|
|
@@ -1,64 +1,55 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { log, spinner } from '@clack/prompts';
|
|
3
|
+
import { DBDOCS_CONFIGS } from '../../config.js';
|
|
3
4
|
import { getCredential } from '../../config/credential-manager.js';
|
|
4
|
-
import {
|
|
5
|
+
import { DOCUMENT_SOURCE_TYPE } from '../../constants/document.constant.js';
|
|
6
|
+
import { AUTH_NOT_LOGGED_IN, DBML_PARSE_ERROR, FILE_READ_ERROR, PROJECT_NAME_INVALID, PROJECT_NAME_MISSING, SOURCE_MISSING, VERSION_NAME_INVALID, WORKSPACE_NAME_INVALID, WORKSPACE_NAME_MISSING, } from '../../constants/cli-error.constant.js';
|
|
7
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
8
|
+
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
5
9
|
import { prepareBuildDocumentData } from '../../services/dbml/dbml.service.js';
|
|
10
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
6
11
|
import { formatDbmlError, getDbmlVersion } from '../../utils/dbml.util.js';
|
|
7
|
-
import {
|
|
8
|
-
import { DBDOCS_CONFIGS } from '../../config.js';
|
|
9
|
-
import { isPortalApiError, getPortalApiErrorMessage } from '../../utils/portal-error.util.js';
|
|
10
|
-
import { printJson } from '../../utils/output.util.js';
|
|
12
|
+
import { displayError, getOutputFormat, printJson } from '../../utils/output.util.js';
|
|
11
13
|
import { validateProjectUrlName, validateVersionName, validateWorkspaceUrlName, } from '../../utils/validation.util.js';
|
|
12
|
-
import { DOCUMENT_SOURCE_TYPE } from '../../constants/document.constant.js';
|
|
13
14
|
const DOCUMENT_SOURCE_CLIENT_TYPE = 'dbdiagram-cli';
|
|
14
15
|
export async function documentAction(options) {
|
|
15
16
|
const credential = getCredential();
|
|
16
17
|
if (!credential) {
|
|
17
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
18
18
|
process.exitCode = 1;
|
|
19
|
-
return;
|
|
19
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(options.json));
|
|
20
20
|
}
|
|
21
21
|
if (options.versionName !== undefined) {
|
|
22
22
|
const versionError = validateVersionName(options.versionName);
|
|
23
23
|
if (versionError) {
|
|
24
|
-
log.error(versionError);
|
|
25
24
|
process.exitCode = 1;
|
|
26
|
-
return;
|
|
25
|
+
return displayError(new CliError(VERSION_NAME_INVALID, versionError), getOutputFormat(options.json));
|
|
27
26
|
}
|
|
28
27
|
}
|
|
29
28
|
if (!options.workspaceUrlName) {
|
|
30
|
-
log.error('Workspace url name is required. Use --project <workspace>/<project> '
|
|
31
|
-
+ 'or configure workspaceUrlName in settings.json');
|
|
32
29
|
process.exitCode = 1;
|
|
33
|
-
return;
|
|
30
|
+
return displayError(new CliError(WORKSPACE_NAME_MISSING, getCliErrorMessageFromCode(WORKSPACE_NAME_MISSING)), getOutputFormat(options.json));
|
|
34
31
|
}
|
|
35
32
|
const workspaceError = validateWorkspaceUrlName(options.workspaceUrlName);
|
|
36
33
|
if (workspaceError) {
|
|
37
|
-
log.error(workspaceError);
|
|
38
34
|
process.exitCode = 1;
|
|
39
|
-
return;
|
|
35
|
+
return displayError(new CliError(WORKSPACE_NAME_INVALID, workspaceError), getOutputFormat(options.json));
|
|
40
36
|
}
|
|
41
37
|
if (!options.projectUrlOrName) {
|
|
42
|
-
log.error('Project name/url name is required. Use --project <workspace>/<project> '
|
|
43
|
-
+ 'or configure projectUrlName in settings.json');
|
|
44
38
|
process.exitCode = 1;
|
|
45
|
-
return;
|
|
39
|
+
return displayError(new CliError(PROJECT_NAME_MISSING, getCliErrorMessageFromCode(PROJECT_NAME_MISSING)), getOutputFormat(options.json));
|
|
46
40
|
}
|
|
47
41
|
if (options.projectUrlOrName.includes('/')) {
|
|
48
|
-
log.error('Invalid --project value. Expected <workspace>/<project> or <project>.');
|
|
49
42
|
process.exitCode = 1;
|
|
50
|
-
return;
|
|
43
|
+
return displayError(new CliError(PROJECT_NAME_INVALID, 'Invalid --project value. Expected <workspace>/<project> or <project>.'), getOutputFormat(options.json));
|
|
51
44
|
}
|
|
52
45
|
const projectError = validateProjectUrlName(options.projectUrlOrName);
|
|
53
46
|
if (projectError) {
|
|
54
|
-
log.error(projectError);
|
|
55
47
|
process.exitCode = 1;
|
|
56
|
-
return;
|
|
48
|
+
return displayError(new CliError(PROJECT_NAME_INVALID, projectError), getOutputFormat(options.json));
|
|
57
49
|
}
|
|
58
50
|
if (options.source === undefined) {
|
|
59
|
-
log.error('One source must be specified: --from-file or --from-diagram');
|
|
60
51
|
process.exitCode = 1;
|
|
61
|
-
return;
|
|
52
|
+
return displayError(new CliError(SOURCE_MISSING, getCliErrorMessageFromCode(SOURCE_MISSING)), getOutputFormat(options.json));
|
|
62
53
|
}
|
|
63
54
|
let content;
|
|
64
55
|
if (options.source.type === DOCUMENT_SOURCE_TYPE.FILE) {
|
|
@@ -67,9 +58,8 @@ export async function documentAction(options) {
|
|
|
67
58
|
}
|
|
68
59
|
catch (error) {
|
|
69
60
|
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
-
log.error(`Failed to read file: ${message}`);
|
|
71
61
|
process.exitCode = 1;
|
|
72
|
-
return;
|
|
62
|
+
return displayError(new CliError(FILE_READ_ERROR, `Failed to read file: ${message}`), getOutputFormat(options.json));
|
|
73
63
|
}
|
|
74
64
|
}
|
|
75
65
|
else {
|
|
@@ -78,15 +68,8 @@ export async function documentAction(options) {
|
|
|
78
68
|
content = diagram.content;
|
|
79
69
|
}
|
|
80
70
|
catch (error) {
|
|
81
|
-
if (isPortalApiError(error)) {
|
|
82
|
-
log.error(getPortalApiErrorMessage(error));
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
86
|
-
log.error(`Failed to fetch diagram: ${message}`);
|
|
87
|
-
}
|
|
88
71
|
process.exitCode = 1;
|
|
89
|
-
return;
|
|
72
|
+
return displayError(toCliError(error), getOutputFormat(options.json));
|
|
90
73
|
}
|
|
91
74
|
}
|
|
92
75
|
if (!content || !content.trim()) {
|
|
@@ -99,9 +82,8 @@ export async function documentAction(options) {
|
|
|
99
82
|
preparedDocumentData = await prepareBuildDocumentData(content);
|
|
100
83
|
}
|
|
101
84
|
catch (error) {
|
|
102
|
-
log.error(`Failed to parse DBML: ${formatDbmlError(error)}`);
|
|
103
85
|
process.exitCode = 1;
|
|
104
|
-
return;
|
|
86
|
+
return displayError(new CliError(DBML_PARSE_ERROR, `Failed to parse DBML: ${formatDbmlError(error)}`), getOutputFormat(options.json));
|
|
105
87
|
}
|
|
106
88
|
const s = spinner();
|
|
107
89
|
s.start('Building document on dbdocs...');
|
|
@@ -130,13 +112,7 @@ export async function documentAction(options) {
|
|
|
130
112
|
}
|
|
131
113
|
catch (error) {
|
|
132
114
|
s.stop('Failed to build document.');
|
|
133
|
-
|
|
134
|
-
log.error(getPortalApiErrorMessage(error));
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
-
log.error(message);
|
|
139
|
-
}
|
|
115
|
+
displayError(toCliError(error), getOutputFormat(options.json));
|
|
140
116
|
process.exitCode = 1;
|
|
141
117
|
}
|
|
142
118
|
}
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { confirm, isCancel, log, spinner } from '@clack/prompts';
|
|
2
2
|
import { getCredential } from '../config/credential-manager.js';
|
|
3
|
-
import { NOT_LOGGED_IN_MESSAGE } from '../constants/auth-message.constant.js';
|
|
4
3
|
import { getSettings, writeSettings } from '../config/settings-manager.js';
|
|
4
|
+
import { AUTH_NOT_LOGGED_IN, DIAGRAM_ID_MISSING } from '../constants/cli-error.constant.js';
|
|
5
|
+
import { CliError } from '../errors/cli.error.js';
|
|
5
6
|
import { portalIntegration } from '../integrations/portal/portal.integration.js';
|
|
6
|
-
import {
|
|
7
|
-
import { printJson } from '../utils/output.util.js';
|
|
7
|
+
import { getCliErrorMessageFromCode, toCliError } from '../utils/cli-error.util.js';
|
|
8
|
+
import { displayError, getOutputFormat, printJson } from '../utils/output.util.js';
|
|
8
9
|
export async function deleteAction(options) {
|
|
9
10
|
const credential = getCredential();
|
|
10
11
|
if (!credential) {
|
|
11
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
12
12
|
process.exitCode = 1;
|
|
13
|
-
return;
|
|
13
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(options.json));
|
|
14
14
|
}
|
|
15
15
|
if (!options.diagramId) {
|
|
16
|
-
log.error('Missing required flag: --diagram-id');
|
|
17
16
|
process.exitCode = 1;
|
|
18
|
-
return;
|
|
17
|
+
return displayError(new CliError(DIAGRAM_ID_MISSING, getCliErrorMessageFromCode(DIAGRAM_ID_MISSING)), getOutputFormat(options.json));
|
|
19
18
|
}
|
|
20
19
|
if (!options.force) {
|
|
21
20
|
const shouldDelete = await confirm({
|
|
@@ -42,7 +41,7 @@ export async function deleteAction(options) {
|
|
|
42
41
|
printJson({
|
|
43
42
|
diagramId: options.diagramId,
|
|
44
43
|
deleted: true,
|
|
45
|
-
...(isRemoveInSettings ? {
|
|
44
|
+
...(isRemoveInSettings ? { diagramIdSettingCleared: true } : {}),
|
|
46
45
|
});
|
|
47
46
|
}
|
|
48
47
|
else {
|
|
@@ -55,13 +54,7 @@ export async function deleteAction(options) {
|
|
|
55
54
|
catch (error) {
|
|
56
55
|
s.error('Failed to delete diagram.');
|
|
57
56
|
s.stop();
|
|
58
|
-
|
|
59
|
-
log.error(getPortalApiErrorMessage(error));
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
63
|
-
log.error(message);
|
|
64
|
-
}
|
|
57
|
+
displayError(toCliError(error), getOutputFormat(options.json));
|
|
65
58
|
process.exitCode = 1;
|
|
66
59
|
}
|
|
67
60
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { log, spinner } from '@clack/prompts';
|
|
2
2
|
import { DBDOCS_CONFIGS } from '../../config.js';
|
|
3
3
|
import { getCredential } from '../../config/credential-manager.js';
|
|
4
|
-
import {
|
|
4
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
5
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
6
|
+
import { AUTH_NOT_LOGGED_IN } from '../../constants/cli-error.constant.js';
|
|
5
7
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
8
|
+
import { formatShortDateTime } from '../../utils/date.util.js';
|
|
6
9
|
import { logConsole } from '../../utils/logger.util.js';
|
|
7
|
-
import { printJson, printTable } from '../../utils/output.util.js';
|
|
8
|
-
import { isPortalApiError, getPortalApiErrorMessage } from '../../utils/portal-error.util.js';
|
|
9
|
-
import { computeColWidths } from '../../utils/table.util.js';
|
|
10
|
+
import { displayError, getOutputFormat, printJson, printTable } from '../../utils/output.util.js';
|
|
10
11
|
function mapRole(role) {
|
|
11
12
|
switch (role) {
|
|
12
13
|
case 'admin':
|
|
@@ -34,9 +35,8 @@ function mapAccessControl(ac) {
|
|
|
34
35
|
export async function listDocumentAction(opts) {
|
|
35
36
|
const credential = getCredential();
|
|
36
37
|
if (!credential) {
|
|
37
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
38
38
|
process.exitCode = 1;
|
|
39
|
-
return;
|
|
39
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(opts.json));
|
|
40
40
|
}
|
|
41
41
|
const s = spinner();
|
|
42
42
|
s.start('Fetching documents...');
|
|
@@ -87,30 +87,29 @@ export async function listDocumentAction(opts) {
|
|
|
87
87
|
return {
|
|
88
88
|
workspace: w.urlName,
|
|
89
89
|
name: p.name,
|
|
90
|
+
url: `${DBDOCS_CONFIGS.baseUrl}/${w.urlName}/${p.urlName}`,
|
|
90
91
|
owner: ownerLabel,
|
|
91
92
|
permission: mapRole(p.role),
|
|
92
93
|
accessControl: mapAccessControl(p.accessControl),
|
|
93
|
-
|
|
94
|
-
updatedAt: p.updatedAt,
|
|
94
|
+
updatedAt: formatShortDateTime(p.updatedAt),
|
|
95
95
|
};
|
|
96
96
|
}));
|
|
97
97
|
printJson(allMappedData);
|
|
98
98
|
}
|
|
99
99
|
else {
|
|
100
100
|
for (const w of workspacesWithProjects) {
|
|
101
|
-
logConsole(`\
|
|
101
|
+
logConsole(`\nWorkspace: ${w.urlName}`);
|
|
102
102
|
printTable(w.projects, {
|
|
103
|
-
head: ['Name', 'Owner', 'Permission', 'Access Control', '
|
|
104
|
-
colWidths: computeColWidths([0.14, 0.22, 0.12, 0.14, 0.24, 0.14]),
|
|
103
|
+
head: ['Name', 'Url', 'Owner', 'Permission', 'Access Control', 'Last updated'],
|
|
105
104
|
rowMapper: (p) => {
|
|
106
105
|
const ownerLabel = p.owner.email === currentUser.email ? `${p.owner.email} (you)` : p.owner.email;
|
|
107
106
|
return [
|
|
108
107
|
p.name,
|
|
108
|
+
`${DBDOCS_CONFIGS.baseUrl}/${w.urlName}/${p.urlName}`,
|
|
109
109
|
ownerLabel,
|
|
110
110
|
mapRole(p.role),
|
|
111
111
|
mapAccessControl(p.accessControl),
|
|
112
|
-
|
|
113
|
-
new Date(p.updatedAt).toLocaleString(),
|
|
112
|
+
formatShortDateTime(p.updatedAt),
|
|
114
113
|
];
|
|
115
114
|
},
|
|
116
115
|
});
|
|
@@ -119,12 +118,7 @@ export async function listDocumentAction(opts) {
|
|
|
119
118
|
}
|
|
120
119
|
catch (error) {
|
|
121
120
|
s.stop('Failed to fetch documents.');
|
|
122
|
-
|
|
123
|
-
log.error(getPortalApiErrorMessage(error));
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
log.error(error instanceof Error ? error.message : String(error));
|
|
127
|
-
}
|
|
121
|
+
displayError(toCliError(error), getOutputFormat(opts.json));
|
|
128
122
|
process.exitCode = 1;
|
|
129
123
|
}
|
|
130
124
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spinner } from '@clack/prompts';
|
|
2
2
|
import { DBDIAGRAM_CONFIGS } from '../../config.js';
|
|
3
3
|
import { getCredential } from '../../config/credential-manager.js';
|
|
4
|
-
import {
|
|
4
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
5
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
6
|
+
import { AUTH_NOT_LOGGED_IN } from '../../constants/cli-error.constant.js';
|
|
5
7
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { printJson, printTable } from '../../utils/output.util.js';
|
|
8
|
+
import { formatShortDateTime } from '../../utils/date.util.js';
|
|
9
|
+
import { displayError, getOutputFormat, printJson, printTable } from '../../utils/output.util.js';
|
|
9
10
|
function mapStatus(status) {
|
|
10
11
|
switch (status) {
|
|
11
12
|
case 'public':
|
|
@@ -24,9 +25,8 @@ function ownerLabel(owner, currentUserEmail) {
|
|
|
24
25
|
export async function listAction(opts) {
|
|
25
26
|
const credential = getCredential();
|
|
26
27
|
if (!credential) {
|
|
27
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
28
28
|
process.exitCode = 1;
|
|
29
|
-
return;
|
|
29
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(opts.json));
|
|
30
30
|
}
|
|
31
31
|
const s = spinner();
|
|
32
32
|
s.start('Fetching diagrams...');
|
|
@@ -52,7 +52,7 @@ export async function listAction(opts) {
|
|
|
52
52
|
owner: ownerLabel(d.owner, currentUser.email),
|
|
53
53
|
status: mapStatus(d.status),
|
|
54
54
|
url: `${DBDIAGRAM_CONFIGS.baseUrl}/d/${d.id}`,
|
|
55
|
-
updatedAt:
|
|
55
|
+
updatedAt: formatShortDateTime(d.updatedAt),
|
|
56
56
|
}));
|
|
57
57
|
if (opts.json) {
|
|
58
58
|
printJson(mappedData);
|
|
@@ -60,7 +60,6 @@ export async function listAction(opts) {
|
|
|
60
60
|
else {
|
|
61
61
|
printTable(mappedData, {
|
|
62
62
|
head: ['Name', 'ID', 'Owner', 'Status', 'Url', 'Last updated'],
|
|
63
|
-
colWidths: computeColWidths([0.18, 0.22, 0.14, 0.09, 0.26, 0.11]),
|
|
64
63
|
rowMapper: (d) => [d.name, d.id, d.owner, d.status, d.url, d.updatedAt],
|
|
65
64
|
});
|
|
66
65
|
}
|
|
@@ -76,28 +75,22 @@ export async function listAction(opts) {
|
|
|
76
75
|
name: d.name,
|
|
77
76
|
id: d.id,
|
|
78
77
|
url: `${DBDIAGRAM_CONFIGS.baseUrl}/d/${d.id}`,
|
|
79
|
-
updatedAt:
|
|
78
|
+
updatedAt: formatShortDateTime(d.updatedAt),
|
|
80
79
|
}));
|
|
81
80
|
if (opts.json) {
|
|
82
81
|
printJson(mappedData);
|
|
83
82
|
}
|
|
84
83
|
else {
|
|
85
84
|
printTable(mappedData, {
|
|
86
|
-
head: ['
|
|
87
|
-
|
|
88
|
-
rowMapper: (d) => [d.name, d.id, d.url, d.updatedAt],
|
|
85
|
+
head: ['ID', 'Url', 'Name', 'Last updated'],
|
|
86
|
+
rowMapper: (d) => [d.id, d.url, d.name, d.updatedAt],
|
|
89
87
|
});
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
}
|
|
93
91
|
catch (error) {
|
|
94
92
|
s.stop('Failed to fetch diagrams.');
|
|
95
|
-
|
|
96
|
-
log.error(getPortalApiErrorMessage(error));
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
log.error(error instanceof Error ? error.message : String(error));
|
|
100
|
-
}
|
|
93
|
+
displayError(toCliError(error), getOutputFormat(opts.json));
|
|
101
94
|
process.exitCode = 1;
|
|
102
95
|
}
|
|
103
96
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { NOT_LOGGED_IN_MESSAGE } from '../constants/auth-message.constant.js';
|
|
1
|
+
import { spinner } from '@clack/prompts';
|
|
3
2
|
import { getCredential } from '../config/credential-manager.js';
|
|
4
3
|
import { writeFileWithDir } from '../services/file.service.js';
|
|
5
4
|
import { portalIntegration } from '../integrations/portal/portal.integration.js';
|
|
6
5
|
import { deriveDiagramVizPathFromDBML, readDiagramVizFile, writeDiagramVizFile, } from '../services/viz/diagram-viz-file.service.js';
|
|
7
|
-
import { getVizReadErrorMessage } from '../utils/diagram-viz-error.util.js';
|
|
8
6
|
import { fromServerFormat } from '../services/viz/diagram-viz-converter.service.js';
|
|
9
7
|
import { logConsole } from '../utils/logger.util.js';
|
|
10
|
-
import {
|
|
8
|
+
import { CliError } from '../errors/cli.error.js';
|
|
9
|
+
import { AUTH_NOT_LOGGED_IN, DIAGRAM_ID_MISSING } from '../constants/cli-error.constant.js';
|
|
10
|
+
import { getCliErrorMessageFromCode, toCliError } from '../utils/cli-error.util.js';
|
|
11
|
+
import { displayError } from '../utils/output.util.js';
|
|
11
12
|
export async function pullAction(options) {
|
|
12
13
|
const credential = getCredential();
|
|
13
14
|
if (!credential) {
|
|
14
|
-
|
|
15
|
+
displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), 'plain');
|
|
15
16
|
process.exitCode = 1;
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
if (!options.diagramId) {
|
|
19
|
-
|
|
20
|
+
displayError(new CliError(DIAGRAM_ID_MISSING, getCliErrorMessageFromCode(DIAGRAM_ID_MISSING)), 'plain');
|
|
20
21
|
process.exitCode = 1;
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
@@ -29,10 +30,6 @@ export async function pullAction(options) {
|
|
|
29
30
|
if (diagram.vizData) {
|
|
30
31
|
const vizPath = deriveDiagramVizPathFromDBML(options.outFile);
|
|
31
32
|
const existingResult = await readDiagramVizFile(vizPath);
|
|
32
|
-
if (!existingResult.ok) {
|
|
33
|
-
const message = getVizReadErrorMessage(existingResult.errorCode, vizPath);
|
|
34
|
-
log.warn(message);
|
|
35
|
-
}
|
|
36
33
|
const state = fromServerFormat(diagram.vizData, existingResult.ok ? existingResult.state : undefined);
|
|
37
34
|
await writeDiagramVizFile(vizPath, state);
|
|
38
35
|
}
|
|
@@ -46,13 +43,7 @@ export async function pullAction(options) {
|
|
|
46
43
|
}
|
|
47
44
|
catch (error) {
|
|
48
45
|
s.stop('Failed to fetch diagram.');
|
|
49
|
-
|
|
50
|
-
log.error(getPortalApiErrorMessage(error));
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
54
|
-
log.error(message);
|
|
55
|
-
}
|
|
46
|
+
displayError(toCliError(error), 'plain');
|
|
56
47
|
process.exitCode = 1;
|
|
57
48
|
}
|
|
58
49
|
}
|
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
2
|
+
import { spinner } from '@clack/prompts';
|
|
3
3
|
import { getCredential } from '../config/credential-manager.js';
|
|
4
|
-
import { NOT_LOGGED_IN_MESSAGE } from '../constants/auth-message.constant.js';
|
|
5
4
|
import { portalIntegration } from '../integrations/portal/portal.integration.js';
|
|
6
5
|
import { deriveDiagramVizPathFromDBML, readDiagramVizFile } from '../services/viz/diagram-viz-file.service.js';
|
|
7
|
-
import { getVizReadErrorMessage } from '../utils/diagram-viz-error.util.js';
|
|
8
6
|
import { toServerFormat } from '../services/viz/diagram-viz-converter.service.js';
|
|
9
7
|
import { preparePushDiagramData } from '../services/dbml/dbml.service.js';
|
|
10
8
|
import { DBDIAGRAM_CONFIGS } from '../config.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
9
|
+
import { CliError } from '../errors/cli.error.js';
|
|
10
|
+
import { getCliErrorMessageFromCode, toCliError } from '../utils/cli-error.util.js';
|
|
11
|
+
import { AUTH_NOT_LOGGED_IN, FILE_PATH_MISSING, FILE_READ_ERROR, DBML_PARSE_ERROR, } from '../constants/cli-error.constant.js';
|
|
12
|
+
import { displayError, getOutputFormat, printJson } from '../utils/output.util.js';
|
|
13
13
|
import { formatDbmlError } from '../utils/dbml.util.js';
|
|
14
14
|
export async function pushAction(filepath, options, thisCommand) {
|
|
15
15
|
const credential = getCredential();
|
|
16
16
|
if (!credential) {
|
|
17
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
18
17
|
process.exitCode = 1;
|
|
19
|
-
return;
|
|
18
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(options.json));
|
|
20
19
|
}
|
|
21
20
|
const resolvedFilepath = thisCommand.args[0] || filepath;
|
|
22
21
|
if (!resolvedFilepath) {
|
|
23
|
-
log.error('Missing required argument: filepath. Provide it as an argument or set dbml.entry in settings.');
|
|
24
22
|
process.exitCode = 1;
|
|
25
|
-
return;
|
|
23
|
+
return displayError(new CliError(FILE_PATH_MISSING, getCliErrorMessageFromCode(FILE_PATH_MISSING)), getOutputFormat(options.json));
|
|
26
24
|
}
|
|
27
25
|
let dbml;
|
|
28
26
|
try {
|
|
@@ -30,18 +28,16 @@ export async function pushAction(filepath, options, thisCommand) {
|
|
|
30
28
|
}
|
|
31
29
|
catch (error) {
|
|
32
30
|
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
-
log.error(`Failed to read file: ${message}`);
|
|
34
31
|
process.exitCode = 1;
|
|
35
|
-
return;
|
|
32
|
+
return displayError(new CliError(FILE_READ_ERROR, `Failed to read file: ${message}`), getOutputFormat(options.json));
|
|
36
33
|
}
|
|
37
34
|
let preparedPushData;
|
|
38
35
|
try {
|
|
39
36
|
preparedPushData = await preparePushDiagramData(dbml);
|
|
40
37
|
}
|
|
41
38
|
catch (error) {
|
|
42
|
-
log.error(`Failed to parse DBML: ${formatDbmlError(error)}`);
|
|
43
39
|
process.exitCode = 1;
|
|
44
|
-
return;
|
|
40
|
+
return displayError(new CliError(DBML_PARSE_ERROR, `Failed to parse DBML: ${formatDbmlError(error)}`), getOutputFormat(options.json));
|
|
45
41
|
}
|
|
46
42
|
const vizPath = deriveDiagramVizPathFromDBML(resolvedFilepath);
|
|
47
43
|
const vizResult = await readDiagramVizFile(vizPath);
|
|
@@ -50,10 +46,6 @@ export async function pushAction(filepath, options, thisCommand) {
|
|
|
50
46
|
const { diagramViews } = preparedPushData;
|
|
51
47
|
vizData = toServerFormat(vizResult.state, diagramViews);
|
|
52
48
|
}
|
|
53
|
-
else {
|
|
54
|
-
const message = getVizReadErrorMessage(vizResult.errorCode, vizPath);
|
|
55
|
-
log.warn(message);
|
|
56
|
-
}
|
|
57
49
|
const s = spinner();
|
|
58
50
|
s.start('Pushing diagram to dbdiagram...');
|
|
59
51
|
try {
|
|
@@ -79,13 +71,7 @@ export async function pushAction(filepath, options, thisCommand) {
|
|
|
79
71
|
}
|
|
80
72
|
catch (error) {
|
|
81
73
|
s.stop('Failed to push diagram.');
|
|
82
|
-
|
|
83
|
-
log.error(getPortalApiErrorMessage(error));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
-
log.error(message);
|
|
88
|
-
}
|
|
74
|
+
displayError(toCliError(error), getOutputFormat(options.json));
|
|
89
75
|
process.exitCode = 1;
|
|
90
76
|
}
|
|
91
77
|
}
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { confirm, isCancel,
|
|
1
|
+
import { confirm, isCancel, spinner } from '@clack/prompts';
|
|
2
2
|
import { getCredential } from '../../config/credential-manager.js';
|
|
3
|
-
import {
|
|
3
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
4
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
5
|
+
import { AUTH_NOT_LOGGED_IN, CONFIRMATION_REQUIRED } from '../../constants/cli-error.constant.js';
|
|
4
6
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
5
|
-
import {
|
|
6
|
-
import { printJson } from '../../utils/output.util.js';
|
|
7
|
+
import { displayError, getOutputFormat, printJson } from '../../utils/output.util.js';
|
|
7
8
|
export async function tokenDeleteAction(tokenId, options) {
|
|
8
9
|
const credential = getCredential();
|
|
9
10
|
if (!credential) {
|
|
10
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
11
11
|
process.exitCode = 1;
|
|
12
|
-
return;
|
|
12
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(options.json));
|
|
13
13
|
}
|
|
14
14
|
if (!options.force) {
|
|
15
15
|
if (!process.stdout.isTTY) {
|
|
16
|
-
log.error('Use -f to force delete in non-interactive environment.');
|
|
17
16
|
process.exitCode = 1;
|
|
18
|
-
return;
|
|
17
|
+
return displayError(new CliError(CONFIRMATION_REQUIRED, getCliErrorMessageFromCode(CONFIRMATION_REQUIRED)), getOutputFormat(options.json));
|
|
19
18
|
}
|
|
20
19
|
const shouldDelete = await confirm({
|
|
21
20
|
message: `Delete token '${tokenId}'?`,
|
|
@@ -39,12 +38,7 @@ export async function tokenDeleteAction(tokenId, options) {
|
|
|
39
38
|
}
|
|
40
39
|
catch (error) {
|
|
41
40
|
s.stop('Failed to delete token.');
|
|
42
|
-
|
|
43
|
-
log.error(getPortalApiErrorMessage(error));
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
log.error(error instanceof Error ? error.message : String(error));
|
|
47
|
-
}
|
|
41
|
+
displayError(toCliError(error), getOutputFormat(options.json));
|
|
48
42
|
process.exitCode = 1;
|
|
49
43
|
}
|
|
50
44
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
|
-
import {
|
|
2
|
+
import { spinner } from '@clack/prompts';
|
|
3
3
|
import packageJson from '../../../package.json' with { type: 'json' };
|
|
4
4
|
import { getCredential } from '../../config/credential-manager.js';
|
|
5
|
-
import {
|
|
5
|
+
import { AUTH_NOT_LOGGED_IN } from '../../constants/cli-error.constant.js';
|
|
6
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
6
7
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
7
|
-
import {
|
|
8
|
-
import { printJson } from '../../utils/output.util.js';
|
|
8
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
9
9
|
import { logConsole } from '../../utils/logger.util.js';
|
|
10
|
+
import { displayError, getOutputFormat, printJson } from '../../utils/output.util.js';
|
|
10
11
|
const PLATFORM_NAMES = {
|
|
11
12
|
darwin: 'macOS',
|
|
12
13
|
win32: 'Windows',
|
|
@@ -19,9 +20,8 @@ export function generateDefaultTokenName() {
|
|
|
19
20
|
export async function tokenGenerateAction(opts) {
|
|
20
21
|
const credential = getCredential();
|
|
21
22
|
if (!credential) {
|
|
22
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
23
23
|
process.exitCode = 1;
|
|
24
|
-
return;
|
|
24
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(opts.json));
|
|
25
25
|
}
|
|
26
26
|
const name = opts.name ?? generateDefaultTokenName();
|
|
27
27
|
const s = spinner();
|
|
@@ -41,12 +41,7 @@ export async function tokenGenerateAction(opts) {
|
|
|
41
41
|
}
|
|
42
42
|
catch (error) {
|
|
43
43
|
s.stop('Failed to generate token.');
|
|
44
|
-
|
|
45
|
-
log.error(getPortalApiErrorMessage(error));
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
log.error(error instanceof Error ? error.message : String(error));
|
|
49
|
-
}
|
|
44
|
+
displayError(toCliError(error), getOutputFormat(opts.json));
|
|
50
45
|
process.exitCode = 1;
|
|
51
46
|
}
|
|
52
47
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { DateTime } from 'luxon';
|
|
1
|
+
import { spinner } from '@clack/prompts';
|
|
3
2
|
import { getCredential } from '../../config/credential-manager.js';
|
|
4
|
-
import {
|
|
3
|
+
import { AUTH_NOT_LOGGED_IN } from '../../constants/cli-error.constant.js';
|
|
4
|
+
import { CliError } from '../../errors/cli.error.js';
|
|
5
5
|
import { portalIntegration } from '../../integrations/portal/portal.integration.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { printJson, printTable } from '../../utils/output.util.js';
|
|
6
|
+
import { getCliErrorMessageFromCode, toCliError } from '../../utils/cli-error.util.js';
|
|
7
|
+
import { formatShortDateTime } from '../../utils/date.util.js';
|
|
8
|
+
import { displayError, getOutputFormat, printJson, printTable } from '../../utils/output.util.js';
|
|
9
9
|
export async function tokenListAction(opts) {
|
|
10
10
|
const credential = getCredential();
|
|
11
11
|
if (!credential) {
|
|
12
|
-
log.error(NOT_LOGGED_IN_MESSAGE);
|
|
13
12
|
process.exitCode = 1;
|
|
14
|
-
return;
|
|
13
|
+
return displayError(new CliError(AUTH_NOT_LOGGED_IN, getCliErrorMessageFromCode(AUTH_NOT_LOGGED_IN)), getOutputFormat(opts.json));
|
|
15
14
|
}
|
|
16
15
|
const s = spinner();
|
|
17
16
|
s.start('Fetching tokens...');
|
|
@@ -25,8 +24,8 @@ export async function tokenListAction(opts) {
|
|
|
25
24
|
const mappedData = tokens.map((t) => ({
|
|
26
25
|
id: t.id,
|
|
27
26
|
name: t.name,
|
|
28
|
-
createdAt:
|
|
29
|
-
lastUsedAt: t.lastUsedAt ?
|
|
27
|
+
createdAt: formatShortDateTime(t.createdAt),
|
|
28
|
+
lastUsedAt: t.lastUsedAt ? formatShortDateTime(t.lastUsedAt) : 'Never',
|
|
30
29
|
}));
|
|
31
30
|
if (opts.json) {
|
|
32
31
|
printJson(mappedData);
|
|
@@ -34,19 +33,13 @@ export async function tokenListAction(opts) {
|
|
|
34
33
|
else {
|
|
35
34
|
printTable(mappedData, {
|
|
36
35
|
head: ['ID', 'Name', 'Created at', 'Last used'],
|
|
37
|
-
colWidths: computeColWidths([0.2, 0.45, 0.17, 0.18]),
|
|
38
36
|
rowMapper: (t) => [t.id, t.name, t.createdAt, t.lastUsedAt],
|
|
39
37
|
});
|
|
40
38
|
}
|
|
41
39
|
}
|
|
42
40
|
catch (error) {
|
|
43
41
|
s.stop('Failed to fetch tokens.');
|
|
44
|
-
|
|
45
|
-
log.error(getPortalApiErrorMessage(error));
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
log.error(error instanceof Error ? error.message : String(error));
|
|
49
|
-
}
|
|
42
|
+
displayError(toCliError(error), getOutputFormat(opts.json));
|
|
50
43
|
process.exitCode = 1;
|
|
51
44
|
}
|
|
52
45
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export const AUTH_NOT_LOGGED_IN = 'auth_not_logged_in';
|
|
2
|
+
export const AUTH_INVALID_CREDENTIALS = 'auth_invalid_credentials';
|
|
3
|
+
export const AUTH_LOGIN_TIMEOUT = 'auth_login_timeout';
|
|
4
|
+
export const AUTH_LOGIN_CANCELLED = 'auth_login_cancelled';
|
|
5
|
+
export const AUTH_LOGIN_STATE_MISMATCH = 'auth_login_state_mismatch';
|
|
6
|
+
export const AUTH_LOGIN_INVALID_CALLBACK = 'auth_login_invalid_callback';
|
|
7
|
+
export const AUTH_LOGIN_EXCHANGE_FAILED = 'auth_login_exchange_failed';
|
|
8
|
+
export const AUTH_LOGIN_SERVER_ERROR = 'auth_login_server_error';
|
|
9
|
+
export const AUTH_LOGIN_FAILED = 'auth_login_failed';
|
|
10
|
+
export const AUTH_LOGOUT_FAILED = 'auth_logout_failed';
|
|
11
|
+
export const DIAGRAM_ID_MISSING = 'diagram_id_missing';
|
|
12
|
+
export const DIAGRAM_NOT_FOUND = 'diagram_not_found';
|
|
13
|
+
export const DIAGRAM_PERMISSION_DENIED = 'diagram_permission_denied';
|
|
14
|
+
export const DIAGRAM_LIMIT_EXCEEDED = 'diagram_limit_exceeded';
|
|
15
|
+
export const WORKSPACE_NAME_MISSING = 'workspace_name_missing';
|
|
16
|
+
export const WORKSPACE_NAME_INVALID = 'workspace_name_invalid';
|
|
17
|
+
export const WORKSPACE_NOT_FOUND = 'workspace_not_found';
|
|
18
|
+
export const WORKSPACE_PERMISSION_DENIED = 'workspace_permission_denied';
|
|
19
|
+
export const PROJECT_NAME_MISSING = 'project_name_missing';
|
|
20
|
+
export const PROJECT_NAME_INVALID = 'project_name_invalid';
|
|
21
|
+
export const VERSION_NAME_INVALID = 'version_name_invalid';
|
|
22
|
+
export const TOKEN_NOT_FOUND = 'token_not_found';
|
|
23
|
+
export const TOKEN_LIMIT_EXCEEDED = 'token_limit_exceeded';
|
|
24
|
+
export const FILE_PATH_MISSING = 'file_path_missing';
|
|
25
|
+
export const FILE_READ_ERROR = 'file_read_error';
|
|
26
|
+
export const SOURCE_MISSING = 'source_missing';
|
|
27
|
+
export const DBML_PARSE_ERROR = 'dbml_parse_error';
|
|
28
|
+
export const CONFIRMATION_REQUIRED = 'confirmation_required';
|
|
29
|
+
export const VALIDATION_FAILED = 'validation_failed';
|
|
30
|
+
export const INTERNAL_SERVER_ERROR = 'internal_server_error';
|
|
31
|
+
export const NETWORK_ERROR = 'network_error';
|
|
32
|
+
export const UNEXPECTED_ERROR = 'unexpected_error';
|
|
33
|
+
export const REAUTH_MESSAGE = [
|
|
34
|
+
'Authentication failed: your credentials are invalid or expired.',
|
|
35
|
+
' - If you set DBDIAGRAM_TOKEN, replace it with a valid token'
|
|
36
|
+
+ ' (it takes precedence, so unset it to use `dbdiagram auth login` instead).',
|
|
37
|
+
' - Otherwise, run `dbdiagram auth login` to re-authenticate.',
|
|
38
|
+
].join('\n');
|
|
39
|
+
export const NOT_LOGGED_IN_MESSAGE = 'Not logged in. Run `dbdiagram auth login`, or set DBDIAGRAM_TOKEN, to authenticate.';
|
|
40
|
+
export const CLI_ERROR_MESSAGES = {
|
|
41
|
+
[AUTH_NOT_LOGGED_IN]: NOT_LOGGED_IN_MESSAGE,
|
|
42
|
+
[AUTH_INVALID_CREDENTIALS]: REAUTH_MESSAGE,
|
|
43
|
+
[AUTH_LOGIN_TIMEOUT]: 'Login timed out. Please try again.',
|
|
44
|
+
[AUTH_LOGIN_CANCELLED]: 'Login cancelled.',
|
|
45
|
+
[AUTH_LOGIN_STATE_MISMATCH]: 'Authentication failed: security validation error. Please try again.',
|
|
46
|
+
[AUTH_LOGIN_INVALID_CALLBACK]: 'Authentication failed: invalid callback received. Please try again.',
|
|
47
|
+
[AUTH_LOGIN_EXCHANGE_FAILED]: 'Authentication failed: could not exchange token. Please try again.',
|
|
48
|
+
[AUTH_LOGIN_SERVER_ERROR]: 'Authentication failed: could not start local server. '
|
|
49
|
+
+ 'Another process may be using the required port. Please try again.',
|
|
50
|
+
[AUTH_LOGIN_FAILED]: 'Authentication failed: an unexpected error occurred.',
|
|
51
|
+
[DIAGRAM_ID_MISSING]: 'Missing required flag: --diagram-id',
|
|
52
|
+
[DIAGRAM_NOT_FOUND]: 'Diagram not found.',
|
|
53
|
+
[DIAGRAM_PERMISSION_DENIED]: 'You do not have permission to perform this action on this diagram.',
|
|
54
|
+
[DIAGRAM_LIMIT_EXCEEDED]: 'Diagram limit exceeded for your current plan.',
|
|
55
|
+
[WORKSPACE_NAME_MISSING]: 'Workspace url name is required. Use --project <workspace>/<project> '
|
|
56
|
+
+ 'or set workspaceUrlName in settings.json',
|
|
57
|
+
[WORKSPACE_NOT_FOUND]: 'Workspace not found.',
|
|
58
|
+
[WORKSPACE_PERMISSION_DENIED]: 'You do not have permission to access this workspace.',
|
|
59
|
+
[PROJECT_NAME_MISSING]: 'Project name/url name is required. Use --project <workspace>/<project> '
|
|
60
|
+
+ 'or set projectUrlName in settings.json',
|
|
61
|
+
[TOKEN_NOT_FOUND]: 'Token not found.',
|
|
62
|
+
[TOKEN_LIMIT_EXCEEDED]: 'Token limit reached. Delete an existing token before creating a new one.',
|
|
63
|
+
[FILE_PATH_MISSING]: 'Missing required argument: filepath. Provide it as an argument or set dbml.entry in settings.json.',
|
|
64
|
+
[SOURCE_MISSING]: 'One source must be specified: --from-file or --from-diagram',
|
|
65
|
+
[CONFIRMATION_REQUIRED]: 'Confirmation required. Pass --force (-f) to delete in a non-interactive environment.',
|
|
66
|
+
[INTERNAL_SERVER_ERROR]: 'An internal server error occurred. Please try again later.',
|
|
67
|
+
[NETWORK_ERROR]: 'Network error: could not reach the server. Check your connection and try again.',
|
|
68
|
+
};
|
|
69
|
+
export const PORTAL_TO_CLI_CODE = {
|
|
70
|
+
diagram_not_found: DIAGRAM_NOT_FOUND,
|
|
71
|
+
diagram_permission_denied_view: DIAGRAM_PERMISSION_DENIED,
|
|
72
|
+
diagram_permission_denied_edit: DIAGRAM_PERMISSION_DENIED,
|
|
73
|
+
diagram_permission_denied_delete: DIAGRAM_PERMISSION_DENIED,
|
|
74
|
+
diagram_limit_exceeded: DIAGRAM_LIMIT_EXCEEDED,
|
|
75
|
+
workspace_not_found: WORKSPACE_NOT_FOUND,
|
|
76
|
+
workspace_permission_denied_view: WORKSPACE_PERMISSION_DENIED,
|
|
77
|
+
token_not_found: TOKEN_NOT_FOUND,
|
|
78
|
+
token_limit_exceeded: TOKEN_LIMIT_EXCEEDED,
|
|
79
|
+
internal_server_error: INTERNAL_SERVER_ERROR,
|
|
80
|
+
unexpected_request_error: NETWORK_ERROR,
|
|
81
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { CliError } from '../errors/cli.error.js';
|
|
2
|
+
import { CLI_ERROR_MESSAGES, PORTAL_TO_CLI_CODE, REAUTH_MESSAGE, AUTH_INVALID_CREDENTIALS, AUTH_LOGIN_TIMEOUT, AUTH_LOGIN_CANCELLED, AUTH_LOGIN_STATE_MISMATCH, AUTH_LOGIN_INVALID_CALLBACK, AUTH_LOGIN_EXCHANGE_FAILED, AUTH_LOGIN_SERVER_ERROR, AUTH_LOGIN_FAILED, VALIDATION_FAILED, UNEXPECTED_ERROR, } from '../constants/cli-error.constant.js';
|
|
3
|
+
import { PortalApiError } from '../errors/portal-api.error.js';
|
|
4
|
+
import { PortalAuthenticationError, PORTAL_AUTH_ERROR_CODES } from '../libs/portal/index.js';
|
|
5
|
+
export function isPortalApiError(error) {
|
|
6
|
+
return error instanceof PortalApiError;
|
|
7
|
+
}
|
|
8
|
+
export const getCliErrorMessageFromCode = (errorCode) => {
|
|
9
|
+
return CLI_ERROR_MESSAGES[errorCode] ?? `An unexpected error occurred [${errorCode}]`;
|
|
10
|
+
};
|
|
11
|
+
export const fromPortalError = (error) => {
|
|
12
|
+
if (error.errorCode.startsWith('auth_')) {
|
|
13
|
+
return new CliError(AUTH_INVALID_CREDENTIALS, REAUTH_MESSAGE);
|
|
14
|
+
}
|
|
15
|
+
if (error.errorCode === 'validation_invalid_payload') {
|
|
16
|
+
return new CliError(VALIDATION_FAILED, error.message);
|
|
17
|
+
}
|
|
18
|
+
const mappedCliErrorCode = PORTAL_TO_CLI_CODE[error.errorCode];
|
|
19
|
+
if (mappedCliErrorCode) {
|
|
20
|
+
return new CliError(mappedCliErrorCode, getCliErrorMessageFromCode(mappedCliErrorCode));
|
|
21
|
+
}
|
|
22
|
+
return new CliError(UNEXPECTED_ERROR, `An unexpected error occurred [${error.errorCode}]`);
|
|
23
|
+
};
|
|
24
|
+
const PORTAL_AUTH_TO_CLI_CODE = {
|
|
25
|
+
[PORTAL_AUTH_ERROR_CODES.loginTimeout]: AUTH_LOGIN_TIMEOUT,
|
|
26
|
+
[PORTAL_AUTH_ERROR_CODES.loginCancelled]: AUTH_LOGIN_CANCELLED,
|
|
27
|
+
[PORTAL_AUTH_ERROR_CODES.stateMismatch]: AUTH_LOGIN_STATE_MISMATCH,
|
|
28
|
+
[PORTAL_AUTH_ERROR_CODES.invalidCallback]: AUTH_LOGIN_INVALID_CALLBACK,
|
|
29
|
+
[PORTAL_AUTH_ERROR_CODES.exchangeFailed]: AUTH_LOGIN_EXCHANGE_FAILED,
|
|
30
|
+
[PORTAL_AUTH_ERROR_CODES.loopbackServerError]: AUTH_LOGIN_SERVER_ERROR,
|
|
31
|
+
[PORTAL_AUTH_ERROR_CODES.unknownError]: AUTH_LOGIN_FAILED,
|
|
32
|
+
};
|
|
33
|
+
export const fromPortalAuthError = (error) => {
|
|
34
|
+
const cliCode = PORTAL_AUTH_TO_CLI_CODE[error.errorCode] ?? AUTH_LOGIN_FAILED;
|
|
35
|
+
return new CliError(cliCode, getCliErrorMessageFromCode(cliCode));
|
|
36
|
+
};
|
|
37
|
+
export const toCliError = (error) => {
|
|
38
|
+
if (error instanceof CliError)
|
|
39
|
+
return error;
|
|
40
|
+
if (error instanceof PortalAuthenticationError)
|
|
41
|
+
return fromPortalAuthError(error);
|
|
42
|
+
if (isPortalApiError(error))
|
|
43
|
+
return fromPortalError(error);
|
|
44
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
+
return new CliError(UNEXPECTED_ERROR, message);
|
|
46
|
+
};
|
|
@@ -1,18 +1,49 @@
|
|
|
1
1
|
import Table from 'cli-table3';
|
|
2
|
+
import { log } from '@clack/prompts';
|
|
2
3
|
import { logConsole } from './logger.util.js';
|
|
4
|
+
export const getOutputFormat = (json) => (json ? 'json' : 'plain');
|
|
3
5
|
export function printJson(data) {
|
|
4
6
|
logConsole(JSON.stringify(data, null, 2));
|
|
5
7
|
}
|
|
8
|
+
export const displayError = (error, format) => {
|
|
9
|
+
if (format === 'json') {
|
|
10
|
+
printJson({ errorCode: error.errorCode, message: error.message });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
log.error(error.message);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const NO_BORDER_CHAR_CONFIG = {
|
|
17
|
+
top: '',
|
|
18
|
+
'top-mid': '',
|
|
19
|
+
'top-left': '',
|
|
20
|
+
'top-right': '',
|
|
21
|
+
bottom: '',
|
|
22
|
+
'bottom-mid': '',
|
|
23
|
+
'bottom-left': '',
|
|
24
|
+
'bottom-right': '',
|
|
25
|
+
left: '',
|
|
26
|
+
'left-mid': '',
|
|
27
|
+
mid: '',
|
|
28
|
+
'mid-mid': '',
|
|
29
|
+
right: '',
|
|
30
|
+
'right-mid': '',
|
|
31
|
+
middle: '',
|
|
32
|
+
};
|
|
6
33
|
export function printTable(data, config) {
|
|
7
34
|
const table = new Table({
|
|
8
35
|
head: config.head,
|
|
9
|
-
style: {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
36
|
+
style: {
|
|
37
|
+
head: ['gray'],
|
|
38
|
+
'padding-left': 0,
|
|
39
|
+
'padding-right': 2,
|
|
40
|
+
},
|
|
41
|
+
chars: NO_BORDER_CHAR_CONFIG,
|
|
13
42
|
});
|
|
14
43
|
for (const item of data) {
|
|
15
44
|
table.push(config.rowMapper(item));
|
|
45
|
+
const spacerRow = new Array(config.head.length).fill('');
|
|
46
|
+
table.push(spacerRow);
|
|
16
47
|
}
|
|
17
48
|
logConsole(table.toString());
|
|
18
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dbdiagram",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dbdiagram": "dist/index.js"
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
51
51
|
"eslint-plugin-import-x": "^4.16.2",
|
|
52
52
|
"globals": "^17.6.0",
|
|
53
|
-
"tsx": "^4.
|
|
53
|
+
"tsx": "^4.23.0",
|
|
54
54
|
"typescript": "^5.7.0",
|
|
55
55
|
"typescript-eslint": "^8.59.3",
|
|
56
56
|
"vitest": "^4.1.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const NOT_LOGGED_IN_MESSAGE = 'Not logged in. Run `dbdiagram auth login`, or set DBDIAGRAM_TOKEN, to authenticate.';
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export const DIAGRAM_NOT_FOUND = 'diagram_not_found';
|
|
2
|
-
export const DIAGRAM_PERMISSION_DENIED_VIEW = 'diagram_permission_denied_view';
|
|
3
|
-
export const DIAGRAM_PERMISSION_DENIED_EDIT = 'diagram_permission_denied_edit';
|
|
4
|
-
export const DIAGRAM_PERMISSION_DENIED_DELETE = 'diagram_permission_denied_delete';
|
|
5
|
-
export const DIAGRAM_LIMIT_EXCEEDED = 'diagram_limit_exceeded';
|
|
6
|
-
export const WORKSPACE_NOT_FOUND = 'workspace_not_found';
|
|
7
|
-
export const WORKSPACE_PERMISSION_DENIED_VIEW = 'workspace_permission_denied_view';
|
|
8
|
-
export const TOKEN_NOT_FOUND = 'token_not_found';
|
|
9
|
-
export const TOKEN_LIMIT_EXCEEDED = 'token_limit_exceeded';
|
|
10
|
-
export const VALIDATION_INVALID_PAYLOAD = 'validation_invalid_payload';
|
|
11
|
-
export const INTERNAL_SERVER_ERROR = 'internal_server_error';
|
|
12
|
-
export const PORTAL_ERROR_MESSAGES = {
|
|
13
|
-
[DIAGRAM_NOT_FOUND]: 'Diagram not found.',
|
|
14
|
-
[DIAGRAM_PERMISSION_DENIED_VIEW]: 'You do not have access to this diagram.',
|
|
15
|
-
[DIAGRAM_PERMISSION_DENIED_EDIT]: 'You do not have edit permission on this diagram.',
|
|
16
|
-
[DIAGRAM_PERMISSION_DENIED_DELETE]: 'You do not have permission to delete this diagram.',
|
|
17
|
-
[DIAGRAM_LIMIT_EXCEEDED]: 'Diagram limit exceeded for your current plan.',
|
|
18
|
-
[WORKSPACE_NOT_FOUND]: 'Workspace not found.',
|
|
19
|
-
[WORKSPACE_PERMISSION_DENIED_VIEW]: 'You do not have access to this workspace.',
|
|
20
|
-
[TOKEN_NOT_FOUND]: 'Token not found.',
|
|
21
|
-
[TOKEN_LIMIT_EXCEEDED]: 'Token limit reached. Delete an existing token before creating a new one.',
|
|
22
|
-
[INTERNAL_SERVER_ERROR]: 'An internal server error occurred. Please try again later.',
|
|
23
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { PortalApiError } from '../errors/portal-api.error.js';
|
|
2
|
-
import { PORTAL_ERROR_MESSAGES, VALIDATION_INVALID_PAYLOAD } from '../errors/portal-error-codes.js';
|
|
3
|
-
export function isPortalApiError(error) {
|
|
4
|
-
return error instanceof PortalApiError;
|
|
5
|
-
}
|
|
6
|
-
export function getPortalApiErrorMessage(error) {
|
|
7
|
-
if (error.errorCode.startsWith('auth_')) {
|
|
8
|
-
return [
|
|
9
|
-
'Authentication failed: your credentials are invalid or expired. Try one of:',
|
|
10
|
-
' - Replace DBDIAGRAM_TOKEN with a valid token',
|
|
11
|
-
' - Unset DBDIAGRAM_TOKEN, then run `dbdiagram auth login` to re-authenticate',
|
|
12
|
-
].join('\n');
|
|
13
|
-
}
|
|
14
|
-
if (error.errorCode === VALIDATION_INVALID_PAYLOAD) {
|
|
15
|
-
return error.message;
|
|
16
|
-
}
|
|
17
|
-
return PORTAL_ERROR_MESSAGES[error.errorCode] ?? `An unexpected error occurred [${error.errorCode}]`;
|
|
18
|
-
}
|
package/dist/utils/table.util.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function computeColWidths(fractions) {
|
|
2
|
-
const terminalWidth = process.stdout.columns || 100;
|
|
3
|
-
const numCols = fractions.length;
|
|
4
|
-
const overhead = numCols * 3 + 1;
|
|
5
|
-
const available = Math.max(terminalWidth - overhead, numCols * 5);
|
|
6
|
-
const widths = fractions.map((f) => Math.max(Math.floor(available * f), 5));
|
|
7
|
-
const used = widths.reduce((a, b) => a + b, 0);
|
|
8
|
-
widths[widths.length - 1] += available - used;
|
|
9
|
-
return widths;
|
|
10
|
-
}
|