@aderis-erp/cli 1.0.14 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -8
- package/dist/commands/access-groups.d.ts +0 -1
- package/dist/commands/access-groups.js +22 -78
- package/dist/commands/account-transaction-allocations.d.ts +0 -1
- package/dist/commands/account-transaction-allocations.js +22 -78
- package/dist/commands/account-transactions.d.ts +0 -1
- package/dist/commands/account-transactions.js +28 -82
- package/dist/commands/accounts.d.ts +0 -1
- package/dist/commands/accounts.js +24 -80
- package/dist/commands/agent-platform.d.ts +0 -1
- package/dist/commands/agent-platform.js +24 -79
- package/dist/commands/analytics.d.ts +39 -0
- package/dist/commands/analytics.js +1113 -0
- package/dist/commands/{documents.d.ts → api-keys.d.ts} +1 -2
- package/dist/commands/api-keys.js +1117 -0
- package/dist/commands/audit-log.d.ts +0 -1
- package/dist/commands/audit-log.js +22 -78
- package/dist/commands/auth/login.d.ts +9 -0
- package/dist/commands/auth/login.js +83 -21
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.js +23 -6
- package/dist/commands/auth/status.js +46 -23
- package/dist/commands/auth/tenant.js +15 -9
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +37 -51
- package/dist/commands/bank-accounts.d.ts +0 -1
- package/dist/commands/bank-accounts.js +22 -78
- package/dist/commands/bank-integrations.d.ts +0 -1
- package/dist/commands/bank-integrations.js +22 -78
- package/dist/commands/business-partners.d.ts +1 -1
- package/dist/commands/business-partners.js +38 -84
- package/dist/commands/chat.d.ts +0 -1
- package/dist/commands/chat.js +22 -78
- package/dist/commands/config/add.d.ts +12 -0
- package/dist/commands/config/add.js +97 -17
- package/dist/commands/config/current.js +12 -4
- package/dist/commands/config/list.js +12 -4
- package/dist/commands/config/set-api-key.d.ts +10 -0
- package/dist/commands/config/set-api-key.js +49 -0
- package/dist/commands/config/use.js +3 -4
- package/dist/commands/credit-card-accounts.d.ts +0 -1
- package/dist/commands/credit-card-accounts.js +22 -78
- package/dist/commands/delivery-notes.d.ts +0 -1
- package/dist/commands/delivery-notes.js +29 -84
- package/dist/commands/dunning-configs.d.ts +0 -1
- package/dist/commands/dunning-configs.js +22 -78
- package/dist/commands/dunning-reminders.d.ts +0 -1
- package/dist/commands/dunning-reminders.js +22 -78
- package/dist/commands/dunning-runs.d.ts +0 -1
- package/dist/commands/dunning-runs.js +22 -78
- package/dist/commands/email-transactions.d.ts +0 -1
- package/dist/commands/email-transactions.js +22 -78
- package/dist/commands/employees.d.ts +0 -1
- package/dist/commands/employees.js +24 -80
- package/dist/commands/entity-configurations.d.ts +0 -1
- package/dist/commands/entity-configurations.js +22 -78
- package/dist/commands/event-processor-mappings.d.ts +0 -1
- package/dist/commands/event-processor-mappings.js +22 -78
- package/dist/commands/{files-internal.d.ts → files.d.ts} +1 -2
- package/dist/commands/{files-internal.js → files.js} +40 -90
- package/dist/commands/health.d.ts +0 -1
- package/dist/commands/health.js +22 -78
- package/dist/commands/inbox.d.ts +0 -1
- package/dist/commands/inbox.js +22 -78
- package/dist/commands/integrations.d.ts +0 -1
- package/dist/commands/integrations.js +22 -78
- package/dist/commands/item-categories.d.ts +0 -1
- package/dist/commands/item-categories.js +22 -78
- package/dist/commands/items.d.ts +0 -1
- package/dist/commands/items.js +24 -80
- package/dist/commands/journal-lines.d.ts +0 -1
- package/dist/commands/journal-lines.js +22 -78
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.js +29 -81
- package/dist/commands/ledgers.d.ts +0 -1
- package/dist/commands/ledgers.js +26 -79
- package/dist/commands/nango-integrations.d.ts +39 -0
- package/dist/commands/nango-integrations.js +1115 -0
- package/dist/commands/office-locations.d.ts +0 -1
- package/dist/commands/office-locations.js +22 -78
- package/dist/commands/payment-methods.d.ts +0 -1
- package/dist/commands/payment-methods.js +22 -78
- package/dist/commands/payment-runs.d.ts +0 -1
- package/dist/commands/payment-runs.js +24 -79
- package/dist/commands/payment-terms.d.ts +0 -1
- package/dist/commands/payment-terms.js +22 -78
- package/dist/commands/payments.d.ts +0 -1
- package/dist/commands/payments.js +22 -78
- package/dist/commands/price-lists.d.ts +0 -1
- package/dist/commands/price-lists.js +22 -78
- package/dist/commands/processor-mappings.d.ts +0 -1
- package/dist/commands/processor-mappings.js +22 -78
- package/dist/commands/processors.d.ts +0 -1
- package/dist/commands/processors.js +22 -78
- package/dist/commands/purchase-order-types.d.ts +0 -1
- package/dist/commands/purchase-order-types.js +22 -78
- package/dist/commands/purchase-orders.d.ts +1 -1
- package/dist/commands/purchase-orders.js +35 -84
- package/dist/commands/reports.d.ts +0 -1
- package/dist/commands/reports.js +23 -79
- package/dist/commands/salary-types.d.ts +0 -1
- package/dist/commands/salary-types.js +22 -78
- package/dist/commands/sales-invoices.d.ts +0 -1
- package/dist/commands/sales-invoices.js +38 -89
- package/dist/commands/sales-orders.d.ts +0 -1
- package/dist/commands/sales-orders.js +26 -82
- package/dist/commands/saved-views.d.ts +0 -1
- package/dist/commands/saved-views.js +22 -78
- package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
- package/dist/commands/scheduled-processor-mappings.js +22 -78
- package/dist/commands/schedules.d.ts +0 -1
- package/dist/commands/schedules.js +22 -78
- package/dist/commands/switch.js +14 -7
- package/dist/commands/tag-configurations.d.ts +39 -0
- package/dist/commands/{documents.js → tag-configurations.js} +40 -96
- package/dist/commands/tags.d.ts +0 -1
- package/dist/commands/tags.js +22 -78
- package/dist/commands/tax-codes.d.ts +0 -1
- package/dist/commands/tax-codes.js +22 -78
- package/dist/commands/tax-matrix.d.ts +0 -1
- package/dist/commands/tax-matrix.js +22 -78
- package/dist/commands/tenants.d.ts +0 -1
- package/dist/commands/tenants.js +24 -79
- package/dist/commands/text-templates.d.ts +0 -1
- package/dist/commands/text-templates.js +22 -78
- package/dist/commands/tools.d.ts +0 -1
- package/dist/commands/tools.js +22 -78
- package/dist/commands/vat-declarations.d.ts +1 -1
- package/dist/commands/vat-declarations.js +28 -79
- package/dist/commands/vendor-invoices.d.ts +0 -1
- package/dist/commands/vendor-invoices.js +31 -86
- package/dist/commands/webhooks.d.ts +0 -1
- package/dist/commands/webhooks.js +22 -78
- package/dist/commands/workflows.d.ts +0 -1
- package/dist/commands/workflows.js +22 -78
- package/dist/lib/api-client.js +8 -6
- package/dist/lib/auth/constants.d.ts +11 -0
- package/dist/lib/auth/constants.js +11 -0
- package/dist/lib/auth/errors.d.ts +17 -0
- package/dist/lib/auth/errors.js +22 -0
- package/dist/lib/auth/flow.d.ts +27 -0
- package/dist/lib/auth/flow.js +163 -0
- package/dist/lib/auth/guards.d.ts +5 -0
- package/dist/lib/auth/guards.js +14 -0
- package/dist/lib/auth/http.d.ts +16 -0
- package/dist/lib/auth/http.js +49 -0
- package/dist/lib/auth/index.d.ts +49 -0
- package/dist/lib/auth/index.js +217 -0
- package/dist/lib/auth/keycloak-provider.d.ts +75 -0
- package/dist/lib/auth/keycloak-provider.js +215 -0
- package/dist/lib/auth/pages.d.ts +25 -0
- package/dist/lib/auth/pages.js +123 -0
- package/dist/lib/auth/pkce.d.ts +11 -0
- package/dist/lib/auth/pkce.js +17 -0
- package/dist/lib/auth/tokens.d.ts +54 -0
- package/dist/lib/auth/tokens.js +104 -0
- package/dist/lib/auth/types.d.ts +57 -0
- package/dist/lib/auth/types.js +1 -0
- package/dist/lib/auth/validated-url.d.ts +6 -0
- package/dist/lib/auth/validated-url.js +53 -0
- package/dist/lib/base-api-command.js +6 -4
- package/dist/lib/config.d.ts +44 -4
- package/dist/lib/config.js +55 -19
- package/oclif.manifest.json +1181 -330
- package/package.json +3 -2
- package/dist/lib/auth.d.ts +0 -35
- package/dist/lib/auth.js +0 -566
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -29,7 +29,7 @@ export default class DunningConfigs extends Command {
|
|
|
29
29
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
30
30
|
};
|
|
31
31
|
static flags = {
|
|
32
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
32
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
33
33
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
34
34
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
35
35
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -43,7 +43,7 @@ export default class DunningConfigs extends Command {
|
|
|
43
43
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
44
44
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
45
45
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
46
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
46
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
47
47
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
48
48
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
49
|
};
|
|
@@ -101,9 +101,9 @@ export default class DunningConfigs extends Command {
|
|
|
101
101
|
}
|
|
102
102
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
103
103
|
if (!context)
|
|
104
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
105
|
-
if (!context
|
|
106
|
-
this.error(
|
|
104
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
105
|
+
if (!hasCredentials(context))
|
|
106
|
+
this.error(missingCredentialsMessage(context));
|
|
107
107
|
const queryParams = {};
|
|
108
108
|
if (flags.page)
|
|
109
109
|
queryParams.page = flags.page;
|
|
@@ -115,6 +115,8 @@ export default class DunningConfigs extends Command {
|
|
|
115
115
|
queryParams.search = flags.search;
|
|
116
116
|
if (flags['sort-by'])
|
|
117
117
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
118
|
+
if (flags.fields)
|
|
119
|
+
queryParams.fields = flags.fields;
|
|
118
120
|
if (flags.query) {
|
|
119
121
|
try {
|
|
120
122
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -317,11 +319,6 @@ export default class DunningConfigs extends Command {
|
|
|
317
319
|
output = obj[arrayKeys[0]];
|
|
318
320
|
}
|
|
319
321
|
}
|
|
320
|
-
// Filter fields if --fields flag is provided
|
|
321
|
-
if (flags.fields) {
|
|
322
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
323
|
-
output = this.filterFields(output, fieldList);
|
|
324
|
-
}
|
|
325
322
|
// Sanitize output if requested
|
|
326
323
|
if (flags.sanitize) {
|
|
327
324
|
output = this.sanitizeOutput(output);
|
|
@@ -346,9 +343,9 @@ export default class DunningConfigs extends Command {
|
|
|
346
343
|
async runImport(flags) {
|
|
347
344
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
348
345
|
if (!context)
|
|
349
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
350
|
-
if (!context
|
|
351
|
-
this.error(
|
|
346
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
347
|
+
if (!hasCredentials(context))
|
|
348
|
+
this.error(missingCredentialsMessage(context));
|
|
352
349
|
// Get data from file, --data, or --set flags
|
|
353
350
|
let items = [];
|
|
354
351
|
if (flags.file) {
|
|
@@ -558,9 +555,9 @@ export default class DunningConfigs extends Command {
|
|
|
558
555
|
async runExport(flags) {
|
|
559
556
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
560
557
|
if (!context)
|
|
561
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
562
|
-
if (!context
|
|
563
|
-
this.error(
|
|
558
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
559
|
+
if (!hasCredentials(context))
|
|
560
|
+
this.error(missingCredentialsMessage(context));
|
|
564
561
|
const listEndpoint = ENDPOINTS['list'];
|
|
565
562
|
if (!listEndpoint)
|
|
566
563
|
this.error('Export requires a list endpoint');
|
|
@@ -576,6 +573,8 @@ export default class DunningConfigs extends Command {
|
|
|
576
573
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
577
574
|
if (flags.include)
|
|
578
575
|
baseParams.include = flags.include;
|
|
576
|
+
if (flags.fields)
|
|
577
|
+
baseParams.fields = flags.fields;
|
|
579
578
|
if (flags.query) {
|
|
580
579
|
try {
|
|
581
580
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -630,12 +629,7 @@ export default class DunningConfigs extends Command {
|
|
|
630
629
|
}
|
|
631
630
|
}
|
|
632
631
|
process.stderr.write(' done\n');
|
|
633
|
-
// Filter fields if specified
|
|
634
632
|
let output = allItems;
|
|
635
|
-
if (flags.fields) {
|
|
636
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
637
|
-
output = this.filterFields(allItems, fieldList);
|
|
638
|
-
}
|
|
639
633
|
// Sanitize output if requested
|
|
640
634
|
if (flags.sanitize) {
|
|
641
635
|
output = this.sanitizeOutput(output);
|
|
@@ -652,9 +646,9 @@ export default class DunningConfigs extends Command {
|
|
|
652
646
|
async runCamt053Import(flags) {
|
|
653
647
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
654
648
|
if (!context)
|
|
655
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
656
|
-
if (!context
|
|
657
|
-
this.error(
|
|
649
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
650
|
+
if (!hasCredentials(context))
|
|
651
|
+
this.error(missingCredentialsMessage(context));
|
|
658
652
|
if (!flags.file) {
|
|
659
653
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
660
654
|
}
|
|
@@ -742,9 +736,9 @@ export default class DunningConfigs extends Command {
|
|
|
742
736
|
}
|
|
743
737
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
744
738
|
if (!context)
|
|
745
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
746
|
-
if (!context
|
|
747
|
-
this.error(
|
|
739
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
740
|
+
if (!hasCredentials(context))
|
|
741
|
+
this.error(missingCredentialsMessage(context));
|
|
748
742
|
// Get data from file, --data, or --set flags
|
|
749
743
|
let items = [];
|
|
750
744
|
if (flags.file) {
|
|
@@ -964,56 +958,6 @@ export default class DunningConfigs extends Command {
|
|
|
964
958
|
return `\$${op}`;
|
|
965
959
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
966
960
|
}
|
|
967
|
-
filterFields(data, fields) {
|
|
968
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
969
|
-
const pick = (obj, keys) => {
|
|
970
|
-
// Group keys by their first segment so sibling sub-paths
|
|
971
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
972
|
-
// and don't clobber each other on merge.
|
|
973
|
-
const directKeys = new Set();
|
|
974
|
-
const nestedKeys = new Map();
|
|
975
|
-
for (const key of keys) {
|
|
976
|
-
if (key.split('.').some(isUnsafeKey))
|
|
977
|
-
continue;
|
|
978
|
-
if (key.includes('.')) {
|
|
979
|
-
const [first, ...rest] = key.split('.');
|
|
980
|
-
if (isUnsafeKey(first))
|
|
981
|
-
continue;
|
|
982
|
-
const list = nestedKeys.get(first);
|
|
983
|
-
if (list) {
|
|
984
|
-
list.push(rest.join('.'));
|
|
985
|
-
}
|
|
986
|
-
else {
|
|
987
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
else {
|
|
991
|
-
directKeys.add(key);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
const result = {};
|
|
995
|
-
for (const key of directKeys) {
|
|
996
|
-
if (key in obj)
|
|
997
|
-
result[key] = obj[key];
|
|
998
|
-
}
|
|
999
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1000
|
-
const val = obj[first];
|
|
1001
|
-
if (!val || typeof val !== 'object')
|
|
1002
|
-
continue;
|
|
1003
|
-
if (Array.isArray(val)) {
|
|
1004
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1005
|
-
}
|
|
1006
|
-
else {
|
|
1007
|
-
result[first] = pick(val, restKeys);
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
return result;
|
|
1011
|
-
};
|
|
1012
|
-
if (Array.isArray(data)) {
|
|
1013
|
-
return data.map(item => pick(item, fields));
|
|
1014
|
-
}
|
|
1015
|
-
return pick(data, fields);
|
|
1016
|
-
}
|
|
1017
961
|
sanitizeOutput(data) {
|
|
1018
962
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1019
963
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -30,7 +30,7 @@ export default class DunningReminders extends Command {
|
|
|
30
30
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
31
31
|
};
|
|
32
32
|
static flags = {
|
|
33
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
33
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
34
34
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
35
35
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
36
36
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -44,7 +44,7 @@ export default class DunningReminders extends Command {
|
|
|
44
44
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
45
45
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
46
46
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
47
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
47
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
48
48
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
49
49
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
50
50
|
};
|
|
@@ -102,9 +102,9 @@ export default class DunningReminders extends Command {
|
|
|
102
102
|
}
|
|
103
103
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
104
104
|
if (!context)
|
|
105
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
106
|
-
if (!context
|
|
107
|
-
this.error(
|
|
105
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
106
|
+
if (!hasCredentials(context))
|
|
107
|
+
this.error(missingCredentialsMessage(context));
|
|
108
108
|
const queryParams = {};
|
|
109
109
|
if (flags.page)
|
|
110
110
|
queryParams.page = flags.page;
|
|
@@ -116,6 +116,8 @@ export default class DunningReminders extends Command {
|
|
|
116
116
|
queryParams.search = flags.search;
|
|
117
117
|
if (flags['sort-by'])
|
|
118
118
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
119
|
+
if (flags.fields)
|
|
120
|
+
queryParams.fields = flags.fields;
|
|
119
121
|
if (flags.query) {
|
|
120
122
|
try {
|
|
121
123
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -318,11 +320,6 @@ export default class DunningReminders extends Command {
|
|
|
318
320
|
output = obj[arrayKeys[0]];
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
|
-
// Filter fields if --fields flag is provided
|
|
322
|
-
if (flags.fields) {
|
|
323
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
324
|
-
output = this.filterFields(output, fieldList);
|
|
325
|
-
}
|
|
326
323
|
// Sanitize output if requested
|
|
327
324
|
if (flags.sanitize) {
|
|
328
325
|
output = this.sanitizeOutput(output);
|
|
@@ -347,9 +344,9 @@ export default class DunningReminders extends Command {
|
|
|
347
344
|
async runImport(flags) {
|
|
348
345
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
349
346
|
if (!context)
|
|
350
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
351
|
-
if (!context
|
|
352
|
-
this.error(
|
|
347
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
348
|
+
if (!hasCredentials(context))
|
|
349
|
+
this.error(missingCredentialsMessage(context));
|
|
353
350
|
// Get data from file, --data, or --set flags
|
|
354
351
|
let items = [];
|
|
355
352
|
if (flags.file) {
|
|
@@ -559,9 +556,9 @@ export default class DunningReminders extends Command {
|
|
|
559
556
|
async runExport(flags) {
|
|
560
557
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
561
558
|
if (!context)
|
|
562
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
563
|
-
if (!context
|
|
564
|
-
this.error(
|
|
559
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
560
|
+
if (!hasCredentials(context))
|
|
561
|
+
this.error(missingCredentialsMessage(context));
|
|
565
562
|
const listEndpoint = ENDPOINTS['list'];
|
|
566
563
|
if (!listEndpoint)
|
|
567
564
|
this.error('Export requires a list endpoint');
|
|
@@ -577,6 +574,8 @@ export default class DunningReminders extends Command {
|
|
|
577
574
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
578
575
|
if (flags.include)
|
|
579
576
|
baseParams.include = flags.include;
|
|
577
|
+
if (flags.fields)
|
|
578
|
+
baseParams.fields = flags.fields;
|
|
580
579
|
if (flags.query) {
|
|
581
580
|
try {
|
|
582
581
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -631,12 +630,7 @@ export default class DunningReminders extends Command {
|
|
|
631
630
|
}
|
|
632
631
|
}
|
|
633
632
|
process.stderr.write(' done\n');
|
|
634
|
-
// Filter fields if specified
|
|
635
633
|
let output = allItems;
|
|
636
|
-
if (flags.fields) {
|
|
637
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
638
|
-
output = this.filterFields(allItems, fieldList);
|
|
639
|
-
}
|
|
640
634
|
// Sanitize output if requested
|
|
641
635
|
if (flags.sanitize) {
|
|
642
636
|
output = this.sanitizeOutput(output);
|
|
@@ -653,9 +647,9 @@ export default class DunningReminders extends Command {
|
|
|
653
647
|
async runCamt053Import(flags) {
|
|
654
648
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
655
649
|
if (!context)
|
|
656
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
657
|
-
if (!context
|
|
658
|
-
this.error(
|
|
650
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
651
|
+
if (!hasCredentials(context))
|
|
652
|
+
this.error(missingCredentialsMessage(context));
|
|
659
653
|
if (!flags.file) {
|
|
660
654
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
661
655
|
}
|
|
@@ -743,9 +737,9 @@ export default class DunningReminders extends Command {
|
|
|
743
737
|
}
|
|
744
738
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
745
739
|
if (!context)
|
|
746
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
747
|
-
if (!context
|
|
748
|
-
this.error(
|
|
740
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
741
|
+
if (!hasCredentials(context))
|
|
742
|
+
this.error(missingCredentialsMessage(context));
|
|
749
743
|
// Get data from file, --data, or --set flags
|
|
750
744
|
let items = [];
|
|
751
745
|
if (flags.file) {
|
|
@@ -965,56 +959,6 @@ export default class DunningReminders extends Command {
|
|
|
965
959
|
return `\$${op}`;
|
|
966
960
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
967
961
|
}
|
|
968
|
-
filterFields(data, fields) {
|
|
969
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
970
|
-
const pick = (obj, keys) => {
|
|
971
|
-
// Group keys by their first segment so sibling sub-paths
|
|
972
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
973
|
-
// and don't clobber each other on merge.
|
|
974
|
-
const directKeys = new Set();
|
|
975
|
-
const nestedKeys = new Map();
|
|
976
|
-
for (const key of keys) {
|
|
977
|
-
if (key.split('.').some(isUnsafeKey))
|
|
978
|
-
continue;
|
|
979
|
-
if (key.includes('.')) {
|
|
980
|
-
const [first, ...rest] = key.split('.');
|
|
981
|
-
if (isUnsafeKey(first))
|
|
982
|
-
continue;
|
|
983
|
-
const list = nestedKeys.get(first);
|
|
984
|
-
if (list) {
|
|
985
|
-
list.push(rest.join('.'));
|
|
986
|
-
}
|
|
987
|
-
else {
|
|
988
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
else {
|
|
992
|
-
directKeys.add(key);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
const result = {};
|
|
996
|
-
for (const key of directKeys) {
|
|
997
|
-
if (key in obj)
|
|
998
|
-
result[key] = obj[key];
|
|
999
|
-
}
|
|
1000
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1001
|
-
const val = obj[first];
|
|
1002
|
-
if (!val || typeof val !== 'object')
|
|
1003
|
-
continue;
|
|
1004
|
-
if (Array.isArray(val)) {
|
|
1005
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1006
|
-
}
|
|
1007
|
-
else {
|
|
1008
|
-
result[first] = pick(val, restKeys);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
return result;
|
|
1012
|
-
};
|
|
1013
|
-
if (Array.isArray(data)) {
|
|
1014
|
-
return data.map(item => pick(item, fields));
|
|
1015
|
-
}
|
|
1016
|
-
return pick(data, fields);
|
|
1017
|
-
}
|
|
1018
962
|
sanitizeOutput(data) {
|
|
1019
963
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1020
964
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = false;
|
|
@@ -18,7 +18,7 @@ export default class DunningRuns extends Command {
|
|
|
18
18
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
19
19
|
};
|
|
20
20
|
static flags = {
|
|
21
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
21
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
22
22
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
23
23
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
24
24
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -32,7 +32,7 @@ export default class DunningRuns extends Command {
|
|
|
32
32
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
33
33
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
34
34
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
35
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
35
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
36
36
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
37
37
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
38
38
|
};
|
|
@@ -90,9 +90,9 @@ export default class DunningRuns extends Command {
|
|
|
90
90
|
}
|
|
91
91
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
92
92
|
if (!context)
|
|
93
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
94
|
-
if (!context
|
|
95
|
-
this.error(
|
|
93
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
94
|
+
if (!hasCredentials(context))
|
|
95
|
+
this.error(missingCredentialsMessage(context));
|
|
96
96
|
const queryParams = {};
|
|
97
97
|
if (flags.page)
|
|
98
98
|
queryParams.page = flags.page;
|
|
@@ -104,6 +104,8 @@ export default class DunningRuns extends Command {
|
|
|
104
104
|
queryParams.search = flags.search;
|
|
105
105
|
if (flags['sort-by'])
|
|
106
106
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
107
|
+
if (flags.fields)
|
|
108
|
+
queryParams.fields = flags.fields;
|
|
107
109
|
if (flags.query) {
|
|
108
110
|
try {
|
|
109
111
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -306,11 +308,6 @@ export default class DunningRuns extends Command {
|
|
|
306
308
|
output = obj[arrayKeys[0]];
|
|
307
309
|
}
|
|
308
310
|
}
|
|
309
|
-
// Filter fields if --fields flag is provided
|
|
310
|
-
if (flags.fields) {
|
|
311
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
312
|
-
output = this.filterFields(output, fieldList);
|
|
313
|
-
}
|
|
314
311
|
// Sanitize output if requested
|
|
315
312
|
if (flags.sanitize) {
|
|
316
313
|
output = this.sanitizeOutput(output);
|
|
@@ -335,9 +332,9 @@ export default class DunningRuns extends Command {
|
|
|
335
332
|
async runImport(flags) {
|
|
336
333
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
337
334
|
if (!context)
|
|
338
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
339
|
-
if (!context
|
|
340
|
-
this.error(
|
|
335
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
336
|
+
if (!hasCredentials(context))
|
|
337
|
+
this.error(missingCredentialsMessage(context));
|
|
341
338
|
// Get data from file, --data, or --set flags
|
|
342
339
|
let items = [];
|
|
343
340
|
if (flags.file) {
|
|
@@ -547,9 +544,9 @@ export default class DunningRuns extends Command {
|
|
|
547
544
|
async runExport(flags) {
|
|
548
545
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
549
546
|
if (!context)
|
|
550
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
551
|
-
if (!context
|
|
552
|
-
this.error(
|
|
547
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
548
|
+
if (!hasCredentials(context))
|
|
549
|
+
this.error(missingCredentialsMessage(context));
|
|
553
550
|
const listEndpoint = ENDPOINTS['list'];
|
|
554
551
|
if (!listEndpoint)
|
|
555
552
|
this.error('Export requires a list endpoint');
|
|
@@ -565,6 +562,8 @@ export default class DunningRuns extends Command {
|
|
|
565
562
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
566
563
|
if (flags.include)
|
|
567
564
|
baseParams.include = flags.include;
|
|
565
|
+
if (flags.fields)
|
|
566
|
+
baseParams.fields = flags.fields;
|
|
568
567
|
if (flags.query) {
|
|
569
568
|
try {
|
|
570
569
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -619,12 +618,7 @@ export default class DunningRuns extends Command {
|
|
|
619
618
|
}
|
|
620
619
|
}
|
|
621
620
|
process.stderr.write(' done\n');
|
|
622
|
-
// Filter fields if specified
|
|
623
621
|
let output = allItems;
|
|
624
|
-
if (flags.fields) {
|
|
625
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
626
|
-
output = this.filterFields(allItems, fieldList);
|
|
627
|
-
}
|
|
628
622
|
// Sanitize output if requested
|
|
629
623
|
if (flags.sanitize) {
|
|
630
624
|
output = this.sanitizeOutput(output);
|
|
@@ -641,9 +635,9 @@ export default class DunningRuns extends Command {
|
|
|
641
635
|
async runCamt053Import(flags) {
|
|
642
636
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
643
637
|
if (!context)
|
|
644
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
645
|
-
if (!context
|
|
646
|
-
this.error(
|
|
638
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
639
|
+
if (!hasCredentials(context))
|
|
640
|
+
this.error(missingCredentialsMessage(context));
|
|
647
641
|
if (!flags.file) {
|
|
648
642
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
649
643
|
}
|
|
@@ -731,9 +725,9 @@ export default class DunningRuns extends Command {
|
|
|
731
725
|
}
|
|
732
726
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
733
727
|
if (!context)
|
|
734
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
735
|
-
if (!context
|
|
736
|
-
this.error(
|
|
728
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
729
|
+
if (!hasCredentials(context))
|
|
730
|
+
this.error(missingCredentialsMessage(context));
|
|
737
731
|
// Get data from file, --data, or --set flags
|
|
738
732
|
let items = [];
|
|
739
733
|
if (flags.file) {
|
|
@@ -953,56 +947,6 @@ export default class DunningRuns extends Command {
|
|
|
953
947
|
return `\$${op}`;
|
|
954
948
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
955
949
|
}
|
|
956
|
-
filterFields(data, fields) {
|
|
957
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
958
|
-
const pick = (obj, keys) => {
|
|
959
|
-
// Group keys by their first segment so sibling sub-paths
|
|
960
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
961
|
-
// and don't clobber each other on merge.
|
|
962
|
-
const directKeys = new Set();
|
|
963
|
-
const nestedKeys = new Map();
|
|
964
|
-
for (const key of keys) {
|
|
965
|
-
if (key.split('.').some(isUnsafeKey))
|
|
966
|
-
continue;
|
|
967
|
-
if (key.includes('.')) {
|
|
968
|
-
const [first, ...rest] = key.split('.');
|
|
969
|
-
if (isUnsafeKey(first))
|
|
970
|
-
continue;
|
|
971
|
-
const list = nestedKeys.get(first);
|
|
972
|
-
if (list) {
|
|
973
|
-
list.push(rest.join('.'));
|
|
974
|
-
}
|
|
975
|
-
else {
|
|
976
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
directKeys.add(key);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
const result = {};
|
|
984
|
-
for (const key of directKeys) {
|
|
985
|
-
if (key in obj)
|
|
986
|
-
result[key] = obj[key];
|
|
987
|
-
}
|
|
988
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
989
|
-
const val = obj[first];
|
|
990
|
-
if (!val || typeof val !== 'object')
|
|
991
|
-
continue;
|
|
992
|
-
if (Array.isArray(val)) {
|
|
993
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
994
|
-
}
|
|
995
|
-
else {
|
|
996
|
-
result[first] = pick(val, restKeys);
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
return result;
|
|
1000
|
-
};
|
|
1001
|
-
if (Array.isArray(data)) {
|
|
1002
|
-
return data.map(item => pick(item, fields));
|
|
1003
|
-
}
|
|
1004
|
-
return pick(data, fields);
|
|
1005
|
-
}
|
|
1006
950
|
sanitizeOutput(data) {
|
|
1007
951
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1008
952
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|