@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,30 +1,30 @@
|
|
|
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;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = ["line-items", "notes", "files", "payments"];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "submit", "approve", "decline", "book", "rebuild-journal", "cancel", "
|
|
9
|
+
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "payment-derivation", "submit", "approve", "decline", "book", "rebuild-journal", "cancel", "change-vendor", "recalculate-payment-status", "validate", "create-line-items", "update-line-items", "delete-line-items", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-payments", "create-payments", "get-payments", "update-payments", "delete-payments", "payments-approve", "payments-reopen", "payments-cancel"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/vendor-invoices', summary: 'Get all vendor invoices with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/vendor-invoices', summary: 'Create a new vendor invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'payments'] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/vendor-invoices', summary: 'Create a new vendor invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'tagCodes', 'payments'] },
|
|
13
13
|
'get': { method: 'GET', path: '/v1/vendor-invoices/{id}', summary: 'Get a vendor invoice by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/vendor-invoices/{id}', summary: 'Update a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/vendor-invoices/{id}', summary: 'Update a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'tagCodes', 'removeFileIds'] },
|
|
15
15
|
'delete': { method: 'DELETE', path: '/v1/vendor-invoices/{id}', summary: 'Delete a vendor invoice', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
+
'payment-derivation': { method: 'GET', path: '/v1/vendor-invoices/{id}/payment-derivation', summary: 'Explain how a vendor invoice\'s paid amount is derived', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
17
|
'submit': { method: 'POST', path: '/v1/vendor-invoices/{id}/submit', summary: 'Submit a vendor invoice for approval (transitions DRAFT to PENDING_APPROVAL)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
-
'approve': { method: 'POST', path: '/v1/vendor-invoices/{id}/approve', summary: 'Approve a vendor invoice (transitions DRAFT/PENDING_APPROVAL to APPROVED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
18
|
+
'approve': { method: 'POST', path: '/v1/vendor-invoices/{id}/approve', summary: 'Approve a vendor invoice (transitions DRAFT/PENDING_APPROVAL to APPROVED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'tagCodes', 'removeFileIds'] },
|
|
18
19
|
'decline': { method: 'POST', path: '/v1/vendor-invoices/{id}/decline', summary: 'Decline a vendor invoice (transitions PENDING_APPROVAL to DECLINED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
20
|
'book': { method: 'POST', path: '/v1/vendor-invoices/{id}/book', summary: 'Manually book a vendor invoice (dispatch to ledger-booking-agent)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
21
|
'rebuild-journal': { method: 'POST', path: '/v1/vendor-invoices/{id}/rebuild-journal', summary: 'Rebuild a vendor invoice booking journal (dispatch to ledger-booking-agent)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
21
22
|
'cancel': { method: 'POST', path: '/v1/vendor-invoices/{id}/cancel', summary: 'Cancel a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
-
'confirm-cancellation': { method: 'POST', path: '/v1/vendor-invoices/{id}/confirm-cancellation', summary: 'Confirm bank cancellation for a vendor invoice (PENDING_CANCELLATION to CANCELLED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
23
|
'change-vendor': { method: 'POST', path: '/v1/vendor-invoices/{id}/change-vendor', summary: 'Change the vendor on a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
24
24
|
'recalculate-payment-status': { method: 'POST', path: '/v1/vendor-invoices/{id}/recalculate-payment-status', summary: 'Recalculate a vendor invoice\'s open amount and payment status', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
|
-
'validate': { method: 'POST', path: '/v1/vendor-invoices/{id}/validate', summary: 'Validate a vendor invoice update without persisting changes', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
26
|
-
'create-line-items': { method: 'POST', path: '/v1/vendor-invoices/{invoiceId}/line-items', summary: 'Add a line item to a vendor invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
|
-
'update-line-items': { method: 'PATCH', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Update a line item on a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
|
+
'validate': { method: 'POST', path: '/v1/vendor-invoices/{id}/validate', summary: 'Validate a vendor invoice update without persisting changes', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['earlyPaymentDiscounts', 'totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'tagCodes', 'removeFileIds'] },
|
|
26
|
+
'create-line-items': { method: 'POST', path: '/v1/vendor-invoices/{invoiceId}/line-items', summary: 'Add a line item to a vendor invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes', 'purchaseOrderLineItems'] },
|
|
27
|
+
'update-line-items': { method: 'PATCH', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Update a line item on a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes', 'purchaseOrderLineItems'] },
|
|
28
28
|
'delete-line-items': { method: 'DELETE', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Remove a line item from a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
29
29
|
'list-notes': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Get all notes for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
30
30
|
'create-notes': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Create a note for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
@@ -43,6 +43,7 @@ const ENDPOINTS = {
|
|
|
43
43
|
'update-payments': { method: 'PATCH', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Update a payment for a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
44
44
|
'delete-payments': { method: 'DELETE', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Delete a payment from a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
45
45
|
'payments-approve': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/approve', summary: 'Approve a payment entry (OPEN → APPROVED)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
46
|
+
'payments-reopen': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/reopen', summary: 'Reopen an approved payment entry (APPROVED → OPEN)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
46
47
|
'payments-cancel': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/cancel', summary: 'Cancel a sent payment entry (SENT -> ERROR)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
47
48
|
};
|
|
48
49
|
export default class VendorInvoices extends Command {
|
|
@@ -60,7 +61,7 @@ export default class VendorInvoices extends Command {
|
|
|
60
61
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
61
62
|
};
|
|
62
63
|
static flags = {
|
|
63
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
64
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
64
65
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
65
66
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
66
67
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -78,7 +79,7 @@ export default class VendorInvoices extends Command {
|
|
|
78
79
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
79
80
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
80
81
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
81
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
82
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
82
83
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
83
84
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
84
85
|
};
|
|
@@ -136,9 +137,9 @@ export default class VendorInvoices extends Command {
|
|
|
136
137
|
}
|
|
137
138
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
138
139
|
if (!context)
|
|
139
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
140
|
-
if (!context
|
|
141
|
-
this.error(
|
|
140
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
141
|
+
if (!hasCredentials(context))
|
|
142
|
+
this.error(missingCredentialsMessage(context));
|
|
142
143
|
const queryParams = {};
|
|
143
144
|
if (flags.page)
|
|
144
145
|
queryParams.page = flags.page;
|
|
@@ -150,6 +151,8 @@ export default class VendorInvoices extends Command {
|
|
|
150
151
|
queryParams.search = flags.search;
|
|
151
152
|
if (flags['sort-by'])
|
|
152
153
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
154
|
+
if (flags.fields)
|
|
155
|
+
queryParams.fields = flags.fields;
|
|
153
156
|
if (flags.query) {
|
|
154
157
|
try {
|
|
155
158
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -352,11 +355,6 @@ export default class VendorInvoices extends Command {
|
|
|
352
355
|
output = obj[arrayKeys[0]];
|
|
353
356
|
}
|
|
354
357
|
}
|
|
355
|
-
// Filter fields if --fields flag is provided
|
|
356
|
-
if (flags.fields) {
|
|
357
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
358
|
-
output = this.filterFields(output, fieldList);
|
|
359
|
-
}
|
|
360
358
|
// Sanitize output if requested
|
|
361
359
|
if (flags.sanitize) {
|
|
362
360
|
output = this.sanitizeOutput(output);
|
|
@@ -381,9 +379,9 @@ export default class VendorInvoices extends Command {
|
|
|
381
379
|
async runImport(flags) {
|
|
382
380
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
383
381
|
if (!context)
|
|
384
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
385
|
-
if (!context
|
|
386
|
-
this.error(
|
|
382
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
383
|
+
if (!hasCredentials(context))
|
|
384
|
+
this.error(missingCredentialsMessage(context));
|
|
387
385
|
// Get data from file, --data, or --set flags
|
|
388
386
|
let items = [];
|
|
389
387
|
if (flags.file) {
|
|
@@ -593,9 +591,9 @@ export default class VendorInvoices extends Command {
|
|
|
593
591
|
async runExport(flags) {
|
|
594
592
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
595
593
|
if (!context)
|
|
596
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
597
|
-
if (!context
|
|
598
|
-
this.error(
|
|
594
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
595
|
+
if (!hasCredentials(context))
|
|
596
|
+
this.error(missingCredentialsMessage(context));
|
|
599
597
|
const listEndpoint = ENDPOINTS['list'];
|
|
600
598
|
if (!listEndpoint)
|
|
601
599
|
this.error('Export requires a list endpoint');
|
|
@@ -611,6 +609,8 @@ export default class VendorInvoices extends Command {
|
|
|
611
609
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
612
610
|
if (flags.include)
|
|
613
611
|
baseParams.include = flags.include;
|
|
612
|
+
if (flags.fields)
|
|
613
|
+
baseParams.fields = flags.fields;
|
|
614
614
|
if (flags.query) {
|
|
615
615
|
try {
|
|
616
616
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -665,12 +665,7 @@ export default class VendorInvoices extends Command {
|
|
|
665
665
|
}
|
|
666
666
|
}
|
|
667
667
|
process.stderr.write(' done\n');
|
|
668
|
-
// Filter fields if specified
|
|
669
668
|
let output = allItems;
|
|
670
|
-
if (flags.fields) {
|
|
671
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
672
|
-
output = this.filterFields(allItems, fieldList);
|
|
673
|
-
}
|
|
674
669
|
// Sanitize output if requested
|
|
675
670
|
if (flags.sanitize) {
|
|
676
671
|
output = this.sanitizeOutput(output);
|
|
@@ -687,9 +682,9 @@ export default class VendorInvoices extends Command {
|
|
|
687
682
|
async runCamt053Import(flags) {
|
|
688
683
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
689
684
|
if (!context)
|
|
690
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
691
|
-
if (!context
|
|
692
|
-
this.error(
|
|
685
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
686
|
+
if (!hasCredentials(context))
|
|
687
|
+
this.error(missingCredentialsMessage(context));
|
|
693
688
|
if (!flags.file) {
|
|
694
689
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
695
690
|
}
|
|
@@ -777,9 +772,9 @@ export default class VendorInvoices extends Command {
|
|
|
777
772
|
}
|
|
778
773
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
779
774
|
if (!context)
|
|
780
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
781
|
-
if (!context
|
|
782
|
-
this.error(
|
|
775
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
776
|
+
if (!hasCredentials(context))
|
|
777
|
+
this.error(missingCredentialsMessage(context));
|
|
783
778
|
// Get data from file, --data, or --set flags
|
|
784
779
|
let items = [];
|
|
785
780
|
if (flags.file) {
|
|
@@ -999,56 +994,6 @@ export default class VendorInvoices extends Command {
|
|
|
999
994
|
return `\$${op}`;
|
|
1000
995
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
1001
996
|
}
|
|
1002
|
-
filterFields(data, fields) {
|
|
1003
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
1004
|
-
const pick = (obj, keys) => {
|
|
1005
|
-
// Group keys by their first segment so sibling sub-paths
|
|
1006
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
1007
|
-
// and don't clobber each other on merge.
|
|
1008
|
-
const directKeys = new Set();
|
|
1009
|
-
const nestedKeys = new Map();
|
|
1010
|
-
for (const key of keys) {
|
|
1011
|
-
if (key.split('.').some(isUnsafeKey))
|
|
1012
|
-
continue;
|
|
1013
|
-
if (key.includes('.')) {
|
|
1014
|
-
const [first, ...rest] = key.split('.');
|
|
1015
|
-
if (isUnsafeKey(first))
|
|
1016
|
-
continue;
|
|
1017
|
-
const list = nestedKeys.get(first);
|
|
1018
|
-
if (list) {
|
|
1019
|
-
list.push(rest.join('.'));
|
|
1020
|
-
}
|
|
1021
|
-
else {
|
|
1022
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
else {
|
|
1026
|
-
directKeys.add(key);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
const result = {};
|
|
1030
|
-
for (const key of directKeys) {
|
|
1031
|
-
if (key in obj)
|
|
1032
|
-
result[key] = obj[key];
|
|
1033
|
-
}
|
|
1034
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1035
|
-
const val = obj[first];
|
|
1036
|
-
if (!val || typeof val !== 'object')
|
|
1037
|
-
continue;
|
|
1038
|
-
if (Array.isArray(val)) {
|
|
1039
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1040
|
-
}
|
|
1041
|
-
else {
|
|
1042
|
-
result[first] = pick(val, restKeys);
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
return result;
|
|
1046
|
-
};
|
|
1047
|
-
if (Array.isArray(data)) {
|
|
1048
|
-
return data.map(item => pick(item, fields));
|
|
1049
|
-
}
|
|
1050
|
-
return pick(data, fields);
|
|
1051
|
-
}
|
|
1052
997
|
sanitizeOutput(data) {
|
|
1053
998
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1054
999
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -31,7 +31,7 @@ export default class Webhooks extends Command {
|
|
|
31
31
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
32
32
|
};
|
|
33
33
|
static flags = {
|
|
34
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
34
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
35
35
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
36
36
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
37
37
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -45,7 +45,7 @@ export default class Webhooks extends Command {
|
|
|
45
45
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
46
46
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
47
47
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
48
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
48
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
49
49
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
50
50
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
51
51
|
};
|
|
@@ -103,9 +103,9 @@ export default class Webhooks extends Command {
|
|
|
103
103
|
}
|
|
104
104
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
105
105
|
if (!context)
|
|
106
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
107
|
-
if (!context
|
|
108
|
-
this.error(
|
|
106
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
107
|
+
if (!hasCredentials(context))
|
|
108
|
+
this.error(missingCredentialsMessage(context));
|
|
109
109
|
const queryParams = {};
|
|
110
110
|
if (flags.page)
|
|
111
111
|
queryParams.page = flags.page;
|
|
@@ -117,6 +117,8 @@ export default class Webhooks extends Command {
|
|
|
117
117
|
queryParams.search = flags.search;
|
|
118
118
|
if (flags['sort-by'])
|
|
119
119
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
120
|
+
if (flags.fields)
|
|
121
|
+
queryParams.fields = flags.fields;
|
|
120
122
|
if (flags.query) {
|
|
121
123
|
try {
|
|
122
124
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -319,11 +321,6 @@ export default class Webhooks extends Command {
|
|
|
319
321
|
output = obj[arrayKeys[0]];
|
|
320
322
|
}
|
|
321
323
|
}
|
|
322
|
-
// Filter fields if --fields flag is provided
|
|
323
|
-
if (flags.fields) {
|
|
324
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
325
|
-
output = this.filterFields(output, fieldList);
|
|
326
|
-
}
|
|
327
324
|
// Sanitize output if requested
|
|
328
325
|
if (flags.sanitize) {
|
|
329
326
|
output = this.sanitizeOutput(output);
|
|
@@ -348,9 +345,9 @@ export default class Webhooks extends Command {
|
|
|
348
345
|
async runImport(flags) {
|
|
349
346
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
350
347
|
if (!context)
|
|
351
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
352
|
-
if (!context
|
|
353
|
-
this.error(
|
|
348
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
349
|
+
if (!hasCredentials(context))
|
|
350
|
+
this.error(missingCredentialsMessage(context));
|
|
354
351
|
// Get data from file, --data, or --set flags
|
|
355
352
|
let items = [];
|
|
356
353
|
if (flags.file) {
|
|
@@ -560,9 +557,9 @@ export default class Webhooks extends Command {
|
|
|
560
557
|
async runExport(flags) {
|
|
561
558
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
562
559
|
if (!context)
|
|
563
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
564
|
-
if (!context
|
|
565
|
-
this.error(
|
|
560
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
561
|
+
if (!hasCredentials(context))
|
|
562
|
+
this.error(missingCredentialsMessage(context));
|
|
566
563
|
const listEndpoint = ENDPOINTS['list'];
|
|
567
564
|
if (!listEndpoint)
|
|
568
565
|
this.error('Export requires a list endpoint');
|
|
@@ -578,6 +575,8 @@ export default class Webhooks extends Command {
|
|
|
578
575
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
579
576
|
if (flags.include)
|
|
580
577
|
baseParams.include = flags.include;
|
|
578
|
+
if (flags.fields)
|
|
579
|
+
baseParams.fields = flags.fields;
|
|
581
580
|
if (flags.query) {
|
|
582
581
|
try {
|
|
583
582
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -632,12 +631,7 @@ export default class Webhooks extends Command {
|
|
|
632
631
|
}
|
|
633
632
|
}
|
|
634
633
|
process.stderr.write(' done\n');
|
|
635
|
-
// Filter fields if specified
|
|
636
634
|
let output = allItems;
|
|
637
|
-
if (flags.fields) {
|
|
638
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
639
|
-
output = this.filterFields(allItems, fieldList);
|
|
640
|
-
}
|
|
641
635
|
// Sanitize output if requested
|
|
642
636
|
if (flags.sanitize) {
|
|
643
637
|
output = this.sanitizeOutput(output);
|
|
@@ -654,9 +648,9 @@ export default class Webhooks extends Command {
|
|
|
654
648
|
async runCamt053Import(flags) {
|
|
655
649
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
656
650
|
if (!context)
|
|
657
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
658
|
-
if (!context
|
|
659
|
-
this.error(
|
|
651
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
652
|
+
if (!hasCredentials(context))
|
|
653
|
+
this.error(missingCredentialsMessage(context));
|
|
660
654
|
if (!flags.file) {
|
|
661
655
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
662
656
|
}
|
|
@@ -744,9 +738,9 @@ export default class Webhooks extends Command {
|
|
|
744
738
|
}
|
|
745
739
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
746
740
|
if (!context)
|
|
747
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
748
|
-
if (!context
|
|
749
|
-
this.error(
|
|
741
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
742
|
+
if (!hasCredentials(context))
|
|
743
|
+
this.error(missingCredentialsMessage(context));
|
|
750
744
|
// Get data from file, --data, or --set flags
|
|
751
745
|
let items = [];
|
|
752
746
|
if (flags.file) {
|
|
@@ -966,56 +960,6 @@ export default class Webhooks extends Command {
|
|
|
966
960
|
return `\$${op}`;
|
|
967
961
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
968
962
|
}
|
|
969
|
-
filterFields(data, fields) {
|
|
970
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
971
|
-
const pick = (obj, keys) => {
|
|
972
|
-
// Group keys by their first segment so sibling sub-paths
|
|
973
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
974
|
-
// and don't clobber each other on merge.
|
|
975
|
-
const directKeys = new Set();
|
|
976
|
-
const nestedKeys = new Map();
|
|
977
|
-
for (const key of keys) {
|
|
978
|
-
if (key.split('.').some(isUnsafeKey))
|
|
979
|
-
continue;
|
|
980
|
-
if (key.includes('.')) {
|
|
981
|
-
const [first, ...rest] = key.split('.');
|
|
982
|
-
if (isUnsafeKey(first))
|
|
983
|
-
continue;
|
|
984
|
-
const list = nestedKeys.get(first);
|
|
985
|
-
if (list) {
|
|
986
|
-
list.push(rest.join('.'));
|
|
987
|
-
}
|
|
988
|
-
else {
|
|
989
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
directKeys.add(key);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
const result = {};
|
|
997
|
-
for (const key of directKeys) {
|
|
998
|
-
if (key in obj)
|
|
999
|
-
result[key] = obj[key];
|
|
1000
|
-
}
|
|
1001
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1002
|
-
const val = obj[first];
|
|
1003
|
-
if (!val || typeof val !== 'object')
|
|
1004
|
-
continue;
|
|
1005
|
-
if (Array.isArray(val)) {
|
|
1006
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1007
|
-
}
|
|
1008
|
-
else {
|
|
1009
|
-
result[first] = pick(val, restKeys);
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
return result;
|
|
1013
|
-
};
|
|
1014
|
-
if (Array.isArray(data)) {
|
|
1015
|
-
return data.map(item => pick(item, fields));
|
|
1016
|
-
}
|
|
1017
|
-
return pick(data, fields);
|
|
1018
|
-
}
|
|
1019
963
|
sanitizeOutput(data) {
|
|
1020
964
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1021
965
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -23,7 +23,7 @@ export default class Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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 Workflows 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;
|