@aderis-erp/cli 1.0.15 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) 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 +54 -78
  4. package/dist/commands/account-transaction-allocations.d.ts +0 -1
  5. package/dist/commands/account-transaction-allocations.js +51 -75
  6. package/dist/commands/account-transactions.d.ts +0 -1
  7. package/dist/commands/account-transactions.js +80 -94
  8. package/dist/commands/accounts.d.ts +0 -1
  9. package/dist/commands/accounts.js +59 -83
  10. package/dist/commands/agent-platform.d.ts +0 -1
  11. package/dist/commands/agent-platform.js +58 -82
  12. package/dist/commands/agent-runs.d.ts +39 -0
  13. package/dist/commands/agent-runs.js +1155 -0
  14. package/dist/commands/analytics.d.ts +0 -1
  15. package/dist/commands/analytics.js +52 -76
  16. package/dist/commands/{text-templates.d.ts → api-keys.d.ts} +1 -2
  17. package/dist/commands/api-keys.js +1150 -0
  18. package/dist/commands/async-jobs.d.ts +39 -0
  19. package/dist/commands/async-jobs.js +1158 -0
  20. package/dist/commands/audit-log.d.ts +0 -1
  21. package/dist/commands/audit-log.js +51 -75
  22. package/dist/commands/auth/login.d.ts +9 -0
  23. package/dist/commands/auth/login.js +73 -20
  24. package/dist/commands/auth/logout.d.ts +4 -0
  25. package/dist/commands/auth/logout.js +4 -0
  26. package/dist/commands/auth/status.js +26 -17
  27. package/dist/commands/auth/tenant.js +3 -6
  28. package/dist/commands/auth.d.ts +0 -1
  29. package/dist/commands/auth.js +5 -34
  30. package/dist/commands/bank-accounts.d.ts +0 -1
  31. package/dist/commands/bank-accounts.js +68 -91
  32. package/dist/commands/bank-integrations.d.ts +1 -1
  33. package/dist/commands/bank-integrations.js +71 -92
  34. package/dist/commands/business-partners.d.ts +1 -1
  35. package/dist/commands/business-partners.js +84 -100
  36. package/dist/commands/chat.d.ts +0 -1
  37. package/dist/commands/chat.js +57 -80
  38. package/dist/commands/config/add.d.ts +3 -0
  39. package/dist/commands/config/add.js +34 -16
  40. package/dist/commands/config/current.js +3 -0
  41. package/dist/commands/config/list.js +3 -0
  42. package/dist/commands/credit-card-accounts.d.ts +1 -1
  43. package/dist/commands/credit-card-accounts.js +72 -90
  44. package/dist/commands/delivery-notes.d.ts +0 -1
  45. package/dist/commands/delivery-notes.js +83 -105
  46. package/dist/commands/dunning-configs.d.ts +0 -1
  47. package/dist/commands/dunning-configs.js +54 -78
  48. package/dist/commands/dunning-reminders.d.ts +0 -1
  49. package/dist/commands/dunning-reminders.js +57 -81
  50. package/dist/commands/dunning-runs.d.ts +0 -1
  51. package/dist/commands/dunning-runs.js +50 -74
  52. package/dist/commands/email-transactions.d.ts +0 -1
  53. package/dist/commands/email-transactions.js +52 -76
  54. package/dist/commands/employees.d.ts +0 -1
  55. package/dist/commands/employees.js +81 -105
  56. package/dist/commands/entity-configurations.d.ts +0 -1
  57. package/dist/commands/entity-configurations.js +52 -76
  58. package/dist/commands/event-processor-mappings.d.ts +0 -1
  59. package/dist/commands/event-processor-mappings.js +54 -78
  60. package/dist/commands/files.d.ts +0 -1
  61. package/dist/commands/files.js +61 -85
  62. package/dist/commands/health.d.ts +0 -1
  63. package/dist/commands/health.js +54 -78
  64. package/dist/commands/imports.d.ts +39 -0
  65. package/dist/commands/imports.js +1151 -0
  66. package/dist/commands/inbox.d.ts +0 -1
  67. package/dist/commands/inbox.js +57 -80
  68. package/dist/commands/integration-identities.d.ts +40 -0
  69. package/dist/commands/integration-identities.js +1151 -0
  70. package/dist/commands/integrations.d.ts +0 -1
  71. package/dist/commands/integrations.js +52 -76
  72. package/dist/commands/item-categories.d.ts +0 -1
  73. package/dist/commands/item-categories.js +54 -78
  74. package/dist/commands/items.d.ts +0 -1
  75. package/dist/commands/items.js +54 -78
  76. package/dist/commands/journal-lines.d.ts +0 -1
  77. package/dist/commands/journal-lines.js +50 -74
  78. package/dist/commands/journals.d.ts +1 -1
  79. package/dist/commands/journals.js +75 -96
  80. package/dist/commands/ledgers.d.ts +3 -2
  81. package/dist/commands/ledgers.js +100 -95
  82. package/dist/commands/my-account.d.ts +39 -0
  83. package/dist/commands/my-account.js +1160 -0
  84. package/dist/commands/office-locations.d.ts +0 -1
  85. package/dist/commands/office-locations.js +54 -78
  86. package/dist/commands/payment-methods.d.ts +0 -1
  87. package/dist/commands/payment-methods.js +59 -83
  88. package/dist/commands/payment-runs.d.ts +0 -1
  89. package/dist/commands/payment-runs.js +66 -90
  90. package/dist/commands/payment-terms.d.ts +0 -1
  91. package/dist/commands/payment-terms.js +55 -79
  92. package/dist/commands/payments.d.ts +0 -1
  93. package/dist/commands/payments.js +56 -80
  94. package/dist/commands/payroll-runs.d.ts +43 -0
  95. package/dist/commands/payroll-runs.js +1188 -0
  96. package/dist/commands/permissions.d.ts +39 -0
  97. package/dist/commands/permissions.js +1146 -0
  98. package/dist/commands/price-lists.d.ts +0 -1
  99. package/dist/commands/price-lists.js +59 -83
  100. package/dist/commands/processor-mappings.d.ts +0 -1
  101. package/dist/commands/processor-mappings.js +53 -77
  102. package/dist/commands/processors.d.ts +0 -1
  103. package/dist/commands/processors.js +60 -85
  104. package/dist/commands/purchase-order-types.d.ts +0 -1
  105. package/dist/commands/purchase-order-types.js +54 -78
  106. package/dist/commands/purchase-orders.d.ts +0 -1
  107. package/dist/commands/purchase-orders.js +74 -97
  108. package/dist/commands/reports.d.ts +0 -1
  109. package/dist/commands/reports.js +54 -78
  110. package/dist/commands/roles.d.ts +39 -0
  111. package/dist/commands/{text-templates.js → roles.js} +64 -90
  112. package/dist/commands/salary-types.d.ts +0 -1
  113. package/dist/commands/salary-types.js +54 -78
  114. package/dist/commands/sales-invoices.d.ts +0 -1
  115. package/dist/commands/sales-invoices.js +90 -110
  116. package/dist/commands/sales-orders.d.ts +0 -1
  117. package/dist/commands/sales-orders.js +83 -105
  118. package/dist/commands/saved-views.d.ts +0 -1
  119. package/dist/commands/saved-views.js +52 -76
  120. package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
  121. package/dist/commands/scheduled-processor-mappings.js +54 -78
  122. package/dist/commands/schedules.d.ts +0 -1
  123. package/dist/commands/schedules.js +58 -82
  124. package/dist/commands/switch.js +4 -4
  125. package/dist/commands/tag-configurations.d.ts +0 -1
  126. package/dist/commands/tag-configurations.js +56 -79
  127. package/dist/commands/tags.d.ts +0 -1
  128. package/dist/commands/tags.js +54 -78
  129. package/dist/commands/tax-codes.d.ts +0 -1
  130. package/dist/commands/tax-codes.js +57 -81
  131. package/dist/commands/tax-matrix.d.ts +0 -1
  132. package/dist/commands/tax-matrix.js +54 -78
  133. package/dist/commands/templates.d.ts +39 -0
  134. package/dist/commands/templates.js +1157 -0
  135. package/dist/commands/tenants.d.ts +0 -1
  136. package/dist/commands/tenants.js +58 -81
  137. package/dist/commands/tools.d.ts +0 -1
  138. package/dist/commands/tools.js +51 -75
  139. package/dist/commands/users.d.ts +42 -0
  140. package/dist/commands/users.js +1174 -0
  141. package/dist/commands/vat-declarations.d.ts +3 -1
  142. package/dist/commands/vat-declarations.js +78 -93
  143. package/dist/commands/vendor-invoices.d.ts +0 -1
  144. package/dist/commands/vendor-invoices.js +87 -110
  145. package/dist/commands/webhooks.d.ts +0 -1
  146. package/dist/commands/webhooks.js +56 -80
  147. package/dist/commands/workflows.d.ts +0 -1
  148. package/dist/commands/workflows.js +52 -76
  149. package/dist/lib/api-client.d.ts +6 -0
  150. package/dist/lib/api-client.js +16 -6
  151. package/dist/lib/auth/constants.d.ts +11 -0
  152. package/dist/lib/auth/constants.js +11 -0
  153. package/dist/lib/auth/errors.d.ts +17 -0
  154. package/dist/lib/auth/errors.js +22 -0
  155. package/dist/lib/auth/flow.d.ts +27 -0
  156. package/dist/lib/auth/flow.js +163 -0
  157. package/dist/lib/auth/guards.d.ts +5 -0
  158. package/dist/lib/auth/guards.js +14 -0
  159. package/dist/lib/auth/http.d.ts +16 -0
  160. package/dist/lib/auth/http.js +49 -0
  161. package/dist/lib/auth/index.d.ts +49 -0
  162. package/dist/lib/auth/index.js +228 -0
  163. package/dist/lib/auth/jwks.d.ts +19 -0
  164. package/dist/lib/auth/jwks.js +112 -0
  165. package/dist/lib/auth/keycloak-provider.d.ts +91 -0
  166. package/dist/lib/auth/keycloak-provider.js +244 -0
  167. package/dist/lib/auth/pages.d.ts +25 -0
  168. package/dist/lib/auth/pages.js +123 -0
  169. package/dist/lib/auth/pkce.d.ts +11 -0
  170. package/dist/lib/auth/pkce.js +17 -0
  171. package/dist/lib/auth/tokens.d.ts +59 -0
  172. package/dist/lib/auth/tokens.js +105 -0
  173. package/dist/lib/auth/types.d.ts +61 -0
  174. package/dist/lib/auth/types.js +1 -0
  175. package/dist/lib/auth/validated-url.d.ts +6 -0
  176. package/dist/lib/auth/validated-url.js +53 -0
  177. package/dist/lib/config.d.ts +13 -3
  178. package/dist/lib/config.js +24 -19
  179. package/oclif.manifest.json +2447 -641
  180. package/package.json +5 -4
  181. package/dist/lib/auth.d.ts +0 -43
  182. package/dist/lib/auth.js +0 -610
