@aderis-erp/cli 1.0.10 → 1.0.11

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 (63) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/access-groups.js +178 -86
  3. package/dist/commands/account-transaction-allocations.js +178 -86
  4. package/dist/commands/account-transactions.js +181 -87
  5. package/dist/commands/accounts.js +178 -86
  6. package/dist/commands/agent-runs.d.ts +1 -0
  7. package/dist/commands/agent-runs.js +183 -87
  8. package/dist/commands/audit-log.js +178 -86
  9. package/dist/commands/auth/login.js +4 -3
  10. package/dist/commands/bank-accounts.js +178 -86
  11. package/dist/commands/bank-integrations.js +178 -86
  12. package/dist/commands/business-partners.js +178 -86
  13. package/dist/commands/config/add.js +4 -3
  14. package/dist/commands/credit-card-accounts.js +178 -86
  15. package/dist/commands/documents.js +178 -86
  16. package/dist/commands/dunning-configs.js +180 -88
  17. package/dist/commands/dunning-reminders.js +178 -86
  18. package/dist/commands/dunning-runs.js +178 -86
  19. package/dist/commands/employees.js +180 -88
  20. package/dist/commands/entity-configurations.d.ts +40 -0
  21. package/dist/commands/entity-configurations.js +1169 -0
  22. package/dist/commands/event-processor-mappings.js +178 -86
  23. package/dist/commands/files-internal.js +178 -86
  24. package/dist/commands/health.js +178 -86
  25. package/dist/commands/inbox.js +181 -89
  26. package/dist/commands/integrations.js +178 -86
  27. package/dist/commands/item-categories.js +178 -86
  28. package/dist/commands/items.js +178 -86
  29. package/dist/commands/journal-lines.js +178 -86
  30. package/dist/commands/journals.js +178 -86
  31. package/dist/commands/ledgers.js +178 -86
  32. package/dist/commands/office-locations.js +178 -86
  33. package/dist/commands/payment-methods.js +178 -86
  34. package/dist/commands/payment-runs.js +178 -86
  35. package/dist/commands/payment-terms.js +178 -86
  36. package/dist/commands/price-lists.js +178 -86
  37. package/dist/commands/processor-mappings.js +178 -86
  38. package/dist/commands/processors.js +181 -87
  39. package/dist/commands/purchase-order-types.d.ts +40 -0
  40. package/dist/commands/purchase-order-types.js +1178 -0
  41. package/dist/commands/purchase-orders.d.ts +40 -0
  42. package/dist/commands/purchase-orders.js +1182 -0
  43. package/dist/commands/reports.js +178 -86
  44. package/dist/commands/salary-types.js +178 -86
  45. package/dist/commands/sales-invoices.js +178 -86
  46. package/dist/commands/sales-orders.js +182 -89
  47. package/dist/commands/saved-views.js +178 -86
  48. package/dist/commands/tags.js +178 -86
  49. package/dist/commands/tax-codes.js +178 -86
  50. package/dist/commands/tax-matrix.js +178 -86
  51. package/dist/commands/tenants.js +178 -86
  52. package/dist/commands/text-templates.js +178 -86
  53. package/dist/commands/tools.js +178 -86
  54. package/dist/commands/vat-declarations.d.ts +1 -0
  55. package/dist/commands/vat-declarations.js +188 -89
  56. package/dist/commands/vendor-invoices.js +178 -86
  57. package/dist/commands/webhooks.js +178 -86
  58. package/dist/commands/workflows.js +178 -86
  59. package/dist/lib/auth.js +2 -2
  60. package/dist/lib/config.d.ts +1 -1
  61. package/dist/lib/config.js +5 -0
  62. package/oclif.manifest.json +516 -9
  63. package/package.json +1 -1
package/README.md CHANGED
@@ -220,6 +220,7 @@ Configuration is stored in `~/.aderis/config.json`.
220
220
  |-------------|----------|---------|
221
221
  | dev | https://auth-dev.aderis.com | https://api-dev.aderis.com |
222
222
  | test | https://auth-test.aderis.com | https://api-test.aderis.com |
223
+ | staging | https://auth-staging.aderis.com | https://api-staging.aderis.com |
223
224
  | live | https://auth.aderis.com | https://api.aderis.com |
224
225
 
225
226
  ## Development
@@ -431,76 +431,126 @@ export default class AccessGroups extends Command {
431
431
  return '';
432
432
  };
433
433
  const results = [];
