@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;
|
|
@@ -27,7 +27,7 @@ export default class ProcessorMappings extends Command {
|
|
|
27
27
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
28
28
|
};
|
|
29
29
|
static flags = {
|
|
30
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
30
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
31
31
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
32
32
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
33
33
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -41,7 +41,7 @@ export default class ProcessorMappings extends Command {
|
|
|
41
41
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
42
42
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
43
43
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
44
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
44
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
45
45
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
46
46
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
47
47
|
};
|
|
@@ -99,9 +99,9 @@ export default class ProcessorMappings extends Command {
|
|
|
99
99
|
}
|
|
100
100
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
101
101
|
if (!context)
|
|
102
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
103
|
-
if (!context
|
|
104
|
-
this.error(
|
|
102
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
103
|
+
if (!hasCredentials(context))
|
|
104
|
+
this.error(missingCredentialsMessage(context));
|
|
105
105
|
const queryParams = {};
|
|
106
106
|
if (flags.page)
|
|
107
107
|
queryParams.page = flags.page;
|
|
@@ -113,6 +113,8 @@ export default class ProcessorMappings extends Command {
|
|
|
113
113
|
queryParams.search = flags.search;
|
|
114
114
|
if (flags['sort-by'])
|
|
115
115
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
116
|
+
if (flags.fields)
|
|
117
|
+
queryParams.fields = flags.fields;
|
|
116
118
|
if (flags.query) {
|
|
117
119
|
try {
|
|
118
120
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -315,11 +317,6 @@ export default class ProcessorMappings extends Command {
|
|
|
315
317
|
output = obj[arrayKeys[0]];
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
|
-
// Filter fields if --fields flag is provided
|
|
319
|
-
if (flags.fields) {
|
|
320
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
321
|
-
output = this.filterFields(output, fieldList);
|
|
322
|
-
}
|
|
323
320
|
// Sanitize output if requested
|
|
324
321
|
if (flags.sanitize) {
|
|
325
322
|
output = this.sanitizeOutput(output);
|
|
@@ -344,9 +341,9 @@ export default class ProcessorMappings extends Command {
|
|
|
344
341
|
async runImport(flags) {
|
|
345
342
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
346
343
|
if (!context)
|
|
347
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
348
|
-
if (!context
|
|
349
|
-
this.error(
|
|
344
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
345
|
+
if (!hasCredentials(context))
|
|
346
|
+
this.error(missingCredentialsMessage(context));
|
|
350
347
|
// Get data from file, --data, or --set flags
|
|
351
348
|
let items = [];
|
|
352
349
|
if (flags.file) {
|
|
@@ -556,9 +553,9 @@ export default class ProcessorMappings extends Command {
|
|
|
556
553
|
async runExport(flags) {
|
|
557
554
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
558
555
|
if (!context)
|
|
559
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
560
|
-
if (!context
|
|
561
|
-
this.error(
|
|
556
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
557
|
+
if (!hasCredentials(context))
|
|
558
|
+
this.error(missingCredentialsMessage(context));
|
|
562
559
|
const listEndpoint = ENDPOINTS['list'];
|
|
563
560
|
if (!listEndpoint)
|
|
564
561
|
this.error('Export requires a list endpoint');
|
|
@@ -574,6 +571,8 @@ export default class ProcessorMappings extends Command {
|
|
|
574
571
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
575
572
|
if (flags.include)
|
|
576
573
|
baseParams.include = flags.include;
|
|
574
|
+
if (flags.fields)
|
|
575
|
+
baseParams.fields = flags.fields;
|
|
577
576
|
if (flags.query) {
|
|
578
577
|
try {
|
|
579
578
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -628,12 +627,7 @@ export default class ProcessorMappings extends Command {
|
|
|
628
627
|
}
|
|
629
628
|
}
|
|
630
629
|
process.stderr.write(' done\n');
|
|
631
|
-
// Filter fields if specified
|
|
632
630
|
let output = allItems;
|
|
633
|
-
if (flags.fields) {
|
|
634
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
635
|
-
output = this.filterFields(allItems, fieldList);
|
|
636
|
-
}
|
|
637
631
|
// Sanitize output if requested
|
|
638
632
|
if (flags.sanitize) {
|
|
639
633
|
output = this.sanitizeOutput(output);
|
|
@@ -650,9 +644,9 @@ export default class ProcessorMappings extends Command {
|
|
|
650
644
|
async runCamt053Import(flags) {
|
|
651
645
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
652
646
|
if (!context)
|
|
653
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
654
|
-
if (!context
|
|
655
|
-
this.error(
|
|
647
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
648
|
+
if (!hasCredentials(context))
|
|
649
|
+
this.error(missingCredentialsMessage(context));
|
|
656
650
|
if (!flags.file) {
|
|
657
651
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
658
652
|
}
|
|
@@ -740,9 +734,9 @@ export default class ProcessorMappings extends Command {
|
|
|
740
734
|
}
|
|
741
735
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
742
736
|
if (!context)
|
|
743
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
744
|
-
if (!context
|
|
745
|
-
this.error(
|
|
737
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
738
|
+
if (!hasCredentials(context))
|
|
739
|
+
this.error(missingCredentialsMessage(context));
|
|
746
740
|
// Get data from file, --data, or --set flags
|
|
747
741
|
let items = [];
|
|
748
742
|
if (flags.file) {
|
|
@@ -962,56 +956,6 @@ export default class ProcessorMappings extends Command {
|
|
|
962
956
|
return `\$${op}`;
|
|
963
957
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
964
958
|
}
|
|
965
|
-
filterFields(data, fields) {
|
|
966
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
967
|
-
const pick = (obj, keys) => {
|
|
968
|
-
// Group keys by their first segment so sibling sub-paths
|
|
969
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
970
|
-
// and don't clobber each other on merge.
|
|
971
|
-
const directKeys = new Set();
|
|
972
|
-
const nestedKeys = new Map();
|
|
973
|
-
for (const key of keys) {
|
|
974
|
-
if (key.split('.').some(isUnsafeKey))
|
|
975
|
-
continue;
|
|
976
|
-
if (key.includes('.')) {
|
|
977
|
-
const [first, ...rest] = key.split('.');
|
|
978
|
-
if (isUnsafeKey(first))
|
|
979
|
-
continue;
|
|
980
|
-
const list = nestedKeys.get(first);
|
|
981
|
-
if (list) {
|
|
982
|
-
list.push(rest.join('.'));
|
|
983
|
-
}
|
|
984
|
-
else {
|
|
985
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
directKeys.add(key);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
const result = {};
|
|
993
|
-
for (const key of directKeys) {
|
|
994
|
-
if (key in obj)
|
|
995
|
-
result[key] = obj[key];
|
|
996
|
-
}
|
|
997
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
998
|
-
const val = obj[first];
|
|
999
|
-
if (!val || typeof val !== 'object')
|
|
1000
|
-
continue;
|
|
1001
|
-
if (Array.isArray(val)) {
|
|
1002
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1003
|
-
}
|
|
1004
|
-
else {
|
|
1005
|
-
result[first] = pick(val, restKeys);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
return result;
|
|
1009
|
-
};
|
|
1010
|
-
if (Array.isArray(data)) {
|
|
1011
|
-
return data.map(item => pick(item, fields));
|
|
1012
|
-
}
|
|
1013
|
-
return pick(data, fields);
|
|
1014
|
-
}
|
|
1015
959
|
sanitizeOutput(data) {
|
|
1016
960
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1017
961
|
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;
|
|
@@ -35,7 +35,7 @@ export default class Processors extends Command {
|
|
|
35
35
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
36
36
|
};
|
|
37
37
|
static flags = {
|
|
38
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
38
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
39
39
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
40
40
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
41
41
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -49,7 +49,7 @@ export default class Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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 Processors 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;
|
|
@@ -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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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 PurchaseOrderTypes 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;
|
|
@@ -16,6 +16,7 @@ export default class PurchaseOrders extends Command {
|
|
|
16
16
|
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
17
|
'line-item-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
18
|
'note-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
20
|
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
21
|
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
22
|
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -33,7 +34,6 @@ export default class PurchaseOrders extends Command {
|
|
|
33
34
|
private runCamt053Import;
|
|
34
35
|
private runNestedImport;
|
|
35
36
|
private parseFilterValue;
|
|
36
|
-
private filterFields;
|
|
37
37
|
private sanitizeOutput;
|
|
38
38
|
private getColumns;
|
|
39
39
|
private getValue;
|