@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
@@ -32,7 +32,6 @@ export default class Inbox extends Command {
32
32
  private runCamt053Import;
33
33
  private runNestedImport;
34
34
  private parseFilterValue;
35
- private filterFields;
36
35
  private sanitizeOutput;
37
36
  private getColumns;
38
37
  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;
@@ -23,7 +23,7 @@ export default class Inbox extends Command {
23
23
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
24
24
  };
25
25
  static flags = {
26
- context: Flags.string({ char: 'c', description: 'Context to use' }),
26
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
27
27
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
28
28
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
29
29
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -38,7 +38,7 @@ export default class Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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 Inbox 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;
@@ -32,7 +32,6 @@ export default class Integrations extends Command {
32
32
  private runCamt053Import;
33
33
  private runNestedImport;
34
34
  private parseFilterValue;
35
- private filterFields;
36
35
  private sanitizeOutput;
37
36
  private getColumns;
38
37
  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;
@@ -23,7 +23,7 @@ export default class Integrations extends Command {
23
23
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
24
24
  };
25
25
  static flags = {
26
- context: Flags.string({ char: 'c', description: 'Context to use' }),
26
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
27
27
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
28
28
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
29
29
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -38,7 +38,7 @@ export default class Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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 Integrations 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;
@@ -31,7 +31,6 @@ export default class ItemCategories 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 = true;
6
6
  const HAS_EXPORT = true;
@@ -29,7 +29,7 @@ export default class ItemCategories extends Command {
29
29
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
30
30
  };
31
31
  static flags = {
32
- context: Flags.string({ char: 'c', description: 'Context to use' }),
32
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
33
33
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
34
34
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
35
35
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -43,7 +43,7 @@ export default class ItemCategories extends Command {
43
43
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
44
44
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
45
45
  query: Flags.string({ description: 'Additional query params as JSON' }),
46
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
46
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
47
47
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
48
48
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
49
49
  };
@@ -101,9 +101,9 @@ export default class ItemCategories extends Command {
101
101
  }
102
102
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
103
103
  if (!context)
104
- this.error('No context configured. Run: aderis auth login --new');
105
- if (!context.tokens)
106
- this.error('Not logged in. Run: aderis auth login');
104
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
105
+ if (!hasCredentials(context))
106
+ this.error(missingCredentialsMessage(context));
107
107
  const queryParams = {};
108
108
  if (flags.page)
109
109
  queryParams.page = flags.page;
@@ -115,6 +115,8 @@ export default class ItemCategories extends Command {
115
115
  queryParams.search = flags.search;
116
116
  if (flags['sort-by'])
117
117
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
118
+ if (flags.fields)
119
+ queryParams.fields = flags.fields;
118
120
  if (flags.query) {
119
121
  try {
120
122
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -317,11 +319,6 @@ export default class ItemCategories extends Command {
317
319
  output = obj[arrayKeys[0]];
318
320
  }
319
321
  }
320
- // Filter fields if --fields flag is provided
321
- if (flags.fields) {
322
- const fieldList = flags.fields.split(',').map(f => f.trim());
323
- output = this.filterFields(output, fieldList);
324
- }
325
322
  // Sanitize output if requested
326
323
  if (flags.sanitize) {
327
324
  output = this.sanitizeOutput(output);
@@ -346,9 +343,9 @@ export default class ItemCategories extends Command {
346
343
  async runImport(flags) {
347
344
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
348
345
  if (!context)
349
- this.error('No context configured. Run: aderis auth login --new');
350
- if (!context.tokens)
351
- this.error('Not logged in. Run: aderis auth login');
346
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
347
+ if (!hasCredentials(context))
348
+ this.error(missingCredentialsMessage(context));
352
349
  // Get data from file, --data, or --set flags
353
350
  let items = [];
354
351
  if (flags.file) {
@@ -558,9 +555,9 @@ export default class ItemCategories extends Command {
558
555
  async runExport(flags) {
559
556
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
560
557
  if (!context)
561
- this.error('No context configured. Run: aderis auth login --new');
562
- if (!context.tokens)
563
- this.error('Not logged in. Run: aderis auth login');
558
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
559
+ if (!hasCredentials(context))
560
+ this.error(missingCredentialsMessage(context));
564
561
  const listEndpoint = ENDPOINTS['list'];
565
562
  if (!listEndpoint)
566
563
  this.error('Export requires a list endpoint');
@@ -576,6 +573,8 @@ export default class ItemCategories extends Command {
576
573
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
577
574
  if (flags.include)
578
575
  baseParams.include = flags.include;
576
+ if (flags.fields)
577
+ baseParams.fields = flags.fields;
579
578
  if (flags.query) {
580
579
  try {
581
580
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -630,12 +629,7 @@ export default class ItemCategories extends Command {
630
629
  }
631
630
  }
632
631
  process.stderr.write(' done\n');
633
- // Filter fields if specified
634
632
  let output = allItems;
635
- if (flags.fields) {
636
- const fieldList = flags.fields.split(',').map(f => f.trim());
637
- output = this.filterFields(allItems, fieldList);
638
- }
639
633
  // Sanitize output if requested
640
634
  if (flags.sanitize) {
641
635
  output = this.sanitizeOutput(output);
@@ -652,9 +646,9 @@ export default class ItemCategories extends Command {
652
646
  async runCamt053Import(flags) {
653
647
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
654
648
  if (!context)
655
- this.error('No context configured. Run: aderis auth login --new');
656
- if (!context.tokens)
657
- this.error('Not logged in. Run: aderis auth login');
649
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
650
+ if (!hasCredentials(context))
651
+ this.error(missingCredentialsMessage(context));
658
652
  if (!flags.file) {
659
653
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
660
654
  }
@@ -742,9 +736,9 @@ export default class ItemCategories extends Command {
742
736
  }
743
737
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
744
738
  if (!context)
745
- this.error('No context configured. Run: aderis auth login --new');
746
- if (!context.tokens)
747
- this.error('Not logged in. Run: aderis auth login');
739
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
740
+ if (!hasCredentials(context))
741
+ this.error(missingCredentialsMessage(context));
748
742
  // Get data from file, --data, or --set flags
749
743
  let items = [];
750
744
  if (flags.file) {
@@ -964,56 +958,6 @@ export default class ItemCategories extends Command {
964
958
  return `\$${op}`;
965
959
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
966
960
  }
967
- filterFields(data, fields) {
968
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
969
- const pick = (obj, keys) => {
970
- // Group keys by their first segment so sibling sub-paths
971
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
972
- // and don't clobber each other on merge.
973
- const directKeys = new Set();
974
- const nestedKeys = new Map();
975
- for (const key of keys) {
976
- if (key.split('.').some(isUnsafeKey))
977
- continue;
978
- if (key.includes('.')) {
979
- const [first, ...rest] = key.split('.');
980
- if (isUnsafeKey(first))
981
- continue;
982
- const list = nestedKeys.get(first);
983
- if (list) {
984
- list.push(rest.join('.'));
985
- }
986
- else {
987
- nestedKeys.set(first, [rest.join('.')]);
988
- }
989
- }
990
- else {
991
- directKeys.add(key);
992
- }
993
- }
994
- const result = {};
995
- for (const key of directKeys) {
996
- if (key in obj)
997
- result[key] = obj[key];
998
- }
999
- for (const [first, restKeys] of nestedKeys) {
1000
- const val = obj[first];
1001
- if (!val || typeof val !== 'object')
1002
- continue;
1003
- if (Array.isArray(val)) {
1004
- result[first] = val.map(item => pick(item, restKeys));
1005
- }
1006
- else {
1007
- result[first] = pick(val, restKeys);
1008
- }
1009
- }
1010
- return result;
1011
- };
1012
- if (Array.isArray(data)) {
1013
- return data.map(item => pick(item, fields));
1014
- }
1015
- return pick(data, fields);
1016
- }
1017
961
  sanitizeOutput(data) {
1018
962
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1019
963
  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 Items 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;