@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.
Files changed (93) hide show
  1. package/dist/commands/access-groups.js +49 -17
  2. package/dist/commands/account-transaction-allocations.js +46 -14
  3. package/dist/commands/account-transactions.js +75 -35
  4. package/dist/commands/accounts.js +54 -22
  5. package/dist/commands/agent-platform.js +53 -21
  6. package/dist/commands/{nango-integrations.d.ts → agent-runs.d.ts} +1 -1
  7. package/dist/commands/agent-runs.js +1155 -0
  8. package/dist/commands/analytics.js +47 -15
  9. package/dist/commands/api-keys.js +49 -16
  10. package/dist/commands/{text-templates.d.ts → async-jobs.d.ts} +1 -1
  11. package/dist/commands/async-jobs.js +1158 -0
  12. package/dist/commands/audit-log.js +46 -14
  13. package/dist/commands/bank-accounts.js +63 -30
  14. package/dist/commands/bank-integrations.d.ts +1 -0
  15. package/dist/commands/bank-integrations.js +66 -31
  16. package/dist/commands/business-partners.js +77 -44
  17. package/dist/commands/chat.js +52 -19
  18. package/dist/commands/credit-card-accounts.d.ts +1 -0
  19. package/dist/commands/credit-card-accounts.js +67 -29
  20. package/dist/commands/delivery-notes.js +78 -44
  21. package/dist/commands/dunning-configs.js +49 -17
  22. package/dist/commands/dunning-reminders.js +52 -20
  23. package/dist/commands/dunning-runs.js +45 -13
  24. package/dist/commands/email-transactions.js +47 -15
  25. package/dist/commands/employees.js +76 -44
  26. package/dist/commands/entity-configurations.js +47 -15
  27. package/dist/commands/event-processor-mappings.js +49 -17
  28. package/dist/commands/files.js +56 -24
  29. package/dist/commands/health.js +49 -17
  30. package/dist/commands/imports.d.ts +39 -0
  31. package/dist/commands/{nango-integrations.js → imports.js} +61 -25
  32. package/dist/commands/inbox.js +52 -19
  33. package/dist/commands/integration-identities.d.ts +40 -0
  34. package/dist/commands/integration-identities.js +1151 -0
  35. package/dist/commands/integrations.js +47 -15
  36. package/dist/commands/item-categories.js +49 -17
  37. package/dist/commands/items.js +49 -17
  38. package/dist/commands/journal-lines.js +45 -13
  39. package/dist/commands/journals.js +68 -36
  40. package/dist/commands/ledgers.d.ts +3 -1
  41. package/dist/commands/ledgers.js +95 -34
  42. package/dist/commands/my-account.d.ts +39 -0
  43. package/dist/commands/my-account.js +1160 -0
  44. package/dist/commands/office-locations.js +49 -17
  45. package/dist/commands/payment-methods.js +54 -22
  46. package/dist/commands/payment-runs.js +61 -29
  47. package/dist/commands/payment-terms.js +50 -18
  48. package/dist/commands/payments.js +51 -19
  49. package/dist/commands/payroll-runs.d.ts +43 -0
  50. package/dist/commands/payroll-runs.js +1188 -0
  51. package/dist/commands/permissions.d.ts +39 -0
  52. package/dist/commands/{text-templates.js → permissions.js} +54 -30
  53. package/dist/commands/price-lists.js +54 -22
  54. package/dist/commands/processor-mappings.js +48 -16
  55. package/dist/commands/processors.js +55 -24
  56. package/dist/commands/purchase-order-types.js +49 -17
  57. package/dist/commands/purchase-orders.js +69 -36
  58. package/dist/commands/reports.js +49 -17
  59. package/dist/commands/roles.d.ts +39 -0
  60. package/dist/commands/roles.js +1152 -0
  61. package/dist/commands/salary-types.js +49 -17
  62. package/dist/commands/sales-invoices.js +84 -51
  63. package/dist/commands/sales-orders.js +78 -44
  64. package/dist/commands/saved-views.js +47 -15
  65. package/dist/commands/scheduled-processor-mappings.js +49 -17
  66. package/dist/commands/schedules.js +53 -21
  67. package/dist/commands/tag-configurations.js +50 -18
  68. package/dist/commands/tags.js +49 -17
  69. package/dist/commands/tax-codes.js +52 -20
  70. package/dist/commands/tax-matrix.js +49 -17
  71. package/dist/commands/templates.d.ts +39 -0
  72. package/dist/commands/templates.js +1157 -0
  73. package/dist/commands/tenants.js +52 -20
  74. package/dist/commands/tools.js +46 -14
  75. package/dist/commands/users.d.ts +42 -0
  76. package/dist/commands/users.js +1174 -0
  77. package/dist/commands/vat-declarations.d.ts +2 -0
  78. package/dist/commands/vat-declarations.js +72 -36
  79. package/dist/commands/vendor-invoices.js +81 -49
  80. package/dist/commands/webhooks.js +51 -19
  81. package/dist/commands/workflows.js +47 -15
  82. package/dist/lib/api-client.d.ts +6 -0
  83. package/dist/lib/api-client.js +13 -0
  84. package/dist/lib/auth/index.js +15 -4
  85. package/dist/lib/auth/jwks.d.ts +19 -0
  86. package/dist/lib/auth/jwks.js +112 -0
  87. package/dist/lib/auth/keycloak-provider.d.ts +23 -7
  88. package/dist/lib/auth/keycloak-provider.js +53 -24
  89. package/dist/lib/auth/tokens.d.ts +8 -3
  90. package/dist/lib/auth/tokens.js +8 -7
  91. package/dist/lib/auth/types.d.ts +5 -1
  92. package/oclif.manifest.json +2152 -715
  93. 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,9 +8,9 @@ const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