@@ -1,5 +1,5 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
2
+ import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
3
3
  import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = true;
@@ -8,38 +8,38 @@ const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = ["salaries", "payments", "notes", "files", "salary-payment-files"];
9
9
  const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-salaries", "create-salaries", "get-salaries-salaryId", "update-salaries", "delete-salaries", "get-payments", "create-payments", "get-payments-paymentId", "update-payments", "delete-payments", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-salary-payment-files", "create-salary-payment-files", "get-salary-payment-files", "update-salary-payment-files", "delete-salary-payment-files", "download-salary-payment-files"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
13
- 'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
15
- 'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
- 'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
17
- 'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
18
- 'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
19
- 'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
20
- 'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
21
- 'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
22
- 'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['salaryComponents', 'files'] },
23
- 'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
24
- 'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['salaryComponents', 'files'] },
25
- 'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
26
- 'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
27
- 'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
28
- 'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
29
- 'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
30
- 'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
31
- 'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
32
- 'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
33
- 'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
34
- 'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
35
- 'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
36
- 'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
37
- 'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
38
- 'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
39
- 'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
40
- 'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
41
- 'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
42
- 'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
11
+ 'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
12
+ 'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
13
+ 'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
+ 'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
15
+ 'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
16
+ 'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
17
+ 'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
18
+ 'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
19
+ 'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
20
+ 'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
21
+ 'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
22
+ 'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
23
+ 'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
24
+ 'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
25
+ 'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
26
+ 'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
27
+ 'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
28
+ 'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
29
+ 'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
30
+ 'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
31
+ 'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
32
+ 'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
33
+ 'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
34
+ 'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
35
+ 'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
36
+ 'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
37
+ 'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
38
+ 'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
39
+ 'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
40
+ 'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
41
+ 'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
42
+ 'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
43
43
  };
44
44
  export default class Employees extends Command {
45
45
  static description = 'Manage employees';
@@ -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
  };
@@ -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));
@@ -293,10 +295,11 @@ export default class Employees extends Command {
293
295
  process.stderr.write('\n');
294
296
  }
295
297
  try {
296
- // Binary response: download to file
298
+ // Binary response: to -f / --file, or to stdout when it is redirected.
297
299
  if (endpoint.isBinaryResponse) {
298
- if (!flags.file) {
299
- this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
300
+ const toStdout = !flags.file;
301
+ if (toStdout && process.stdout.isTTY) {
302
+ this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
300
303
  }
301
304
  const binResponse = await apiRequest(endpoint.method, apiPath, {
302
305
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
@@ -304,24 +307,55 @@ export default class Employees extends Command {
304
307
  contextName: flags.context,
305
308
  binary: true,
306
309
  });
307
- const fsModule = await import('node:fs');
308
310
  const binData = binResponse.data;
309
311
  const buffer = Buffer.isBuffer(binData)
310
312
  ? binData
311
313
  : Buffer.from(binData);
314
+ if (toStdout) {
315
+ // Nothing else may reach stdout here — it is the file.
316
+ process.stdout.write(buffer);
317
+ return;
318
+ }
319
+ const fsModule = await import('node:fs');
312
320
  fsModule.writeFileSync(flags.file, buffer);
313
321
  this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
314
322
  return;
315
323
  }
316
- const response = await apiRequest(endpoint.method, apiPath, {
317
- params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
318
- data,
319
- contextName: flags.context,
320
- acceptAny: true,
321
- });
324
+ let response;
325
+ if (endpoint.hasBinaryVariant) {
326
+ // This route answers JSON or a file depending on the request body, so the
327
+ // bytes are read first and the response's own content-type decides. Asking
328
+ // for text here would corrupt an xlsx/pdf before anything could inspect it.
329
+ const raw = await apiRequest(endpoint.method, apiPath, {
330
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
331
+ data,
332
+ contextName: flags.context,
333
+ binary: true,
334
+ });
335
+ const rawType = String(raw.headers['content-type'] || '').toLowerCase();
336
+ const rawData = raw.data;
337
+ const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
338
+ if (!isTextualMediaType(rawType)) {
339
+ if (process.stdout.isTTY) {
340
+ this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
341
+ }
342
+ // Nothing else may reach stdout here — it is the file.
343
+ process.stdout.write(buffer);
344
+ return;
345
+ }
346
+ response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
347
+ }
348
+ else {
349
+ response = await apiRequest(endpoint.method, apiPath, {
350
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
351
+ data,
352
+ contextName: flags.context,
353
+ acceptAny: true,
354
+ });
355
+ }
322
356
  // Check content-type for non-JSON responses (XML, text, etc.)
323
357
  const contentType = (response.headers['content-type'] || '').toLowerCase();
324
- if (contentType.includes('xml') || contentType.includes('text/')) {
358
+ if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
325
359
  // Output raw content for XML/text responses (CSV, plain, HTML, etc.)
326
360
  this.log(String(response.data));
327
361
  return;
@@ -348,11 +382,6 @@ export default class Employees extends Command {
348
382
  output = obj[arrayKeys[0]];
349
383
  }
350
384
  }
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
385
  // Sanitize output if requested
357
386
  if (flags.sanitize) {
358
387
  output = this.sanitizeOutput(output);
@@ -607,6 +636,8 @@ export default class Employees extends Command {
607
636
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
608
637
  if (flags.include)
609
638
  baseParams.include = flags.include;
639
+ if (flags.fields)
640
+ baseParams.fields = flags.fields;
610
641
  if (flags.query) {
611
642
  try {
612
643
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -661,12 +692,7 @@ export default class Employees extends Command {
661
692
  }
662
693
  }
663
694
  process.stderr.write(' done\n');
664
- // Filter fields if specified
665
695
  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
696
  // Sanitize output if requested
671
697
  if (flags.sanitize) {
672
698
  output = this.sanitizeOutput(output);
@@ -995,56 +1021,6 @@ export default class Employees extends Command {
995
1021
  return `\$${op}`;
996
1022
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
997
1023
  }
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
1024
  sanitizeOutput(data) {
1049
1025
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1050
1026
  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,5 +1,5 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
2
+ import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
3
3
  import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = false;
@@ -8,9 +8,9 @@ const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
9
  const SUBCOMMANDS = [...["list-entities", "get-entities", "update-entities"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
13
- 'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
11
+ 'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
12
+ 'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
13
+ 'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
14
  };
15
15
  export default class EntityConfigurations extends Command {
16
16
  static description = 'Manage entity configurations';
@@ -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
  };
@@ -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));
@@ -253,10 +255,11 @@ export default class EntityConfigurations extends Command {
253
255
  process.stderr.write('\n');
254
256
  }
255
257
  try {
256
- // Binary response: download to file
258
+ // Binary response: to -f / --file, or to stdout when it is redirected.
257
259
  if (endpoint.isBinaryResponse) {
258
- if (!flags.file) {
259
- this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
260
+ const toStdout = !flags.file;
261
+ if (toStdout && process.stdout.isTTY) {
262
+ this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
260
263
  }
261
264
  const binResponse = await apiRequest(endpoint.method, apiPath, {
262
265
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
@@ -264,24 +267,55 @@ export default class EntityConfigurations extends Command {
264
267
  contextName: flags.context,
265
268
  binary: true,
266
269
  });
267
- const fsModule = await import('node:fs');
268
270
  const binData = binResponse.data;
269
271
  const buffer = Buffer.isBuffer(binData)
270
272
  ? binData
271
273
  : Buffer.from(binData);
274
+ if (toStdout) {
275
+ // Nothing else may reach stdout here — it is the file.
276
+ process.stdout.write(buffer);
277
+ return;
278
+ }
279
+ const fsModule = await import('node:fs');
272
280
  fsModule.writeFileSync(flags.file, buffer);
273
281
  this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
274
282
  return;
275
283
  }
276
- const response = await apiRequest(endpoint.method, apiPath, {
277
- params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
278
- data,
279
- contextName: flags.context,
280
- acceptAny: true,
281
- });
284
+ let response;
285
+ if (endpoint.hasBinaryVariant) {
286
+ // This route answers JSON or a file depending on the request body, so the
287
+ // bytes are read first and the response's own content-type decides. Asking
288
+ // for text here would corrupt an xlsx/pdf before anything could inspect it.
289
+ const raw = await apiRequest(endpoint.method, apiPath, {
290
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
291
+ data,
292
+ contextName: flags.context,
293
+ binary: true,
294
+ });
295
+ const rawType = String(raw.headers['content-type'] || '').toLowerCase();
296
+ const rawData = raw.data;
297
+ const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
298
+ if (!isTextualMediaType(rawType)) {
299
+ if (process.stdout.isTTY) {
300
+ this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
301
+ }
302
+ // Nothing else may reach stdout here — it is the file.
303
+ process.stdout.write(buffer);
304
+ return;
305
+ }
306
+ response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
307
+ }
308
+ else {
309
+ response = await apiRequest(endpoint.method, apiPath, {
310
+ params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
311
+ data,
312
+ contextName: flags.context,
313
+ acceptAny: true,
314
+ });
315
+ }
282
316
  // Check content-type for non-JSON responses (XML, text, etc.)
283
317
  const contentType = (response.headers['content-type'] || '').toLowerCase();
284
- if (contentType.includes('xml') || contentType.includes('text/')) {
318
+ if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
285
319
  // Output raw content for XML/text responses (CSV, plain, HTML, etc.)
286
320
  this.log(String(response.data));
287
321
  return;
@@ -308,11 +342,6 @@ export default class EntityConfigurations extends Command {
308
342
  output = obj[arrayKeys[0]];
309
343
  }
310
344
  }
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
345
  // Sanitize output if requested
317
346
  if (flags.sanitize) {
318
347
  output = this.sanitizeOutput(output);
@@ -567,6 +596,8 @@ export default class EntityConfigurations extends Command {
567
596
  baseParams.sortBy = normalizeSortBy(flags['sort-by']);
568
597
  if (flags.include)
569
598
  baseParams.include = flags.include;
599
+ if (flags.fields)
600
+ baseParams.fields = flags.fields;
570
601
  if (flags.query) {
571
602
  try {
572
603
  Object.assign(baseParams, JSON.parse(flags.query));
@@ -621,12 +652,7 @@ export default class EntityConfigurations extends Command {
621
652
  }
622
653
  }
623
654
  process.stderr.write(' done\n');
624
- // Filter fields if specified
625
655
  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
656
  // Sanitize output if requested
631
657
  if (flags.sanitize) {
632
658
  output = this.sanitizeOutput(output);
@@ -955,56 +981,6 @@ export default class EntityConfigurations extends Command {
955
981
  return `\$${op}`;
956
982
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
957
983
  }
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
984
  sanitizeOutput(data) {
1009
985
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1010
986
  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;