@nzz/q-cli 2.1.1 → 2.2.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.
@@ -7,10 +7,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
8
|
});
|
9
9
|
};
|
10
|
-
import { logSuccess, logError, updateItem, getAccessToken, getQServerUrl } from '
|
10
|
+
import { logSuccess, logError, updateItem, getAccessToken, getQServerUrl } from '../utils.js';
|
11
11
|
import { readFileSync, existsSync, writeFileSync } from 'fs';
|
12
12
|
import { resolve } from 'path';
|
13
|
-
export
|
13
|
+
export function createCreateCustomCodeItemCommand(program) {
|
14
|
+
return program
|
15
|
+
.command('create-custom-code-item')
|
16
|
+
.description('creates a new q custom code item in the db and adds it to the q config file')
|
17
|
+
.option('-c, --config [path]', 'set config path to q.config.json. defaults to ./q.config.json', `${process.cwd()}/q.config.json`)
|
18
|
+
.option('-e, --environment [env]', 'set environment where the new q custom code item should be created in')
|
19
|
+
.option('-t, --title [title]', 'set title of the new q custom code item')
|
20
|
+
.action((command) => __awaiter(this, void 0, void 0, function* () {
|
21
|
+
yield createCustomCodeItem(command);
|
22
|
+
}));
|
23
|
+
}
|
24
|
+
function createCustomCodeItem(command) {
|
14
25
|
return __awaiter(this, void 0, void 0, function* () {
|
15
26
|
const qConfigPath = resolve(command.config);
|
16
27
|
if (!existsSync(qConfigPath)) {
|
@@ -35,6 +46,7 @@ export default function (command) {
|
|
35
46
|
files: [],
|
36
47
|
options: {
|
37
48
|
previewDisabled: true,
|
49
|
+
qEditorPreviewDisabled: false,
|
38
50
|
},
|
39
51
|
// @ts-ignore
|
40
52
|
publication: 'nzz',
|
@@ -1,8 +1,18 @@
|
|
1
|
-
import * as fs from 'fs';
|
2
1
|
import * as path from 'path';
|
2
|
+
import * as fs from 'fs';
|
3
3
|
import { execSync } from 'child_process';
|
4
|
-
import { logError, logSuccess } from '
|
5
|
-
export
|
4
|
+
import { logError, logSuccess } from '../utils.js';
|
5
|
+
export function createNewCustomCodeCommand(program) {
|
6
|
+
return program
|
7
|
+
.command('new-custom-code')
|
8
|
+
.argument('<path>', 'the base directory to bootstrap the new custom code project in')
|
9
|
+
.description('bootstrap a new custom code project')
|
10
|
+
.action(() => {
|
11
|
+
const dir = program.args[1];
|
12
|
+
newCustomCode({ dir });
|
13
|
+
});
|
14
|
+
}
|
15
|
+
function newCustomCode(command) {
|
6
16
|
const { dir } = command;
|
7
17
|
if (!dir) {
|
8
18
|
logError('No custom-code project name/directory given');
|
@@ -12,9 +12,19 @@ import { readFileSync, existsSync, createReadStream } from 'fs';
|
|
12
12
|
import { resolve } from 'path';
|
13
13
|
import FormData from 'form-data';
|
14
14
|
import fetch from 'node-fetch'; // Use node-fetch instead of native fetch, because native fetch seems to have issues with FormData/uploading files
|
15
|
-
import { getAccessToken, getQServerUrl, logError, logSuccess, updateItem } from '
|
16
|
-
import updateSchemaJson from '
|
17
|
-
import { Environment } from '
|
15
|
+
import { getAccessToken, getQServerUrl, logError, logSuccess, updateItem as updateItemUtils } from '../utils.js';
|
16
|
+
import updateSchemaJson from '../assets/updateSchema.json' with { type: 'json' };
|
17
|
+
import { Environment } from '../enums.js';
|
18
|
+
export function createUpdateItemCommand(program) {
|
19
|
+
return program
|
20
|
+
.command('update-item')
|
21
|
+
.description('update q item')
|
22
|
+
.option('-c, --config [path]', 'set config path which defines the q items to be updated. defaults to ./q.config.json', `${process.cwd()}/q.config.json`)
|
23
|
+
.option('-e, --environment [env]', 'set environment which should be updated, defaults to update all items of all environments defined in config')
|
24
|
+
.action((command) => __awaiter(this, void 0, void 0, function* () {
|
25
|
+
yield updateItem(command);
|
26
|
+
}));
|
27
|
+
}
|
18
28
|
const envCredentials = {
|
19
29
|
[Environment.LOCAL]: {
|
20
30
|
qServerUrl: '',
|
@@ -84,6 +94,28 @@ function uploadFile(path, qServerUrl, accessToken) {
|
|
84
94
|
body: form,
|
85
95
|
headers: Object.assign(Object.assign({}, form.getHeaders()), { 'user-agent': 'Q Command-line Tool', Authorization: `Bearer ${accessToken}` }),
|
86
96
|
});
|
97
|
+
// Handle HTTP errors before parsing JSON
|
98
|
+
if (!response.ok) {
|
99
|
+
let errorMessage;
|
100
|
+
switch (response.status) {
|
101
|
+
case 401:
|
102
|
+
errorMessage = 'Authentication error: Invalid or expired access token';
|
103
|
+
break;
|
104
|
+
case 403:
|
105
|
+
errorMessage = 'Authorization error: Insufficient permissions to upload files';
|
106
|
+
break;
|
107
|
+
case 413:
|
108
|
+
errorMessage = 'File too large: The file exceeds the maximum allowed size';
|
109
|
+
break;
|
110
|
+
case 415:
|
111
|
+
errorMessage = 'Unsupported file type: The file type is not allowed';
|
112
|
+
break;
|
113
|
+
default:
|
114
|
+
errorMessage = createGenericFileUploadErrorMsg(response);
|
115
|
+
}
|
116
|
+
logError(errorMessage);
|
117
|
+
return undefined;
|
118
|
+
}
|
87
119
|
const data = (yield response.json());
|
88
120
|
if (!data.apiResponseStatus.success) {
|
89
121
|
logError(`Failed to upload file: ${data.apiResponseStatus.msg}`);
|
@@ -97,6 +129,9 @@ function uploadFile(path, qServerUrl, accessToken) {
|
|
97
129
|
}
|
98
130
|
});
|
99
131
|
}
|
132
|
+
function createGenericFileUploadErrorMsg(response) {
|
133
|
+
return `HTTP ${response.status}: File upload failed`;
|
134
|
+
}
|
100
135
|
/**
|
101
136
|
* Recursively processes a document structure, looking for 'path' properties
|
102
137
|
* and processing them with the processResource function.
|
@@ -127,7 +162,7 @@ function processPathProperties(item, processResource) {
|
|
127
162
|
return result;
|
128
163
|
});
|
129
164
|
}
|
130
|
-
|
165
|
+
function updateItem(command) {
|
131
166
|
return __awaiter(this, void 0, void 0, function* () {
|
132
167
|
const qConfigPath = resolve(command.config);
|
133
168
|
if (!existsSync(qConfigPath)) {
|
@@ -170,7 +205,7 @@ export default function (command) {
|
|
170
205
|
return yield uploadFile(formattedPath, qServerUrl, accessToken);
|
171
206
|
}));
|
172
207
|
// Update the item on the Q server
|
173
|
-
const result = yield
|
208
|
+
const result = yield updateItemUtils(qDoc, qServerUrl, accessToken);
|
174
209
|
if (result.success) {
|
175
210
|
logSuccess(`Successfully updated item with id ${environment.id} on ${environmentToUpdate} environment`);
|
176
211
|
}
|
@@ -182,3 +217,8 @@ export default function (command) {
|
|
182
217
|
}
|
183
218
|
});
|
184
219
|
}
|
220
|
+
// Export for testing only
|
221
|
+
export const __test__ = {
|
222
|
+
uploadFile,
|
223
|
+
createGenericFileUploadErrorMsg,
|
224
|
+
};
|
package/dist/index.js
CHANGED
@@ -10,40 +10,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
10
10
|
};
|
11
11
|
import { Command } from 'commander';
|
12
12
|
import packageJson from '../package.json' with { type: 'json' };
|
13
|
-
import
|
14
|
-
import
|
15
|
-
import
|
13
|
+
import { createCreateCustomCodeItemCommand } from './commands/createCustomCodeItem.js';
|
14
|
+
import { createUpdateItemCommand } from './commands/updateItem.js';
|
15
|
+
import { createNewCustomCodeCommand } from './commands/newCustomCode.js';
|
16
16
|
const program = new Command();
|
17
|
-
// Get the version from the package.json file
|
18
17
|
const version = packageJson.version;
|
19
18
|
function main() {
|
20
19
|
return __awaiter(this, void 0, void 0, function* () {
|
21
20
|
program.version(version).description('Q Toolbox cli');
|
22
|
-
program
|
23
|
-
|
24
|
-
|
25
|
-
.description('bootstrap a new custom code project')
|
26
|
-
.action(() => {
|
27
|
-
const dir = program.args[1];
|
28
|
-
newCustomCode({ dir });
|
29
|
-
});
|
30
|
-
program
|
31
|
-
.command('update-item')
|
32
|
-
.description('update q item')
|
33
|
-
.option('-c, --config [path]', 'set config path which defines the q items to be updated. defaults to ./q.config.json', `${process.cwd()}/q.config.json`)
|
34
|
-
.option('-e, --environment [env]', 'set environment which should be updated, defaults to update all items of all environments defined in config')
|
35
|
-
.action((command) => __awaiter(this, void 0, void 0, function* () {
|
36
|
-
yield updateItem(command);
|
37
|
-
}));
|
38
|
-
program
|
39
|
-
.command('create-custom-code-item')
|
40
|
-
.description('creates a new q custom code item in the db and adds it to the q config file')
|
41
|
-
.option('-c, --config [path]', 'set config path to q.config.json. defaults to ./q.config.json', `${process.cwd()}/q.config.json`)
|
42
|
-
.option('-e, --environment [env]', 'set environment where the new q custom code item should be created in')
|
43
|
-
.option('-t, --title [title]', 'set title of the new q custom code item')
|
44
|
-
.action((command) => __awaiter(this, void 0, void 0, function* () {
|
45
|
-
yield createCustomCodeItem(command);
|
46
|
-
}));
|
21
|
+
createNewCustomCodeCommand(program);
|
22
|
+
createUpdateItemCommand(program);
|
23
|
+
createCreateCustomCodeItemCommand(program);
|
47
24
|
yield program.parseAsync(process.argv);
|
48
25
|
});
|
49
26
|
}
|
package/dist/utils.js
CHANGED
@@ -37,9 +37,10 @@ export function updateItem(qDoc, qServerUrl, accessToken) {
|
|
37
37
|
msg: '',
|
38
38
|
success: false,
|
39
39
|
};
|
40
|
+
let response;
|
40
41
|
let data;
|
41
42
|
try {
|
42
|
-
|
43
|
+
response = yield fetch(`${qServerUrl}/item`, {
|
43
44
|
method: 'POST',
|
44
45
|
body: JSON.stringify(qDoc),
|
45
46
|
headers: {
|
@@ -60,6 +61,30 @@ export function updateItem(qDoc, qServerUrl, accessToken) {
|
|
60
61
|
}
|
61
62
|
return retVal;
|
62
63
|
}
|
64
|
+
// Handle different HTTP status codes
|
65
|
+
if (!response.ok) {
|
66
|
+
switch (response.status) {
|
67
|
+
case 400:
|
68
|
+
retVal.msg = `Bad Request: ${isAuthError(data) ? data.error : 'Invalid request data'}`;
|
69
|
+
break;
|
70
|
+
case 401:
|
71
|
+
retVal.msg = 'Authentication error: Invalid or expired access token';
|
72
|
+
break;
|
73
|
+
case 403:
|
74
|
+
retVal.msg = 'Authorization error: Insufficient permissions';
|
75
|
+
break;
|
76
|
+
case 413:
|
77
|
+
retVal.msg =
|
78
|
+
'Request too large: The item data is too large. Please reduce the size of your content or contact support to increase the limit.';
|
79
|
+
break;
|
80
|
+
case 500:
|
81
|
+
retVal.msg = 'Server error: Internal server error occurred';
|
82
|
+
break;
|
83
|
+
default:
|
84
|
+
retVal.msg = createUnknownErrorMsg(response, data);
|
85
|
+
}
|
86
|
+
return retVal;
|
87
|
+
}
|
63
88
|
if (isAuthError(data)) {
|
64
89
|
retVal.msg = `Authentication error: ${data.error}`;
|
65
90
|
return retVal;
|
@@ -73,9 +98,12 @@ export function updateItem(qDoc, qServerUrl, accessToken) {
|
|
73
98
|
return retVal;
|
74
99
|
});
|
75
100
|
}
|
101
|
+
function createUnknownErrorMsg(response, data) {
|
102
|
+
return `HTTP ${response.status}: ${isAuthError(data) ? data.error : 'Unknown error occurred'}`;
|
103
|
+
}
|
76
104
|
// Use type predicate to check response type
|
77
105
|
function isAuthError(data) {
|
78
|
-
return 'error' in data;
|
106
|
+
return data !== null && typeof data === 'object' && 'error' in data && typeof data.error === 'string';
|
79
107
|
}
|
80
108
|
function readSecret(reference) {
|
81
109
|
try {
|
@@ -86,3 +114,7 @@ function readSecret(reference) {
|
|
86
114
|
process.exit(1);
|
87
115
|
}
|
88
116
|
}
|
117
|
+
// Export for testing only
|
118
|
+
export const __test__ = {
|
119
|
+
createUnknownErrorMsg,
|
120
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nzz/q-cli",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.2.1",
|
4
4
|
"description": "",
|
5
5
|
"type": "module",
|
6
6
|
"main": "./src/index.ts",
|
@@ -16,6 +16,9 @@
|
|
16
16
|
"create-custom-code-item": "tsx ./src/index.ts create-custom-code-item -e local -c ./tests/q.config.json -t 'TEST CUSTOM CODE ITEM'",
|
17
17
|
"update-item": "tsx ./src/index.ts update-item -e local -c ./tests/q.config.json",
|
18
18
|
"new-custom-code": "tsx ./src/index.ts new-custom-code -d my-custom-code-project",
|
19
|
+
"test": "vitest",
|
20
|
+
"test:run": "vitest run",
|
21
|
+
"test:coverage": "vitest run --coverage",
|
19
22
|
"eslint": "TIMING=1 eslint --ext .svelte,.ts --config .eslintrc.cjs .",
|
20
23
|
"lint:all": "run-s -c tscheck lint svelte-check",
|
21
24
|
"tscheck": "tsc --noEmit"
|
@@ -33,6 +36,7 @@
|
|
33
36
|
"@repo/types-custom-code": "workspace:^",
|
34
37
|
"@repo/types-db": "workspace:^",
|
35
38
|
"@repo/types-files": "workspace:^",
|
39
|
+
"@vitest/coverage-v8": "^3.0.8",
|
36
40
|
"delivery-server": "workspace:*",
|
37
41
|
"typescript": "^5.2.2",
|
38
42
|
"vitest": "^0.34.6"
|