@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 = false;
|
|
6
6
|
const HAS_EXPORT = false;
|
|
@@ -23,7 +23,7 @@ export default class SavedViews extends Command {
|
|
|
23
23
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
24
24
|
};
|
|
25
25
|
static flags = {
|
|
26
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
26
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
27
27
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
28
28
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
29
29
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -37,7 +37,7 @@ export default class SavedViews extends Command {
|
|
|
37
37
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
38
38
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
39
39
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
40
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
40
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
41
41
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
42
42
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
43
43
|
};
|
|
@@ -95,9 +95,9 @@ export default class SavedViews extends Command {
|
|
|
95
95
|
}
|
|
96
96
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
97
97
|
if (!context)
|
|
98
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
99
|
-
if (!context
|
|
100
|
-
this.error(
|
|
98
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
99
|
+
if (!hasCredentials(context))
|
|
100
|
+
this.error(missingCredentialsMessage(context));
|
|
101
101
|
const queryParams = {};
|
|
102
102
|
if (flags.page)
|
|
103
103
|
queryParams.page = flags.page;
|
|
@@ -109,6 +109,8 @@ export default class SavedViews extends Command {
|
|
|
109
109
|
queryParams.search = flags.search;
|
|
110
110
|
if (flags['sort-by'])
|
|
111
111
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
112
|
+
if (flags.fields)
|
|
113
|
+
queryParams.fields = flags.fields;
|
|
112
114
|
if (flags.query) {
|
|
113
115
|
try {
|
|
114
116
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -311,11 +313,6 @@ export default class SavedViews extends Command {
|
|
|
311
313
|
output = obj[arrayKeys[0]];
|
|
312
314
|
}
|
|
313
315
|
}
|
|
314
|
-
// Filter fields if --fields flag is provided
|
|
315
|
-
if (flags.fields) {
|
|
316
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
317
|
-
output = this.filterFields(output, fieldList);
|
|
318
|
-
}
|
|
319
316
|
// Sanitize output if requested
|
|
320
317
|
if (flags.sanitize) {
|
|
321
318
|
output = this.sanitizeOutput(output);
|
|
@@ -340,9 +337,9 @@ export default class SavedViews extends Command {
|
|
|
340
337
|
async runImport(flags) {
|
|
341
338
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
342
339
|
if (!context)
|
|
343
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
344
|
-
if (!context
|
|
345
|
-
this.error(
|
|
340
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
341
|
+
if (!hasCredentials(context))
|
|
342
|
+
this.error(missingCredentialsMessage(context));
|
|
346
343
|
// Get data from file, --data, or --set flags
|
|
347
344
|
let items = [];
|
|
348
345
|
if (flags.file) {
|
|
@@ -552,9 +549,9 @@ export default class SavedViews extends Command {
|
|
|
552
549
|
async runExport(flags) {
|
|
553
550
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
554
551
|
if (!context)
|
|
555
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
556
|
-
if (!context
|
|
557
|
-
this.error(
|
|
552
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
553
|
+
if (!hasCredentials(context))
|
|
554
|
+
this.error(missingCredentialsMessage(context));
|
|
558
555
|
const listEndpoint = ENDPOINTS['list'];
|
|
559
556
|
if (!listEndpoint)
|
|
560
557
|
this.error('Export requires a list endpoint');
|
|
@@ -570,6 +567,8 @@ export default class SavedViews extends Command {
|
|
|
570
567
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
571
568
|
if (flags.include)
|
|
572
569
|
baseParams.include = flags.include;
|
|
570
|
+
if (flags.fields)
|
|
571
|
+
baseParams.fields = flags.fields;
|
|
573
572
|
if (flags.query) {
|
|
574
573
|
try {
|
|
575
574
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -624,12 +623,7 @@ export default class SavedViews extends Command {
|
|
|
624
623
|
}
|
|
625
624
|
}
|
|
626
625
|
process.stderr.write(' done\n');
|
|
627
|
-
// Filter fields if specified
|
|
628
626
|
let output = allItems;
|
|
629
|
-
if (flags.fields) {
|
|
630
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
631
|
-
output = this.filterFields(allItems, fieldList);
|
|
632
|
-
}
|
|
633
627
|
// Sanitize output if requested
|
|
634
628
|
if (flags.sanitize) {
|
|
635
629
|
output = this.sanitizeOutput(output);
|
|
@@ -646,9 +640,9 @@ export default class SavedViews extends Command {
|
|
|
646
640
|
async runCamt053Import(flags) {
|
|
647
641
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
648
642
|
if (!context)
|
|
649
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
650
|
-
if (!context
|
|
651
|
-
this.error(
|
|
643
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
644
|
+
if (!hasCredentials(context))
|
|
645
|
+
this.error(missingCredentialsMessage(context));
|
|
652
646
|
if (!flags.file) {
|
|
653
647
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
654
648
|
}
|
|
@@ -736,9 +730,9 @@ export default class SavedViews extends Command {
|
|
|
736
730
|
}
|
|
737
731
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
738
732
|
if (!context)
|
|
739
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
740
|
-
if (!context
|
|
741
|
-
this.error(
|
|
733
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
734
|
+
if (!hasCredentials(context))
|
|
735
|
+
this.error(missingCredentialsMessage(context));
|
|
742
736
|
// Get data from file, --data, or --set flags
|
|
743
737
|
let items = [];
|
|
744
738
|
if (flags.file) {
|
|
@@ -958,56 +952,6 @@ export default class SavedViews extends Command {
|
|
|
958
952
|
return `\$${op}`;
|
|
959
953
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
960
954
|
}
|
|
961
|
-
filterFields(data, fields) {
|
|
962
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
963
|
-
const pick = (obj, keys) => {
|
|
964
|
-
// Group keys by their first segment so sibling sub-paths
|
|
965
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
966
|
-
// and don't clobber each other on merge.
|
|
967
|
-
const directKeys = new Set();
|
|
968
|
-
const nestedKeys = new Map();
|
|
969
|
-
for (const key of keys) {
|
|
970
|
-
if (key.split('.').some(isUnsafeKey))
|
|
971
|
-
continue;
|
|
972
|
-
if (key.includes('.')) {
|
|
973
|
-
const [first, ...rest] = key.split('.');
|
|
974
|
-
if (isUnsafeKey(first))
|
|
975
|
-
continue;
|
|
976
|
-
const list = nestedKeys.get(first);
|
|
977
|
-
if (list) {
|
|
978
|
-
list.push(rest.join('.'));
|
|
979
|
-
}
|
|
980
|
-
else {
|
|
981
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
else {
|
|
985
|
-
directKeys.add(key);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
const result = {};
|
|
989
|
-
for (const key of directKeys) {
|
|
990
|
-
if (key in obj)
|
|
991
|
-
result[key] = obj[key];
|
|
992
|
-
}
|
|
993
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
994
|
-
const val = obj[first];
|
|
995
|
-
if (!val || typeof val !== 'object')
|
|
996
|
-
continue;
|
|
997
|
-
if (Array.isArray(val)) {
|
|
998
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
999
|
-
}
|
|
1000
|
-
else {
|
|
1001
|
-
result[first] = pick(val, restKeys);
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
return result;
|
|
1005
|
-
};
|
|
1006
|
-
if (Array.isArray(data)) {
|
|
1007
|
-
return data.map(item => pick(item, fields));
|
|
1008
|
-
}
|
|
1009
|
-
return pick(data, fields);
|
|
1010
|
-
}
|
|
1011
955
|
sanitizeOutput(data) {
|
|
1012
956
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1013
957
|
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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 ScheduledProcessorMappings 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 = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -33,7 +33,7 @@ export default class Schedules extends Command {
|
|
|
33
33
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
34
34
|
};
|
|
35
35
|
static flags = {
|
|
36
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
36
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
37
37
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
38
38
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
39
39
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -47,7 +47,7 @@ export default class Schedules extends Command {
|
|
|
47
47
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
48
48
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
49
49
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
50
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
50
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
51
51
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
52
52
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
53
53
|
};
|
|
@@ -105,9 +105,9 @@ export default class Schedules extends Command {
|
|
|
105
105
|
}
|
|
106
106
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
107
107
|
if (!context)
|
|
108
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
109
|
-
if (!context
|
|
110
|
-
this.error(
|
|
108
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
109
|
+
if (!hasCredentials(context))
|
|
110
|
+
this.error(missingCredentialsMessage(context));
|
|
111
111
|
const queryParams = {};
|
|
112
112
|
if (flags.page)
|
|
113
113
|
queryParams.page = flags.page;
|
|
@@ -119,6 +119,8 @@ export default class Schedules extends Command {
|
|
|
119
119
|
queryParams.search = flags.search;
|
|
120
120
|
if (flags['sort-by'])
|
|
121
121
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
122
|
+
if (flags.fields)
|
|
123
|
+
queryParams.fields = flags.fields;
|
|
122
124
|
if (flags.query) {
|
|
123
125
|
try {
|
|
124
126
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -321,11 +323,6 @@ export default class Schedules extends Command {
|
|
|
321
323
|
output = obj[arrayKeys[0]];
|
|
322
324
|
}
|
|
323
325
|
}
|
|
324
|
-
// Filter fields if --fields flag is provided
|
|
325
|
-
if (flags.fields) {
|
|
326
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
327
|
-
output = this.filterFields(output, fieldList);
|
|
328
|
-
}
|
|
329
326
|
// Sanitize output if requested
|
|
330
327
|
if (flags.sanitize) {
|
|
331
328
|
output = this.sanitizeOutput(output);
|
|
@@ -350,9 +347,9 @@ export default class Schedules extends Command {
|
|
|
350
347
|
async runImport(flags) {
|
|
351
348
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
352
349
|
if (!context)
|
|
353
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
354
|
-
if (!context
|
|
355
|
-
this.error(
|
|
350
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
351
|
+
if (!hasCredentials(context))
|
|
352
|
+
this.error(missingCredentialsMessage(context));
|
|
356
353
|
// Get data from file, --data, or --set flags
|
|
357
354
|
let items = [];
|
|
358
355
|
if (flags.file) {
|
|
@@ -562,9 +559,9 @@ export default class Schedules extends Command {
|
|
|
562
559
|
async runExport(flags) {
|
|
563
560
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
564
561
|
if (!context)
|
|
565
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
566
|
-
if (!context
|
|
567
|
-
this.error(
|
|
562
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
563
|
+
if (!hasCredentials(context))
|
|
564
|
+
this.error(missingCredentialsMessage(context));
|
|
568
565
|
const listEndpoint = ENDPOINTS['list'];
|
|
569
566
|
if (!listEndpoint)
|
|
570
567
|
this.error('Export requires a list endpoint');
|
|
@@ -580,6 +577,8 @@ export default class Schedules extends Command {
|
|
|
580
577
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
581
578
|
if (flags.include)
|
|
582
579
|
baseParams.include = flags.include;
|
|
580
|
+
if (flags.fields)
|
|
581
|
+
baseParams.fields = flags.fields;
|
|
583
582
|
if (flags.query) {
|
|
584
583
|
try {
|
|
585
584
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -634,12 +633,7 @@ export default class Schedules extends Command {
|
|
|
634
633
|
}
|
|
635
634
|
}
|
|
636
635
|
process.stderr.write(' done\n');
|
|
637
|
-
// Filter fields if specified
|
|
638
636
|
let output = allItems;
|
|
639
|
-
if (flags.fields) {
|
|
640
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
641
|
-
output = this.filterFields(allItems, fieldList);
|
|
642
|
-
}
|
|
643
637
|
// Sanitize output if requested
|
|
644
638
|
if (flags.sanitize) {
|
|
645
639
|
output = this.sanitizeOutput(output);
|
|
@@ -656,9 +650,9 @@ export default class Schedules extends Command {
|
|
|
656
650
|
async runCamt053Import(flags) {
|
|
657
651
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
658
652
|
if (!context)
|
|
659
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
660
|
-
if (!context
|
|
661
|
-
this.error(
|
|
653
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
654
|
+
if (!hasCredentials(context))
|
|
655
|
+
this.error(missingCredentialsMessage(context));
|
|
662
656
|
if (!flags.file) {
|
|
663
657
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
664
658
|
}
|
|
@@ -746,9 +740,9 @@ export default class Schedules extends Command {
|
|
|
746
740
|
}
|
|
747
741
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
748
742
|
if (!context)
|
|
749
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
750
|
-
if (!context
|
|
751
|
-
this.error(
|
|
743
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
744
|
+
if (!hasCredentials(context))
|
|
745
|
+
this.error(missingCredentialsMessage(context));
|
|
752
746
|
// Get data from file, --data, or --set flags
|
|
753
747
|
let items = [];
|
|
754
748
|
if (flags.file) {
|
|
@@ -968,56 +962,6 @@ export default class Schedules extends Command {
|
|
|
968
962
|
return `\$${op}`;
|
|
969
963
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
970
964
|
}
|
|
971
|
-
filterFields(data, fields) {
|
|
972
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
973
|
-
const pick = (obj, keys) => {
|
|
974
|
-
// Group keys by their first segment so sibling sub-paths
|
|
975
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
976
|
-
// and don't clobber each other on merge.
|
|
977
|
-
const directKeys = new Set();
|
|
978
|
-
const nestedKeys = new Map();
|
|
979
|
-
for (const key of keys) {
|
|
980
|
-
if (key.split('.').some(isUnsafeKey))
|
|
981
|
-
continue;
|
|
982
|
-
if (key.includes('.')) {
|
|
983
|
-
const [first, ...rest] = key.split('.');
|
|
984
|
-
if (isUnsafeKey(first))
|
|
985
|
-
continue;
|
|
986
|
-
const list = nestedKeys.get(first);
|
|
987
|
-
if (list) {
|
|
988
|
-
list.push(rest.join('.'));
|
|
989
|
-
}
|
|
990
|
-
else {
|
|
991
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
995
|
-
directKeys.add(key);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
const result = {};
|
|
999
|
-
for (const key of directKeys) {
|
|
1000
|
-
if (key in obj)
|
|
1001
|
-
result[key] = obj[key];
|
|
1002
|
-
}
|
|
1003
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1004
|
-
const val = obj[first];
|
|
1005
|
-
if (!val || typeof val !== 'object')
|
|
1006
|
-
continue;
|
|
1007
|
-
if (Array.isArray(val)) {
|
|
1008
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1009
|
-
}
|
|
1010
|
-
else {
|
|
1011
|
-
result[first] = pick(val, restKeys);
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
return result;
|
|
1015
|
-
};
|
|
1016
|
-
if (Array.isArray(data)) {
|
|
1017
|
-
return data.map(item => pick(item, fields));
|
|
1018
|
-
}
|
|
1019
|
-
return pick(data, fields);
|
|
1020
|
-
}
|
|
1021
965
|
sanitizeOutput(data) {
|
|
1022
966
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1023
967
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
package/dist/commands/switch.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { confirm, select } from '@inquirer/prompts';
|
|
2
2
|
import { Command } from '@oclif/core';
|
|
3
|
-
import { loginAndSwitchTenant } from '../lib/auth.js';
|
|
4
|
-
import { getContext, getCurrentContext, listContexts, setCurrentContext } from '../lib/config.js';
|
|
3
|
+
import { loginAndSwitchTenant, tenantLabel } from '../lib/auth/index.js';
|
|
4
|
+
import { getAuthType, getContext, getCurrentContext, hasCredentials, listContexts, setCurrentContext, } from '../lib/config.js';
|
|
5
5
|
export default class Switch extends Command {
|
|
6
6
|
static description = 'Switch context and tenant interactively';
|
|
7
7
|
static examples = ['<%= config.bin %> switch'];
|
|
@@ -23,9 +23,10 @@ export default class Switch extends Command {
|
|
|
23
23
|
const selectedContext = await select({
|
|
24
24
|
choices: sortedContexts.map((ctx) => {
|
|
25
25
|
const isCurrent = current?.name === ctx.name;
|
|
26
|
-
const auth = ctx
|
|
26
|
+
const auth = hasCredentials(ctx) ? '✓' : '✗';
|
|
27
|
+
const kind = getAuthType(ctx) === 'api_key' ? ' api-key' : '';
|
|
27
28
|
return {
|
|
28
|
-
name: `${ctx.name} [${ctx.environment}] auth:${auth}${isCurrent ? ' (current)' : ''}`,
|
|
29
|
+
name: `${ctx.name} [${ctx.environment}] auth:${auth}${kind}${isCurrent ? ' (current)' : ''}`,
|
|
29
30
|
value: ctx.name,
|
|
30
31
|
};
|
|
31
32
|
}),
|
|
@@ -35,6 +36,12 @@ export default class Switch extends Command {
|
|
|
35
36
|
setCurrentContext(selectedContext);
|
|
36
37
|
this.log(`Switched to context: ${selectedContext}`);
|
|
37
38
|
}
|
|
39
|
+
// An API key is issued for one tenant, so there is no tenant step to run.
|
|
40
|
+
const selected = getContext(selectedContext);
|
|
41
|
+
if (selected && getAuthType(selected) === 'api_key') {
|
|
42
|
+
this.log('This context authenticates with an API key, which is scoped to a single tenant.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
38
45
|
// Step 2: Select tenant within chosen context.
|
|
39
46
|
// If the session is expired, prompt the user to re-login and then retry.
|
|
40
47
|
const { default: AuthTenant } = await import('./auth/tenant.js');
|
|
@@ -55,8 +62,8 @@ export default class Switch extends Command {
|
|
|
55
62
|
if (!shouldLogin)
|
|
56
63
|
return;
|
|
57
64
|
// If we have a cached tenant list from a previous session, let the user pick
|
|
58
|
-
// tenant FIRST. Then run the combined login + tenant-switch flow which
|
|
59
|
-
// a single browser tab
|
|
65
|
+
// tenant FIRST. Then run the combined login + tenant-switch flow, which
|
|
66
|
+
// uses a single browser tab.
|
|
60
67
|
const ctx = getContext(selectedContext);
|
|
61
68
|
const cached = ctx?.cachedTenants ?? [];
|
|
62
69
|
if (cached.length > 1) {
|
|
@@ -69,7 +76,7 @@ export default class Switch extends Command {
|
|
|
69
76
|
});
|
|
70
77
|
const selectedTenant = await select({
|
|
71
78
|
choices: sorted.map((t) => ({
|
|
72
|
-
name: t.tenantId === ctx?.tenant_id ? `${t
|
|
79
|
+
name: t.tenantId === ctx?.tenant_id ? `${tenantLabel(t)} (previous)` : tenantLabel(t),
|
|
73
80
|
value: t.tenantId,
|
|
74
81
|
})),
|
|
75
82
|
message: 'Select a tenant:',
|