@aderis-erp/cli 1.0.15 → 1.1.0
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 +54 -78
- package/dist/commands/account-transaction-allocations.d.ts +0 -1
- package/dist/commands/account-transaction-allocations.js +51 -75
- package/dist/commands/account-transactions.d.ts +0 -1
- package/dist/commands/account-transactions.js +80 -94
- package/dist/commands/accounts.d.ts +0 -1
- package/dist/commands/accounts.js +59 -83
- package/dist/commands/agent-platform.d.ts +0 -1
- package/dist/commands/agent-platform.js +58 -82
- package/dist/commands/agent-runs.d.ts +39 -0
- package/dist/commands/agent-runs.js +1155 -0
- package/dist/commands/analytics.d.ts +0 -1
- package/dist/commands/analytics.js +52 -76
- package/dist/commands/{text-templates.d.ts → api-keys.d.ts} +1 -2
- package/dist/commands/api-keys.js +1150 -0
- package/dist/commands/async-jobs.d.ts +39 -0
- package/dist/commands/async-jobs.js +1158 -0
- package/dist/commands/audit-log.d.ts +0 -1
- package/dist/commands/audit-log.js +51 -75
- 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 +68 -91
- package/dist/commands/bank-integrations.d.ts +1 -1
- package/dist/commands/bank-integrations.js +71 -92
- package/dist/commands/business-partners.d.ts +1 -1
- package/dist/commands/business-partners.js +84 -100
- package/dist/commands/chat.d.ts +0 -1
- package/dist/commands/chat.js +57 -80
- 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 +1 -1
- package/dist/commands/credit-card-accounts.js +72 -90
- package/dist/commands/delivery-notes.d.ts +0 -1
- package/dist/commands/delivery-notes.js +83 -105
- package/dist/commands/dunning-configs.d.ts +0 -1
- package/dist/commands/dunning-configs.js +54 -78
- package/dist/commands/dunning-reminders.d.ts +0 -1
- package/dist/commands/dunning-reminders.js +57 -81
- package/dist/commands/dunning-runs.d.ts +0 -1
- package/dist/commands/dunning-runs.js +50 -74
- package/dist/commands/email-transactions.d.ts +0 -1
- package/dist/commands/email-transactions.js +52 -76
- package/dist/commands/employees.d.ts +0 -1
- package/dist/commands/employees.js +81 -105
- package/dist/commands/entity-configurations.d.ts +0 -1
- package/dist/commands/entity-configurations.js +52 -76
- package/dist/commands/event-processor-mappings.d.ts +0 -1
- package/dist/commands/event-processor-mappings.js +54 -78
- package/dist/commands/files.d.ts +0 -1
- package/dist/commands/files.js +61 -85
- package/dist/commands/health.d.ts +0 -1
- package/dist/commands/health.js +54 -78
- package/dist/commands/imports.d.ts +39 -0
- package/dist/commands/imports.js +1151 -0
- package/dist/commands/inbox.d.ts +0 -1
- package/dist/commands/inbox.js +57 -80
- package/dist/commands/integration-identities.d.ts +40 -0
- package/dist/commands/integration-identities.js +1151 -0
- package/dist/commands/integrations.d.ts +0 -1
- package/dist/commands/integrations.js +52 -76
- package/dist/commands/item-categories.d.ts +0 -1
- package/dist/commands/item-categories.js +54 -78
- package/dist/commands/items.d.ts +0 -1
- package/dist/commands/items.js +54 -78
- package/dist/commands/journal-lines.d.ts +0 -1
- package/dist/commands/journal-lines.js +50 -74
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.js +75 -96
- package/dist/commands/ledgers.d.ts +3 -2
- package/dist/commands/ledgers.js +100 -95
- package/dist/commands/my-account.d.ts +39 -0
- package/dist/commands/my-account.js +1160 -0
- package/dist/commands/office-locations.d.ts +0 -1
- package/dist/commands/office-locations.js +54 -78
- package/dist/commands/payment-methods.d.ts +0 -1
- package/dist/commands/payment-methods.js +59 -83
- package/dist/commands/payment-runs.d.ts +0 -1
- package/dist/commands/payment-runs.js +66 -90
- package/dist/commands/payment-terms.d.ts +0 -1
- package/dist/commands/payment-terms.js +55 -79
- package/dist/commands/payments.d.ts +0 -1
- package/dist/commands/payments.js +56 -80
- package/dist/commands/payroll-runs.d.ts +43 -0
- package/dist/commands/payroll-runs.js +1188 -0
- package/dist/commands/permissions.d.ts +39 -0
- package/dist/commands/permissions.js +1146 -0
- package/dist/commands/price-lists.d.ts +0 -1
- package/dist/commands/price-lists.js +59 -83
- package/dist/commands/processor-mappings.d.ts +0 -1
- package/dist/commands/processor-mappings.js +53 -77
- package/dist/commands/processors.d.ts +0 -1
- package/dist/commands/processors.js +60 -85
- package/dist/commands/purchase-order-types.d.ts +0 -1
- package/dist/commands/purchase-order-types.js +54 -78
- package/dist/commands/purchase-orders.d.ts +0 -1
- package/dist/commands/purchase-orders.js +74 -97
- package/dist/commands/reports.d.ts +0 -1
- package/dist/commands/reports.js +54 -78
- package/dist/commands/roles.d.ts +39 -0
- package/dist/commands/{text-templates.js → roles.js} +64 -90
- package/dist/commands/salary-types.d.ts +0 -1
- package/dist/commands/salary-types.js +54 -78
- package/dist/commands/sales-invoices.d.ts +0 -1
- package/dist/commands/sales-invoices.js +90 -110
- package/dist/commands/sales-orders.d.ts +0 -1
- package/dist/commands/sales-orders.js +83 -105
- package/dist/commands/saved-views.d.ts +0 -1
- package/dist/commands/saved-views.js +52 -76
- package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
- package/dist/commands/scheduled-processor-mappings.js +54 -78
- package/dist/commands/schedules.d.ts +0 -1
- package/dist/commands/schedules.js +58 -82
- package/dist/commands/switch.js +4 -4
- package/dist/commands/tag-configurations.d.ts +0 -1
- package/dist/commands/tag-configurations.js +56 -79
- package/dist/commands/tags.d.ts +0 -1
- package/dist/commands/tags.js +54 -78
- package/dist/commands/tax-codes.d.ts +0 -1
- package/dist/commands/tax-codes.js +57 -81
- package/dist/commands/tax-matrix.d.ts +0 -1
- package/dist/commands/tax-matrix.js +54 -78
- package/dist/commands/templates.d.ts +39 -0
- package/dist/commands/templates.js +1157 -0
- package/dist/commands/tenants.d.ts +0 -1
- package/dist/commands/tenants.js +58 -81
- package/dist/commands/tools.d.ts +0 -1
- package/dist/commands/tools.js +51 -75
- package/dist/commands/users.d.ts +42 -0
- package/dist/commands/users.js +1174 -0
- package/dist/commands/vat-declarations.d.ts +3 -1
- package/dist/commands/vat-declarations.js +78 -93
- package/dist/commands/vendor-invoices.d.ts +0 -1
- package/dist/commands/vendor-invoices.js +87 -110
- package/dist/commands/webhooks.d.ts +0 -1
- package/dist/commands/webhooks.js +56 -80
- package/dist/commands/workflows.d.ts +0 -1
- package/dist/commands/workflows.js +52 -76
- package/dist/lib/api-client.d.ts +6 -0
- package/dist/lib/api-client.js +16 -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 +228 -0
- package/dist/lib/auth/jwks.d.ts +19 -0
- package/dist/lib/auth/jwks.js +112 -0
- package/dist/lib/auth/keycloak-provider.d.ts +91 -0
- package/dist/lib/auth/keycloak-provider.js +244 -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 +59 -0
- package/dist/lib/auth/tokens.js +105 -0
- package/dist/lib/auth/types.d.ts +61 -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 +2447 -641
- package/package.json +5 -4
- package/dist/lib/auth.d.ts +0 -43
- package/dist/lib/auth.js +0 -610
|
@@ -1,38 +1,45 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
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;
|
|
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", "match-candidates", "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
|
-
'list': { method: 'GET', path: '/v1/business-partners', summary: 'Get all business partners with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
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'] },
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
11
|
+
'list': { method: 'GET', path: '/v1/business-partners', summary: 'Get all business partners with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/business-partners', summary: 'Create a new business partner', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderRecipientCc', 'salesOrderRecipientBcc', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc', 'contacts', 'tagIds', 'tagCodes', 'salesEarlyPaymentDiscounts', 'purchaseEarlyPaymentDiscounts', 'notes'] },
|
|
13
|
+
'match-candidates': { method: 'GET', path: '/v1/business-partners/match-candidates', summary: 'Rank the business partners whose names resemble a bank counterparty text', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'get': { method: 'GET', path: '/v1/business-partners/{id}', summary: 'Get a business partner by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'update': { method: 'PATCH', path: '/v1/business-partners/{id}', summary: 'Update a business partner', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderRecipientCc', 'salesOrderRecipientBcc', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc', 'contacts', 'tagIds', 'tagCodes', 'salesEarlyPaymentDiscounts', 'purchaseEarlyPaymentDiscounts', 'notes'] },
|
|
16
|
+
'delete': { method: 'DELETE', path: '/v1/business-partners/{id}', summary: 'Delete a business partner', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'merge': { method: 'POST', path: '/v1/business-partners/{id}/merge', summary: 'Merge a business partner into another', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
+
'activate': { method: 'POST', path: '/v1/business-partners/{id}/activate', summary: 'Activate a business partner', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
+
'get-favicon': { method: 'GET', path: '/v1/business-partners/{id}/favicon', summary: 'Download a business partner\'s stored favicon', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
+
'update-favicon': { method: 'PUT', path: '/v1/business-partners/{id}/favicon', summary: 'Manually upload a business partner\'s favicon', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
+
'trigger-favicon-backfill': { method: 'POST', path: '/v1/business-partners/favicon-backfill', summary: 'Fetch favicons for every business partner in this tenant that has none yet', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
+
'list-notes': { method: 'GET', path: '/v1/business-partners/{businessPartnerId}/notes', summary: 'Get all notes for a business partner', pathParams: ['businessPartnerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
+
'create-notes': { method: 'POST', path: '/v1/business-partners/{businessPartnerId}/notes', summary: 'Create a note for a business partner', pathParams: ['businessPartnerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
+
'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: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
+
'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, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'notes'] },
|
|
35
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
+
'update-contacts': { method: 'PATCH', path: '/v1/business-partners/{businessPartnerId}/contacts/{id}', summary: 'Update a contact', pathParams: ['id', 'businessPartnerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'notes'] },
|
|
37
|
+
'delete-contacts': { method: 'DELETE', path: '/v1/business-partners/{businessPartnerId}/contacts/{id}', summary: 'Delete a contact', pathParams: ['id', 'businessPartnerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
+
'list-contacts-notes': { method: 'GET', path: '/v1/business-partners/contacts/{contactId}/notes', summary: 'Get all notes for a contact', pathParams: ['contactId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
+
'create-contacts-notes': { method: 'POST', path: '/v1/business-partners/contacts/{contactId}/notes', summary: 'Create a note for a contact', pathParams: ['contactId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
+
'get-contacts-notes': { method: 'GET', path: '/v1/business-partners/contacts/{contactId}/notes/{noteId}', summary: 'Get a specific note for a contact', pathParams: ['contactId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
+
'update-contacts-notes': { method: 'PATCH', path: '/v1/business-partners/contacts/{contactId}/notes/{noteId}', summary: 'Update a note for a contact', pathParams: ['contactId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
+
'delete-contacts-notes': { method: 'DELETE', path: '/v1/business-partners/contacts/{contactId}/notes/{noteId}', summary: 'Delete a note from a contact', pathParams: ['contactId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
43
|
};
|
|
37
44
|
export default class BusinessPartners extends Command {
|
|
38
45
|
static description = 'Manage business partners';
|
|
@@ -57,6 +64,7 @@ export default class BusinessPartners extends Command {
|
|
|
57
64
|
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
58
65
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
59
66
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
67
|
+
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
60
68
|
'business-partner-id': Flags.string({ description: 'Path param: businessPartnerId' }),
|
|
61
69
|
page: Flags.string({ description: 'Page number' }),
|
|
62
70
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -65,7 +73,7 @@ export default class BusinessPartners extends Command {
|
|
|
65
73
|
'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
74
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
67
75
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
68
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
76
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
69
77
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
70
78
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
71
79
|
};
|
|
@@ -137,6 +145,8 @@ export default class BusinessPartners extends Command {
|
|
|
137
145
|
queryParams.search = flags.search;
|
|
138
146
|
if (flags['sort-by'])
|
|
139
147
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
148
|
+
if (flags.fields)
|
|
149
|
+
queryParams.fields = flags.fields;
|
|
140
150
|
if (flags.query) {
|
|
141
151
|
try {
|
|
142
152
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -284,10 +294,11 @@ export default class BusinessPartners extends Command {
|
|
|
284
294
|
process.stderr.write('\n');
|
|
285
295
|
}
|
|
286
296
|
try {
|
|
287
|
-
// Binary response:
|
|
297
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
288
298
|
if (endpoint.isBinaryResponse) {
|
|
289
|
-
|
|
290
|
-
|
|
299
|
+
const toStdout = !flags.file;
|
|
300
|
+
if (toStdout && process.stdout.isTTY) {
|
|
301
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
291
302
|
}
|
|
292
303
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
293
304
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -295,24 +306,55 @@ export default class BusinessPartners extends Command {
|
|
|
295
306
|
contextName: flags.context,
|
|
296
307
|
binary: true,
|
|
297
308
|
});
|
|
298
|
-
const fsModule = await import('node:fs');
|
|
299
309
|
const binData = binResponse.data;
|
|
300
310
|
const buffer = Buffer.isBuffer(binData)
|
|
301
311
|
? binData
|
|
302
312
|
: Buffer.from(binData);
|
|
313
|
+
if (toStdout) {
|
|
314
|
+
// Nothing else may reach stdout here — it is the file.
|
|
315
|
+
process.stdout.write(buffer);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const fsModule = await import('node:fs');
|
|
303
319
|
fsModule.writeFileSync(flags.file, buffer);
|
|
304
320
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
305
321
|
return;
|
|
306
322
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
323
|
+
let response;
|
|
324
|
+
if (endpoint.hasBinaryVariant) {
|
|
325
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
326
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
327
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
328
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
329
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
330
|
+
data,
|
|
331
|
+
contextName: flags.context,
|
|
332
|
+
binary: true,
|
|
333
|
+
});
|
|
334
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
335
|
+
const rawData = raw.data;
|
|
336
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
337
|
+
if (!isTextualMediaType(rawType)) {
|
|
338
|
+
if (process.stdout.isTTY) {
|
|
339
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
340
|
+
}
|
|
341
|
+
// Nothing else may reach stdout here — it is the file.
|
|
342
|
+
process.stdout.write(buffer);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
349
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
350
|
+
data,
|
|
351
|
+
contextName: flags.context,
|
|
352
|
+
acceptAny: true,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
313
355
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
314
356
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
315
|
-
if (contentType
|
|
357
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
316
358
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
317
359
|
this.log(String(response.data));
|
|
318
360
|
return;
|
|
@@ -339,11 +381,6 @@ export default class BusinessPartners extends Command {
|
|
|
339
381
|
output = obj[arrayKeys[0]];
|
|
340
382
|
}
|
|
341
383
|
}
|
|
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
384
|
// Sanitize output if requested
|
|
348
385
|
if (flags.sanitize) {
|
|
349
386
|
output = this.sanitizeOutput(output);
|
|
@@ -598,6 +635,8 @@ export default class BusinessPartners extends Command {
|
|
|
598
635
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
599
636
|
if (flags.include)
|
|
600
637
|
baseParams.include = flags.include;
|
|
638
|
+
if (flags.fields)
|
|
639
|
+
baseParams.fields = flags.fields;
|
|
601
640
|
if (flags.query) {
|
|
602
641
|
try {
|
|
603
642
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -652,12 +691,7 @@ export default class BusinessPartners extends Command {
|
|
|
652
691
|
}
|
|
653
692
|
}
|
|
654
693
|
process.stderr.write(' done\n');
|
|
655
|
-
// Filter fields if specified
|
|
656
694
|
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
695
|
// Sanitize output if requested
|
|
662
696
|
if (flags.sanitize) {
|
|
663
697
|
output = this.sanitizeOutput(output);
|
|
@@ -986,56 +1020,6 @@ export default class BusinessPartners extends Command {
|
|
|
986
1020
|
return `\$${op}`;
|
|
987
1021
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
988
1022
|
}
|
|
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
1023
|
sanitizeOutput(data) {
|
|
1040
1024
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1041
1025
|
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
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
|
-
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
2
|
+
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
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 = false;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["create", "get", "get-all", "update", "delete", "stream"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["create", "get", "get-all", "update", "delete", "stream", "token-refresh"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'create': { method: 'POST', path: '/v1/chat', summary: 'Send a chat message and stream the assistant reply (SSE).', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['attachments'] },
|
|
12
|
-
'get': { method: 'GET', path: '/v1/conversations', summary: 'List the caller\'s chat conversations, most recently updated first.', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
13
|
-
'get-all': { method: 'GET', path: '/v1/conversations/{id}', summary: 'Fetch one conversation with its messages.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/conversations/{id}', summary: 'Store client-owned UI state on a conversation.', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/conversations/{id}', summary: 'Delete one conversation.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
-
'stream': { method: 'GET', path: '/v1/conversations/{id}/stream', summary: 'Reattach to a conversation\'s running turn (SSE replay + follow).', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
11
|
+
'create': { method: 'POST', path: '/v1/chat', summary: 'Send a chat message and stream the assistant reply (SSE).', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['attachments'] },
|
|
12
|
+
'get': { method: 'GET', path: '/v1/conversations', summary: 'List the caller\'s chat conversations, most recently updated first.', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'get-all': { method: 'GET', path: '/v1/conversations/{id}', summary: 'Fetch one conversation with its messages.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/conversations/{id}', summary: 'Store client-owned UI state on a conversation.', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/conversations/{id}', summary: 'Delete one conversation.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
+
'stream': { method: 'GET', path: '/v1/conversations/{id}/stream', summary: 'Reattach to a conversation\'s running turn (SSE replay + follow).', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
+
'token-refresh': { method: 'POST', path: '/v1/chat/token/refresh', summary: 'Refresh the delegated token a chat turn runs on', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
18
|
};
|
|
18
19
|
export default class Chat extends Command {
|
|
19
20
|
static description = 'Manage chat';
|
|
@@ -42,7 +43,7 @@ export default class Chat extends Command {
|
|
|
42
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.' }),
|
|
43
44
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
44
45
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
45
|
-
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)' }),
|
|
46
47
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
47
48
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
48
49
|
};
|
|
@@ -114,6 +115,8 @@ export default class Chat extends Command {
|
|
|
114
115
|
queryParams.search = flags.search;
|
|
115
116
|
if (flags['sort-by'])
|
|
116
117
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
118
|
+
if (flags.fields)
|
|
119
|
+
queryParams.fields = flags.fields;
|
|
117
120
|
if (flags.query) {
|
|
118
121
|
try {
|
|
119
122
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -261,10 +264,11 @@ export default class Chat extends Command {
|
|
|
261
264
|
process.stderr.write('\n');
|
|
262
265
|
}
|
|
263
266
|
try {
|
|
264
|
-
// Binary response:
|
|
267
|
+
// Binary response: to -f / --file, or to stdout when it is redirected.
|
|
265
268
|
if (endpoint.isBinaryResponse) {
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
const toStdout = !flags.file;
|
|
270
|
+
if (toStdout && process.stdout.isTTY) {
|
|
271
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx), or redirect stdout to a file.`);
|
|
268
272
|
}
|
|
269
273
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
270
274
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
@@ -272,24 +276,55 @@ export default class Chat extends Command {
|
|
|
272
276
|
contextName: flags.context,
|
|
273
277
|
binary: true,
|
|
274
278
|
});
|
|
275
|
-
const fsModule = await import('node:fs');
|
|
276
279
|
const binData = binResponse.data;
|
|
277
280
|
const buffer = Buffer.isBuffer(binData)
|
|
278
281
|
? binData
|
|
279
282
|
: Buffer.from(binData);
|
|
283
|
+
if (toStdout) {
|
|
284
|
+
// Nothing else may reach stdout here — it is the file.
|
|
285
|
+
process.stdout.write(buffer);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const fsModule = await import('node:fs');
|
|
280
289
|
fsModule.writeFileSync(flags.file, buffer);
|
|
281
290
|
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
282
291
|
return;
|
|
283
292
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
293
|
+
let response;
|
|
294
|
+
if (endpoint.hasBinaryVariant) {
|
|
295
|
+
// This route answers JSON or a file depending on the request body, so the
|
|
296
|
+
// bytes are read first and the response's own content-type decides. Asking
|
|
297
|
+
// for text here would corrupt an xlsx/pdf before anything could inspect it.
|
|
298
|
+
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
299
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
300
|
+
data,
|
|
301
|
+
contextName: flags.context,
|
|
302
|
+
binary: true,
|
|
303
|
+
});
|
|
304
|
+
const rawType = String(raw.headers['content-type'] || '').toLowerCase();
|
|
305
|
+
const rawData = raw.data;
|
|
306
|
+
const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);
|
|
307
|
+
if (!isTextualMediaType(rawType)) {
|
|
308
|
+
if (process.stdout.isTTY) {
|
|
309
|
+
this.error(`The API returned ${rawType || 'binary data'}. Redirect stdout to a file, e.g. ... > report.xlsx`);
|
|
310
|
+
}
|
|
311
|
+
// Nothing else may reach stdout here — it is the file.
|
|
312
|
+
process.stdout.write(buffer);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
response = { data: buffer.toString('utf8'), headers: raw.headers, status: raw.status };
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
response = await apiRequest(endpoint.method, apiPath, {
|
|
319
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
320
|
+
data,
|
|
321
|
+
contextName: flags.context,
|
|
322
|
+
acceptAny: true,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
290
325
|
// Check content-type for non-JSON responses (XML, text, etc.)
|
|
291
326
|
const contentType = (response.headers['content-type'] || '').toLowerCase();
|
|
292
|
-
if (contentType
|
|
327
|
+
if (isTextualMediaType(contentType) && !contentType.startsWith('application/json')) {
|
|
293
328
|
// Output raw content for XML/text responses (CSV, plain, HTML, etc.)
|
|
294
329
|
this.log(String(response.data));
|
|
295
330
|
return;
|
|
@@ -316,11 +351,6 @@ export default class Chat extends Command {
|
|
|
316
351
|
output = obj[arrayKeys[0]];
|
|
317
352
|
}
|
|
318
353
|
}
|
|
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
354
|
// Sanitize output if requested
|
|
325
355
|
if (flags.sanitize) {
|
|
326
356
|
output = this.sanitizeOutput(output);
|
|
@@ -575,6 +605,8 @@ export default class Chat extends Command {
|
|
|
575
605
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
576
606
|
if (flags.include)
|
|
577
607
|
baseParams.include = flags.include;
|
|
608
|
+
if (flags.fields)
|
|
609
|
+
baseParams.fields = flags.fields;
|
|
578
610
|
if (flags.query) {
|
|
579
611
|
try {
|
|
580
612
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -629,12 +661,7 @@ export default class Chat extends Command {
|
|
|
629
661
|
}
|
|
630
662
|
}
|
|
631
663
|
process.stderr.write(' done\n');
|
|
632
|
-
// Filter fields if specified
|
|
633
664
|
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
665
|
// Sanitize output if requested
|
|
639
666
|
if (flags.sanitize) {
|
|
640
667
|
output = this.sanitizeOutput(output);
|
|
@@ -963,56 +990,6 @@ export default class Chat extends Command {
|
|
|
963
990
|
return `\$${op}`;
|
|
964
991
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
965
992
|
}
|
|
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
993
|
sanitizeOutput(data) {
|
|
1017
994
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1018
995
|
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
|
}
|