@aderis-erp/cli 1.0.14 → 1.0.17

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 (167) hide show
  1. package/README.md +30 -8
  2. package/dist/commands/access-groups.d.ts +0 -1
  3. package/dist/commands/access-groups.js +22 -78
  4. package/dist/commands/account-transaction-allocations.d.ts +0 -1
  5. package/dist/commands/account-transaction-allocations.js +22 -78
  6. package/dist/commands/account-transactions.d.ts +0 -1
  7. package/dist/commands/account-transactions.js +28 -82
  8. package/dist/commands/accounts.d.ts +0 -1
  9. package/dist/commands/accounts.js +24 -80
  10. package/dist/commands/agent-platform.d.ts +0 -1
  11. package/dist/commands/agent-platform.js +24 -79
  12. package/dist/commands/analytics.d.ts +39 -0
  13. package/dist/commands/analytics.js +1113 -0
  14. package/dist/commands/{documents.d.ts → api-keys.d.ts} +1 -2
  15. package/dist/commands/api-keys.js +1117 -0
  16. package/dist/commands/audit-log.d.ts +0 -1
  17. package/dist/commands/audit-log.js +22 -78
  18. package/dist/commands/auth/login.d.ts +9 -0
  19. package/dist/commands/auth/login.js +83 -21
  20. package/dist/commands/auth/logout.d.ts +6 -0
  21. package/dist/commands/auth/logout.js +23 -6
  22. package/dist/commands/auth/status.js +46 -23
  23. package/dist/commands/auth/tenant.js +15 -9
  24. package/dist/commands/auth.d.ts +0 -1
  25. package/dist/commands/auth.js +37 -51
  26. package/dist/commands/bank-accounts.d.ts +0 -1
  27. package/dist/commands/bank-accounts.js +22 -78
  28. package/dist/commands/bank-integrations.d.ts +0 -1
  29. package/dist/commands/bank-integrations.js +22 -78
  30. package/dist/commands/business-partners.d.ts +1 -1
  31. package/dist/commands/business-partners.js +38 -84
  32. package/dist/commands/chat.d.ts +0 -1
  33. package/dist/commands/chat.js +22 -78
  34. package/dist/commands/config/add.d.ts +12 -0
  35. package/dist/commands/config/add.js +97 -17
  36. package/dist/commands/config/current.js +12 -4
  37. package/dist/commands/config/list.js +12 -4
  38. package/dist/commands/config/set-api-key.d.ts +10 -0
  39. package/dist/commands/config/set-api-key.js +49 -0
  40. package/dist/commands/config/use.js +3 -4
  41. package/dist/commands/credit-card-accounts.d.ts +0 -1
  42. package/dist/commands/credit-card-accounts.js +22 -78
  43. package/dist/commands/delivery-notes.d.ts +0 -1
  44. package/dist/commands/delivery-notes.js +29 -84
  45. package/dist/commands/dunning-configs.d.ts +0 -1
  46. package/dist/commands/dunning-configs.js +22 -78
  47. package/dist/commands/dunning-reminders.d.ts +0 -1
  48. package/dist/commands/dunning-reminders.js +22 -78
  49. package/dist/commands/dunning-runs.d.ts +0 -1
  50. package/dist/commands/dunning-runs.js +22 -78
  51. package/dist/commands/email-transactions.d.ts +0 -1
  52. package/dist/commands/email-transactions.js +22 -78
  53. package/dist/commands/employees.d.ts +0 -1
  54. package/dist/commands/employees.js +24 -80
  55. package/dist/commands/entity-configurations.d.ts +0 -1
  56. package/dist/commands/entity-configurations.js +22 -78
  57. package/dist/commands/event-processor-mappings.d.ts +0 -1
  58. package/dist/commands/event-processor-mappings.js +22 -78
  59. package/dist/commands/{files-internal.d.ts → files.d.ts} +1 -2
  60. package/dist/commands/{files-internal.js → files.js} +40 -90
  61. package/dist/commands/health.d.ts +0 -1
  62. package/dist/commands/health.js +22 -78
  63. package/dist/commands/inbox.d.ts +0 -1
  64. package/dist/commands/inbox.js +22 -78
  65. package/dist/commands/integrations.d.ts +0 -1
  66. package/dist/commands/integrations.js +22 -78
  67. package/dist/commands/item-categories.d.ts +0 -1
  68. package/dist/commands/item-categories.js +22 -78
  69. package/dist/commands/items.d.ts +0 -1
  70. package/dist/commands/items.js +24 -80
  71. package/dist/commands/journal-lines.d.ts +0 -1
  72. package/dist/commands/journal-lines.js +22 -78
  73. package/dist/commands/journals.d.ts +1 -1
  74. package/dist/commands/journals.js +29 -81
  75. package/dist/commands/ledgers.d.ts +0 -1
  76. package/dist/commands/ledgers.js +26 -79
  77. package/dist/commands/nango-integrations.d.ts +39 -0
  78. package/dist/commands/nango-integrations.js +1115 -0
  79. package/dist/commands/office-locations.d.ts +0 -1
  80. package/dist/commands/office-locations.js +22 -78
  81. package/dist/commands/payment-methods.d.ts +0 -1
  82. package/dist/commands/payment-methods.js +22 -78
  83. package/dist/commands/payment-runs.d.ts +0 -1
  84. package/dist/commands/payment-runs.js +24 -79
  85. package/dist/commands/payment-terms.d.ts +0 -1
  86. package/dist/commands/payment-terms.js +22 -78
  87. package/dist/commands/payments.d.ts +0 -1
  88. package/dist/commands/payments.js +22 -78
  89. package/dist/commands/price-lists.d.ts +0 -1
  90. package/dist/commands/price-lists.js +22 -78
  91. package/dist/commands/processor-mappings.d.ts +0 -1
  92. package/dist/commands/processor-mappings.js +22 -78
  93. package/dist/commands/processors.d.ts +0 -1
  94. package/dist/commands/processors.js +22 -78
  95. package/dist/commands/purchase-order-types.d.ts +0 -1
  96. package/dist/commands/purchase-order-types.js +22 -78
  97. package/dist/commands/purchase-orders.d.ts +1 -1
  98. package/dist/commands/purchase-orders.js +35 -84
  99. package/dist/commands/reports.d.ts +0 -1
  100. package/dist/commands/reports.js +23 -79
  101. package/dist/commands/salary-types.d.ts +0 -1
  102. package/dist/commands/salary-types.js +22 -78
  103. package/dist/commands/sales-invoices.d.ts +0 -1
  104. package/dist/commands/sales-invoices.js +38 -89
  105. package/dist/commands/sales-orders.d.ts +0 -1
  106. package/dist/commands/sales-orders.js +26 -82
  107. package/dist/commands/saved-views.d.ts +0 -1
  108. package/dist/commands/saved-views.js +22 -78
  109. package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
  110. package/dist/commands/scheduled-processor-mappings.js +22 -78
  111. package/dist/commands/schedules.d.ts +0 -1
  112. package/dist/commands/schedules.js +22 -78
  113. package/dist/commands/switch.js +14 -7
  114. package/dist/commands/tag-configurations.d.ts +39 -0
  115. package/dist/commands/{documents.js → tag-configurations.js} +40 -96
  116. package/dist/commands/tags.d.ts +0 -1
  117. package/dist/commands/tags.js +22 -78
  118. package/dist/commands/tax-codes.d.ts +0 -1
  119. package/dist/commands/tax-codes.js +22 -78
  120. package/dist/commands/tax-matrix.d.ts +0 -1
  121. package/dist/commands/tax-matrix.js +22 -78
  122. package/dist/commands/tenants.d.ts +0 -1
  123. package/dist/commands/tenants.js +24 -79
  124. package/dist/commands/text-templates.d.ts +0 -1
  125. package/dist/commands/text-templates.js +22 -78
  126. package/dist/commands/tools.d.ts +0 -1
  127. package/dist/commands/tools.js +22 -78
  128. package/dist/commands/vat-declarations.d.ts +1 -1
  129. package/dist/commands/vat-declarations.js +28 -79
  130. package/dist/commands/vendor-invoices.d.ts +0 -1
  131. package/dist/commands/vendor-invoices.js +31 -86
  132. package/dist/commands/webhooks.d.ts +0 -1
  133. package/dist/commands/webhooks.js +22 -78
  134. package/dist/commands/workflows.d.ts +0 -1
  135. package/dist/commands/workflows.js +22 -78
  136. package/dist/lib/api-client.js +8 -6
  137. package/dist/lib/auth/constants.d.ts +11 -0
  138. package/dist/lib/auth/constants.js +11 -0
  139. package/dist/lib/auth/errors.d.ts +17 -0
  140. package/dist/lib/auth/errors.js +22 -0
  141. package/dist/lib/auth/flow.d.ts +27 -0
  142. package/dist/lib/auth/flow.js +163 -0
  143. package/dist/lib/auth/guards.d.ts +5 -0
  144. package/dist/lib/auth/guards.js +14 -0
  145. package/dist/lib/auth/http.d.ts +16 -0
  146. package/dist/lib/auth/http.js +49 -0
  147. package/dist/lib/auth/index.d.ts +49 -0
  148. package/dist/lib/auth/index.js +217 -0
  149. package/dist/lib/auth/keycloak-provider.d.ts +75 -0
  150. package/dist/lib/auth/keycloak-provider.js +215 -0
  151. package/dist/lib/auth/pages.d.ts +25 -0
  152. package/dist/lib/auth/pages.js +123 -0
  153. package/dist/lib/auth/pkce.d.ts +11 -0
  154. package/dist/lib/auth/pkce.js +17 -0
  155. package/dist/lib/auth/tokens.d.ts +54 -0
  156. package/dist/lib/auth/tokens.js +104 -0
  157. package/dist/lib/auth/types.d.ts +57 -0
  158. package/dist/lib/auth/types.js +1 -0
  159. package/dist/lib/auth/validated-url.d.ts +6 -0
  160. package/dist/lib/auth/validated-url.js +53 -0
  161. package/dist/lib/base-api-command.js +6 -4
  162. package/dist/lib/config.d.ts +44 -4
  163. package/dist/lib/config.js +55 -19
  164. package/oclif.manifest.json +1181 -330
  165. package/package.json +3 -2
  166. package/dist/lib/auth.d.ts +0 -35
  167. package/dist/lib/auth.js +0 -566
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
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;
@@ -24,7 +24,7 @@ export default class EmailTransactions extends Command {
24
24
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
25
25
  };