434
- for (const item of items) {
434
+ // Stream output row-by-row so progress is visible during long imports.
435
+ // Pre-compute the identifier column width from the input items so the
436
+ // table stays aligned without buffering all rows.
437
+ // When stdout is piped (IDE terminals, tee, CI), Node switches to async-buffered
438
+ // mode and rows accumulate in the pipe buffer until it fills. Force blocking
439
+ // mode so each \n-terminated write flushes immediately.
440
+ const stdoutHandle = process.stdout._handle;
441
+ if (stdoutHandle?.setBlocking)
442
+ stdoutHandle.setBlocking(true);
443
+ const outputFormat = flags.output || 'table';
444
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
445
+ const useJson = outputFormat === 'json';
446
+ const statusWidth = 8;
447
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
448
+ if (useCsv) {
449
+ this.log('status,identifier,id,error');
450
+ }
451
+ else if (!useJson) {
452
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
453
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
454
+ }
455
+ const emitRow = (r) => {
456
+ if (useJson)
457
+ return;
458
+ if (useCsv) {
459
+ const err = (r.error || '').replace(/"/g, '""');
460
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
461
+ }
462
+ else {
463
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
464
+ }
465
+ };
466
+ // Server-managed fields the API rejects in create/update bodies. Stripped
467
+ // before every request so re-importing a previously-exported payload Just Works.
468
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
469
+ const stripServerFields = (item) => {
470
+ const out = {};
471
+ for (const [k, v] of Object.entries(item)) {
472
+ if (!STRIP_FIELDS.has(k))
473
+ out[k] = v;
474
+ }
475
+ return out;
476
+ };
477
+ const processItem = async (item) => {
435
478
  const identifier = getItemIdentifier(item);
479
+ const body = stripServerFields(item);
480
+ // If the payload carries an id (e.g. re-importing an export), PATCH directly.
481
+ // Fall through to POST only on 404 (so a missing record still gets created).
482
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
483
+ if (itemId) {
484
+ try {
485
+ const updatePath = updateEndpoint.path.replace('{id}', itemId);
486
+ await apiRequest('PATCH', updatePath, {
487
+ data: body,
488
+ contextName: flags.context,
489
+ });
490
+ return { status: 'updated', id: itemId, identifier };
491
+ }
492
+ catch (error) {
493
+ if (!(error instanceof ApiError && error.status === 404)) {
494
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
495
+ return { status: 'error', id: itemId, identifier, error: msg };
496
+ }
497
+ // 404 → record gone, try create below
498
+ }
499
+ }
436
500
  try {
437
- // Try to create
438
501
  const response = await apiRequest('POST', createEndpoint.path, {
439
- data: item,
502
+ data: body,
440
503
  contextName: flags.context,
441
504
  });
442
505
  const id = response.data?.id;
443
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
506
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
444
507
  }
445
508
  catch (error) {
446
509
  if (error instanceof ApiError && error.status === 409) {
447
- // Conflict - try to update existing
448
510
  const errorData = error.data;
449
511
  const existingId = errorData?.existingId;
450
512
  if (existingId) {
451
513
  try {
452
514
  const updatePath = updateEndpoint.path.replace('{id}', existingId);
453
515
  await apiRequest('PATCH', updatePath, {
454
- data: item,
516
+ data: body,
455
517
  contextName: flags.context,
456
518
  });
457
- results.push({ status: 'updated', id: existingId, identifier });
519
+ return { status: 'updated', id: existingId, identifier };
458
520
  }
459
521
  catch (updateError) {
460
522
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
461
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
523
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
462
524
  }
463
525
  }
464
- else {
465
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
466
- }
467
- }
468
- else {
469
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
470
- results.push({ status: 'error', identifier, error: msg });
526
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
471
527
  }
528
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
529
+ return { status: 'error', identifier, error: msg };
472
530
  }
473
- }
531
+ };
532
+ // Worker pool: keep N requests in flight at all times. Rows are emitted as
533
+ // each request resolves (so output order may differ from input order). The
534
+ // summary at the end remains accurate regardless.
535
+ const concurrency = 4;
536
+ const queue = [...items];
537
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
538
+ for (;;) {
539
+ const item = queue.shift();
540
+ if (!item)
541
+ return;
542
+ const r = await processItem(item);
543
+ results.push(r);
544
+ emitRow(r);
545
+ }
546
+ }));
474
547
  // Summary counts
475
548
  const created = results.filter(r => r.status === 'created').length;
476
549
  const updated = results.filter(r => r.status === 'updated').length;
477
550
  const errors = results.filter(r => r.status === 'error');
