@aderis-erp/cli 1.0.17 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/imports.d.ts +39 -0
- package/dist/commands/{nango-integrations.js → imports.js} +61 -25
- 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 +95 -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/roles.js +1152 -0
- 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/tag-configurations.js +50 -18
- package/dist/commands/tags.js +49 -17
- 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/index.js +15 -4
- 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 +23 -7
- package/dist/lib/auth/keycloak-provider.js +53 -24
- 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/oclif.manifest.json +2152 -715
- package/package.json +4 -4
|
@@ -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 = false;
|
|
@@ -8,8 +8,8 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "get"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/audit-logs', summary: 'Get audit log entries', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'get': { method: 'GET', path: '/v1/audit-logs/{id}', summary: 'Get a single audit log entry', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/audit-logs', summary: 'Get audit log entries', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'get': { method: 'GET', path: '/v1/audit-logs/{id}', summary: 'Get a single audit log entry', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
13
|
};
|
|
14
14
|
export default class AuditLog extends Command {
|
|
15
15
|
static description = 'Manage audit log';
|
|
@@ -258,10 +258,11 @@ export default class AuditLog extends Command {
|
|
|
258
258
|
process.stderr.write('\n');
|
|
259
259
|
}
|
|
260
260
|
try {
|
|
261
|
-
// Binary response:
|
|
261
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
262
262
|
if (endpoint.isBinaryResponse) {
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
const toStdout = !flags.file;
|
|
264
|
+
if (toStdout && process.stdout.isTTY) {
|
|
265
|
+
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.`);
|
|
265
266
|
}
|
|
266
267
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
267
268
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -269,24 +270,55 @@ export default class AuditLog extends Command {
|
|
|
269
270
|
contextName: flags.context,
|
|
270
271
|
binary: true,
|
|
271
272
|
});
|
|
272
|
-
const fsModule = await import('node:fs');
|
|
273
273
|
const binData = binResponse.data;
|
|
274
274
|
const buffer = Buffer.isBuffer(binData)
|
|
275
275
|
? binData
|
|
276
276
|
: Buffer.from(binData);
|
|
277
|
+
if (toStdout) {
|
|
278
|
+
// Nothing else may reach stdout here — it is the file.
|
|
279
|
+
process.stdout.write(buffer);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const fsModule = await import('node:fs');
|
|
277
283
|
fsModule.writeFileSync(flags.file, buffer);
|
|
278
284
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
279
285
|
return;
|
|
280
286
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
+
let response;
|
|
288
|
+
if (endpoint.hasBinaryVariant) {
|
|
289
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
290
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
291
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
292
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
293
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
294
|
+
data,
|
|
295
|
+
contextName: flags.context,
|
|
296
|
+
binary: true,
|
|
297
|
+
});
|
|
298
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
299
|
+
const rawData = raw.data;
|
|
300
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
301
|
+
if (!isTextualMediaType(rawType)) {
|
|
302
|
+
if (process.stdout.isTTY) {
|
|
303
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
304
|
+
}
|
|
305
|
+
// Nothing else may reach stdout here — it is the file.
|
|
306
|
+
process.stdout.write(buffer);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
313
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
314
|
+
data,
|
|
315
|
+
contextName: flags.context,
|
|
316
|
+
acceptAny: true,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
287
319
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
288
320
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
289
|
-
if (contentType
|
|
321
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
290
322
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
291
323
|
this.log(String(response.data));
|
|
292
324
|
return;
|
|
@@ -1,30 +1,31 @@
|
|
|
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 = ["ledger-mappings", "notes"];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-balances", "get-balances-latest", "list-ledger-mappings", "create-ledger-mappings", "get-ledger-mappings", "update-ledger-mappings", "delete-ledger-mappings", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-balances", "get-balances-latest", "list-ledger-mappings", "create-ledger-mappings", "get-ledger-mappings", "update-ledger-mappings", "delete-ledger-mappings", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-daily-balances"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/bank-accounts', summary: 'Get all bank accounts with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/bank-accounts', summary: 'Create a new bank account (with optional notes)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/bank-accounts/{id}', summary: 'Get a bank account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/bank-accounts/{id}', summary: 'Update a bank account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/bank-accounts/{id}', summary: 'Delete a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'get-balances': { method: 'GET', path: '/v1/bank-accounts/{id}/balances', summary: 'Get balance history for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
-
'get-balances-latest': { method: 'GET', path: '/v1/bank-accounts/{id}/balances/latest', summary: 'Get latest balances (OPBD, CLBD, CLAV) for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
18
|
-
'list-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Get all ledger mappings for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
-
'create-ledger-mappings': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Create a ledger mapping for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
|
-
'get-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Get a ledger mapping by ID', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
21
|
-
'update-ledger-mappings': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Update a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
-
'delete-ledger-mappings': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Delete a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
|
-
'list-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Get all notes for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
24
|
-
'create-notes': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Create a note for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
|
-
'get-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Get a specific note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
26
|
-
'update-notes': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Update a note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
|
-
'delete-notes': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Delete a note from a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/bank-accounts', summary: 'Get all bank accounts with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/bank-accounts', summary: 'Create a new bank account (with optional notes)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
13
|
+
'get': { method: 'GET', path: '/v1/bank-accounts/{id}', summary: 'Get a bank account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/bank-accounts/{id}', summary: 'Update a bank account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/bank-accounts/{id}', summary: 'Delete a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'get-balances': { method: 'GET', path: '/v1/bank-accounts/{id}/balances', summary: 'Get balance history for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'get-balances-latest': { method: 'GET', path: '/v1/bank-accounts/{id}/balances/latest', summary: 'Get latest balances (OPBD, CLBD, CLAV) for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
+
'list-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Get all ledger mappings for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'create-ledger-mappings': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Create a ledger mapping for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'get-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Get a ledger mapping by ID', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
+
'update-ledger-mappings': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Update a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
+
'delete-ledger-mappings': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Delete a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
+
'list-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Get all notes for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
+
'create-notes': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Create a note for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
+
'get-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Get a specific note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
+
'update-notes': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Update a note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
+
'delete-notes': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Delete a note from a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
+
'list-daily-balances': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/daily-balances', summary: 'Get a bank account\'s daily closing balances for a date range', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
29
|
};
|
|
29
30
|
export default class BankAccounts extends Command {
|
|
30
31
|
static description = 'Manage bank accounts';
|
|
@@ -278,10 +279,11 @@ export default class BankAccounts extends Command {
|
|
|
278
279
|
process.stderr.write('\n');
|
|
279
280
|
}
|
|
280
281
|
try {
|
|
281
|
-
// Binary response:
|
|
282
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
282
283
|
if (endpoint.isBinaryResponse) {
|
|
283
|
-
|
|
284
|
-
|
|
284
|
+
const toStdout = !flags.file;
|
|
285
|
+
if (toStdout && process.stdout.isTTY) {
|
|
286
|
+
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.`);
|
|
285
287
|
}
|
|
286
288
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
287
289
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -289,24 +291,55 @@ export default class BankAccounts extends Command {
|
|
|
289
291
|
contextName: flags.context,
|
|
290
292
|
binary: true,
|
|
291
293
|
});
|
|
292
|
-
const fsModule = await import('node:fs');
|
|
293
294
|
const binData = binResponse.data;
|
|
294
295
|
const buffer = Buffer.isBuffer(binData)
|
|
295
296
|
? binData
|
|
296
297
|
: Buffer.from(binData);
|
|
298
|
+
if (toStdout) {
|
|
299
|
+
// Nothing else may reach stdout here — it is the file.
|
|
300
|
+
process.stdout.write(buffer);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const fsModule = await import('node:fs');
|
|
297
304
|
fsModule.writeFileSync(flags.file, buffer);
|
|
298
305
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
299
306
|
return;
|
|
300
307
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
308
|
+
let response;
|
|
309
|
+
if (endpoint.hasBinaryVariant) {
|
|
310
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
311
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
312
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
313
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
314
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
315
|
+
data,
|
|
316
|
+
contextName: flags.context,
|
|
317
|
+
binary: true,
|
|
318
|
+
});
|
|
319
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
320
|
+
const rawData = raw.data;
|
|
321
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
322
|
+
if (!isTextualMediaType(rawType)) {
|
|
323
|
+
if (process.stdout.isTTY) {
|
|
324
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
325
|
+
}
|
|
326
|
+
// Nothing else may reach stdout here — it is the file.
|
|
327
|
+
process.stdout.write(buffer);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
334
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
335
|
+
data,
|
|
336
|
+
contextName: flags.context,
|
|
337
|
+
acceptAny: true,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
307
340
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
308
341
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
309
|
-
if (contentType
|
|
342
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
310
343
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
311
344
|
this.log(String(response.data));
|
|
312
345
|
return;
|
|
@@ -15,6 +15,7 @@ export default class BankIntegrations extends Command {
|
|
|
15
15
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
16
|
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
17
|
'import-run-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
19
|
'statement-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
20
|
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
21
|
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,31 +1,33 @@
|
|
|
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 = [...["initiate", "providers-supported", "providers-consent-status", "delete-providers-consent", "list", "create", "get", "update", "delete", "log", "list-account-statement-runs", "trigger-account-statement-runs", "get-account-statement-runs", "account-statement-runs-files", "trigger-account-statement-runs-reimport", "list-statements", "statements", "download-statements-xml"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["initiate", "providers-supported", "providers-consent-status", "delete-providers-consent", "list", "create", "get", "update", "delete", "log", "list-account-statement-runs", "trigger-account-statement-runs", "get-account-statement-runs", "account-statement-runs-files", "trigger-account-statement-runs-reimport", "account-statement-runs-files-download", "list-all", "list-statements", "statements", "download-statements-xml"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'initiate': { method: 'POST', path: '/v1/bank-integrations/initiate', summary: 'Initiate the OAuth/auth flow for a bank integration', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'providers-supported': { method: 'GET', path: '/v1/bank-integrations/providers/supported', summary: 'List supported bLink providers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'providers-consent-status': { method: 'GET', path: '/v1/bank-integrations/providers/consent-status', summary: 'Get bLink consent status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'delete-providers-consent': { method: 'DELETE', path: '/v1/bank-integrations/providers/{providerId}/consent', summary: 'Revoke bLink consent for a provider', pathParams: ['providerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
-
'list': { method: 'GET', path: '/v1/bank-integrations', summary: 'List all BankIntegrations for the current tenant with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'create': { method: 'POST', path: '/v1/bank-integrations', summary: 'Create a BankIntegration record', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['methods'] },
|
|
17
|
-
'get': { method: 'GET', path: '/v1/bank-integrations/{id}', summary: 'Get a BankIntegration by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
18
|
-
'update': { method: 'PATCH', path: '/v1/bank-integrations/{id}', summary: 'Update the display name of a BankIntegration', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
-
'delete': { method: 'DELETE', path: '/v1/bank-integrations/{id}', summary: 'Delete a BankIntegration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
|
-
'log': { method: 'GET', path: '/v1/bank-integrations/{id}/log', summary: 'Get activity log for a bank integration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
21
|
-
'list-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'List bank statement import runs', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
-
'trigger-account-statement-runs': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'Trigger a bank statement import', pathParams: ['bankIntegrationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
|
-
'get-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}', summary: 'Get import run details', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
24
|
-
'account-statement-runs-files': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files', summary: 'Get files for an import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
|
-
'trigger-account-statement-runs-reimport': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/reimport', summary: 'Trigger reimport of an existing account statement import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['fileIds'] },
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
11
|
+
'initiate': { method: 'POST', path: '/v1/bank-integrations/initiate', summary: 'Initiate the OAuth/auth flow for a bank integration', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'providers-supported': { method: 'GET', path: '/v1/bank-integrations/providers/supported', summary: 'List supported bLink providers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'providers-consent-status': { method: 'GET', path: '/v1/bank-integrations/providers/consent-status', summary: 'Get bLink consent status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'delete-providers-consent': { method: 'DELETE', path: '/v1/bank-integrations/providers/{providerId}/consent', summary: 'Revoke bLink consent for a provider', pathParams: ['providerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/bank-integrations', summary: 'List all BankIntegrations for the current tenant with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/bank-integrations', summary: 'Create a BankIntegration record', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['methods'] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/bank-integrations/{id}', summary: 'Get a BankIntegration by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/bank-integrations/{id}', summary: 'Update the display name of a BankIntegration', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/bank-integrations/{id}', summary: 'Delete a BankIntegration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'log': { method: 'GET', path: '/v1/bank-integrations/{id}/log', summary: 'Get activity log for a bank integration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
+
'list-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'List bank statement import runs', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
+
'trigger-account-statement-runs': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'Trigger a bank statement import', pathParams: ['bankIntegrationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
+
'get-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}', summary: 'Get import run details', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
+
'account-statement-runs-files': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files', summary: 'Get files for an import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
+
'trigger-account-statement-runs-reimport': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/reimport', summary: 'Trigger reimport of an existing account statement import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fileIds'] },
|
|
26
|
+
'account-statement-runs-files-download': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files/{fileId}/download', summary: 'Download the stored CAMT XML for a statement file', pathParams: ['bankIntegrationId', 'importRunId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
+
'list-all': { method: 'GET', path: '/v1/account-statement-files', summary: 'List statement import files across this tenant’s bank integrations', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
+
'list-statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements', summary: 'List CAMT.053 statements for a bank integration', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
+
'statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}', summary: 'Get CAMT.053 statement detail', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
+
'download-statements-xml': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}/xml', summary: 'Get raw CAMT.053 XML for a statement', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
31
|
};
|
|
30
32
|
export default class BankIntegrations extends Command {
|
|
31
33
|
static description = 'Manage bank integrations';
|
|
@@ -50,6 +52,7 @@ export default class BankIntegrations extends Command {
|
|
|
50
52
|
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
51
53
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
52
54
|
'import-run-id': Flags.string({ description: 'Path param: importRunId' }),
|
|
55
|
+
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
53
56
|
'statement-id': Flags.string({ description: 'Path param: statementId' }),
|
|
54
57
|
page: Flags.string({ description: 'Page number' }),
|
|
55
58
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -279,10 +282,11 @@ export default class BankIntegrations extends Command {
|
|
|
279
282
|
process.stderr.write('\n');
|
|
280
283
|
}
|
|
281
284
|
try {
|
|
282
|
-
// Binary response:
|
|
285
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
283
286
|
if (endpoint.isBinaryResponse) {
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
const toStdout = !flags.file;
|
|
288
|
+
if (toStdout && process.stdout.isTTY) {
|
|
289
|
+
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.`);
|
|
286
290
|
}
|
|
287
291
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
288
292
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -290,24 +294,55 @@ export default class BankIntegrations extends Command {
|
|
|
290
294
|
contextName: flags.context,
|
|
291
295
|
binary: true,
|
|
292
296
|
});
|
|
293
|
-
const fsModule = await import('node:fs');
|
|
294
297
|
const binData = binResponse.data;
|
|
295
298
|
const buffer = Buffer.isBuffer(binData)
|
|
296
299
|
? binData
|
|
297
300
|
: Buffer.from(binData);
|
|
301
|
+
if (toStdout) {
|
|
302
|
+
// Nothing else may reach stdout here — it is the file.
|
|
303
|
+
process.stdout.write(buffer);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const fsModule = await import('node:fs');
|
|
298
307
|
fsModule.writeFileSync(flags.file, buffer);
|
|
299
308
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
300
309
|
return;
|
|
301
310
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
311
|
+
let response;
|
|
312
|
+
if (endpoint.hasBinaryVariant) {
|
|
313
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
314
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
315
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
316
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
317
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
318
|
+
data,
|
|
319
|
+
contextName: flags.context,
|
|
320
|
+
binary: true,
|
|
321
|
+
});
|
|
322
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
323
|
+
const rawData = raw.data;
|
|
324
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
325
|
+
if (!isTextualMediaType(rawType)) {
|
|
326
|
+
if (process.stdout.isTTY) {
|
|
327
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
328
|
+
}
|
|
329
|
+
// Nothing else may reach stdout here — it is the file.
|
|
330
|
+
process.stdout.write(buffer);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
337
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
338
|
+
data,
|
|
339
|
+
contextName: flags.context,
|
|
340
|
+
acceptAny: true,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
308
343
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
309
344
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
310
|
-
if (contentType
|
|
345
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
311
346
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
312
347
|
this.log(String(response.data));
|
|
313
348
|
return;
|