@aderis-erp/cli 1.0.17 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/access-groups.js +49 -17
- package/dist/commands/account-transaction-allocations.js +46 -14
- package/dist/commands/account-transactions.js +75 -35
- package/dist/commands/accounts.js +54 -22
- package/dist/commands/agent-platform.js +53 -21
- package/dist/commands/{nango-integrations.d.ts → agent-runs.d.ts} +1 -1
- package/dist/commands/agent-runs.js +1155 -0
- package/dist/commands/analytics.js +47 -15
- package/dist/commands/api-keys.js +49 -16
- package/dist/commands/{text-templates.d.ts → async-jobs.d.ts} +1 -1
- package/dist/commands/async-jobs.js +1158 -0
- package/dist/commands/audit-log.js +46 -14
- package/dist/commands/bank-accounts.js +63 -30
- package/dist/commands/bank-integrations.d.ts +1 -0
- package/dist/commands/bank-integrations.js +66 -31
- package/dist/commands/business-partners.js +77 -44
- package/dist/commands/chat.js +52 -19
- package/dist/commands/credit-card-accounts.d.ts +1 -0
- package/dist/commands/credit-card-accounts.js +67 -29
- package/dist/commands/delivery-notes.js +78 -44
- package/dist/commands/dunning-configs.js +49 -17
- package/dist/commands/dunning-reminders.js +52 -20
- package/dist/commands/dunning-runs.js +45 -13
- package/dist/commands/email-transactions.js +47 -15
- package/dist/commands/employees.js +76 -44
- package/dist/commands/entity-configurations.js +47 -15
- package/dist/commands/event-processor-mappings.js +49 -17
- package/dist/commands/files.js +56 -24
- package/dist/commands/health.js +49 -17
- package/dist/commands/{tag-configurations.d.ts → imports.d.ts} +1 -1
- package/dist/commands/{tag-configurations.js → imports.js} +59 -31
- package/dist/commands/inbox.js +52 -19
- package/dist/commands/integration-identities.d.ts +40 -0
- package/dist/commands/integration-identities.js +1151 -0
- package/dist/commands/integrations.js +47 -15
- package/dist/commands/item-categories.js +49 -17
- package/dist/commands/items.js +49 -17
- package/dist/commands/journal-lines.js +45 -13
- package/dist/commands/journals.js +68 -36
- package/dist/commands/ledgers.d.ts +3 -1
- package/dist/commands/ledgers.js +96 -34
- package/dist/commands/my-account.d.ts +39 -0
- package/dist/commands/my-account.js +1160 -0
- package/dist/commands/office-locations.js +49 -17
- package/dist/commands/payment-methods.js +54 -22
- package/dist/commands/payment-runs.js +61 -29
- package/dist/commands/payment-terms.js +50 -18
- package/dist/commands/payments.js +51 -19
- package/dist/commands/payroll-runs.d.ts +43 -0
- package/dist/commands/payroll-runs.js +1188 -0
- package/dist/commands/permissions.d.ts +39 -0
- package/dist/commands/{text-templates.js → permissions.js} +54 -30
- package/dist/commands/price-lists.js +54 -22
- package/dist/commands/processor-mappings.js +48 -16
- package/dist/commands/processors.js +55 -24
- package/dist/commands/purchase-order-types.js +49 -17
- package/dist/commands/purchase-orders.js +69 -36
- package/dist/commands/reports.js +49 -17
- package/dist/commands/roles.d.ts +39 -0
- package/dist/commands/{nango-integrations.js → roles.js} +63 -26
- package/dist/commands/salary-types.js +49 -17
- package/dist/commands/sales-invoices.js +84 -51
- package/dist/commands/sales-orders.js +78 -44
- package/dist/commands/saved-views.js +47 -15
- package/dist/commands/scheduled-processor-mappings.js +49 -17
- package/dist/commands/schedules.js +53 -21
- package/dist/commands/support/end.d.ts +9 -0
- package/dist/commands/support/end.js +29 -0
- package/dist/commands/support/start.d.ts +14 -0
- package/dist/commands/support/start.js +50 -0
- package/dist/commands/support/status.d.ts +10 -0
- package/dist/commands/support/status.js +45 -0
- package/dist/commands/support/tenants.d.ts +10 -0
- package/dist/commands/support/tenants.js +39 -0
- package/dist/commands/tags.js +51 -18
- package/dist/commands/tax-codes.js +52 -20
- package/dist/commands/tax-matrix.js +49 -17
- package/dist/commands/templates.d.ts +39 -0
- package/dist/commands/templates.js +1157 -0
- package/dist/commands/tenants.js +52 -20
- package/dist/commands/tools.js +46 -14
- package/dist/commands/users.d.ts +42 -0
- package/dist/commands/users.js +1174 -0
- package/dist/commands/vat-declarations.d.ts +2 -0
- package/dist/commands/vat-declarations.js +72 -36
- package/dist/commands/vendor-invoices.js +81 -49
- package/dist/commands/webhooks.js +51 -19
- package/dist/commands/workflows.js +47 -15
- package/dist/lib/api-client.d.ts +6 -0
- package/dist/lib/api-client.js +13 -0
- package/dist/lib/auth/constants.d.ts +12 -0
- package/dist/lib/auth/constants.js +12 -0
- package/dist/lib/auth/index.d.ts +11 -1
- package/dist/lib/auth/index.js +105 -6
- package/dist/lib/auth/jwks.d.ts +19 -0
- package/dist/lib/auth/jwks.js +112 -0
- package/dist/lib/auth/keycloak-provider.d.ts +45 -7
- package/dist/lib/auth/keycloak-provider.js +161 -27
- package/dist/lib/auth/tokens.d.ts +8 -3
- package/dist/lib/auth/tokens.js +8 -7
- package/dist/lib/auth/types.d.ts +5 -1
- package/dist/lib/config.d.ts +18 -0
- package/dist/lib/config.js +10 -0
- package/oclif.manifest.json +2182 -744
- package/package.json +7 -4
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class Permissions extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'sort-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
};
|
|
28
|
+
run(): Promise<void>;
|
|
29
|
+
private runImport;
|
|
30
|
+
private runExport;
|
|
31
|
+
private runCamt053Import;
|
|
32
|
+
private runNestedImport;
|
|
33
|
+
private parseFilterValue;
|
|
34
|
+
private sanitizeOutput;
|
|
35
|
+
private getColumns;
|
|
36
|
+
private getValue;
|
|
37
|
+
private printTable;
|
|
38
|
+
private printCsv;
|
|
39
|
+
}
|
|
@@ -1,28 +1,20 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
|
-
const HAS_IMPORT =
|
|
5
|
+
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["list"
|
|
9
|
+
const SUBCOMMANDS = [...["list"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/
|
|
12
|
-
'create': { method: 'POST', path: '/v1/text-templates', summary: 'Create a new text template', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/text-templates/{id}', summary: 'Get a single text template by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/text-templates/{id}', summary: 'Update a text template', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/text-templates/{id}', summary: 'Delete a text template', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/permissions', summary: 'List permissions selectable for tenant-created roles', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
12
|
};
|
|
17
|
-
export default class
|
|
18
|
-
static description = 'Manage
|
|
13
|
+
export default class Permissions extends Command {
|
|
14
|
+
static description = 'Manage permissions';
|
|
19
15
|
static examples = [
|
|
20
|
-
'<%= config.bin %>
|
|
21
|
-
'<%= config.bin %>
|
|
22
|
-
'<%= config.bin %> text-templates create --data \'{...}\'',
|
|
23
|
-
'<%= config.bin %> text-templates update <id> --set field=value',
|
|
24
|
-
'<%= config.bin %> text-templates import --file data.json',
|
|
25
|
-
'<%= config.bin %> text-templates export --csv > text-templates.csv',
|
|
16
|
+
'<%= config.bin %> permissions list',
|
|
17
|
+
'<%= config.bin %> permissions export --csv > permissions.csv',
|
|
26
18
|
];
|
|
27
19
|
static args = {
|
|
28
20
|
action: Args.string({ description: 'Action: ' + SUBCOMMANDS.join(', '), required: true }),
|
|
@@ -48,7 +40,7 @@ export default class TextTemplates extends Command {
|
|
|
48
40
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
41
|
};
|
|
50
42
|
async run() {
|
|
51
|
-
const { args, flags } = await this.parse(
|
|
43
|
+
const { args, flags } = await this.parse(Permissions);
|
|
52
44
|
// Handle import action specially
|
|
53
45
|
if (args.action === 'import') {
|
|
54
46
|
if (!HAS_IMPORT)
|
|
@@ -89,7 +81,7 @@ export default class TextTemplates extends Command {
|
|
|
89
81
|
// First path param always comes from positional argument
|
|
90
82
|
value = args.id;
|
|
91
83
|
if (!value)
|
|
92
|
-
this.error('Missing required argument: id. Usage: aderis
|
|
84
|
+
this.error('Missing required argument: id. Usage: aderis permissions <action> <id>');
|
|
93
85
|
}
|
|
94
86
|
else {
|
|
95
87
|
const flagName = param.replace(/\./g, '-').replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
|
|
@@ -264,10 +256,11 @@ export default class TextTemplates extends Command {
|
|
|
264
256
|
process.stderr.write('\n');
|
|
265
257
|
}
|
|
266
258
|
try {
|
|
267
|
-
// Binary response:
|
|
259
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
268
260
|
if (endpoint.isBinaryResponse) {
|
|
269
|
-
|
|
270
|
-
|
|
261
|
+
const toStdout = !flags.file;
|
|
262
|
+
if (toStdout && process.stdout.isTTY) {
|
|
263
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
271
264
|
}
|
|
272
265
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
273
266
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -275,24 +268,55 @@ export default class TextTemplates extends Command {
|
|
|
275
268
|
contextName: flags.context,
|
|
276
269
|
binary: true,
|
|
277
270
|
});
|
|
278
|
-
const fsModule = await import('node:fs');
|
|
279
271
|
const binData = binResponse.data;
|
|
280
272
|
const buffer = Buffer.isBuffer(binData)
|
|
281
273
|
? binData
|
|
282
274
|
: Buffer.from(binData);
|
|
275
|
+
if (toStdout) {
|
|
276
|
+
// Nothing else may reach stdout here — it is the file.
|
|
277
|
+
process.stdout.write(buffer);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const fsModule = await import('node:fs');
|
|
283
281
|
fsModule.writeFileSync(flags.file, buffer);
|
|
284
282
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
285
283
|
return;
|
|
286
284
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
285
|
+
let response;
|
|
286
|
+
if (endpoint.hasBinaryVariant) {
|
|
287
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
288
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
289
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
290
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
291
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
292
|
+
data,
|
|
293
|
+
contextName: flags.context,
|
|
294
|
+
binary: true,
|
|
295
|
+
});
|
|
296
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
297
|
+
const rawData = raw.data;
|
|
298
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
299
|
+
if (!isTextualMediaType(rawType)) {
|
|
300
|
+
if (process.stdout.isTTY) {
|
|
301
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
302
|
+
}
|
|
303
|
+
// Nothing else may reach stdout here — it is the file.
|
|
304
|
+
process.stdout.write(buffer);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
311
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
312
|
+
data,
|
|
313
|
+
contextName: flags.context,
|
|
314
|
+
acceptAny: true,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
293
317
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
294
318
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
295
|
-
if (contentType
|
|
319
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
296
320
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
297
321
|
this.log(String(response.data));
|
|
298
322
|
return;
|
|
@@ -732,7 +756,7 @@ export default class TextTemplates extends Command {
|
|
|
732
756
|
}
|
|
733
757
|
async runNestedImport(suffix, parentId, flags) {
|
|
734
758
|
if (!parentId) {
|
|
735
|
-
this.error(`Missing required argument: id. Usage: aderis
|
|
759
|
+
this.error(`Missing required argument: id. Usage: aderis permissions import-${suffix} <parent-id> --file data.json`);
|
|
736
760
|
}
|
|
737
761
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
738
762
|
if (!context)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
@@ -8,16 +8,16 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = ["prices"];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "list-prices", "create-prices", "get-prices", "update-prices", "delete-prices"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/price-lists', summary: 'Get all price lists with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/price-lists', summary: 'Create a new price list', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/price-lists/{id}', summary: 'Get a price list by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/price-lists/{id}', summary: 'Update a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/price-lists/{id}', summary: 'Delete a price list', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'list-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices', summary: 'Get all prices in a price list with pagination', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
-
'create-prices': { method: 'POST', path: '/v1/price-lists/{id}/prices', summary: 'Create a new price in a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
18
|
-
'get-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Get a price by ID', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
-
'update-prices': { method: 'PATCH', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Update a price', pathParams: ['id', 'priceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
|
-
'delete-prices': { method: 'DELETE', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Delete a price', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/price-lists', summary: 'Get all price lists with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/price-lists', summary: 'Create a new price list', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'get': { method: 'GET', path: '/v1/price-lists/{id}', summary: 'Get a price list by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/price-lists/{id}', summary: 'Update a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/price-lists/{id}', summary: 'Delete a price list', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'list-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices', summary: 'Get all prices in a price list with pagination', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'create-prices': { method: 'POST', path: '/v1/price-lists/{id}/prices', summary: 'Create a new price in a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
+
'get-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Get a price by ID', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'update-prices': { method: 'PATCH', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Update a price', pathParams: ['id', 'priceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'delete-prices': { method: 'DELETE', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Delete a price', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
21
|
};
|
|
22
22
|
export default class PriceLists extends Command {
|
|
23
23
|
static description = 'Manage price lists';
|
|
@@ -270,10 +270,11 @@ export default class PriceLists extends Command {
|
|
|
270
270
|
process.stderr.write('\n');
|
|
271
271
|
}
|
|
272
272
|
try {
|
|
273
|
-
// Binary response:
|
|
273
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
274
274
|
if (endpoint.isBinaryResponse) {
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
const toStdout = !flags.file;
|
|
276
|
+
if (toStdout && process.stdout.isTTY) {
|
|
277
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
277
278
|
}
|
|
278
279
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
279
280
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -281,24 +282,55 @@ export default class PriceLists extends Command {
|
|
|
281
282
|
contextName: flags.context,
|
|
282
283
|
binary: true,
|
|
283
284
|
});
|
|
284
|
-
const fsModule = await import('node:fs');
|
|
285
285
|
const binData = binResponse.data;
|
|
286
286
|
const buffer = Buffer.isBuffer(binData)
|
|
287
287
|
? binData
|
|
288
288
|
: Buffer.from(binData);
|
|
289
|
+
if (toStdout) {
|
|
290
|
+
// Nothing else may reach stdout here — it is the file.
|
|
291
|
+
process.stdout.write(buffer);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const fsModule = await import('node:fs');
|
|
289
295
|
fsModule.writeFileSync(flags.file, buffer);
|
|
290
296
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
291
297
|
return;
|
|
292
298
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
+
let response;
|
|
300
|
+
if (endpoint.hasBinaryVariant) {
|
|
301
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
302
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
303
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
304
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
305
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
306
|
+
data,
|
|
307
|
+
contextName: flags.context,
|
|
308
|
+
binary: true,
|
|
309
|
+
});
|
|
310
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
311
|
+
const rawData = raw.data;
|
|
312
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
313
|
+
if (!isTextualMediaType(rawType)) {
|
|
314
|
+
if (process.stdout.isTTY) {
|
|
315
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
316
|
+
}
|
|
317
|
+
// Nothing else may reach stdout here — it is the file.
|
|
318
|
+
process.stdout.write(buffer);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
325
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
326
|
+
data,
|
|
327
|
+
contextName: flags.context,
|
|
328
|
+
acceptAny: true,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
299
331
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
300
332
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
301
|
-
if (contentType
|
|
333
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
302
334
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
303
335
|
this.log(String(response.data));
|
|
304
336
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
@@ -8,10 +8,10 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/processor-mappings', summary: 'List all document type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/processor-mappings', summary: 'Create a new document type processor mapping', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['documentTypes'] },
|
|
13
|
-
'update': { method: 'PATCH', path: '/v1/processor-mappings/{id}', summary: 'Update a document type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['documentTypes'] },
|
|
14
|
-
'delete': { method: 'DELETE', path: '/v1/processor-mappings/{id}', summary: 'Delete a document type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/processor-mappings', summary: 'List all document type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/processor-mappings', summary: 'Create a new document type processor mapping', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'] },
|
|
13
|
+
'update': { method: 'PATCH', path: '/v1/processor-mappings/{id}', summary: 'Update a document type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'] },
|
|
14
|
+
'delete': { method: 'DELETE', path: '/v1/processor-mappings/{id}', summary: 'Delete a document type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
15
|
};
|
|
16
16
|
export default class ProcessorMappings extends Command {
|
|
17
17
|
static description = 'Manage processor mappings';
|
|
@@ -262,10 +262,11 @@ export default class ProcessorMappings extends Command {
|
|
|
262
262
|
process.stderr.write('\n');
|
|
263
263
|
}
|
|
264
264
|
try {
|
|
265
|
-
// Binary response:
|
|
265
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
266
266
|
if (endpoint.isBinaryResponse) {
|
|
267
|
-
|
|
268
|
-
|
|
267
|
+
const toStdout = !flags.file;
|
|
268
|
+
if (toStdout && process.stdout.isTTY) {
|
|
269
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
269
270
|
}
|
|
270
271
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
271
272
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -273,24 +274,55 @@ export default class ProcessorMappings extends Command {
|
|
|
273
274
|
contextName: flags.context,
|
|
274
275
|
binary: true,
|
|
275
276
|
});
|
|
276
|
-
const fsModule = await import('node:fs');
|
|
277
277
|
const binData = binResponse.data;
|
|
278
278
|
const buffer = Buffer.isBuffer(binData)
|
|
279
279
|
? binData
|
|
280
280
|
: Buffer.from(binData);
|
|
281
|
+
if (toStdout) {
|
|
282
|
+
// Nothing else may reach stdout here — it is the file.
|
|
283
|
+
process.stdout.write(buffer);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const fsModule = await import('node:fs');
|
|
281
287
|
fsModule.writeFileSync(flags.file, buffer);
|
|
282
288
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
283
289
|
return;
|
|
284
290
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
+
let response;
|
|
292
|
+
if (endpoint.hasBinaryVariant) {
|
|
293
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
294
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
295
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
296
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
297
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
298
|
+
data,
|
|
299
|
+
contextName: flags.context,
|
|
300
|
+
binary: true,
|
|
301
|
+
});
|
|
302
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
303
|
+
const rawData = raw.data;
|
|
304
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
305
|
+
if (!isTextualMediaType(rawType)) {
|
|
306
|
+
if (process.stdout.isTTY) {
|
|
307
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
308
|
+
}
|
|
309
|
+
// Nothing else may reach stdout here — it is the file.
|
|
310
|
+
process.stdout.write(buffer);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
317
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
318
|
+
data,
|
|
319
|
+
contextName: flags.context,
|
|
320
|
+
acceptAny: true,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
291
323
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
292
324
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
293
|
-
if (contentType
|
|
325
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
294
326
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
295
327
|
this.log(String(response.data));
|
|
296
328
|
return;
|
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["list-tools", "list", "create", "resolve", "resolve-event", "get", "update", "delete", "
|
|
9
|
+
const SUBCOMMANDS = [...["list-tools", "list", "create", "resolve", "resolve-event", "get", "update", "delete", "update-config", "delete-config"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list-tools': { method: 'GET', path: '/v1/processors/tools', summary: 'List all available tools', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'list': { method: 'GET', path: '/v1/processors', summary: 'List processors available to the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'create': { method: 'POST', path: '/v1/processors', summary: 'Create a new tenant-scoped processor', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['processorTools', 'options'] },
|
|
14
|
-
'resolve': { method: 'GET', path: '/v1/processors/resolve/{documentType}', summary: 'Resolve processor for a document type', pathParams: ['documentType'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
-
'resolve-event': { method: 'GET', path: '/v1/processors/resolve/event/{eventType}', summary: 'Resolve processors for an event type', pathParams: ['eventType'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/processors/{id}', summary: 'Get a single processor by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/processors/{id}', summary: 'Update a tenant-scoped processor', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['processorTools', 'options'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/processors/{id}', summary: 'Delete a tenant-scoped processor', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'delete-config': { method: 'DELETE', path: '/v1/processors/{id}/config', summary: 'Remove the tenant prompt overlay on a system processor', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list-tools': { method: 'GET', path: '/v1/processors/tools', summary: 'List all available tools', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'list': { method: 'GET', path: '/v1/processors', summary: 'List processors available to the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'create': { method: 'POST', path: '/v1/processors', summary: 'Create a new tenant-scoped processor', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['processorTools', 'options'] },
|
|
14
|
+
'resolve': { method: 'GET', path: '/v1/processors/resolve/{documentType}', summary: 'Resolve processor for a document type', pathParams: ['documentType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'resolve-event': { method: 'GET', path: '/v1/processors/resolve/event/{eventType}', summary: 'Resolve processors for an event type', pathParams: ['eventType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'get': { method: 'GET', path: '/v1/processors/{id}', summary: 'Get a single processor by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'update': { method: 'PATCH', path: '/v1/processors/{id}', summary: 'Update a tenant-scoped processor', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['processorTools', 'options'] },
|
|
18
|
+
'delete': { method: 'DELETE', path: '/v1/processors/{id}', summary: 'Delete a tenant-scoped processor', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'update-config': { method: 'PUT', path: '/v1/processors/{id}/config', summary: 'Set or replace the tenant\'s overwrite on a system processor', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'delete-config': { method: 'DELETE', path: '/v1/processors/{id}/config', summary: 'Remove the tenant\'s overwrite on a system processor', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
21
|
};
|
|
23
22
|
export default class Processors extends Command {
|
|
24
23
|
static description = 'Manage processors';
|
|
@@ -270,10 +269,11 @@ export default class Processors extends Command {
|
|
|
270
269
|
process.stderr.write('\n');
|
|
271
270
|
}
|
|
272
271
|
try {
|
|
273
|
-
// Binary response:
|
|
272
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
274
273
|
if (endpoint.isBinaryResponse) {
|
|
275
|
-
|
|
276
|
-
|
|
274
|
+
const toStdout = !flags.file;
|
|
275
|
+
if (toStdout && process.stdout.isTTY) {
|
|
276
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
277
277
|
}
|
|
278
278
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
279
279
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -281,24 +281,55 @@ export default class Processors extends Command {
|
|
|
281
281
|
contextName: flags.context,
|
|
282
282
|
binary: true,
|
|
283
283
|
});
|
|
284
|
-
const fsModule = await import('node:fs');
|
|
285
284
|
const binData = binResponse.data;
|
|
286
285
|
const buffer = Buffer.isBuffer(binData)
|
|
287
286
|
? binData
|
|
288
287
|
: Buffer.from(binData);
|
|
288
|
+
if (toStdout) {
|
|
289
|
+
// Nothing else may reach stdout here — it is the file.
|
|
290
|
+
process.stdout.write(buffer);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const fsModule = await import('node:fs');
|
|
289
294
|
fsModule.writeFileSync(flags.file, buffer);
|
|
290
295
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
291
296
|
return;
|
|
292
297
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
let response;
|
|
299
|
+
if (endpoint.hasBinaryVariant) {
|
|
300
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
301
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
302
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
303
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
304
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
305
|
+
data,
|
|
306
|
+
contextName: flags.context,
|
|
307
|
+
binary: true,
|
|
308
|
+
});
|
|
309
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
310
|
+
const rawData = raw.data;
|
|
311
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
312
|
+
if (!isTextualMediaType(rawType)) {
|
|
313
|
+
if (process.stdout.isTTY) {
|
|
314
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
315
|
+
}
|
|
316
|
+
// Nothing else may reach stdout here — it is the file.
|
|
317
|
+
process.stdout.write(buffer);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
324
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
325
|
+
data,
|
|
326
|
+
contextName: flags.context,
|
|
327
|
+
acceptAny: true,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
299
330
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
300
331
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
301
|
-
if (contentType
|
|
332
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
302
333
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
303
334
|
this.log(String(response.data));
|
|
304
335
|
return;
|