@aderis-erp/cli 1.0.15 → 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 +5 -61
- package/dist/commands/account-transaction-allocations.d.ts +0 -1
- package/dist/commands/account-transaction-allocations.js +5 -61
- package/dist/commands/account-transactions.d.ts +0 -1
- package/dist/commands/account-transactions.js +9 -63
- package/dist/commands/accounts.d.ts +0 -1
- package/dist/commands/accounts.js +5 -61
- package/dist/commands/agent-platform.d.ts +0 -1
- package/dist/commands/agent-platform.js +5 -61
- package/dist/commands/analytics.d.ts +0 -1
- package/dist/commands/analytics.js +5 -61
- package/dist/commands/api-keys.d.ts +39 -0
- package/dist/commands/api-keys.js +1117 -0
- package/dist/commands/audit-log.d.ts +0 -1
- package/dist/commands/audit-log.js +5 -61
- package/dist/commands/auth/login.d.ts +9 -0
- package/dist/commands/auth/login.js +73 -20
- package/dist/commands/auth/logout.d.ts +4 -0
- package/dist/commands/auth/logout.js +4 -0
- package/dist/commands/auth/status.js +26 -17
- package/dist/commands/auth/tenant.js +3 -6
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +5 -34
- package/dist/commands/bank-accounts.d.ts +0 -1
- package/dist/commands/bank-accounts.js +5 -61
- package/dist/commands/bank-integrations.d.ts +0 -1
- package/dist/commands/bank-integrations.js +5 -61
- package/dist/commands/business-partners.d.ts +1 -1
- package/dist/commands/business-partners.js +14 -63
- package/dist/commands/chat.d.ts +0 -1
- package/dist/commands/chat.js +5 -61
- package/dist/commands/config/add.d.ts +3 -0
- package/dist/commands/config/add.js +34 -16
- package/dist/commands/config/current.js +3 -0
- package/dist/commands/config/list.js +3 -0
- package/dist/commands/credit-card-accounts.d.ts +0 -1
- package/dist/commands/credit-card-accounts.js +5 -61
- package/dist/commands/delivery-notes.d.ts +0 -1
- package/dist/commands/delivery-notes.js +7 -63
- package/dist/commands/dunning-configs.d.ts +0 -1
- package/dist/commands/dunning-configs.js +5 -61
- package/dist/commands/dunning-reminders.d.ts +0 -1
- package/dist/commands/dunning-reminders.js +5 -61
- package/dist/commands/dunning-runs.d.ts +0 -1
- package/dist/commands/dunning-runs.js +5 -61
- package/dist/commands/email-transactions.d.ts +0 -1
- package/dist/commands/email-transactions.js +5 -61
- package/dist/commands/employees.d.ts +0 -1
- package/dist/commands/employees.js +5 -61
- package/dist/commands/entity-configurations.d.ts +0 -1
- package/dist/commands/entity-configurations.js +5 -61
- package/dist/commands/event-processor-mappings.d.ts +0 -1
- package/dist/commands/event-processor-mappings.js +5 -61
- package/dist/commands/files.d.ts +0 -1
- package/dist/commands/files.js +5 -61
- package/dist/commands/health.d.ts +0 -1
- package/dist/commands/health.js +5 -61
- package/dist/commands/inbox.d.ts +0 -1
- package/dist/commands/inbox.js +5 -61
- package/dist/commands/integrations.d.ts +0 -1
- package/dist/commands/integrations.js +5 -61
- package/dist/commands/item-categories.d.ts +0 -1
- package/dist/commands/item-categories.js +5 -61
- package/dist/commands/items.d.ts +0 -1
- package/dist/commands/items.js +5 -61
- package/dist/commands/journal-lines.d.ts +0 -1
- package/dist/commands/journal-lines.js +5 -61
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.js +9 -62
- package/dist/commands/ledgers.d.ts +0 -1
- package/dist/commands/ledgers.js +5 -61
- 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 +5 -61
- package/dist/commands/payment-methods.d.ts +0 -1
- package/dist/commands/payment-methods.js +5 -61
- package/dist/commands/payment-runs.d.ts +0 -1
- package/dist/commands/payment-runs.js +5 -61
- package/dist/commands/payment-terms.d.ts +0 -1
- package/dist/commands/payment-terms.js +5 -61
- package/dist/commands/payments.d.ts +0 -1
- package/dist/commands/payments.js +5 -61
- package/dist/commands/price-lists.d.ts +0 -1
- package/dist/commands/price-lists.js +5 -61
- package/dist/commands/processor-mappings.d.ts +0 -1
- package/dist/commands/processor-mappings.js +5 -61
- package/dist/commands/processors.d.ts +0 -1
- package/dist/commands/processors.js +5 -61
- package/dist/commands/purchase-order-types.d.ts +0 -1
- package/dist/commands/purchase-order-types.js +5 -61
- package/dist/commands/purchase-orders.d.ts +0 -1
- package/dist/commands/purchase-orders.js +7 -63
- package/dist/commands/reports.d.ts +0 -1
- package/dist/commands/reports.js +6 -62
- package/dist/commands/salary-types.d.ts +0 -1
- package/dist/commands/salary-types.js +5 -61
- package/dist/commands/sales-invoices.d.ts +0 -1
- package/dist/commands/sales-invoices.js +12 -65
- package/dist/commands/sales-orders.d.ts +0 -1
- package/dist/commands/sales-orders.js +7 -63
- package/dist/commands/saved-views.d.ts +0 -1
- package/dist/commands/saved-views.js +5 -61
- package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
- package/dist/commands/scheduled-processor-mappings.js +5 -61
- package/dist/commands/schedules.d.ts +0 -1
- package/dist/commands/schedules.js +5 -61
- package/dist/commands/switch.js +4 -4
- package/dist/commands/tag-configurations.d.ts +0 -1
- package/dist/commands/tag-configurations.js +9 -64
- package/dist/commands/tags.d.ts +0 -1
- package/dist/commands/tags.js +5 -61
- package/dist/commands/tax-codes.d.ts +0 -1
- package/dist/commands/tax-codes.js +5 -61
- package/dist/commands/tax-matrix.d.ts +0 -1
- package/dist/commands/tax-matrix.js +5 -61
- package/dist/commands/tenants.d.ts +0 -1
- package/dist/commands/tenants.js +7 -62
- package/dist/commands/text-templates.d.ts +0 -1
- package/dist/commands/text-templates.js +5 -61
- package/dist/commands/tools.d.ts +0 -1
- package/dist/commands/tools.js +5 -61
- package/dist/commands/vat-declarations.d.ts +1 -1
- package/dist/commands/vat-declarations.js +11 -62
- package/dist/commands/vendor-invoices.d.ts +0 -1
- package/dist/commands/vendor-invoices.js +10 -65
- package/dist/commands/webhooks.d.ts +0 -1
- package/dist/commands/webhooks.js +5 -61
- package/dist/commands/workflows.d.ts +0 -1
- package/dist/commands/workflows.js +5 -61
- package/dist/lib/api-client.js +3 -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/config.d.ts +13 -3
- package/dist/lib/config.js +24 -19
- package/oclif.manifest.json +440 -71
- package/package.json +2 -1
- package/dist/lib/auth.d.ts +0 -43
- package/dist/lib/auth.js +0 -610
|
@@ -58,7 +58,7 @@ export default class BankIntegrations extends Command {
|
|
|
58
58
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
59
59
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
60
60
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
61
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
61
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
62
62
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
63
63
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
64
64
|
};
|
|
@@ -130,6 +130,8 @@ export default class BankIntegrations extends Command {
|
|
|
130
130
|
queryParams.search = flags.search;
|
|
131
131
|
if (flags['sort-by'])
|
|
132
132
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
133
|
+
if (flags.fields)
|
|
134
|
+
queryParams.fields = flags.fields;
|
|
133
135
|
if (flags.query) {
|
|
134
136
|
try {
|
|
135
137
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -332,11 +334,6 @@ export default class BankIntegrations extends Command {
|
|
|
332
334
|
output = obj[arrayKeys[0]];
|
|
333
335
|
}
|
|
334
336
|
}
|
|
335
|
-
// Filter fields if --fields flag is provided
|
|
336
|
-
if (flags.fields) {
|
|
337
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
338
|
-
output = this.filterFields(output, fieldList);
|
|
339
|
-
}
|
|
340
337
|
// Sanitize output if requested
|
|
341
338
|
if (flags.sanitize) {
|
|
342
339
|
output = this.sanitizeOutput(output);
|
|
@@ -591,6 +588,8 @@ export default class BankIntegrations extends Command {
|
|
|
591
588
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
592
589
|
if (flags.include)
|
|
593
590
|
baseParams.include = flags.include;
|
|
591
|
+
if (flags.fields)
|
|
592
|
+
baseParams.fields = flags.fields;
|
|
594
593
|
if (flags.query) {
|
|
595
594
|
try {
|
|
596
595
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -645,12 +644,7 @@ export default class BankIntegrations extends Command {
|
|
|
645
644
|
}
|
|
646
645
|
}
|
|
647
646
|
process.stderr.write(' done\n');
|
|
648
|
-
// Filter fields if specified
|
|
649
647
|
let output = allItems;
|
|
650
|
-
if (flags.fields) {
|
|
651
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
652
|
-
output = this.filterFields(allItems, fieldList);
|
|
653
|
-
}
|
|
654
648
|
// Sanitize output if requested
|
|
655
649
|
if (flags.sanitize) {
|
|
656
650
|
output = this.sanitizeOutput(output);
|
|
@@ -979,56 +973,6 @@ export default class BankIntegrations extends Command {
|
|
|
979
973
|
return `\$${op}`;
|
|
980
974
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
981
975
|
}
|
|
982
|
-
filterFields(data, fields) {
|
|
983
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
984
|
-
const pick = (obj, keys) => {
|
|
985
|
-
// Group keys by their first segment so sibling sub-paths
|
|
986
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
987
|
-
// and don't clobber each other on merge.
|
|
988
|
-
const directKeys = new Set();
|
|
989
|
-
const nestedKeys = new Map();
|
|
990
|
-
for (const key of keys) {
|
|
991
|
-
if (key.split('.').some(isUnsafeKey))
|
|
992
|
-
continue;
|
|
993
|
-
if (key.includes('.')) {
|
|
994
|
-
const [first, ...rest] = key.split('.');
|
|
995
|
-
if (isUnsafeKey(first))
|
|
996
|
-
continue;
|
|
997
|
-
const list = nestedKeys.get(first);
|
|
998
|
-
if (list) {
|
|
999
|
-
list.push(rest.join('.'));
|
|
1000
|
-
}
|
|
1001
|
-
else {
|
|
1002
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
else {
|
|
1006
|
-
directKeys.add(key);
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
const result = {};
|
|
1010
|
-
for (const key of directKeys) {
|
|
1011
|
-
if (key in obj)
|
|
1012
|
-
result[key] = obj[key];
|
|
1013
|
-
}
|
|
1014
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1015
|
-
const val = obj[first];
|
|
1016
|
-
if (!val || typeof val !== 'object')
|
|
1017
|
-
continue;
|
|
1018
|
-
if (Array.isArray(val)) {
|
|
1019
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1020
|
-
}
|
|
1021
|
-
else {
|
|
1022
|
-
result[first] = pick(val, restKeys);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
return result;
|
|
1026
|
-
};
|
|
1027
|
-
if (Array.isArray(data)) {
|
|
1028
|
-
return data.map(item => pick(item, fields));
|
|
1029
|
-
}
|
|
1030
|
-
return pick(data, fields);
|
|
1031
|
-
}
|
|
1032
976
|
sanitizeOutput(data) {
|
|
1033
977
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1034
978
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -15,6 +15,7 @@ export default class BusinessPartners extends Command {
|
|
|
15
15
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
16
|
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
17
|
'note-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
19
|
'business-partner-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>;
|
|
@@ -33,7 +34,6 @@ export default class BusinessPartners 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;
|
|
@@ -5,8 +5,8 @@ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCred
|
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
|
-
const NESTED_IMPORTS = ["notes", "contacts", "contacts-notes"];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "merge", "activate", "get-favicon", "update-favicon", "trigger-favicon-backfill", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-contacts", "create-contacts", "get-contacts", "update-contacts", "delete-contacts", "list-contacts-notes", "create-contacts-notes", "get-contacts-notes", "update-contacts-notes", "delete-contacts-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
8
|
+
const NESTED_IMPORTS = ["notes", "files", "contacts", "contacts-notes"];
|
|
9
|
+
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "merge", "activate", "get-favicon", "update-favicon", "trigger-favicon-backfill", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-contacts", "create-contacts", "get-contacts", "update-contacts", "delete-contacts", "list-contacts-notes", "create-contacts-notes", "get-contacts-notes", "update-contacts-notes", "delete-contacts-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/business-partners', summary: 'Get all business partners with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
12
|
'create': { method: 'POST', path: '/v1/business-partners', summary: 'Create a new business partner', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['salesOrderRecipientCc', 'salesOrderRecipientBcc', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc', 'contacts', 'tagIds', 'tagCodes', 'salesEarlyPaymentDiscounts', 'purchaseEarlyPaymentDiscounts', 'notes'] },
|
|
@@ -23,6 +23,12 @@ const ENDPOINTS = {
|
|
|
23
23
|
'get-notes': { method: 'GET', path: '/v1/business-partners/{businessPartnerId}/notes/{noteId}', summary: 'Get a specific note for a business partner', pathParams: ['businessPartnerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
24
24
|
'update-notes': { method: 'PATCH', path: '/v1/business-partners/{businessPartnerId}/notes/{noteId}', summary: 'Update a note for a business partner', pathParams: ['businessPartnerId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
25
|
'delete-notes': { method: 'DELETE', path: '/v1/business-partners/{businessPartnerId}/notes/{noteId}', summary: 'Delete a note from a business partner', pathParams: ['businessPartnerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
26
|
+
'list-files': { method: 'GET', path: '/v1/business-partners/{parentId}/files', summary: 'List file attachments for a business partner', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
|
+
'create-files': { method: 'POST', path: '/v1/business-partners/{parentId}/files', summary: 'Upload a file attachment to a business partner', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
|
|
28
|
+
'get-files': { method: 'GET', path: '/v1/business-partners/{parentId}/files/{fileId}', summary: 'Get a file attachment for a business partner', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
29
|
+
'update-files': { method: 'PATCH', path: '/v1/business-partners/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a business partner', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
30
|
+
'delete-files': { method: 'DELETE', path: '/v1/business-partners/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a business partner', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
31
|
+
'files-download': { method: 'GET', path: '/v1/business-partners/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a business partner', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
26
32
|
'list-contacts': { method: 'GET', path: '/v1/business-partners/{businessPartnerId}/contacts', summary: 'Get all contacts for a business partner with pagination', pathParams: ['businessPartnerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
33
|
'create-contacts': { method: 'POST', path: '/v1/business-partners/{businessPartnerId}/contacts', summary: 'Create a new contact for a business partner', pathParams: ['businessPartnerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes', 'notes'] },
|
|
28
34
|
'get-contacts': { method: 'GET', path: '/v1/business-partners/{businessPartnerId}/contacts/{id}', summary: 'Get a contact by ID', pathParams: ['id', 'businessPartnerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
@@ -57,6 +63,7 @@ export default class BusinessPartners extends Command {
|
|
|
57
63
|
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
58
64
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
59
65
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
66
|
+
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
60
67
|
'business-partner-id': Flags.string({ description: 'Path param: businessPartnerId' }),
|
|
61
68
|
page: Flags.string({ description: 'Page number' }),
|
|
62
69
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -65,7 +72,7 @@ export default class BusinessPartners extends Command {
|
|
|
65
72
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
66
73
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
67
74
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
68
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
75
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
69
76
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
70
77
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
71
78
|
};
|
|
@@ -137,6 +144,8 @@ export default class BusinessPartners extends Command {
|
|
|
137
144
|
queryParams.search = flags.search;
|
|
138
145
|
if (flags['sort-by'])
|
|
139
146
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
147
|
+
if (flags.fields)
|
|
148
|
+
queryParams.fields = flags.fields;
|
|
140
149
|
if (flags.query) {
|
|
141
150
|
try {
|
|
142
151
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -339,11 +348,6 @@ export default class BusinessPartners extends Command {
|
|
|
339
348
|
output = obj[arrayKeys[0]];
|
|
340
349
|
}
|
|
341
350
|
}
|
|
342
|
-
// Filter fields if --fields flag is provided
|
|
343
|
-
if (flags.fields) {
|
|
344
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
345
|
-
output = this.filterFields(output, fieldList);
|
|
346
|
-
}
|
|
347
351
|
// Sanitize output if requested
|
|
348
352
|
if (flags.sanitize) {
|
|
349
353
|
output = this.sanitizeOutput(output);
|
|
@@ -598,6 +602,8 @@ export default class BusinessPartners extends Command {
|
|
|
598
602
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
599
603
|
if (flags.include)
|
|
600
604
|
baseParams.include = flags.include;
|
|
605
|
+
if (flags.fields)
|
|
606
|
+
baseParams.fields = flags.fields;
|
|
601
607
|
if (flags.query) {
|
|
602
608
|
try {
|
|
603
609
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -652,12 +658,7 @@ export default class BusinessPartners extends Command {
|
|
|
652
658
|
}
|
|
653
659
|
}
|
|
654
660
|
process.stderr.write(' done\n');
|
|
655
|
-
// Filter fields if specified
|
|
656
661
|
let output = allItems;
|
|
657
|
-
if (flags.fields) {
|
|
658
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
659
|
-
output = this.filterFields(allItems, fieldList);
|
|
660
|
-
}
|
|
661
662
|
// Sanitize output if requested
|
|
662
663
|
if (flags.sanitize) {
|
|
663
664
|
output = this.sanitizeOutput(output);
|
|
@@ -986,56 +987,6 @@ export default class BusinessPartners extends Command {
|
|
|
986
987
|
return `\$${op}`;
|
|
987
988
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
988
989
|
}
|
|
989
|
-
filterFields(data, fields) {
|
|
990
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
991
|
-
const pick = (obj, keys) => {
|
|
992
|
-
// Group keys by their first segment so sibling sub-paths
|
|
993
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
994
|
-
// and don't clobber each other on merge.
|
|
995
|
-
const directKeys = new Set();
|
|
996
|
-
const nestedKeys = new Map();
|
|
997
|
-
for (const key of keys) {
|
|
998
|
-
if (key.split('.').some(isUnsafeKey))
|
|
999
|
-
continue;
|
|
1000
|
-
if (key.includes('.')) {
|
|
1001
|
-
const [first, ...rest] = key.split('.');
|
|
1002
|
-
if (isUnsafeKey(first))
|
|
1003
|
-
continue;
|
|
1004
|
-
const list = nestedKeys.get(first);
|
|
1005
|
-
if (list) {
|
|
1006
|
-
list.push(rest.join('.'));
|
|
1007
|
-
}
|
|
1008
|
-
else {
|
|
1009
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
else {
|
|
1013
|
-
directKeys.add(key);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
const result = {};
|
|
1017
|
-
for (const key of directKeys) {
|
|
1018
|
-
if (key in obj)
|
|
1019
|
-
result[key] = obj[key];
|
|
1020
|
-
}
|
|
1021
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1022
|
-
const val = obj[first];
|
|
1023
|
-
if (!val || typeof val !== 'object')
|
|
1024
|
-
continue;
|
|
1025
|
-
if (Array.isArray(val)) {
|
|
1026
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1027
|
-
}
|
|
1028
|
-
else {
|
|
1029
|
-
result[first] = pick(val, restKeys);
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
return result;
|
|
1033
|
-
};
|
|
1034
|
-
if (Array.isArray(data)) {
|
|
1035
|
-
return data.map(item => pick(item, fields));
|
|
1036
|
-
}
|
|
1037
|
-
return pick(data, fields);
|
|
1038
|
-
}
|
|
1039
990
|
sanitizeOutput(data) {
|
|
1040
991
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1041
992
|
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/chat.d.ts
CHANGED
package/dist/commands/chat.js
CHANGED
|
@@ -42,7 +42,7 @@ export default class Chat extends Command {
|
|
|
42
42
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
43
43
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
44
44
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
45
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
45
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
46
46
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
47
47
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
48
48
|
};
|
|
@@ -114,6 +114,8 @@ export default class Chat extends Command {
|
|
|
114
114
|
queryParams.search = flags.search;
|
|
115
115
|
if (flags['sort-by'])
|
|
116
116
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
117
|
+
if (flags.fields)
|
|
118
|
+
queryParams.fields = flags.fields;
|
|
117
119
|
if (flags.query) {
|
|
118
120
|
try {
|
|
119
121
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -316,11 +318,6 @@ export default class Chat extends Command {
|
|
|
316
318
|
output = obj[arrayKeys[0]];
|
|
317
319
|
}
|
|
318
320
|
}
|
|
319
|
-
// Filter fields if --fields flag is provided
|
|
320
|
-
if (flags.fields) {
|
|
321
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
322
|
-
output = this.filterFields(output, fieldList);
|
|
323
|
-
}
|
|
324
321
|
// Sanitize output if requested
|
|
325
322
|
if (flags.sanitize) {
|
|
326
323
|
output = this.sanitizeOutput(output);
|
|
@@ -575,6 +572,8 @@ export default class Chat extends Command {
|
|
|
575
572
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
576
573
|
if (flags.include)
|
|
577
574
|
baseParams.include = flags.include;
|
|
575
|
+
if (flags.fields)
|
|
576
|
+
baseParams.fields = flags.fields;
|
|
578
577
|
if (flags.query) {
|
|
579
578
|
try {
|
|
580
579
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -629,12 +628,7 @@ export default class Chat extends Command {
|
|
|
629
628
|
}
|
|
630
629
|
}
|
|
631
630
|
process.stderr.write(' done\n');
|
|
632
|
-
// Filter fields if specified
|
|
633
631
|
let output = allItems;
|
|
634
|
-
if (flags.fields) {
|
|
635
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
636
|
-
output = this.filterFields(allItems, fieldList);
|
|
637
|
-
}
|
|
638
632
|
// Sanitize output if requested
|
|
639
633
|
if (flags.sanitize) {
|
|
640
634
|
output = this.sanitizeOutput(output);
|
|
@@ -963,56 +957,6 @@ export default class Chat extends Command {
|
|
|
963
957
|
return `\$${op}`;
|
|
964
958
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
965
959
|
}
|
|
966
|
-
filterFields(data, fields) {
|
|
967
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
968
|
-
const pick = (obj, keys) => {
|
|
969
|
-
// Group keys by their first segment so sibling sub-paths
|
|
970
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
971
|
-
// and don't clobber each other on merge.
|
|
972
|
-
const directKeys = new Set();
|
|
973
|
-
const nestedKeys = new Map();
|
|
974
|
-
for (const key of keys) {
|
|
975
|
-
if (key.split('.').some(isUnsafeKey))
|
|
976
|
-
continue;
|
|
977
|
-
if (key.includes('.')) {
|
|
978
|
-
const [first, ...rest] = key.split('.');
|
|
979
|
-
if (isUnsafeKey(first))
|
|
980
|
-
continue;
|
|
981
|
-
const list = nestedKeys.get(first);
|
|
982
|
-
if (list) {
|
|
983
|
-
list.push(rest.join('.'));
|
|
984
|
-
}
|
|
985
|
-
else {
|
|
986
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
else {
|
|
990
|
-
directKeys.add(key);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
const result = {};
|
|
994
|
-
for (const key of directKeys) {
|
|
995
|
-
if (key in obj)
|
|
996
|
-
result[key] = obj[key];
|
|
997
|
-
}
|
|
998
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
999
|
-
const val = obj[first];
|
|
1000
|
-
if (!val || typeof val !== 'object')
|
|
1001
|
-
continue;
|
|
1002
|
-
if (Array.isArray(val)) {
|
|
1003
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1004
|
-
}
|
|
1005
|
-
else {
|
|
1006
|
-
result[first] = pick(val, restKeys);
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
return result;
|
|
1010
|
-
};
|
|
1011
|
-
if (Array.isArray(data)) {
|
|
1012
|
-
return data.map(item => pick(item, fields));
|
|
1013
|
-
}
|
|
1014
|
-
return pick(data, fields);
|
|
1015
|
-
}
|
|
1016
960
|
sanitizeOutput(data) {
|
|
1017
961
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1018
962
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -9,6 +9,7 @@ export default class ConfigAdd extends Command {
|
|
|
9
9
|
'client-secret': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
environment: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
'keycloak-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
13
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
14
|
};
|
|
14
15
|
run(): Promise<void>;
|
|
@@ -18,5 +19,7 @@ export default class ConfigAdd extends Command {
|
|
|
18
19
|
* OAuth, and a non-TTY stdin means we must not block on a prompt — both keep
|
|
19
20
|
* scripted `config add` calls working exactly as before API-key support.
|
|
20
21
|
*/
|
|
22
|
+
/** Validates `--keycloak-url` before the context is stored. */
|
|
23
|
+
private resolveKeycloakBaseUrl;
|
|
21
24
|
private resolveAuthType;
|
|
22
25
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { confirm, input, password, select } from '@inquirer/prompts';
|
|
2
2
|
import { Command, Flags } from '@oclif/core';
|
|
3
|
-
import {
|
|
3
|
+
import { keycloakBaseUrlOf, parseKeycloakBaseUrl } from '../../lib/auth/index.js';
|
|
4
|
+
import { addContext, DEFAULT_KEYCLOAK_CLIENT_ID, getContext, } from '../../lib/config.js';
|
|
4
5
|
export default class ConfigAdd extends Command {
|
|
5
6
|
static description = 'Add a new context configuration';
|
|
6
7
|
static examples = [
|
|
@@ -8,6 +9,7 @@ export default class ConfigAdd extends Command {
|
|
|
8
9
|
'<%= config.bin %> config add --name my-client --environment live',
|
|
9
10
|
'<%= config.bin %> config add --name dev-context --environment dev --client-id abc123',
|
|
10
11
|
'<%= config.bin %> config add --name ci --environment live --auth-type api-key --api-key <key>',
|
|
12
|
+
'<%= config.bin %> config add --name test-kc --environment test --keycloak-url https://iam-test.aderis.com',
|
|
11
13
|
];
|
|
12
14
|
static flags = {
|
|
13
15
|
'api-key': Flags.string({
|
|
@@ -25,14 +27,17 @@ export default class ConfigAdd extends Command {
|
|
|
25
27
|
}),
|
|
26
28
|
environment: Flags.string({
|
|
27
29
|
char: 'e',
|
|
28
|
-
description: 'Environment (dev, staging, live)',
|
|
29
|
-
options: ['dev', 'staging', 'live'],
|
|
30
|
+
description: 'Environment (dev, test, staging, live)',
|
|
31
|
+
options: ['dev', 'test', 'staging', 'live'],
|
|
30
32
|
}),
|
|
31
33
|
force: Flags.boolean({
|
|
32
34
|
char: 'f',
|
|
33
35
|
default: false,
|
|
34
36
|
description: 'Overwrite existing context without prompting',
|
|
35
37
|
}),
|
|
38
|
+
'keycloak-url': Flags.string({
|
|
39
|
+
description: 'Keycloak origin to use instead of the default host for the environment (https, allowlisted). The realm stays that of the environment',
|
|
40
|
+
}),
|
|
36
41
|
name: Flags.string({
|
|
37
42
|
char: 'n',
|
|
38
43
|
description: 'Context name',
|
|
@@ -74,6 +79,7 @@ export default class ConfigAdd extends Command {
|
|
|
74
79
|
choices: [
|
|
75
80
|
{ name: 'live (production)', value: 'live' },
|
|
76
81
|
{ name: 'staging', value: 'staging' },
|
|
82
|
+
{ name: 'test (QA)', value: 'test' },
|
|
77
83
|
{ name: 'dev (development)', value: 'dev' },
|
|
78
84
|
],
|
|
79
85
|
message: 'Environment:',
|
|
@@ -87,6 +93,9 @@ export default class ConfigAdd extends Command {
|
|
|
87
93
|
if (flags['client-id'] || flags['client-secret']) {
|
|
88
94
|
this.error('--client-id and --client-secret only apply to OAuth contexts; omit them with --auth-type api-key.');
|
|
89
95
|
}
|
|
96
|
+
if (flags['keycloak-url']) {
|
|
97
|
+
this.error('--keycloak-url only applies to OAuth contexts; omit it with --auth-type api-key.');
|
|
98
|
+
}
|
|
90
99
|
const apiKey = flags['api-key'] ??
|
|
91
100
|
(await password({
|
|
92
101
|
mask: true,
|
|
@@ -108,25 +117,21 @@ export default class ConfigAdd extends Command {
|
|
|
108
117
|
this.log(`\nNo login needed — the CLI is ready to use.`);
|
|
109
118
|
return;
|
|
110
119
|
}
|
|
111
|
-
|
|
120
|
+
const keycloakBaseUrl = this.resolveKeycloakBaseUrl(flags['keycloak-url']);
|
|
121
|
+
// Without a terminal the default client id is taken without confirmation.
|
|
112
122
|
let clientId = flags['client-id'];
|
|
113
123
|
if (!clientId) {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const useDefault = await confirm({
|
|
124
|
+
const useDefault = !process.stdin.isTTY ||
|
|
125
|
+
(await confirm({
|
|
117
126
|
default: true,
|
|
118
|
-
message: `Use default client ID
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
if (!clientId) {
|
|
125
|
-
clientId = await input({
|
|
127
|
+
message: `Use default client ID (${DEFAULT_KEYCLOAK_CLIENT_ID})?`,
|
|
128
|
+
}));
|
|
129
|
+
clientId = useDefault
|
|
130
|
+
? DEFAULT_KEYCLOAK_CLIENT_ID
|
|
131
|
+
: await input({
|
|
126
132
|
message: 'OAuth client ID:',
|
|
127
133
|
validate: (value) => (value.trim() ? true : 'Client ID is required'),
|
|
128
134
|
});
|
|
129
|
-
}
|
|
130
135
|
}
|
|
131
136
|
// Get client secret (optional)
|
|
132
137
|
let clientSecret = flags['client-secret'];
|
|
@@ -148,10 +153,12 @@ export default class ConfigAdd extends Command {
|
|
|
148
153
|
client_id: clientId,
|
|
149
154
|
client_secret: clientSecret,
|
|
150
155
|
environment,
|
|
156
|
+
keycloak_base_url: keycloakBaseUrl,
|
|
151
157
|
name,
|
|
152
158
|
});
|
|
153
159
|
this.log(`\nContext "${name}" created successfully.`);
|
|
154
160
|
this.log(`Environment: ${environment}`);
|
|
161
|
+
this.log(`Keycloak URL: ${keycloakBaseUrlOf({ environment, keycloak_base_url: keycloakBaseUrl })}`);
|
|
155
162
|
this.log(`Client ID: ${clientId}`);
|
|
156
163
|
this.log(`\nTo authenticate, run: aderis auth login`);
|
|
157
164
|
}
|
|
@@ -161,6 +168,17 @@ export default class ConfigAdd extends Command {
|
|
|
161
168
|
* OAuth, and a non-TTY stdin means we must not block on a prompt — both keep
|
|
162
169
|
* scripted `config add` calls working exactly as before API-key support.
|
|
163
170
|
*/
|
|
171
|
+
/** Validates `--keycloak-url` before the context is stored. */
|
|
172
|
+
resolveKeycloakBaseUrl(flag) {
|
|
173
|
+
if (flag === undefined)
|
|
174
|
+
return undefined;
|
|
175
|
+
try {
|
|
176
|
+
return parseKeycloakBaseUrl(flag);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
this.error(`Invalid --keycloak-url: ${error instanceof Error ? error.message : String(error)}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
164
182
|
async resolveAuthType(flags) {
|
|
165
183
|
if (flags['auth-type']) {
|
|
166
184
|
return flags['auth-type'] === 'api-key' ? 'api_key' : 'oauth2';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { keycloakBaseUrlOf } from '../../lib/auth/index.js';
|
|
2
3
|
import { getAuthType, getCurrentContext, hasCredentials } from '../../lib/config.js';
|
|
3
4
|
export default class ConfigCurrent extends Command {
|
|
4
5
|
static description = 'Show the current context';
|
|
@@ -28,6 +29,7 @@ export default class ConfigCurrent extends Command {
|
|
|
28
29
|
authenticated: hasCredentials(context),
|
|
29
30
|
client_id: context.client_id,
|
|
30
31
|
environment: context.environment,
|
|
32
|
+
keycloak_base_url: getAuthType(context) === 'oauth2' ? keycloakBaseUrlOf(context) : undefined,
|
|
31
33
|
name: context.name,
|
|
32
34
|
tenant_id: context.tenant_id,
|
|
33
35
|
}, null, 2));
|
|
@@ -38,6 +40,7 @@ export default class ConfigCurrent extends Command {
|
|
|
38
40
|
this.log(`Environment: ${context.environment}`);
|
|
39
41
|
this.log(`Auth: ${authType === 'api_key' ? 'API key (x-api-key)' : 'oauth2'}`);
|
|
40
42
|
if (authType === 'oauth2') {
|
|
43
|
+
this.log(`Keycloak URL: ${keycloakBaseUrlOf(context)}`);
|
|
41
44
|
this.log(`Client ID: ${context.client_id ?? 'N/A'}`);
|
|
42
45
|
}
|
|
43
46
|
if (context.tenant_id) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { keycloakBaseUrlOf } from '../../lib/auth/index.js';
|
|
2
3
|
import { getAuthType, getCurrentContext, hasCredentials, listContexts } from '../../lib/config.js';
|
|
3
4
|
export default class ConfigList extends Command {
|
|
4
5
|
static description = 'List all configured contexts';
|
|
@@ -20,6 +21,7 @@ export default class ConfigList extends Command {
|
|
|
20
21
|
authenticated: hasCredentials(c),
|
|
21
22
|
client_id: c.client_id,
|
|
22
23
|
environment: c.environment,
|
|
24
|
+
keycloak_base_url: getAuthType(c) === 'oauth2' ? keycloakBaseUrlOf(c) : undefined,
|
|
23
25
|
name: c.name,
|
|
24
26
|
tenant_id: c.tenant_id,
|
|
25
27
|
})),
|
|
@@ -42,6 +44,7 @@ export default class ConfigList extends Command {
|
|
|
42
44
|
this.log(` Environment: ${ctx.environment}`);
|
|
43
45
|
this.log(` Auth: ${authType === 'api_key' ? 'API key (x-api-key)' : 'oauth2'}`);
|
|
44
46
|
if (authType === 'oauth2') {
|
|
47
|
+
this.log(` Keycloak URL: ${keycloakBaseUrlOf(ctx)}`);
|
|
45
48
|
this.log(` Client ID: ${ctx.client_id ?? 'N/A'}`);
|
|
46
49
|
}
|
|
47
50
|
this.log(` Authenticated: ${auth}`);
|