478
- // Output results based on format (default: table)
479
- const outputFormat = flags.output || 'table';
480
- if (outputFormat === 'json') {
551
+ if (useJson) {
481
552
  this.log(JSON.stringify(results, null, 2));
482
553
  }
483
- else if (outputFormat === 'csv' || flags.csv) {
484
- // CSV output
485
- this.log('status,identifier,id,error');
486
- for (const r of results) {
487
- const err = (r.error || '').replace(/"/g, '""');
488
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
489
- }
490
- }
491
- else {
492
- // Table output (default)
493
- if (results.length > 0) {
494
- const statusWidth = 8;
495
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
496
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
497
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
498
- for (const r of results) {
499
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
500
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
501
- }
502
- }
503
- }
504
554
  // Always show summary at the end
505
555
  this.log('');
506
556
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
@@ -780,80 +830,122 @@ export default class AccessGroups extends Command {
780
830
  return '';
781
831
  };
782
832
  const results = [];
783
- for (const item of items) {
833
+ const stdoutHandle = process.stdout._handle;
834
+ if (stdoutHandle?.setBlocking)
835
+ stdoutHandle.setBlocking(true);
836
+ const outputFormat = flags.output || 'table';
837
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
838
+ const useJson = outputFormat === 'json';
839
+ const statusWidth = 8;
840
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
841
+ if (useCsv) {
842
+ this.log('status,identifier,id,error');
843
+ }
844
+ else if (!useJson) {
845
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
846
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
847
+ }
848
+ const emitRow = (r) => {
849
+ if (useJson)
850
+ return;
851
+ if (useCsv) {
852
+ const err = (r.error || '').replace(/"/g, '""');
853
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
854
+ }
855
+ else {
856
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
857
+ }
858
+ };
859
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
860
+ const stripServerFields = (item) => {
861
+ const out = {};
862
+ for (const [k, v] of Object.entries(item)) {
863
+ if (!STRIP_FIELDS.has(k))
864
+ out[k] = v;
865
+ }
866
+ return out;
867
+ };
868
+ const buildUpdatePath = (existingId) => {
869
+ const firstUpdateParam = updateEndpoint.pathParams[0];
870
+ const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
871
+ let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
872
+ if (nestedIdParam) {
873
+ updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
874
+ }
875
+ return updatePath;
876
+ };
877
+ const processItem = async (item) => {
784
878
  const identifier = getItemIdentifier(item);
879
+ const body = stripServerFields(item);
880
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
881
+ if (itemId) {
882
+ try {
883
+ await apiRequest('PATCH', buildUpdatePath(itemId), {
884
+ data: body,
885
+ contextName: flags.context,
886
+ });
887
+ return { status: 'updated', id: itemId, identifier };
888
+ }
889
+ catch (error) {
890
+ if (!(error instanceof ApiError && error.status === 404)) {
891
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
892
+ return { status: 'error', id: itemId, identifier, error: msg };
893
+ }
894
+ // 404 → fall through and try create
895
+ }
896
+ }
785
897
  try {
786
- // Try to create
787
898
  const response = await apiRequest('POST', basePath, {
788
- data: item,
899
+ data: body,
789
900
  contextName: flags.context,
790
901
  });
791
902
  const id = response.data?.id;
792
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
903
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
793
904
  }
794
905
  catch (error) {
795
906
  if (error instanceof ApiError && error.status === 409) {
796
- // Conflict - try to update existing
797
907
  const errorData = error.data;
798
908
  const existingId = errorData?.existingId || item.id;
799
909
  if (existingId) {
800
910
  try {
801
- // Find the nested ID param name (e.g., 'priceId' for prices)
802
- const firstUpdateParam = updateEndpoint.pathParams[0];
803
- const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
804
- let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
805
- if (nestedIdParam) {
806
- updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
807
- }
808
- await apiRequest('PATCH', updatePath, {
809
- data: item,
911
+ await apiRequest('PATCH', buildUpdatePath(existingId), {
912
+ data: body,
810
913
  contextName: flags.context,
811
914
  });
812
- results.push({ status: 'updated', id: existingId, identifier });
915
+ return { status: 'updated', id: existingId, identifier };
813
916
  }
814
917
  catch (updateError) {
815
918
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
816
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
919
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
817
920
  }
818
921
  }
819
- else {
820
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
821
- }
822
- }
823
- else {
824
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
825
- results.push({ status: 'error', identifier, error: msg });
922
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
826
923
  }
924
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
925
+ return { status: 'error', identifier, error: msg };
827
926
  }
828
- }
927
+ };
928
+ // Worker pool: 4 requests in flight at a time. Rows are emitted as each
929
+ // request resolves so output order may differ from input order.
930
+ const concurrency = 4;
931
+ const queue = [...items];
932
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
933
+ for (;;) {
934
+ const item = queue.shift();
935
+ if (!item)
936
+ return;
937
+ const r = await processItem(item);
938
+ results.push(r);
939
+ emitRow(r);
940
+ }
941
+ }));
829
942
  // Summary counts
830
943
  const created = results.filter(r => r.status === 'created').length;
831
944
  const updated = results.filter(r => r.status === 'updated').length;
832
945
  const errors = results.filter(r => r.status === 'error');
833
- // Output results based on format (default: table)
834
- const outputFormat = flags.output || 'table';
835
- if (outputFormat === 'json') {
946
+ if (useJson) {
836
947
  this.log(JSON.stringify(results, null, 2));
837
948
  }
838
- else if (outputFormat === 'csv' || flags.csv) {
839
- this.log('status,identifier,id,error');
840
- for (const r of results) {
841
- const err = (r.error || '').replace(/"/g, '""');
842
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
843
- }
844
- }
845
- else {
846
- if (results.length > 0) {
847
- const statusWidth = 8;
848
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
849
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
850
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
851
- for (const r of results) {
852
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
853
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
854
- }
855
- }
856
- }
857
949
  this.log('');
858
950
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
859
951
  }