26
26
  static flags = {
27
- context: Flags.string({ char: 'c', description: 'Context to use' }),
27
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
28
28
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
29
29
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
30
30
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -38,7 +38,7 @@ export default class EmailTransactions extends Command {
38
38
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
39
39
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
40
40
  query: Flags.string({ description: 'Additional query params as JSON' }),
41
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
41
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
42
42
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
43
43
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
44
44
  };
@@ -96,9 +96,9 @@ export default class EmailTransactions extends Command {
96
96
  }
97
97
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
98
98
  if (!context)
99
- this.error('No context configured. Run: aderis auth login --new');
100
- if (!context.tokens)
101
- this.error('Not logged in. Run: aderis auth login');
99
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
100
+ if (!hasCredentials(context))
101
+ this.error(missingCredentialsMessage(context));
102
102
  const queryParams = {};
103
103
  if (flags.page)
104
104
  queryParams.page = flags.page;
@@ -110,6 +110,8 @@ export default class EmailTransactions extends Command {
110
110
  queryParams.search = flags.search;
111
111
  if (flags['sort-by'])
112
112
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
113
+ if (flags.fields)
114
+ queryParams.fields = flags.fields;
113
115
  if (flags.query) {
114
116
  try {
115
117
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -312,11 +314,6 @@ export default class EmailTransactions extends Command {
312
314
  output = obj[arrayKeys[0]];
313
315
  }
314
316
  }
315
- // Filter fields if --fields flag is provided
316
- if (flags.fields) {
317
- const fieldList = flags.fields.split(',').map(f => f.trim());
318
- output = this.filterFields(output, fieldList);
319
- }
320
317
  // Sanitize output if requested
321
318
  if (flags.sanitize) {
322
319
  output = this.sanitizeOutput(output);
@@ -341,9 +338,9 @@ export default class EmailTransactions extends Command {
341
338
  async runImport(flags) {
342
339
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
343
340
  if (!context)
344
- this.error('No context configured. Run: aderis auth login --new');
345
- if (!context.tokens)
346
- this.error('Not logged in. Run: aderis auth login');
341
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
342
+ if (!hasCredentials(context))
343
+ this.error(missingCredentialsMessage(context));
347
344
  // Get data from file, --data, or --set flags
348
345
  let items = [];
349
346
  if (flags.file) {
@@ -553,9 +550,9 @@ export default class EmailTransactions extends Command {
553
550
  async runExport(flags) {
554
551
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
555
552
  if (!context)
556
- this.error('No context configured. Run: aderis auth login --new');
557
- if (!context.tokens)
558
- this.error('Not logged in. Run: aderis auth login');
553
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
554
+ if (!hasCredentials(context))
555
+ this.error(missingCredentialsMessage(context));
559
556
  const listEndpoint = ENDPOINTS['list'];
560
557
  if (!listEndpoint)
561
558
  this.error('Export requires a list endpoint');
@@ -571,6 +568,8 @@ export default class EmailTransactions extends Command {
571
568
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
572
569
  if (flags.include)
573
570
  baseParams.include = flags.include;
571
+ if (flags.fields)
572
+ baseParams.fields = flags.fields;
574
573
  if (flags.query) {
575
574
  try {
576
575
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -625,12 +624,7 @@ export default class EmailTransactions extends Command {
625
624
  }
626
625
  }
627
626
  process.stderr.write(' done\n');
628
- // Filter fields if specified
629
627
  let output = allItems;
630
- if (flags.fields) {
631
- const fieldList = flags.fields.split(',').map(f => f.trim());
632
- output = this.filterFields(allItems, fieldList);
633
- }
634
628
  // Sanitize output if requested
635
629
  if (flags.sanitize) {
636
630
  output = this.sanitizeOutput(output);
@@ -647,9 +641,9 @@ export default class EmailTransactions extends Command {
647
641
  async runCamt053Import(flags) {
648
642
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
649
643
  if (!context)
650
- this.error('No context configured. Run: aderis auth login --new');
651
- if (!context.tokens)
652
- this.error('Not logged in. Run: aderis auth login');
644
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
645
+ if (!hasCredentials(context))
646
+ this.error(missingCredentialsMessage(context));
653
647
  if (!flags.file) {
654
648
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
655
649
  }
@@ -737,9 +731,9 @@ export default class EmailTransactions extends Command {
737
731
  }
738
732
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
739
733
  if (!context)
740
- this.error('No context configured. Run: aderis auth login --new');
741
- if (!context.tokens)
742
- this.error('Not logged in. Run: aderis auth login');
734
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
735
+ if (!hasCredentials(context))
736
+ this.error(missingCredentialsMessage(context));
743
737
  // Get data from file, --data, or --set flags
744
738
  let items = [];
745
739
  if (flags.file) {
@@ -959,56 +953,6 @@ export default class EmailTransactions extends Command {
959
953
  return `\$${op}`;
960
954
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
961
955
  }
962
- filterFields(data, fields) {
963
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
964
- const pick = (obj, keys) => {
965
- // Group keys by their first segment so sibling sub-paths
966
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
967
- // and don't clobber each other on merge.
968
- const directKeys = new Set();
969
- const nestedKeys = new Map();
970
- for (const key of keys) {
971
- if (key.split('.').some(isUnsafeKey))
972
- continue;
973
- if (key.includes('.')) {
974
- const [first, ...rest] = key.split('.');
975
- if (isUnsafeKey(first))
976
- continue;
977
- const list = nestedKeys.get(first);
978
- if (list) {
979
- list.push(rest.join('.'));
980
- }
981
- else {
982
- nestedKeys.set(first, [rest.join('.')]);
983
- }
984
- }
985
- else {
986
- directKeys.add(key);
987
- }
988
- }
989
- const result = {};
990
- for (const key of directKeys) {
991
- if (key in obj)
992
- result[key] = obj[key];
993
- }
994
- for (const [first, restKeys] of nestedKeys) {
995
- const val = obj[first];
996
- if (!val || typeof val !== 'object')
997
- continue;
998
- if (Array.isArray(val)) {
999
- result[first] = val.map(item => pick(item, restKeys));
1000
- }
1001
- else {
1002
- result[first] = pick(val, restKeys);
1003
- }
1004
- }
1005
- return result;
1006
- };
1007
- if (Array.isArray(data)) {
1008
- return data.map(item => pick(item, fields));
1009
- }
1010
- return pick(data, fields);
1011
- }
1012
956
  sanitizeOutput(data) {
1013
957
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1014
958
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -35,7 +35,6 @@ export default class Employees extends Command {
35
35
  private runCamt053Import;
36
36
  private runNestedImport;
37
37
  private parseFilterValue;
38
- private filterFields;
39
38
  private sanitizeOutput;
40
39
  private getColumns;
41
40
  private getValue;
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
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;
@@ -9,9 +9,9 @@ const NESTED_IMPORTS = ["salaries", "payments", "notes", "files", "salary-paymen
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
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'] },
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
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'] },
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
15
  'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
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
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: [] },
@@ -56,7 +56,7 @@ export default class Employees extends Command {
56
56
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
57
57
  };
58
58
  static flags = {
59
- context: Flags.string({ char: 'c', description: 'Context to use' }),
59
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
60
60
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
61
61
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
62
62
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -74,7 +74,7 @@ export default class Employees extends Command {
74
74
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
75
75
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
76
76
  query: Flags.string({ description: 'Additional query params as JSON' }),
77
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
77
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
78
78
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
79
79
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
80
80
  };
@@ -132,9 +132,9 @@ export default class Employees extends Command {
132
132
  }
133
133
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
134
134
  if (!context)
135
- this.error('No context configured. Run: aderis auth login --new');
136
- if (!context.tokens)
137
- this.error('Not logged in. Run: aderis auth login');
135
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
136
+ if (!hasCredentials(context))
137
+ this.error(missingCredentialsMessage(context));
138
138
  const queryParams = {};
139
139
  if (flags.page)
140
140
  queryParams.page = flags.page;
@@ -146,6 +146,8 @@ export default class Employees extends Command {
146
146
  queryParams.search = flags.search;
147
147
  if (flags['sort-by'])
148
148
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
149
+ if (flags.fields)
150
+ queryParams.fields = flags.fields;
149
151
  if (flags.query) {
150
152
  try {
151
153
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -348,11 +350,6 @@ export default class Employees extends Command {
348
350
  output = obj[arrayKeys[0]];
349
351
  }
350
352
  }
351
- // Filter fields if --fields flag is provided
352
- if (flags.fields) {
353
- const fieldList = flags.fields.split(',').map(f => f.trim());
354
- output = this.filterFields(output, fieldList);
355
- }
356
353
  // Sanitize output if requested
357
354
  if (flags.sanitize) {
358
355
  output = this.sanitizeOutput(output);
@@ -377,9 +374,9 @@ export default class Employees extends Command {
377
374
  async runImport(flags) {
378
375
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
379
376
  if (!context)
380
- this.error('No context configured. Run: aderis auth login --new');
381
- if (!context.tokens)
382
- this.error('Not logged in. Run: aderis auth login');
377
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
378
+ if (!hasCredentials(context))
379
+ this.error(missingCredentialsMessage(context));
383
380
  // Get data from file, --data, or --set flags
384
381
  let items = [];
385
382
  if (flags.file) {
@@ -589,9 +586,9 @@ export default class Employees extends Command {
589
586
  async runExport(flags) {
590
587
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
591
588
  if (!context)
592
- this.error('No context configured. Run: aderis auth login --new');
593
- if (!context.tokens)
594
- this.error('Not logged in. Run: aderis auth login');
589
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
590
+ if (!hasCredentials(context))
591
+ this.error(missingCredentialsMessage(context));
595
592
  const listEndpoint = ENDPOINTS['list'];
596
593
  if (!listEndpoint)
597
594
  this.error('Export requires a list endpoint');
@@ -607,6 +604,8 @@ export default class Employees extends Command {
607
604
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
608
605
  if (flags.include)
609
606
  baseParams.include = flags.include;
607
+ if (flags.fields)
608
+ baseParams.fields = flags.fields;
610
609
  if (flags.query) {
611
610
  try {
612
611
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -661,12 +660,7 @@ export default class Employees extends Command {
661
660
  }
662
661
  }
663
662
  process.stderr.write(' done\n');
664
- // Filter fields if specified
665
663
  let output = allItems;
666
- if (flags.fields) {
667
- const fieldList = flags.fields.split(',').map(f => f.trim());
668
- output = this.filterFields(allItems, fieldList);
669
- }
670
664
  // Sanitize output if requested
671
665
  if (flags.sanitize) {
672
666
  output = this.sanitizeOutput(output);
@@ -683,9 +677,9 @@ export default class Employees extends Command {
683
677
  async runCamt053Import(flags) {
684
678
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
685
679
  if (!context)
686
- this.error('No context configured. Run: aderis auth login --new');
687
- if (!context.tokens)
688
- this.error('Not logged in. Run: aderis auth login');
680
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
681
+ if (!hasCredentials(context))
682
+ this.error(missingCredentialsMessage(context));
689
683
  if (!flags.file) {
690
684
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
691
685
  }
@@ -773,9 +767,9 @@ export default class Employees extends Command {
773
767
  }
774
768
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
775
769
  if (!context)
776
- this.error('No context configured. Run: aderis auth login --new');
777
- if (!context.tokens)
778
- this.error('Not logged in. Run: aderis auth login');
770
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
771
+ if (!hasCredentials(context))
772
+ this.error(missingCredentialsMessage(context));
779
773
  // Get data from file, --data, or --set flags
780
774
  let items = [];
781
775
  if (flags.file) {
@@ -995,56 +989,6 @@ export default class Employees extends Command {
995
989
  return `\$${op}`;
996
990
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
997
991
  }
998
- filterFields(data, fields) {
999
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
1000
- const pick = (obj, keys) => {
1001
- // Group keys by their first segment so sibling sub-paths
1002
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
1003
- // and don't clobber each other on merge.
1004
- const directKeys = new Set();
1005
- const nestedKeys = new Map();
1006
- for (const key of keys) {
1007
- if (key.split('.').some(isUnsafeKey))
1008
- continue;
1009
- if (key.includes('.')) {
1010
- const [first, ...rest] = key.split('.');
1011
- if (isUnsafeKey(first))
1012
- continue;
1013
- const list = nestedKeys.get(first);
1014
- if (list) {
1015
- list.push(rest.join('.'));
1016
- }
1017
- else {
1018
- nestedKeys.set(first, [rest.join('.')]);
1019
- }
1020
- }
1021
- else {
1022
- directKeys.add(key);
1023
- }
1024
- }
1025
- const result = {};
1026
- for (const key of directKeys) {
1027
- if (key in obj)
1028
- result[key] = obj[key];
1029
- }
1030
- for (const [first, restKeys] of nestedKeys) {
1031
- const val = obj[first];
1032
- if (!val || typeof val !== 'object')
1033
- continue;
1034
- if (Array.isArray(val)) {
1035
- result[first] = val.map(item => pick(item, restKeys));
1036
- }
1037
- else {
1038
- result[first] = pick(val, restKeys);
1039
- }
1040
- }
1041
- return result;
1042
- };
1043
- if (Array.isArray(data)) {
1044
- return data.map(item => pick(item, fields));
1045
- }
1046
- return pick(data, fields);
1047
- }
1048
992
  sanitizeOutput(data) {
1049
993
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1050
994
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -31,7 +31,6 @@ export default class EntityConfigurations extends Command {
31
31
  private runCamt053Import;
32
32
  private runNestedImport;
33
33
  private parseFilterValue;
34
- private filterFields;
35
34
  private sanitizeOutput;
36
35
  private getColumns;
37
36
  private getValue;
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
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 = false;
@@ -20,7 +20,7 @@ export default class EntityConfigurations extends Command {
20
20
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
21
21
  };
22
22
  static flags = {
23
- context: Flags.string({ char: 'c', description: 'Context to use' }),
23
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
24
24
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
25
25
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
26
26
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -34,7 +34,7 @@ export default class EntityConfigurations extends Command {
34
34
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
35
35
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
36
36
  query: Flags.string({ description: 'Additional query params as JSON' }),
37
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
37
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
38
38
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
39
39
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
40
40
  };
@@ -92,9 +92,9 @@ export default class EntityConfigurations extends Command {
92
92
  }
93
93
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
94
94
  if (!context)
95
- this.error('No context configured. Run: aderis auth login --new');
96
- if (!context.tokens)
97
- this.error('Not logged in. Run: aderis auth login');
95
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
96
+ if (!hasCredentials(context))
97
+ this.error(missingCredentialsMessage(context));
98
98
  const queryParams = {};
99
99
  if (flags.page)
100
100
  queryParams.page = flags.page;
@@ -106,6 +106,8 @@ export default class EntityConfigurations extends Command {
106
106
  queryParams.search = flags.search;
107
107
  if (flags['sort-by'])
108
108
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
109
+ if (flags.fields)
110
+ queryParams.fields = flags.fields;
109
111
  if (flags.query) {
110
112
  try {
111
113
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -308,11 +310,6 @@ export default class EntityConfigurations extends Command {
308
310
  output = obj[arrayKeys[0]];
309
311
  }
310
312
  }
311
- // Filter fields if --fields flag is provided
312
- if (flags.fields) {
313
- const fieldList = flags.fields.split(',').map(f => f.trim());
314
- output = this.filterFields(output, fieldList);
315
- }
316
313
  // Sanitize output if requested
317
314
  if (flags.sanitize) {
318
315
  output = this.sanitizeOutput(output);
@@ -337,9 +334,9 @@ export default class EntityConfigurations extends Command {
337
334
  async runImport(flags) {
338
335
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
339
336
  if (!context)
340
- this.error('No context configured. Run: aderis auth login --new');
341
- if (!context.tokens)
342
- this.error('Not logged in. Run: aderis auth login');
337
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
338
+ if (!hasCredentials(context))
339
+ this.error(missingCredentialsMessage(context));
343
340
  // Get data from file, --data, or --set flags
344
341
  let items = [];
345
342
  if (flags.file) {
@@ -549,9 +546,9 @@ export default class EntityConfigurations extends Command {
549
546
  async runExport(flags) {
550
547
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
551
548
  if (!context)
552
- this.error('No context configured. Run: aderis auth login --new');
553
- if (!context.tokens)
554
- this.error('Not logged in. Run: aderis auth login');
549
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
550
+ if (!hasCredentials(context))
551
+ this.error(missingCredentialsMessage(context));
555
552
  const listEndpoint = ENDPOINTS['list'];
556
553
  if (!listEndpoint)
557
554
  this.error('Export requires a list endpoint');
@@ -567,6 +564,8 @@ export default class EntityConfigurations extends Command {
567
564
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
568
565
  if (flags.include)
569
566
  baseParams.include = flags.include;
567
+ if (flags.fields)
568
+ baseParams.fields = flags.fields;
570
569
  if (flags.query) {
571
570
  try {
572
571
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -621,12 +620,7 @@ export default class EntityConfigurations extends Command {
621
620
  }
622
621
  }
623
622
  process.stderr.write(' done\n');
624
- // Filter fields if specified
625
623
  let output = allItems;
626
- if (flags.fields) {
627
- const fieldList = flags.fields.split(',').map(f => f.trim());
628
- output = this.filterFields(allItems, fieldList);
629
- }
630
624
  // Sanitize output if requested
631
625
  if (flags.sanitize) {
632
626
  output = this.sanitizeOutput(output);
@@ -643,9 +637,9 @@ export default class EntityConfigurations extends Command {
643
637
  async runCamt053Import(flags) {
644
638
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
645
639
  if (!context)
646
- this.error('No context configured. Run: aderis auth login --new');
647
- if (!context.tokens)
648
- this.error('Not logged in. Run: aderis auth login');
640
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
641
+ if (!hasCredentials(context))
642
+ this.error(missingCredentialsMessage(context));
649
643
  if (!flags.file) {
650
644
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
651
645
  }
@@ -733,9 +727,9 @@ export default class EntityConfigurations extends Command {
733
727
  }
734
728
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
735
729
  if (!context)
736
- this.error('No context configured. Run: aderis auth login --new');
737
- if (!context.tokens)
738
- this.error('Not logged in. Run: aderis auth login');
730
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
731
+ if (!hasCredentials(context))
732
+ this.error(missingCredentialsMessage(context));
739
733
  // Get data from file, --data, or --set flags
740
734
  let items = [];
741
735
  if (flags.file) {
@@ -955,56 +949,6 @@ export default class EntityConfigurations extends Command {
955
949
  return `\$${op}`;
956
950
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
957
951
  }
958
- filterFields(data, fields) {
959
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
960
- const pick = (obj, keys) => {
961
- // Group keys by their first segment so sibling sub-paths
962
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
963
- // and don't clobber each other on merge.
964
- const directKeys = new Set();
965
- const nestedKeys = new Map();
966
- for (const key of keys) {
967
- if (key.split('.').some(isUnsafeKey))
968
- continue;
969
- if (key.includes('.')) {
970
- const [first, ...rest] = key.split('.');
971
- if (isUnsafeKey(first))
972
- continue;
973
- const list = nestedKeys.get(first);
974
- if (list) {
975
- list.push(rest.join('.'));
976
- }
977
- else {
978
- nestedKeys.set(first, [rest.join('.')]);
979
- }
980
- }
981
- else {
982
- directKeys.add(key);
983
- }
984
- }
985
- const result = {};
986
- for (const key of directKeys) {
987
- if (key in obj)
988
- result[key] = obj[key];
989
- }
990
- for (const [first, restKeys] of nestedKeys) {
991
- const val = obj[first];
992
- if (!val || typeof val !== 'object')
993
- continue;
994
- if (Array.isArray(val)) {
995
- result[first] = val.map(item => pick(item, restKeys));
996
- }
997
- else {
998
- result[first] = pick(val, restKeys);
999
- }
1000
- }
1001
- return result;
1002
- };
1003
- if (Array.isArray(data)) {
1004
- return data.map(item => pick(item, fields));
1005
- }
1006
- return pick(data, fields);
1007
- }
1008
952
  sanitizeOutput(data) {
1009
953
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1010
954
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -31,7 +31,6 @@ export default class EventProcessorMappings extends Command {
31
31
  private runCamt053Import;
32
32
  private runNestedImport;
33
33
  private parseFilterValue;
34
- private filterFields;
35
34
  private sanitizeOutput;
36
35
  private getColumns;
37
36
  private getValue;