@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;
|
|
@@ -30,7 +30,7 @@ export default class PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 PaymentTerms 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 = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -31,7 +31,7 @@ export default class Payments extends Command {
|
|
|
31
31
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
32
32
|
};
|
|
33
33
|
static flags = {
|
|
34
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
34
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
35
35
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
36
36
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
37
37
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -45,7 +45,7 @@ export default class Payments extends Command {
|
|
|
45
45
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
46
46
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
47
47
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
48
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
48
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
49
49
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
50
50
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
51
51
|
};
|
|
@@ -103,9 +103,9 @@ export default class Payments extends Command {
|
|
|
103
103
|
}
|
|
104
104
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
105
105
|
if (!context)
|
|
106
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
107
|
-
if (!context
|
|
108
|
-
this.error(
|
|
106
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
107
|
+
if (!hasCredentials(context))
|
|
108
|
+
this.error(missingCredentialsMessage(context));
|
|
109
109
|
const queryParams = {};
|
|
110
110
|
if (flags.page)
|
|
111
111
|
queryParams.page = flags.page;
|
|
@@ -117,6 +117,8 @@ export default class Payments extends Command {
|
|
|
117
117
|
queryParams.search = flags.search;
|
|
118
118
|
if (flags['sort-by'])
|
|
119
119
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
120
|
+
if (flags.fields)
|
|
121
|
+
queryParams.fields = flags.fields;
|
|
120
122
|
if (flags.query) {
|
|
121
123
|
try {
|
|
122
124
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -319,11 +321,6 @@ export default class Payments extends Command {
|
|
|
319
321
|
output = obj[arrayKeys[0]];
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
// Filter fields if --fields flag is provided
|
|
323
|
-
if (flags.fields) {
|
|
324
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
325
|
-
output = this.filterFields(output, fieldList);
|
|
326
|
-
}
|
|
327
324
|
// Sanitize output if requested
|
|
328
325
|
if (flags.sanitize) {
|
|
329
326
|
output = this.sanitizeOutput(output);
|
|
@@ -348,9 +345,9 @@ export default class Payments extends Command {
|
|
|
348
345
|
async runImport(flags) {
|
|
349
346
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
350
347
|
if (!context)
|
|
351
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
352
|
-
if (!context
|
|
353
|
-
this.error(
|
|
348
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
349
|
+
if (!hasCredentials(context))
|
|
350
|
+
this.error(missingCredentialsMessage(context));
|
|
354
351
|
// Get data from file, --data, or --set flags
|
|
355
352
|
let items = [];
|
|
356
353
|
if (flags.file) {
|
|
@@ -560,9 +557,9 @@ export default class Payments extends Command {
|
|
|
560
557
|
async runExport(flags) {
|
|
561
558
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
562
559
|
if (!context)
|
|
563
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
564
|
-
if (!context
|
|
565
|
-
this.error(
|
|
560
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
561
|
+
if (!hasCredentials(context))
|
|
562
|
+
this.error(missingCredentialsMessage(context));
|
|
566
563
|
const listEndpoint = ENDPOINTS['list'];
|
|
567
564
|
if (!listEndpoint)
|
|
568
565
|
this.error('Export requires a list endpoint');
|
|
@@ -578,6 +575,8 @@ export default class Payments extends Command {
|
|
|
578
575
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
579
576
|
if (flags.include)
|
|
580
577
|
baseParams.include = flags.include;
|
|
578
|
+
if (flags.fields)
|
|
579
|
+
baseParams.fields = flags.fields;
|
|
581
580
|
if (flags.query) {
|
|
582
581
|
try {
|
|
583
582
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -632,12 +631,7 @@ export default class Payments extends Command {
|
|
|
632
631
|
}
|
|
633
632
|
}
|
|
634
633
|
process.stderr.write(' done\n');
|
|
635
|
-
// Filter fields if specified
|
|
636
634
|
let output = allItems;
|
|
637
|
-
if (flags.fields) {
|
|
638
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
639
|
-
output = this.filterFields(allItems, fieldList);
|
|
640
|
-
}
|
|
641
635
|
// Sanitize output if requested
|
|
642
636
|
if (flags.sanitize) {
|
|
643
637
|
output = this.sanitizeOutput(output);
|
|
@@ -654,9 +648,9 @@ export default class Payments extends Command {
|
|
|
654
648
|
async runCamt053Import(flags) {
|
|
655
649
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
656
650
|
if (!context)
|
|
657
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
658
|
-
if (!context
|
|
659
|
-
this.error(
|
|
651
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
652
|
+
if (!hasCredentials(context))
|
|
653
|
+
this.error(missingCredentialsMessage(context));
|
|
660
654
|
if (!flags.file) {
|
|
661
655
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
662
656
|
}
|
|
@@ -744,9 +738,9 @@ export default class Payments extends Command {
|
|
|
744
738
|
}
|
|
745
739
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
746
740
|
if (!context)
|
|
747
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
748
|
-
if (!context
|
|
749
|
-
this.error(
|
|
741
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
742
|
+
if (!hasCredentials(context))
|
|
743
|
+
this.error(missingCredentialsMessage(context));
|
|
750
744
|
// Get data from file, --data, or --set flags
|
|
751
745
|
let items = [];
|
|
752
746
|
if (flags.file) {
|
|
@@ -966,56 +960,6 @@ export default class Payments extends Command {
|
|
|
966
960
|
return `\$${op}`;
|
|
967
961
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
968
962
|
}
|
|
969
|
-
filterFields(data, fields) {
|
|
970
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
971
|
-
const pick = (obj, keys) => {
|
|
972
|
-
// Group keys by their first segment so sibling sub-paths
|
|
973
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
974
|
-
// and don't clobber each other on merge.
|
|
975
|
-
const directKeys = new Set();
|
|
976
|
-
const nestedKeys = new Map();
|
|
977
|
-
for (const key of keys) {
|
|
978
|
-
if (key.split('.').some(isUnsafeKey))
|
|
979
|
-
continue;
|
|
980
|
-
if (key.includes('.')) {
|
|
981
|
-
const [first, ...rest] = key.split('.');
|
|
982
|
-
if (isUnsafeKey(first))
|
|
983
|
-
continue;
|
|
984
|
-
const list = nestedKeys.get(first);
|
|
985
|
-
if (list) {
|
|
986
|
-
list.push(rest.join('.'));
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
directKeys.add(key);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
const result = {};
|
|
997
|
-
for (const key of directKeys) {
|
|
998
|
-
if (key in obj)
|
|
999
|
-
result[key] = obj[key];
|
|
1000
|
-
}
|
|
1001
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1002
|
-
const val = obj[first];
|
|
1003
|
-
if (!val || typeof val !== 'object')
|
|
1004
|
-
continue;
|
|
1005
|
-
if (Array.isArray(val)) {
|
|
1006
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1007
|
-
}
|
|
1008
|
-
else {
|
|
1009
|
-
result[first] = pick(val, restKeys);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
return result;
|
|
1013
|
-
};
|
|
1014
|
-
if (Array.isArray(data)) {
|
|
1015
|
-
return data.map(item => pick(item, fields));
|
|
1016
|
-
}
|
|
1017
|
-
return pick(data, fields);
|
|
1018
|
-
}
|
|
1019
963
|
sanitizeOutput(data) {
|
|
1020
964
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1021
965
|
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 = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -34,7 +34,7 @@ export default class PriceLists extends Command {
|
|
|
34
34
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
35
35
|
};
|
|
36
36
|
static flags = {
|
|
37
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
37
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
38
38
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
39
39
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
40
40
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -49,7 +49,7 @@ export default class PriceLists extends Command {
|
|
|
49
49
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
50
50
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
51
51
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
52
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
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
54
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
55
55
|
};
|
|
@@ -107,9 +107,9 @@ export default class PriceLists extends Command {
|
|
|
107
107
|
}
|
|
108
108
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
109
109
|
if (!context)
|
|
110
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
111
|
-
if (!context
|
|
112
|
-
this.error(
|
|
110
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
111
|
+
if (!hasCredentials(context))
|
|
112
|
+
this.error(missingCredentialsMessage(context));
|
|
113
113
|
const queryParams = {};
|
|
114
114
|
if (flags.page)
|
|
115
115
|
queryParams.page = flags.page;
|
|
@@ -121,6 +121,8 @@ export default class PriceLists extends Command {
|
|
|
121
121
|
queryParams.search = flags.search;
|
|
122
122
|
if (flags['sort-by'])
|
|
123
123
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
124
|
+
if (flags.fields)
|
|
125
|
+
queryParams.fields = flags.fields;
|
|
124
126
|
if (flags.query) {
|
|
125
127
|
try {
|
|
126
128
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -323,11 +325,6 @@ export default class PriceLists extends Command {
|
|
|
323
325
|
output = obj[arrayKeys[0]];
|
|
324
326
|
}
|
|
325
327
|
}
|
|
326
|
-
// Filter fields if --fields flag is provided
|
|
327
|
-
if (flags.fields) {
|
|
328
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
329
|
-
output = this.filterFields(output, fieldList);
|
|
330
|
-
}
|
|
331
328
|
// Sanitize output if requested
|
|
332
329
|
if (flags.sanitize) {
|
|
333
330
|
output = this.sanitizeOutput(output);
|
|
@@ -352,9 +349,9 @@ export default class PriceLists extends Command {
|
|
|
352
349
|
async runImport(flags) {
|
|
353
350
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
354
351
|
if (!context)
|
|
355
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
356
|
-
if (!context
|
|
357
|
-
this.error(
|
|
352
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
353
|
+
if (!hasCredentials(context))
|
|
354
|
+
this.error(missingCredentialsMessage(context));
|
|
358
355
|
// Get data from file, --data, or --set flags
|
|
359
356
|
let items = [];
|
|
360
357
|
if (flags.file) {
|
|
@@ -564,9 +561,9 @@ export default class PriceLists extends Command {
|
|
|
564
561
|
async runExport(flags) {
|
|
565
562
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
566
563
|
if (!context)
|
|
567
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
568
|
-
if (!context
|
|
569
|
-
this.error(
|
|
564
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
565
|
+
if (!hasCredentials(context))
|
|
566
|
+
this.error(missingCredentialsMessage(context));
|
|
570
567
|
const listEndpoint = ENDPOINTS['list'];
|
|
571
568
|
if (!listEndpoint)
|
|
572
569
|
this.error('Export requires a list endpoint');
|
|
@@ -582,6 +579,8 @@ export default class PriceLists extends Command {
|
|
|
582
579
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
583
580
|
if (flags.include)
|
|
584
581
|
baseParams.include = flags.include;
|
|
582
|
+
if (flags.fields)
|
|
583
|
+
baseParams.fields = flags.fields;
|
|
585
584
|
if (flags.query) {
|
|
586
585
|
try {
|
|
587
586
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -636,12 +635,7 @@ export default class PriceLists extends Command {
|
|
|
636
635
|
}
|
|
637
636
|
}
|
|
638
637
|
process.stderr.write(' done\n');
|
|
639
|
-
// Filter fields if specified
|
|
640
638
|
let output = allItems;
|
|
641
|
-
if (flags.fields) {
|
|
642
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
643
|
-
output = this.filterFields(allItems, fieldList);
|
|
644
|
-
}
|
|
645
639
|
// Sanitize output if requested
|
|
646
640
|
if (flags.sanitize) {
|
|
647
641
|
output = this.sanitizeOutput(output);
|
|
@@ -658,9 +652,9 @@ export default class PriceLists extends Command {
|
|
|
658
652
|
async runCamt053Import(flags) {
|
|
659
653
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
660
654
|
if (!context)
|
|
661
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
662
|
-
if (!context
|
|
663
|
-
this.error(
|
|
655
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
656
|
+
if (!hasCredentials(context))
|
|
657
|
+
this.error(missingCredentialsMessage(context));
|
|
664
658
|
if (!flags.file) {
|
|
665
659
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
666
660
|
}
|
|
@@ -748,9 +742,9 @@ export default class PriceLists extends Command {
|
|
|
748
742
|
}
|
|
749
743
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
750
744
|
if (!context)
|
|
751
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
752
|
-
if (!context
|
|
753
|
-
this.error(
|
|
745
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
746
|
+
if (!hasCredentials(context))
|
|
747
|
+
this.error(missingCredentialsMessage(context));
|
|
754
748
|
// Get data from file, --data, or --set flags
|
|
755
749
|
let items = [];
|
|
756
750
|
if (flags.file) {
|
|
@@ -970,56 +964,6 @@ export default class PriceLists extends Command {
|
|
|
970
964
|
return `\$${op}`;
|
|
971
965
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
972
966
|
}
|
|
973
|
-
filterFields(data, fields) {
|
|
974
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
975
|
-
const pick = (obj, keys) => {
|
|
976
|
-
// Group keys by their first segment so sibling sub-paths
|
|
977
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
978
|
-
// and don't clobber each other on merge.
|
|
979
|
-
const directKeys = new Set();
|
|
980
|
-
const nestedKeys = new Map();
|
|
981
|
-
for (const key of keys) {
|
|
982
|
-
if (key.split('.').some(isUnsafeKey))
|
|
983
|
-
continue;
|
|
984
|
-
if (key.includes('.')) {
|
|
985
|
-
const [first, ...rest] = key.split('.');
|
|
986
|
-
if (isUnsafeKey(first))
|
|
987
|
-
continue;
|
|
988
|
-
const list = nestedKeys.get(first);
|
|
989
|
-
if (list) {
|
|
990
|
-
list.push(rest.join('.'));
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
else {
|
|
997
|
-
directKeys.add(key);
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
const result = {};
|
|
1001
|
-
for (const key of directKeys) {
|
|
1002
|
-
if (key in obj)
|
|
1003
|
-
result[key] = obj[key];
|
|
1004
|
-
}
|
|
1005
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1006
|
-
const val = obj[first];
|
|
1007
|
-
if (!val || typeof val !== 'object')
|
|
1008
|
-
continue;
|
|
1009
|
-
if (Array.isArray(val)) {
|
|
1010
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1011
|
-
}
|
|
1012
|
-
else {
|
|
1013
|
-
result[first] = pick(val, restKeys);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
return result;
|
|
1017
|
-
};
|
|
1018
|
-
if (Array.isArray(data)) {
|
|
1019
|
-
return data.map(item => pick(item, fields));
|
|
1020
|
-
}
|
|
1021
|
-
return pick(data, fields);
|
|
1022
|
-
}
|
|
1023
967
|
sanitizeOutput(data) {
|
|
1024
968
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1025
969
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|