9
  const SUBCOMMANDS = [...["query", "views", "views-name"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'query': { method: 'POST', path: '/v1/analytics/query', summary: 'Run a structured aggregate query over a reporting view', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['measures', 'dimensions', 'filters', 'order'] },
12
- 'views': { method: 'GET', path: '/v1/analytics/views', summary: 'List the analytics views for discovery', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
13
- 'views-name': { method: 'GET', path: '/v1/analytics/views/{name}', summary: 'Describe one analytics view with full metadata', pathParams: ['name'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
11
+ 'query': { method: 'POST', path: '/v1/analytics/query', summary: 'Run a structured aggregate query over a reporting view', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['measures', 'dimensions', 'filters', 'order'] },
12
+ 'views': { method: 'GET', path: '/v1/analytics/views', summary: 'List the analytics views for discovery', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
13
+ 'views-name': { method: 'GET', path: '/v1/analytics/views/{name}', summary: 'Describe one analytics view with full metadata', pathParams: ['name'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
14
  };
15
15
  export default class Analytics extends Command {
16
16
  static description = 'Manage analytics';
@@ -255,10 +255,11 @@ export default class Analytics extends Command {
255
255
  process.stderr.write('\n');
256
256
  }
257
257
  try {
258
- // Binary response: download to file
258
+ // Binary response: to -f / --file, or to stdout when it is redirected.
259
259
  if (endpoint.isBinaryResponse) {
260
- if (!flags.file) {
261
- this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
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 Analytics 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
- const response = await apiRequest(endpoint.method, apiPath, {
279
- params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
280
- data,
281
- contextName: flags.context,
282
- acceptAny: true,
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.includes('xml') || contentType.includes('text/')) {
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,16 +1,17 @@
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;
6
6
  const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
- const SUBCOMMANDS = [...["list", "create", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["list", "create", "api-keys-rotate", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'list': { method: 'GET', path: '/v1/auth/api-keys', summary: 'List the tenant\'s API keys', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/auth/api-keys', summary: 'Create an API key for the tenant', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['permissions'] },
13
- 'delete': { method: 'DELETE', path: '/v1/auth/api-keys/{apiKeyId}', summary: 'Revoke an API key', pathParams: ['apiKeyId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
11
+ 'list': { method: 'GET', path: '/v1/auth/api-keys', summary: 'List the tenant\'s API keys', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
12
+ 'create': { method: 'POST', path: '/v1/auth/api-keys', summary: 'Create an API key for the tenant', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['permissions'] },
13
+ 'api-keys-rotate': { method: 'POST', path: '/v1/auth/api-keys/{apiKeyId}/rotate', summary: 'Rotate an API key', pathParams: ['apiKeyId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
+ 'delete': { method: 'DELETE', path: '/v1/auth/api-keys/{apiKeyId}', summary: 'Revoke an API key', pathParams: ['apiKeyId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
15
  };
15
16
  export default class ApiKeys extends Command {
16
17
  static description = 'Manage api keys';
@@ -259,10 +260,11 @@ export default class ApiKeys extends Command {
259
260
  process.stderr.write('\n');
260
261
  }
261
262
  try {
262
- // Binary response: download to file
263
+ // Binary response: to -f / --file, or to stdout when it is redirected.
263
264
  if (endpoint.isBinaryResponse) {
264
- if (!flags.file) {
265
- this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
265
+ const toStdout = !flags.file;
266
+ if (toStdout && process.stdout.isTTY) {
267
+ 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
268
  }
267
269
  const binResponse = await apiRequest(endpoint.method, apiPath, {
268
270
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
@@ -270,24 +272,55 @@ export default class ApiKeys extends Command {
270
272
  contextName: flags.context,
271
273
  binary: true,
272
274
  });
273
- const fsModule = await import('node:fs');
274
275
  const binData = binResponse.data;
275
276
  const buffer = Buffer.isBuffer(binData)
276
277
  ? binData
277
278
  : Buffer.from(binData);
279
+ if (toStdout) {
280
+ // Nothing else may reach stdout here — it is the file.
281
+ process.stdout.write(buffer);
282
+ return;
283
+ }
284
+ const fsModule = await import('node:fs');
278
285
  fsModule.writeFileSync(flags.file, buffer);
279
286
  this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
280
287
  return;
281
288
  }
282
- const response = await apiRequest(endpoint.method, apiPath, {
283
- params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
284
- data,
285
- contextName: flags.context,
286
- acceptAny: true,
287
- });
289
+ let response;
290
+ if (endpoint.hasBinaryVariant) {
291
+ // This route answers JSON or a file depending on the request body, so the
292
+ // bytes are read first and the response's own content-type decides. Asking
293
+ // for text here would corrupt an xlsx/pdf before anything could inspect it.
294
+ const raw = await apiRequest(endpoint.method, apiPath, {
295
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
296
+ data,
297
+ contextName: flags.context,
298
+ binary: true,
299
+ });
300
+ const rawType = String(raw.headers['content-type'] || '').toLowerCase();
301
+ const rawData = raw.data;
302
+ const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
303
+ if (!isTextualMediaType(rawType)) {
304
+ if (process.stdout.isTTY) {
305
+ this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
306
+ }
307
+ // Nothing else may reach stdout here — it is the file.
308
+ process.stdout.write(buffer);
309
+ return;
310
+ }
311
+ response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
312
+ }
313
+ else {
314
+ response = await apiRequest(endpoint.method, apiPath, {
315
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
316
+ data,
317
+ contextName: flags.context,
318
+ acceptAny: true,
319
+ });
320
+ }
288
321
  // Check content-type for non-JSON responses (XML, text, etc.)
289
322
  const contentType = (response.headers['content-type'] || '').toLowerCase();
290
- if (contentType.includes('xml') || contentType.includes('text/')) {
323
+ if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
291
324
  // Output raw content for XML/text responses (CSV, plain, HTML, etc.)
292
325
  this.log(String(response.data));
293
326
  return;
@@ -1,5 +1,5 @@
1
1
  import { Command } from '@oclif/core';
2
- export default class TextTemplates extends Command {
2
+ export default class AsyncJobs extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {