@aderis-erp/cli 1.1.0 → 1.1.2

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 (152) hide show
  1. package/dist/commands/access-groups.d.ts +8 -0
  2. package/dist/commands/access-groups.js +56 -8
  3. package/dist/commands/account-transaction-allocations.d.ts +8 -0
  4. package/dist/commands/account-transaction-allocations.js +52 -5
  5. package/dist/commands/account-transactions.d.ts +8 -0
  6. package/dist/commands/account-transactions.js +55 -7
  7. package/dist/commands/accounts.d.ts +8 -0
  8. package/dist/commands/accounts.js +52 -5
  9. package/dist/commands/agent-platform.d.ts +8 -0
  10. package/dist/commands/agent-platform.js +52 -5
  11. package/dist/commands/agent-runs.d.ts +8 -0
  12. package/dist/commands/agent-runs.js +52 -5
  13. package/dist/commands/analytics.d.ts +8 -0
  14. package/dist/commands/analytics.js +52 -5
  15. package/dist/commands/api-keys.d.ts +8 -0
  16. package/dist/commands/api-keys.js +52 -5
  17. package/dist/commands/async-jobs.d.ts +8 -0
  18. package/dist/commands/async-jobs.js +52 -5
  19. package/dist/commands/audit-log.d.ts +8 -0
  20. package/dist/commands/audit-log.js +52 -5
  21. package/dist/commands/bank-accounts.d.ts +8 -0
  22. package/dist/commands/bank-accounts.js +52 -5
  23. package/dist/commands/bank-integrations.d.ts +8 -0
  24. package/dist/commands/bank-integrations.js +52 -5
  25. package/dist/commands/business-partners.d.ts +9 -0
  26. package/dist/commands/business-partners.js +66 -9
  27. package/dist/commands/chat.d.ts +8 -0
  28. package/dist/commands/chat.js +52 -5
  29. package/dist/commands/credit-card-accounts.d.ts +8 -0
  30. package/dist/commands/credit-card-accounts.js +52 -5
  31. package/dist/commands/delivery-notes.d.ts +8 -0
  32. package/dist/commands/delivery-notes.js +52 -5
  33. package/dist/commands/dunning-configs.d.ts +8 -0
  34. package/dist/commands/dunning-configs.js +52 -5
  35. package/dist/commands/dunning-reminders.d.ts +8 -0
  36. package/dist/commands/dunning-reminders.js +52 -5
  37. package/dist/commands/dunning-runs.d.ts +8 -0
  38. package/dist/commands/dunning-runs.js +52 -5
  39. package/dist/commands/email-transactions.d.ts +8 -0
  40. package/dist/commands/email-transactions.js +52 -5
  41. package/dist/commands/employees.d.ts +8 -0
  42. package/dist/commands/employees.js +52 -5
  43. package/dist/commands/entity-configurations.d.ts +8 -0
  44. package/dist/commands/entity-configurations.js +52 -5
  45. package/dist/commands/event-processor-mappings.d.ts +8 -0
  46. package/dist/commands/event-processor-mappings.js +52 -5
  47. package/dist/commands/files.d.ts +8 -0
  48. package/dist/commands/files.js +53 -6
  49. package/dist/commands/health.d.ts +8 -0
  50. package/dist/commands/health.js +52 -5
  51. package/dist/commands/imports.d.ts +8 -0
  52. package/dist/commands/imports.js +53 -8
  53. package/dist/commands/inbox.d.ts +8 -0
  54. package/dist/commands/inbox.js +53 -7
  55. package/dist/commands/integration-identities.d.ts +8 -0
  56. package/dist/commands/integration-identities.js +52 -5
  57. package/dist/commands/integrations.d.ts +8 -0
  58. package/dist/commands/integrations.js +52 -5
  59. package/dist/commands/item-categories.d.ts +8 -0
  60. package/dist/commands/item-categories.js +52 -5
  61. package/dist/commands/items.d.ts +8 -0
  62. package/dist/commands/items.js +52 -5
  63. package/dist/commands/journal-lines.d.ts +8 -0
  64. package/dist/commands/journal-lines.js +52 -5
  65. package/dist/commands/journals.d.ts +8 -0
  66. package/dist/commands/journals.js +52 -5
  67. package/dist/commands/ledgers.d.ts +8 -0
  68. package/dist/commands/ledgers.js +57 -9
  69. package/dist/commands/my-account.d.ts +8 -0
  70. package/dist/commands/my-account.js +52 -5
  71. package/dist/commands/office-locations.d.ts +8 -0
  72. package/dist/commands/office-locations.js +52 -5
  73. package/dist/commands/payment-methods.d.ts +8 -0
  74. package/dist/commands/payment-methods.js +52 -5
  75. package/dist/commands/payment-runs.d.ts +8 -0
  76. package/dist/commands/payment-runs.js +54 -6
  77. package/dist/commands/payment-terms.d.ts +8 -0
  78. package/dist/commands/payment-terms.js +52 -5
  79. package/dist/commands/payments.d.ts +8 -0
  80. package/dist/commands/payments.js +52 -5
  81. package/dist/commands/payroll-runs.d.ts +8 -0
  82. package/dist/commands/payroll-runs.js +52 -5
  83. package/dist/commands/permissions.d.ts +8 -0
  84. package/dist/commands/permissions.js +52 -5
  85. package/dist/commands/price-lists.d.ts +8 -0
  86. package/dist/commands/price-lists.js +52 -5
  87. package/dist/commands/processor-mappings.d.ts +8 -0
  88. package/dist/commands/processor-mappings.js +52 -5
  89. package/dist/commands/processors.d.ts +8 -0
  90. package/dist/commands/processors.js +52 -5
  91. package/dist/commands/purchase-order-types.d.ts +8 -0
  92. package/dist/commands/purchase-order-types.js +52 -5
  93. package/dist/commands/purchase-orders.d.ts +8 -0
  94. package/dist/commands/purchase-orders.js +52 -5
  95. package/dist/commands/reports.d.ts +8 -0
  96. package/dist/commands/reports.js +52 -5
  97. package/dist/commands/roles.d.ts +8 -0
  98. package/dist/commands/roles.js +52 -5
  99. package/dist/commands/salary-types.d.ts +8 -0
  100. package/dist/commands/salary-types.js +52 -5
  101. package/dist/commands/sales-invoices.d.ts +10 -0
  102. package/dist/commands/sales-invoices.js +62 -6
  103. package/dist/commands/sales-orders.d.ts +8 -0
  104. package/dist/commands/sales-orders.js +52 -5
  105. package/dist/commands/saved-views.d.ts +8 -0
  106. package/dist/commands/saved-views.js +52 -5
  107. package/dist/commands/scheduled-processor-mappings.d.ts +8 -0
  108. package/dist/commands/scheduled-processor-mappings.js +52 -5
  109. package/dist/commands/schedules.d.ts +8 -0
  110. package/dist/commands/schedules.js +52 -5
  111. package/dist/commands/support/end.d.ts +9 -0
  112. package/dist/commands/support/end.js +29 -0
  113. package/dist/commands/support/start.d.ts +14 -0
  114. package/dist/commands/support/start.js +50 -0
  115. package/dist/commands/support/status.d.ts +10 -0
  116. package/dist/commands/support/status.js +45 -0
  117. package/dist/commands/support/tenants.d.ts +10 -0
  118. package/dist/commands/support/tenants.js +39 -0
  119. package/dist/commands/tags.d.ts +8 -0
  120. package/dist/commands/tags.js +56 -8
  121. package/dist/commands/tax-codes.d.ts +8 -0
  122. package/dist/commands/tax-codes.js +52 -5
  123. package/dist/commands/tax-matrix.d.ts +8 -0
  124. package/dist/commands/tax-matrix.js +52 -5
  125. package/dist/commands/templates.d.ts +8 -0
  126. package/dist/commands/templates.js +52 -5
  127. package/dist/commands/tenants.d.ts +8 -0
  128. package/dist/commands/tenants.js +52 -5
  129. package/dist/commands/tools.d.ts +8 -0
  130. package/dist/commands/tools.js +52 -5
  131. package/dist/commands/users.d.ts +8 -0
  132. package/dist/commands/users.js +52 -5
  133. package/dist/commands/vat-declarations.d.ts +8 -0
  134. package/dist/commands/vat-declarations.js +52 -5
  135. package/dist/commands/vendor-invoices.d.ts +9 -0
  136. package/dist/commands/vendor-invoices.js +60 -8
  137. package/dist/commands/webhooks.d.ts +8 -0
  138. package/dist/commands/webhooks.js +52 -5
  139. package/dist/commands/workflows.d.ts +8 -0
  140. package/dist/commands/workflows.js +52 -5
  141. package/dist/lib/auth/constants.d.ts +12 -0
  142. package/dist/lib/auth/constants.js +12 -0
  143. package/dist/lib/auth/index.d.ts +11 -1
  144. package/dist/lib/auth/index.js +90 -2
  145. package/dist/lib/auth/keycloak-provider.d.ts +22 -0
  146. package/dist/lib/auth/keycloak-provider.js +108 -3
  147. package/dist/lib/config.d.ts +18 -0
  148. package/dist/lib/config.js +10 -0
  149. package/oclif.manifest.json +640 -216
  150. package/package.json +4 -1
  151. package/dist/commands/tag-configurations.d.ts +0 -39
  152. package/dist/commands/tag-configurations.js +0 -1155
@@ -23,6 +23,7 @@ export default class AccessGroups extends Command {
23
23
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
24
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
25
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
27
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
28
  };
28
29
  run(): Promise<void>;
@@ -31,6 +32,13 @@ export default class AccessGroups extends Command {
31
32
  private runCamt053Import;
32
33
  private runNestedImport;
33
34
  private parseFilterValue;
35
+ /** The page line under a table: which page, how many, and any sums the API returned. */
36
+ private printPageSummary;
37
+ /**
38
+ * The API caps how many records a page may hold. Asking for more and getting
39
+ * fewer looks like "that is everything" unless it is said out loud.
40
+ */
41
+ private warnShortPage;
34
42
  private sanitizeOutput;
35
43
  private getColumns;
36
44
  private getValue;
@@ -6,12 +6,13 @@ const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
- const SUBCOMMANDS = [...["list", "create", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["list", "create", "list-summaries", "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/access-groups', summary: 'List access groups (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/access-groups', summary: 'Create a new access group', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'employeeIds'] },
12
+ 'create': { method: 'POST', path: '/v1/access-groups', summary: 'Create a new access group', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
13
+ 'list-summaries': { method: 'GET', path: '/v1/access-groups/summaries', summary: 'List access groups without members (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
13
14
  'get': { method: 'GET', path: '/v1/access-groups/{id}', summary: 'Get a single access group by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/access-groups/{id}', summary: 'Update an existing access group', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'employeeIds'] },
15
+ 'update': { method: 'PATCH', path: '/v1/access-groups/{id}', summary: 'Update an existing access group', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
15
16
  'delete': { method: 'DELETE', path: '/v1/access-groups/{id}', summary: 'Delete an access group', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
16
17
  };
17
18
  export default class AccessGroups extends Command {
@@ -45,6 +46,7 @@ export default class AccessGroups extends Command {
45
46
  query: Flags.string({ description: 'Additional query params as JSON' }),
46
47
  fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
47
48
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
49
+ meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
48
50
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
49
51
  };
50
52
  async run() {
@@ -337,9 +339,15 @@ export default class AccessGroups extends Command {
337
339
  }
338
340
  catch { /* keep as string */ }
339
341
  }
340
- // Extract data array from paginated wrapper (e.g., { data: [...], total: 3 })
342
+ // A paginated answer is { data, meta, links, totals }. The records are
343
+ // unwrapped for output, but what the API said about the page is kept:
344
+ // dropping it silently let a script read one page as the whole result
345
+ // (AderisERP/product#61).
346
+ let envelope;
341
347
  if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
342
- output = output.data;
348
+ const page = output;
349
+ envelope = page;
350
+ output = page.data;
343
351
  }
344
352
  // For table/csv on non-array responses, auto-extract the primary array
345
353
  // e.g., { payments: [...], total: 3 } → extract payments array
@@ -356,12 +364,24 @@ export default class AccessGroups extends Command {
356
364
  output = this.sanitizeOutput(output);
357
365
  }
358
366
  const fieldList = flags.fields?.split(',').map(f => f.trim());
359
- if (flags.csv || flags.output === 'csv')
367
+ if (envelope)
368
+ this.warnShortPage(envelope, flags.limit);
369
+ if (flags.csv || flags.output === 'csv') {
360
370
  this.printCsv(output, fieldList);
361
- else if (flags.table || flags.output === 'table')
371
+ }
372
+ else if (flags.table || flags.output === 'table') {
362
373
  this.printTable(output, fieldList);
363
- else
374
+ if (envelope)
375
+ this.printPageSummary(envelope);
376
+ }
377
+ else if (envelope && flags.meta) {
378
+ // The whole envelope, for a caller that asked for it; the default stays
379
+ // a bare array so existing scripts are unaffected.
380
+ this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
381
+ }
382
+ else {
364
383
  this.log(JSON.stringify(output, null, 2));
384
+ }
365
385
  }
366
386
  catch (error) {
367
387
  if (error instanceof ApiError) {
@@ -990,6 +1010,34 @@ export default class AccessGroups extends Command {
990
1010
  return `\$${op}`;
991
1011
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
992
1012
  }
1013
+ /** The page line under a table: which page, how many, and any sums the API returned. */
1014
+ printPageSummary(envelope) {
1015
+ const meta = envelope.meta;
1016
+ if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
1017
+ const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
1018
+ this.log(`
1019
+ Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
1020
+ }
1021
+ for (const total of envelope.totals ?? []) {
1022
+ const { currency, ...sums } = total;
1023
+ const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
1024
+ this.log(`Total ${currency ?? ''}: ${parts}`.trim());
1025
+ }
1026
+ }
1027
+ /**
1028
+ * The API caps how many records a page may hold. Asking for more and getting
1029
+ * fewer looks like "that is everything" unless it is said out loud.
1030
+ */
1031
+ warnShortPage(envelope, requestedLimit) {
1032
+ const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
1033
+ const perPage = envelope.meta?.itemsPerPage;
1034
+ if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
1035
+ return;
1036
+ const pages = envelope.meta?.totalPages;
1037
+ const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
1038
+ process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
1039
+ `);
1040
+ }
993
1041
  sanitizeOutput(data) {
994
1042
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
995
1043
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -23,6 +23,7 @@ export default class AccountTransactionAllocations extends Command {
23
23
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
24
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
25
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
27
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
28
  };
28
29
  run(): Promise<void>;
@@ -31,6 +32,13 @@ export default class AccountTransactionAllocations extends Command {
31
32
  private runCamt053Import;
32
33
  private runNestedImport;
33
34
  private parseFilterValue;
35
+ /** The page line under a table: which page, how many, and any sums the API returned. */
36
+ private printPageSummary;
37
+ /**
38
+ * The API caps how many records a page may hold. Asking for more and getting
39
+ * fewer looks like "that is everything" unless it is said out loud.
40
+ */
41
+ private warnShortPage;
34
42
  private sanitizeOutput;
35
43
  private getColumns;
36
44
  private getValue;
@@ -39,6 +39,7 @@ export default class AccountTransactionAllocations extends Command {
39
39
  query: Flags.string({ description: 'Additional query params as JSON' }),
40
40
  fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
41
41
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
42
+ meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
42
43
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
43
44
  };
44
45
  async run() {
@@ -331,9 +332,15 @@ export default class AccountTransactionAllocations extends Command {
331
332
  }
332
333
  catch { /* keep as string */ }
333
334
  }
334
- // Extract data array from paginated wrapper (e.g., { data: [...], total: 3 })
335
+ // A paginated answer is { data, meta, links, totals }. The records are
336
+ // unwrapped for output, but what the API said about the page is kept:
337
+ // dropping it silently let a script read one page as the whole result
338
+ // (AderisERP/product#61).
339
+ let envelope;
335
340
  if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
336
- output = output.data;
341
+ const page = output;
342
+ envelope = page;
343
+ output = page.data;
337
344
  }
338
345
  // For table/csv on non-array responses, auto-extract the primary array
339
346
  // e.g., { payments: [...], total: 3 } → extract payments array
@@ -350,12 +357,24 @@ export default class AccountTransactionAllocations extends Command {
350
357
  output = this.sanitizeOutput(output);
351
358
  }
352
359
  const fieldList = flags.fields?.split(',').map(f => f.trim());
353
- if (flags.csv || flags.output === 'csv')
360
+ if (envelope)
361
+ this.warnShortPage(envelope, flags.limit);
362
+ if (flags.csv || flags.output === 'csv') {
354
363
  this.printCsv(output, fieldList);
355
- else if (flags.table || flags.output === 'table')
364
+ }
365
+ else if (flags.table || flags.output === 'table') {
356
366
  this.printTable(output, fieldList);
357
- else
367
+ if (envelope)
368
+ this.printPageSummary(envelope);
369
+ }
370
+ else if (envelope && flags.meta) {
371
+ // The whole envelope, for a caller that asked for it; the default stays
372
+ // a bare array so existing scripts are unaffected.
373
+ this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
374
+ }
375
+ else {
358
376
  this.log(JSON.stringify(output, null, 2));
377
+ }
359
378
  }
360
379
  catch (error) {
361
380
  if (error instanceof ApiError) {
@@ -984,6 +1003,34 @@ export default class AccountTransactionAllocations extends Command {
984
1003
  return `\$${op}`;
985
1004
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
986
1005
  }
1006
+ /** The page line under a table: which page, how many, and any sums the API returned. */
1007
+ printPageSummary(envelope) {
1008
+ const meta = envelope.meta;
1009
+ if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
1010
+ const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
1011
+ this.log(`
1012
+ Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
1013
+ }
1014
+ for (const total of envelope.totals ?? []) {
1015
+ const { currency, ...sums } = total;
1016
+ const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
1017
+ this.log(`Total ${currency ?? ''}: ${parts}`.trim());
1018
+ }
1019
+ }
1020
+ /**
1021
+ * The API caps how many records a page may hold. Asking for more and getting
1022
+ * fewer looks like "that is everything" unless it is said out loud.
1023
+ */
1024
+ warnShortPage(envelope, requestedLimit) {
1025
+ const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
1026
+ const perPage = envelope.meta?.itemsPerPage;
1027
+ if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
1028
+ return;
1029
+ const pages = envelope.meta?.totalPages;
1030
+ const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
1031
+ process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
1032
+ `);
1033
+ }
987
1034
  sanitizeOutput(data) {
988
1035
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
989
1036
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -25,6 +25,7 @@ export default class AccountTransactions extends Command {
25
25
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
26
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
27
27
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
29
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
29
30
  };
30
31
  run(): Promise<void>;
@@ -33,6 +34,13 @@ export default class AccountTransactions extends Command {
33
34
  private runCamt053Import;
34
35
  private runNestedImport;
35
36
  private parseFilterValue;
37
+ /** The page line under a table: which page, how many, and any sums the API returned. */
38
+ private printPageSummary;
39
+ /**
40
+ * The API caps how many records a page may hold. Asking for more and getting
41
+ * fewer looks like "that is everything" unless it is said out loud.
42
+ */
43
+ private warnShortPage;
36
44
  private sanitizeOutput;
37
45
  private getColumns;
38
46
  private getValue;
@@ -6,12 +6,13 @@ const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = true;
8
8
  const NESTED_IMPORTS = ["allocations", "allocations-notes", "notes"];
9
- const SUBCOMMANDS = [...["retry-booking", "recover-booking", "list", "create", "get", "update", "delete", "reconcile", "allocations-reprocess-unbooked", "allocations-unbooked", "list-allocations", "create-allocations", "get-allocations", "update-allocations", "delete-allocations", "list-allocations-settlement-accounts", "allocations-confirm", "import", "import-camt053", "list-allocations-notes", "create-allocations-notes", "get-allocations-notes", "update-allocations-notes", "delete-allocations-notes", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["retry-booking", "recover-booking", "list", "create", "status-counts", "get", "update", "delete", "reconcile", "allocations-reprocess-unbooked", "allocations-unbooked", "list-allocations", "create-allocations", "get-allocations", "update-allocations", "delete-allocations", "list-allocations-settlement-accounts", "allocations-confirm", "import", "import-camt053", "list-allocations-notes", "create-allocations-notes", "get-allocations-notes", "update-allocations-notes", "delete-allocations-notes", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'retry-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/retry-booking', summary: 'Retry complete booking of an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
12
12
  'recover-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/recover-booking', summary: 'Verify existing accounting and book missing entries together', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
13
13
  'list': { method: 'GET', path: '/v1/account-transactions', summary: 'Get all account transactions with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
14
14
  'create': { method: 'POST', path: '/v1/account-transactions', summary: 'Create a new account transaction', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
15
+ 'status-counts': { method: 'GET', path: '/v1/account-transactions/status-counts', summary: 'Count account transactions per reconciliation status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
15
16
  'get': { method: 'GET', path: '/v1/account-transactions/{id}', summary: 'Get an account transaction by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
16
17
  'update': { method: 'PATCH', path: '/v1/account-transactions/{id}', summary: 'Update an account transaction', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
17
18
  'delete': { method: 'DELETE', path: '/v1/account-transactions/{id}', summary: 'Delete an account transaction', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
@@ -25,7 +26,7 @@ const ENDPOINTS = {
25
26
  'delete-allocations': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Delete an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
26
27
  'list-allocations-settlement-accounts': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/settlement-accounts', summary: 'Which account each ledger would settle the allocated document against', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
27
28
  'allocations-confirm': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/confirm', summary: 'Confirm an allocation (transition from REVIEW to CONFIRMED)', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['counterAccounts'] },
28
- 'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import a batch of account transactions', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['transactions'] },
29
+ 'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import account transactions', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
29
30
  'import-camt053': { method: 'POST', path: '/v1/account-transactions/import/camt053', summary: 'Import CAMT.053 bank statement (ISO 20022 format)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
30
31
  'list-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Get all notes for an allocation', pathParams: ['allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
31
32
  'create-allocations-notes': { method: 'POST', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Create a note for an allocation', pathParams: ['allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
@@ -71,6 +72,7 @@ export default class AccountTransactions extends Command {
71
72
  query: Flags.string({ description: 'Additional query params as JSON' }),
72
73
  fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
73
74
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
75
+ meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
74
76
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
75
77
  };
76
78
  async run() {
@@ -363,9 +365,15 @@ export default class AccountTransactions extends Command {
363
365
  }
364
366
  catch { /* keep as string */ }
365
367
  }
366
- // Extract data array from paginated wrapper (e.g., { data: [...], total: 3 })
368
+ // A paginated answer is { data, meta, links, totals }. The records are
369
+ // unwrapped for output, but what the API said about the page is kept:
370
+ // dropping it silently let a script read one page as the whole result
371
+ // (AderisERP/product#61).
372
+ let envelope;
367
373
  if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
368
- output = output.data;
374
+ const page = output;
375
+ envelope = page;
376
+ output = page.data;
369
377
  }
370
378
  // For table/csv on non-array responses, auto-extract the primary array
371
379
  // e.g., { payments: [...], total: 3 } → extract payments array
@@ -382,12 +390,24 @@ export default class AccountTransactions extends Command {
382
390
  output = this.sanitizeOutput(output);
383
391
  }
384
392
  const fieldList = flags.fields?.split(',').map(f => f.trim());
385
- if (flags.csv || flags.output === 'csv')
393
+ if (envelope)
394
+ this.warnShortPage(envelope, flags.limit);
395
+ if (flags.csv || flags.output === 'csv') {
386
396
  this.printCsv(output, fieldList);
387
- else if (flags.table || flags.output === 'table')
397
+ }
398
+ else if (flags.table || flags.output === 'table') {
388
399
  this.printTable(output, fieldList);
389
- else
400
+ if (envelope)
401
+ this.printPageSummary(envelope);
402
+ }
403
+ else if (envelope && flags.meta) {
404
+ // The whole envelope, for a caller that asked for it; the default stays
405
+ // a bare array so existing scripts are unaffected.
406
+ this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
407
+ }
408
+ else {
390
409
  this.log(JSON.stringify(output, null, 2));
410
+ }
391
411
  }
392
412
  catch (error) {
393
413
  if (error instanceof ApiError) {
@@ -1016,6 +1036,34 @@ export default class AccountTransactions extends Command {
1016
1036
  return `\$${op}`;
1017
1037
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
1018
1038
  }
1039
+ /** The page line under a table: which page, how many, and any sums the API returned. */
1040
+ printPageSummary(envelope) {
1041
+ const meta = envelope.meta;
1042
+ if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
1043
+ const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
1044
+ this.log(`
1045
+ Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
1046
+ }
1047
+ for (const total of envelope.totals ?? []) {
1048
+ const { currency, ...sums } = total;
1049
+ const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
1050
+ this.log(`Total ${currency ?? ''}: ${parts}`.trim());
1051
+ }
1052
+ }
1053
+ /**
1054
+ * The API caps how many records a page may hold. Asking for more and getting
1055
+ * fewer looks like "that is everything" unless it is said out loud.
1056
+ */
1057
+ warnShortPage(envelope, requestedLimit) {
1058
+ const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
1059
+ const perPage = envelope.meta?.itemsPerPage;
1060
+ if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
1061
+ return;
1062
+ const pages = envelope.meta?.totalPages;
1063
+ const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
1064
+ process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
1065
+ `);
1066
+ }
1019
1067
  sanitizeOutput(data) {
1020
1068
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1021
1069
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -24,6 +24,7 @@ export default class Accounts extends Command {
24
24
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
25
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
26
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
28
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
29
  };
29
30
  run(): Promise<void>;
@@ -32,6 +33,13 @@ export default class Accounts extends Command {
32
33
  private runCamt053Import;
33
34
  private runNestedImport;
34
35
  private parseFilterValue;
36
+ /** The page line under a table: which page, how many, and any sums the API returned. */
37
+ private printPageSummary;
38
+ /**
39
+ * The API caps how many records a page may hold. Asking for more and getting
40
+ * fewer looks like "that is everything" unless it is said out loud.
41
+ */
42
+ private warnShortPage;
35
43
  private sanitizeOutput;
36
44
  private getColumns;
37
45
  private getValue;
@@ -51,6 +51,7 @@ export default class Accounts extends Command {
51
51
  query: Flags.string({ description: 'Additional query params as JSON' }),
52
52
  fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
53
53
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
54
+ meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
54
55
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
55
56
  };
56
57
  async run() {
@@ -343,9 +344,15 @@ export default class Accounts extends Command {
343
344
  }
344
345
  catch { /* keep as string */ }
345
346
  }
346
- // Extract data array from paginated wrapper (e.g., { data: [...], total: 3 })
347
+ // A paginated answer is { data, meta, links, totals }. The records are
348
+ // unwrapped for output, but what the API said about the page is kept:
349
+ // dropping it silently let a script read one page as the whole result
350
+ // (AderisERP/product#61).
351
+ let envelope;
347
352
  if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
348
- output = output.data;
353
+ const page = output;
354
+ envelope = page;
355
+ output = page.data;
349
356
  }
350
357
  // For table/csv on non-array responses, auto-extract the primary array
351
358
  // e.g., { payments: [...], total: 3 } → extract payments array
@@ -362,12 +369,24 @@ export default class Accounts extends Command {
362
369
  output = this.sanitizeOutput(output);
363
370
  }
364
371
  const fieldList = flags.fields?.split(',').map(f => f.trim());
365
- if (flags.csv || flags.output === 'csv')
372
+ if (envelope)
373
+ this.warnShortPage(envelope, flags.limit);
374
+ if (flags.csv || flags.output === 'csv') {
366
375
  this.printCsv(output, fieldList);
367
- else if (flags.table || flags.output === 'table')
376
+ }
377
+ else if (flags.table || flags.output === 'table') {
368
378
  this.printTable(output, fieldList);
369
- else
379
+ if (envelope)
380
+ this.printPageSummary(envelope);
381
+ }
382
+ else if (envelope && flags.meta) {
383
+ // The whole envelope, for a caller that asked for it; the default stays
384
+ // a bare array so existing scripts are unaffected.
385
+ this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
386
+ }
387
+ else {
370
388
  this.log(JSON.stringify(output, null, 2));
389
+ }
371
390
  }
372
391
  catch (error) {
373
392
  if (error instanceof ApiError) {
@@ -996,6 +1015,34 @@ export default class Accounts extends Command {
996
1015
  return `\$${op}`;
997
1016
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
998
1017
  }
1018
+ /** The page line under a table: which page, how many, and any sums the API returned. */
1019
+ printPageSummary(envelope) {
1020
+ const meta = envelope.meta;
1021
+ if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
1022
+ const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
1023
+ this.log(`
1024
+ Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
1025
+ }
1026
+ for (const total of envelope.totals ?? []) {
1027
+ const { currency, ...sums } = total;
1028
+ const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
1029
+ this.log(`Total ${currency ?? ''}: ${parts}`.trim());
1030
+ }
1031
+ }
1032
+ /**
1033
+ * The API caps how many records a page may hold. Asking for more and getting
1034
+ * fewer looks like "that is everything" unless it is said out loud.
1035
+ */
1036
+ warnShortPage(envelope, requestedLimit) {
1037
+ const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
1038
+ const perPage = envelope.meta?.itemsPerPage;
1039
+ if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
1040
+ return;
1041
+ const pages = envelope.meta?.totalPages;
1042
+ const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
1043
+ process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
1044
+ `);
1045
+ }
999
1046
  sanitizeOutput(data) {
1000
1047
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
1001
1048
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -24,6 +24,7 @@ export default class AgentPlatform extends Command {
24
24
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
25
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
26
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
28
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
29
  };
29
30
  run(): Promise<void>;
@@ -32,6 +33,13 @@ export default class AgentPlatform extends Command {
32
33
  private runCamt053Import;
33
34
  private runNestedImport;
34
35
  private parseFilterValue;
36
+ /** The page line under a table: which page, how many, and any sums the API returned. */
37
+ private printPageSummary;
38
+ /**
39
+ * The API caps how many records a page may hold. Asking for more and getting
40
+ * fewer looks like "that is everything" unless it is said out loud.
41
+ */
42
+ private warnShortPage;
35
43
  private sanitizeOutput;
36
44
  private getColumns;
37
45
  private getValue;
@@ -43,6 +43,7 @@ export default class AgentPlatform extends Command {
43
43
  query: Flags.string({ description: 'Additional query params as JSON' }),
44
44
  fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
45
45
  sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
46
+ meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
46
47
  'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
47
48
  };
48
49
  async run() {
@@ -335,9 +336,15 @@ export default class AgentPlatform extends Command {
335
336
  }
336
337
  catch { /* keep as string */ }
337
338
  }
338
- // Extract data array from paginated wrapper (e.g., { data: [...], total: 3 })
339
+ // A paginated answer is { data, meta, links, totals }. The records are
340
+ // unwrapped for output, but what the API said about the page is kept:
341
+ // dropping it silently let a script read one page as the whole result
342
+ // (AderisERP/product#61).
343
+ let envelope;
339
344
  if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
340
- output = output.data;
345
+ const page = output;
346
+ envelope = page;
347
+ output = page.data;
341
348
  }
342
349
  // For table/csv on non-array responses, auto-extract the primary array
343
350
  // e.g., { payments: [...], total: 3 } → extract payments array
@@ -354,12 +361,24 @@ export default class AgentPlatform extends Command {
354
361
  output = this.sanitizeOutput(output);
355
362
  }
356
363
  const fieldList = flags.fields?.split(',').map(f => f.trim());
357
- if (flags.csv || flags.output === 'csv')
364
+ if (envelope)
365
+ this.warnShortPage(envelope, flags.limit);
366
+ if (flags.csv || flags.output === 'csv') {
358
367
  this.printCsv(output, fieldList);
359
- else if (flags.table || flags.output === 'table')
368
+ }
369
+ else if (flags.table || flags.output === 'table') {
360
370
  this.printTable(output, fieldList);
361
- else
371
+ if (envelope)
372
+ this.printPageSummary(envelope);
373
+ }
374
+ else if (envelope && flags.meta) {
375
+ // The whole envelope, for a caller that asked for it; the default stays
376
+ // a bare array so existing scripts are unaffected.
377
+ this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
378
+ }
379
+ else {
362
380
  this.log(JSON.stringify(output, null, 2));
381
+ }
363
382
  }
364
383
  catch (error) {
365
384
  if (error instanceof ApiError) {
@@ -988,6 +1007,34 @@ export default class AgentPlatform extends Command {
988
1007
  return `\$${op}`;
989
1008
  return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
990
1009
  }
1010
+ /** The page line under a table: which page, how many, and any sums the API returned. */
1011
+ printPageSummary(envelope) {
1012
+ const meta = envelope.meta;
1013
+ if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
1014
+ const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
1015
+ this.log(`
1016
+ Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
1017
+ }
1018
+ for (const total of envelope.totals ?? []) {
1019
+ const { currency, ...sums } = total;
1020
+ const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
1021
+ this.log(`Total ${currency ?? ''}: ${parts}`.trim());
1022
+ }
1023
+ }
1024
+ /**
1025
+ * The API caps how many records a page may hold. Asking for more and getting
1026
+ * fewer looks like "that is everything" unless it is said out loud.
1027
+ */
1028
+ warnShortPage(envelope, requestedLimit) {
1029
+ const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
1030
+ const perPage = envelope.meta?.itemsPerPage;
1031
+ if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
1032
+ return;
1033
+ const pages = envelope.meta?.totalPages;
1034
+ const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
1035
+ process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
1036
+ `);
1037
+ }
991
1038
  sanitizeOutput(data) {
992
1039
  const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
993
1040
  const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -23,6 +23,7 @@ export default class AgentRuns extends Command {
23
23
  query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
24
  fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
25
  sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
27
  'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
28
  };
28
29
  run(): Promise<void>;
@@ -31,6 +32,13 @@ export default class AgentRuns extends Command {
31
32
  private runCamt053Import;
32
33
  private runNestedImport;
33
34
  private parseFilterValue;
35
+ /** The page line under a table: which page, how many, and any sums the API returned. */
36
+ private printPageSummary;
37
+ /**
38
+ * The API caps how many records a page may hold. Asking for more and getting
39
+ * fewer looks like "that is everything" unless it is said out loud.
40
+ */
41
+ private warnShortPage;
34
42
  private sanitizeOutput;
35
43
  private getColumns;
36
44
  private getValue;