@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 = true;
6
6
  const HAS_EXPORT = true;
@@ -9,9 +9,9 @@ const NESTED_IMPORTS = [];
9
9
  const SUBCOMMANDS = [...["list", "create", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'list': { method: 'GET', path: '/v1/items', summary: 'Get all items with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds'] },
12
+ 'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
13
13
  'get': { method: 'GET', path: '/v1/items/{id}', summary: 'Get an item by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds'] },
14
+ 'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
15
15
  'delete': { method: 'DELETE', path: '/v1/items/{id}', summary: 'Delete an item', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
16
  };
17
17
  export default class Items extends Command {
@@ -29,7 +29,7 @@ export default class Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 Items 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 JournalLines 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 = true;
@@ -21,7 +21,7 @@ export default class JournalLines extends Command {
21
21
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
22
22
  };
23
23
  static flags = {
24
- context: Flags.string({ char: 'c', description: 'Context to use' }),
24
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
25
25
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
26
26
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
27
27
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -35,7 +35,7 @@ export default class JournalLines extends Command {
35
35
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
36
36
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
37
37
  query: Flags.string({ description: 'Additional query params as JSON' }),
38
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
38
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
39
39
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
40
40
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
41
41
  };
@@ -93,9 +93,9 @@ export default class JournalLines extends Command {
93
93
  }
94
94
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
95
95
  if (!context)
96
- this.error('No context configured. Run: aderis auth login --new');
97
- if (!context.tokens)
98
- this.error('Not logged in. Run: aderis auth login');
96
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
97
+ if (!hasCredentials(context))
98
+ this.error(missingCredentialsMessage(context));
99
99
  const queryParams = {};
100
100
  if (flags.page)
101
101
  queryParams.page = flags.page;
@@ -107,6 +107,8 @@ export default class JournalLines extends Command {
107
107
  queryParams.search = flags.search;
108
108
  if (flags['sort-by'])
109
109
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
110
+ if (flags.fields)
111
+ queryParams.fields = flags.fields;
110
112
  if (flags.query) {
111
113
  try {
112
114
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -309,11 +311,6 @@ export default class JournalLines extends Command {
309
311
  output = obj[arrayKeys[0]];
310
312
  }
311
313
  }
312
- // Filter fields if --fields flag is provided
313
- if (flags.fields) {
314
- const fieldList = flags.fields.split(',').map(f => f.trim());
315
- output = this.filterFields(output, fieldList);
316
- }
317
314
  // Sanitize output if requested
318
315
  if (flags.sanitize) {
319
316
  output = this.sanitizeOutput(output);
@@ -338,9 +335,9 @@ export default class JournalLines extends Command {
338
335
  async runImport(flags) {
339
336
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
340
337
  if (!context)
341
- this.error('No context configured. Run: aderis auth login --new');
342
- if (!context.tokens)
343
- this.error('Not logged in. Run: aderis auth login');
338
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
339
+ if (!hasCredentials(context))
340
+ this.error(missingCredentialsMessage(context));
344
341
  // Get data from file, --data, or --set flags
345
342
  let items = [];
346
343
  if (flags.file) {
@@ -550,9 +547,9 @@ export default class JournalLines extends Command {
550
547
  async runExport(flags) {
551
548
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
552
549
  if (!context)
553
- this.error('No context configured. Run: aderis auth login --new');
554
- if (!context.tokens)
555
- this.error('Not logged in. Run: aderis auth login');
550
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
551
+ if (!hasCredentials(context))
552
+ this.error(missingCredentialsMessage(context));
556
553
  const listEndpoint = ENDPOINTS['list'];
557
554
  if (!listEndpoint)
558
555
  this.error('Export requires a list endpoint');
@@ -568,6 +565,8 @@ export default class JournalLines extends Command {
568
565
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
569
566
  if (flags.include)
570
567
  baseParams.include = flags.include;
568
+ if (flags.fields)
569
+ baseParams.fields = flags.fields;
571
570
  if (flags.query) {
572
571
  try {
573
572
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -622,12 +621,7 @@ export default class JournalLines extends Command {
622
621
  }
623
622
  }
624
623
  process.stderr.write(' done\n');
625
- // Filter fields if specified
626
624
  let output = allItems;
627
- if (flags.fields) {
628
- const fieldList = flags.fields.split(',').map(f => f.trim());
629
- output = this.filterFields(allItems, fieldList);
630
- }
631
625
  // Sanitize output if requested
632
626
  if (flags.sanitize) {
633
627
  output = this.sanitizeOutput(output);
@@ -644,9 +638,9 @@ export default class JournalLines extends Command {
644
638
  async runCamt053Import(flags) {
645
639
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
646
640
  if (!context)
647
- this.error('No context configured. Run: aderis auth login --new');
648
- if (!context.tokens)
649
- this.error('Not logged in. Run: aderis auth login');
641
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
642
+ if (!hasCredentials(context))
643
+ this.error(missingCredentialsMessage(context));
650
644
  if (!flags.file) {
651
645
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
652
646
  }
@@ -734,9 +728,9 @@ export default class JournalLines extends Command {
734
728
  }
735
729
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
736
730
  if (!context)
737
- this.error('No context configured. Run: aderis auth login --new');
738
- if (!context.tokens)
739
- this.error('Not logged in. Run: aderis auth login');
731
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
732
+ if (!hasCredentials(context))
733
+ this.error(missingCredentialsMessage(context));
740
734
  // Get data from file, --data, or --set flags
741
735
  let items = [];
742
736
  if (flags.file) {
@@ -956,56 +950,6 @@ export default class JournalLines extends Command {
956
950
  return `\$${op}`;
957
951
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
958
952
  }
959
- filterFields(data, fields) {
960
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
961
- const pick = (obj, keys) => {
962
- // Group keys by their first segment so sibling sub-paths
963
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
964
- // and don't clobber each other on merge.
965
- const directKeys = new Set();
966
- const nestedKeys = new Map();
967
- for (const key of keys) {
968
- if (key.split('.').some(isUnsafeKey))
969
- continue;
970
- if (key.includes('.')) {
971
- const [first, ...rest] = key.split('.');
972
- if (isUnsafeKey(first))
973
- continue;
974
- const list = nestedKeys.get(first);
975
- if (list) {
976
- list.push(rest.join('.'));
977
- }
978
- else {
979
- nestedKeys.set(first, [rest.join('.')]);
980
- }
981
- }
982
- else {
983
- directKeys.add(key);
984
- }
985
- }
986
- const result = {};
987
- for (const key of directKeys) {
988
- if (key in obj)
989
- result[key] = obj[key];
990
- }
991
- for (const [first, restKeys] of nestedKeys) {
992
- const val = obj[first];
993
- if (!val || typeof val !== 'object')
994
- continue;
995
- if (Array.isArray(val)) {
996
- result[first] = val.map(item => pick(item, restKeys));
997
- }
998
- else {
999
- result[first] = pick(val, restKeys);
1000
- }
1001
- }
1002
- return result;
1003
- };
1004
- if (Array.isArray(data)) {
1005
- return data.map(item => pick(item, fields));
1006
- }
1007
- return pick(data, fields);
1008
- }
1009
953
  sanitizeOutput(data) {
1010
954
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1011
955
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -14,6 +14,7 @@ export default class Journals extends Command {
14
14
  data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
15
  file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
16
  set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ 'line-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
18
  'note-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
19
  'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
20
  page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -33,7 +34,6 @@ export default class Journals extends Command {
33
34
  private runCamt053Import;
34
35
  private runNestedImport;
35
36
  private parseFilterValue;
36
- private filterFields;
37
37
  private sanitizeOutput;
38
38
  private getColumns;
39
39
  private getValue;
@@ -1,21 +1,24 @@
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;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = ["notes", "files"];
9
- const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "post", "approve", "cancel", "get-deferrals", "create-deferrals", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["list", "create", "stats", "get", "update", "delete", "post", "approve", "cancel", "reverse", "update-lines", "get-deferrals", "create-deferrals", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'list': { method: 'GET', path: '/v1/journals', summary: 'List all journals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'lines', 'notes'] },
12
+ 'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['lines', 'notes'] },
13
+ 'stats': { method: 'GET', path: '/v1/journals/stats', summary: 'Journal counts and debit totals per date range', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
13
14
  'get': { method: 'GET', path: '/v1/journals/{id}', summary: 'Get a journal by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'lines'] },
15
+ 'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['lines'] },
15
16
  'delete': { method: 'DELETE', path: '/v1/journals/{id}', summary: 'Delete a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
17
  'post': { method: 'POST', path: '/v1/journals/{id}/post', summary: 'Post journal (finalize)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
17
18
  'approve': { method: 'POST', path: '/v1/journals/{id}/approve', summary: 'Approve a journal (transitions DRAFT to APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
18
19
  'cancel': { method: 'POST', path: '/v1/journals/{id}/cancel', summary: 'Cancel a journal', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
20
+ 'reverse': { method: 'POST', path: '/v1/journals/{id}/reverse', summary: 'Reverse a posted journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
21
+ 'update-lines': { method: 'PATCH', path: '/v1/journals/{id}/lines/{lineId}', summary: 'Update a single journal line in place', pathParams: ['id', 'lineId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
19
22
  'get-deferrals': { method: 'GET', path: '/v1/journals/{id}/deferrals', summary: 'List the deferral schedules of a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
20
23
  'create-deferrals': { method: 'POST', path: '/v1/journals/{id}/deferrals', summary: 'Create deferral schedules for one line of a journal (manual trigger)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['periods'] },
21
24
  'list-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes', summary: 'Get all notes for a journal', pathParams: ['journalId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
@@ -45,13 +48,14 @@ export default class Journals extends Command {
45
48
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
46
49
  };
47
50
  static flags = {
48
- context: Flags.string({ char: 'c', description: 'Context to use' }),
51
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
49
52
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
50
53
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
51
54
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
52
55
  data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
53
56
  file: Flags.string({ char: 'f', description: 'Read request body from file' }),
54
57
  set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
58
+ 'line-id': Flags.string({ description: 'Path param: lineId' }),
55
59
  'note-id': Flags.string({ description: 'Path param: noteId' }),
56
60
  'file-id': Flags.string({ description: 'Path param: fileId' }),
57
61
  page: Flags.string({ description: 'Page number' }),
@@ -61,7 +65,7 @@ export default class Journals extends Command {
61
65
  'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
62
66
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
63
67
  query: Flags.string({ description: 'Additional query params as JSON' }),
64
- fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
68
+ fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
65
69
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
66
70
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
67
71
  };
@@ -119,9 +123,9 @@ export default class Journals extends Command {
119
123
  }
120
124
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
121
125
  if (!context)
122
- this.error('No context configured. Run: aderis auth login --new');
123
- if (!context.tokens)
124
- this.error('Not logged in. Run: aderis auth login');
126
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
127
+ if (!hasCredentials(context))
128
+ this.error(missingCredentialsMessage(context));
125
129
  const queryParams = {};
126
130
  if (flags.page)
127
131
  queryParams.page = flags.page;
@@ -133,6 +137,8 @@ export default class Journals extends Command {
133
137
  queryParams.search = flags.search;
134
138
  if (flags['sort-by'])
135
139
  queryParams.sortBy = normalizeSortBy(flags['sort-by']);
140
+ if (flags.fields)
141
+ queryParams.fields = flags.fields;
136
142
  if (flags.query) {
137
143
  try {
138
144
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -335,11 +341,6 @@ export default class Journals extends Command {
335
341
  output = obj[arrayKeys[0]];
336
342
  }
337
343
  }
338
- // Filter fields if --fields flag is provided
339
- if (flags.fields) {
340
- const fieldList = flags.fields.split(',').map(f => f.trim());
341
- output = this.filterFields(output, fieldList);
342
- }
343
344
  // Sanitize output if requested
344
345
  if (flags.sanitize) {
345
346
  output = this.sanitizeOutput(output);
@@ -364,9 +365,9 @@ export default class Journals extends Command {
364
365
  async runImport(flags) {
365
366
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
366
367
  if (!context)
367
- this.error('No context configured. Run: aderis auth login --new');
368
- if (!context.tokens)
369
- this.error('Not logged in. Run: aderis auth login');
368
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
369
+ if (!hasCredentials(context))
370
+ this.error(missingCredentialsMessage(context));
370
371
  // Get data from file, --data, or --set flags
371
372
  let items = [];
372
373
  if (flags.file) {
@@ -576,9 +577,9 @@ export default class Journals extends Command {
576
577
  async runExport(flags) {
577
578
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
578
579
  if (!context)
579
- this.error('No context configured. Run: aderis auth login --new');
580
- if (!context.tokens)
581
- this.error('Not logged in. Run: aderis auth login');
580
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
581
+ if (!hasCredentials(context))
582
+ this.error(missingCredentialsMessage(context));
582
583
  const listEndpoint = ENDPOINTS['list'];
583
584
  if (!listEndpoint)
584
585
  this.error('Export requires a list endpoint');
@@ -594,6 +595,8 @@ export default class Journals extends Command {
594
595
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
595
596
  if (flags.include)
596
597
  baseParams.include = flags.include;
598
+ if (flags.fields)
599
+ baseParams.fields = flags.fields;
597
600
  if (flags.query) {
598
601
  try {
599
602
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -648,12 +651,7 @@ export default class Journals extends Command {
648
651
  }
649
652
  }
650
653
  process.stderr.write(' done\n');
651
- // Filter fields if specified
652
654
  let output = allItems;
653
- if (flags.fields) {
654
- const fieldList = flags.fields.split(',').map(f => f.trim());
655
- output = this.filterFields(allItems, fieldList);
656
- }
657
655
  // Sanitize output if requested
658
656
  if (flags.sanitize) {
659
657
  output = this.sanitizeOutput(output);
@@ -670,9 +668,9 @@ export default class Journals extends Command {
670
668
  async runCamt053Import(flags) {
671
669
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
672
670
  if (!context)
673
- this.error('No context configured. Run: aderis auth login --new');
674
- if (!context.tokens)
675
- this.error('Not logged in. Run: aderis auth login');
671
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
672
+ if (!hasCredentials(context))
673
+ this.error(missingCredentialsMessage(context));
676
674
  if (!flags.file) {
677
675
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
678
676
  }
@@ -760,9 +758,9 @@ export default class Journals extends Command {
760
758
  }
761
759
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
762
760
  if (!context)
763
- this.error('No context configured. Run: aderis auth login --new');
764
- if (!context.tokens)
765
- this.error('Not logged in. Run: aderis auth login');
761
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
762
+ if (!hasCredentials(context))
763
+ this.error(missingCredentialsMessage(context));
766
764
  // Get data from file, --data, or --set flags
767
765
  let items = [];
768
766
  if (flags.file) {
@@ -982,56 +980,6 @@ export default class Journals extends Command {
982
980
  return `\$${op}`;
983
981
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
984
982
  }
985
- filterFields(data, fields) {
986
- const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
987
- const pick = (obj, keys) => {
988
- // Group keys by their first segment so sibling sub-paths
989
- // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
990
- // and don't clobber each other on merge.
991
- const directKeys = new Set();
992
- const nestedKeys = new Map();
993
- for (const key of keys) {
994
- if (key.split('.').some(isUnsafeKey))
995
- continue;
996
- if (key.includes('.')) {
997
- const [first, ...rest] = key.split('.');
998
- if (isUnsafeKey(first))
999
- continue;
1000
- const list = nestedKeys.get(first);
1001
- if (list) {
1002
- list.push(rest.join('.'));
1003
- }
1004
- else {
1005
- nestedKeys.set(first, [rest.join('.')]);
1006
- }
1007
- }
1008
- else {
1009
- directKeys.add(key);
1010
- }
1011
- }
1012
- const result = {};
1013
- for (const key of directKeys) {
1014
- if (key in obj)
1015
- result[key] = obj[key];
1016
- }
1017
- for (const [first, restKeys] of nestedKeys) {
1018
- const val = obj[first];
1019
- if (!val || typeof val !== 'object')
1020
- continue;
1021
- if (Array.isArray(val)) {
1022
- result[first] = val.map(item => pick(item, restKeys));
1023
- }
1024
- else {
1025
- result[first] = pick(val, restKeys);
1026
- }
1027
- }
1028
- return result;
1029
- };
1030
- if (Array.isArray(data)) {
1031
- return data.map(item => pick(item, fields));
1032
- }
1033
- return pick(data, fields);
1034
- }
1035
983
  sanitizeOutput(data) {
1036
984
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1037
985
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -33,7 +33,6 @@ export default class Ledgers extends Command {
33
33
  private runCamt053Import;
34
34
  private runNestedImport;
35
35
  private parseFilterValue;
36
- private filterFields;
37
36
  private sanitizeOutput;
38
37
  private getColumns;
39
38
  private getValue;