@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
|
@@ -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,9 +8,9 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["event-webhook", "list", "get"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'event-webhook': { method: 'POST', path: '/v1/email-transactions/event-webhook', summary: 'SendGrid delivery-event webhook (ECDSA signature-verified, no bearer token)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'list': { method: 'GET', path: '/v1/email-transactions', summary: 'List email transactions for the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/email-transactions/{id}', summary: 'Get a single email transaction (404 if not in this tenant)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'event-webhook': { method: 'POST', path: '/v1/email-transactions/event-webhook', summary: 'SendGrid delivery-event webhook (ECDSA signature-verified, no bearer token)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'list': { method: 'GET', path: '/v1/email-transactions', summary: 'List email transactions for the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'get': { method: 'GET', path: '/v1/email-transactions/{id}', summary: 'Get a single email transaction (404 if not in this tenant)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
14
|
};
|
|
15
15
|
export default class EmailTransactions extends Command {
|
|
16
16
|
static description = 'Manage email transactions';
|
|
@@ -259,10 +259,11 @@ export default class EmailTransactions extends Command {
|
|
|
259
259
|
process.stderr.write('\n');
|
|
260
260
|
}
|
|
261
261
|
try {
|
|
262
|
-
// Binary response:
|
|
262
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
263
263
|
if (endpoint.isBinaryResponse) {
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
const toStdout = !flags.file;
|
|
265
|
+
if (toStdout && process.stdout.isTTY) {
|
|
266
|
+
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.`);
|
|
266
267
|
}
|
|
267
268
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
268
269
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -270,24 +271,55 @@ export default class EmailTransactions extends Command {
|
|
|
270
271
|
contextName: flags.context,
|
|
271
272
|
binary: true,
|
|
272
273
|
});
|
|
273
|
-
const fsModule = await import('node:fs');
|
|
274
274
|
const binData = binResponse.data;
|
|
275
275
|
const buffer = Buffer.isBuffer(binData)
|
|
276
276
|
? binData
|
|
277
277
|
: Buffer.from(binData);
|
|
278
|
+
if (toStdout) {
|
|
279
|
+
// Nothing else may reach stdout here — it is the file.
|
|
280
|
+
process.stdout.write(buffer);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const fsModule = await import('node:fs');
|
|
278
284
|
fsModule.writeFileSync(flags.file, buffer);
|
|
279
285
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
280
286
|
return;
|
|
281
287
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
let response;
|
|
289
|
+
if (endpoint.hasBinaryVariant) {
|
|
290
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
291
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
292
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
293
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
294
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
295
|
+
data,
|
|
296
|
+
contextName: flags.context,
|
|
297
|
+
binary: true,
|
|
298
|
+
});
|
|
299
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
300
|
+
const rawData = raw.data;
|
|
301
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
302
|
+
if (!isTextualMediaType(rawType)) {
|
|
303
|
+
if (process.stdout.isTTY) {
|
|
304
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
305
|
+
}
|
|
306
|
+
// Nothing else may reach stdout here — it is the file.
|
|
307
|
+
process.stdout.write(buffer);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
314
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
315
|
+
data,
|
|
316
|
+
contextName: flags.context,
|
|
317
|
+
acceptAny: true,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
288
320
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
289
321
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
290
|
-
if (contentType
|
|
322
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
291
323
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
292
324
|
this.log(String(response.data));
|
|
293
325
|
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,38 +8,38 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = ["salaries", "payments", "notes", "files", "salary-payment-files"];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-salaries", "create-salaries", "get-salaries-salaryId", "update-salaries", "delete-salaries", "get-payments", "create-payments", "get-payments-paymentId", "update-payments", "delete-payments", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-salary-payment-files", "create-salary-payment-files", "get-salary-payment-files", "update-salary-payment-files", "delete-salary-payment-files", "download-salary-payment-files"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
-
'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
18
|
-
'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
-
'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
|
-
'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
21
|
-
'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
-
'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
23
|
-
'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
24
|
-
'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
25
|
-
'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
26
|
-
'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
|
-
'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
28
|
-
'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
29
|
-
'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
30
|
-
'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
31
|
-
'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
32
|
-
'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
|
|
33
|
-
'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
34
|
-
'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
35
|
-
'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
36
|
-
'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
37
|
-
'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
38
|
-
'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
|
|
39
|
-
'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
40
|
-
'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
41
|
-
'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
42
|
-
'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
13
|
+
'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
+
'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
+
'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
+
'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
23
|
+
'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
+
'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
25
|
+
'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
+
'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
+
'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
+
'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
+
'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
+
'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
+
'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
+
'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
+
'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
+
'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
+
'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
+
'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
+
'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
+
'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
+
'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
+
'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
+
'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
+
'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
43
43
|
};
|
|
44
44
|
export default class Employees extends Command {
|
|
45
45
|
static description = 'Manage employees';
|
|
@@ -295,10 +295,11 @@ export default class Employees extends Command {
|
|
|
295
295
|
process.stderr.write('\n');
|
|
296
296
|
}
|
|
297
297
|
try {
|
|
298
|
-
// Binary response:
|
|
298
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
299
299
|
if (endpoint.isBinaryResponse) {
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
const toStdout = !flags.file;
|
|
301
|
+
if (toStdout && process.stdout.isTTY) {
|
|
302
|
+
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.`);
|
|
302
303
|
}
|
|
303
304
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
304
305
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -306,24 +307,55 @@ export default class Employees extends Command {
|
|
|
306
307
|
contextName: flags.context,
|
|
307
308
|
binary: true,
|
|
308
309
|
});
|
|
309
|
-
const fsModule = await import('node:fs');
|
|
310
310
|
const binData = binResponse.data;
|
|
311
311
|
const buffer = Buffer.isBuffer(binData)
|
|
312
312
|
? binData
|
|
313
313
|
: Buffer.from(binData);
|
|
314
|
+
if (toStdout) {
|
|
315
|
+
// Nothing else may reach stdout here — it is the file.
|
|
316
|
+
process.stdout.write(buffer);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const fsModule = await import('node:fs');
|
|
314
320
|
fsModule.writeFileSync(flags.file, buffer);
|
|
315
321
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
316
322
|
return;
|
|
317
323
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
+
let response;
|
|
325
|
+
if (endpoint.hasBinaryVariant) {
|
|
326
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
327
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
328
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
329
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
330
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
331
|
+
data,
|
|
332
|
+
contextName: flags.context,
|
|
333
|
+
binary: true,
|
|
334
|
+
});
|
|
335
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
336
|
+
const rawData = raw.data;
|
|
337
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
338
|
+
if (!isTextualMediaType(rawType)) {
|
|
339
|
+
if (process.stdout.isTTY) {
|
|
340
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
341
|
+
}
|
|
342
|
+
// Nothing else may reach stdout here — it is the file.
|
|
343
|
+
process.stdout.write(buffer);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
350
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
351
|
+
data,
|
|
352
|
+
contextName: flags.context,
|
|
353
|
+
acceptAny: true,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
324
356
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
325
357
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
326
|
-
if (contentType
|
|
358
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
327
359
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
328
360
|
this.log(String(response.data));
|
|
329
361
|
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 = false;
|
|
@@ -8,9 +8,9 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["list-entities", "get-entities", "update-entities"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
14
|
};
|
|
15
15
|
export default class EntityConfigurations extends Command {
|
|
16
16
|
static description = 'Manage entity configurations';
|
|
@@ -255,10 +255,11 @@ export default class EntityConfigurations extends Command {
|
|
|
255
255
|
process.stderr.write('\n');
|
|
256
256
|
}
|
|
257
257
|
try {
|
|
258
|
-
// Binary response:
|
|
258
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
259
259
|
if (endpoint.isBinaryResponse) {
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
const toStdout = !flags.file;
|
|
261
|
+
if (toStdout && process.stdout.isTTY) {
|
|
262
|
+
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.`);
|
|
262
263
|
}
|
|
263
264
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
264
265
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -266,24 +267,55 @@ export default class EntityConfigurations extends Command {
|
|
|
266
267
|
contextName: flags.context,
|
|
267
268
|
binary: true,
|
|
268
269
|
});
|
|
269
|
-
const fsModule = await import('node:fs');
|
|
270
270
|
const binData = binResponse.data;
|
|
271
271
|
const buffer = Buffer.isBuffer(binData)
|
|
272
272
|
? binData
|
|
273
273
|
: Buffer.from(binData);
|
|
274
|
+
if (toStdout) {
|
|
275
|
+
// Nothing else may reach stdout here — it is the file.
|
|
276
|
+
process.stdout.write(buffer);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const fsModule = await import('node:fs');
|
|
274
280
|
fsModule.writeFileSync(flags.file, buffer);
|
|
275
281
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
276
282
|
return;
|
|
277
283
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
+
let response;
|
|
285
|
+
if (endpoint.hasBinaryVariant) {
|
|
286
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
287
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
288
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
289
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
290
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
291
|
+
data,
|
|
292
|
+
contextName: flags.context,
|
|
293
|
+
binary: true,
|
|
294
|
+
});
|
|
295
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
296
|
+
const rawData = raw.data;
|
|
297
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
298
|
+
if (!isTextualMediaType(rawType)) {
|
|
299
|
+
if (process.stdout.isTTY) {
|
|
300
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
301
|
+
}
|
|
302
|
+
// Nothing else may reach stdout here — it is the file.
|
|
303
|
+
process.stdout.write(buffer);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
310
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
311
|
+
data,
|
|
312
|
+
contextName: flags.context,
|
|
313
|
+
acceptAny: true,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
284
316
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
285
317
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
286
|
-
if (contentType
|
|
318
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
287
319
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
288
320
|
this.log(String(response.data));
|
|
289
321
|
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,11 +8,11 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["events", "list", "create", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'events': { method: 'GET', path: '/v1/event-processor-mappings/events', summary: 'List all valid event types', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'list': { method: 'GET', path: '/v1/event-processor-mappings', summary: 'List all event type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'create': { method: 'POST', path: '/v1/event-processor-mappings', summary: 'Create event type processor mappings', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['eventTypes', 'includes'] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/event-processor-mappings/{id}', summary: 'Update an event type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['includes'] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/event-processor-mappings/{id}', summary: 'Delete an event type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'events': { method: 'GET', path: '/v1/event-processor-mappings/events', summary: 'List all valid event types', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'list': { method: 'GET', path: '/v1/event-processor-mappings', summary: 'List all event type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'create': { method: 'POST', path: '/v1/event-processor-mappings', summary: 'Create event type processor mappings', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['eventTypes', 'includes'] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/event-processor-mappings/{id}', summary: 'Update an event type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['includes'] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/event-processor-mappings/{id}', summary: 'Delete an event type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
16
|
};
|
|
17
17
|
export default class EventProcessorMappings extends Command {
|
|
18
18
|
static description = 'Manage event processor mappings';
|
|
@@ -263,10 +263,11 @@ export default class EventProcessorMappings extends Command {
|
|
|
263
263
|
process.stderr.write('\n');
|
|
264
264
|
}
|
|
265
265
|
try {
|
|
266
|
-
// Binary response:
|
|
266
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
267
267
|
if (endpoint.isBinaryResponse) {
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
const toStdout = !flags.file;
|
|
269
|
+
if (toStdout && process.stdout.isTTY) {
|
|
270
|
+
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.`);
|
|
270
271
|
}
|
|
271
272
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
272
273
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -274,24 +275,55 @@ export default class EventProcessorMappings extends Command {
|
|
|
274
275
|
contextName: flags.context,
|
|
275
276
|
binary: true,
|
|
276
277
|
});
|
|
277
|
-
const fsModule = await import('node:fs');
|
|
278
278
|
const binData = binResponse.data;
|
|
279
279
|
const buffer = Buffer.isBuffer(binData)
|
|
280
280
|
? binData
|
|
281
281
|
: Buffer.from(binData);
|
|
282
|
+
if (toStdout) {
|
|
283
|
+
// Nothing else may reach stdout here — it is the file.
|
|
284
|
+
process.stdout.write(buffer);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const fsModule = await import('node:fs');
|
|
282
288
|
fsModule.writeFileSync(flags.file, buffer);
|
|
283
289
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
284
290
|
return;
|
|
285
291
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
+
let response;
|
|
293
|
+
if (endpoint.hasBinaryVariant) {
|
|
294
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
295
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
296
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
297
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
298
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
299
|
+
data,
|
|
300
|
+
contextName: flags.context,
|
|
301
|
+
binary: true,
|
|
302
|
+
});
|
|
303
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
304
|
+
const rawData = raw.data;
|
|
305
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
306
|
+
if (!isTextualMediaType(rawType)) {
|
|
307
|
+
if (process.stdout.isTTY) {
|
|
308
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
309
|
+
}
|
|
310
|
+
// Nothing else may reach stdout here — it is the file.
|
|
311
|
+
process.stdout.write(buffer);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
318
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
319
|
+
data,
|
|
320
|
+
contextName: flags.context,
|
|
321
|
+
acceptAny: true,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
292
324
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
293
325
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
294
|
-
if (contentType
|
|
326
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
295
327
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
296
328
|
this.log(String(response.data));
|
|
297
329
|
return;
|