@aderis-erp/cli 1.1.4 → 1.1.5
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/dist/commands/access-groups.js +42 -8
- package/dist/commands/account-transaction-allocations.js +38 -4
- package/dist/commands/account-transactions.d.ts +2 -0
- package/dist/commands/account-transactions.js +68 -32
- package/dist/commands/accounts.js +46 -12
- package/dist/commands/agent-platform.js +37 -3
- package/dist/commands/agent-runs.js +49 -15
- package/dist/commands/analytics.js +39 -5
- package/dist/commands/api-clients.js +47 -13
- package/dist/commands/api-keys.js +40 -6
- package/dist/commands/async-jobs.js +45 -11
- package/dist/commands/audit-log.js +38 -4
- package/dist/commands/bank-accounts.js +54 -20
- package/dist/commands/bank-integrations.js +56 -22
- package/dist/commands/business-partners.js +77 -43
- package/dist/commands/chat.js +43 -9
- package/dist/commands/credit-card-accounts.js +57 -23
- package/dist/commands/currencies.js +37 -3
- package/dist/commands/custody-accounts.js +41 -7
- package/dist/commands/dashboards.js +52 -18
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +1 -0
- package/dist/commands/document-checksums.js +38 -3
- package/dist/commands/dunning-configs.js +41 -7
- package/dist/commands/dunning-reminders.js +44 -10
- package/dist/commands/dunning-runs.js +37 -3
- package/dist/commands/email-transactions.js +39 -5
- package/dist/commands/employees.js +77 -43
- package/dist/commands/entity-configurations.js +39 -5
- package/dist/commands/event-mapping-rules.js +37 -3
- package/dist/commands/event-processor-mappings.js +41 -7
- package/dist/commands/files.js +48 -14
- package/dist/commands/financial-instrument-transactions.d.ts +56 -0
- package/dist/commands/financial-instrument-transactions.js +1369 -0
- package/dist/commands/financial-instrument-types.js +41 -7
- package/dist/commands/financial-instruments.js +41 -7
- package/dist/commands/health.js +41 -7
- package/dist/commands/imports.js +39 -5
- package/dist/commands/inbox.js +42 -8
- package/dist/commands/integrations.js +39 -5
- package/dist/commands/item-categories.js +41 -7
- package/dist/commands/items.js +42 -8
- package/dist/commands/journal-lines.js +37 -3
- package/dist/commands/journals.js +61 -27
- package/dist/commands/kpis.js +44 -10
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.js +37 -3
- package/dist/commands/office-locations.js +41 -7
- package/dist/commands/payment-methods.js +46 -12
- package/dist/commands/payment-runs.js +54 -20
- package/dist/commands/payment-terms.js +42 -8
- package/dist/commands/payments.js +43 -9
- package/dist/commands/payroll-runs.js +71 -37
- package/dist/commands/permissions.js +37 -3
- package/dist/commands/price-lists.js +48 -14
- package/dist/commands/processor-mappings.js +40 -6
- package/dist/commands/processors.js +46 -12
- package/dist/commands/purchase-order-types.js +41 -7
- package/dist/commands/purchase-orders.js +60 -26
- package/dist/commands/reports.js +43 -8
- package/dist/commands/roles.js +40 -6
- package/dist/commands/salary-types.js +41 -7
- package/dist/commands/sales-invoices.js +85 -51
- package/dist/commands/sales-orders.js +69 -35
- package/dist/commands/saved-views.js +39 -5
- package/dist/commands/scheduled-processor-mappings.js +41 -7
- package/dist/commands/schedules.js +45 -11
- package/dist/commands/settings.js +38 -4
- package/dist/commands/tags.js +42 -8
- package/dist/commands/tax-codes.js +44 -10
- package/dist/commands/tax-matrix.js +41 -7
- package/dist/commands/templates.js +49 -15
- package/dist/commands/tenants.js +44 -10
- package/dist/commands/tools.js +38 -4
- package/dist/commands/users.js +58 -24
- package/dist/commands/vat-declarations.js +61 -27
- package/dist/commands/vendor-invoices.js +81 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.js +37 -3
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.js +2 -0
- package/oclif.manifest.json +199 -2
- package/package.json +9 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,15 +12,15 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "submit", "list-attempts", "list-items", "payload"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/async-jobs', summary: 'List the jobs the caller may see', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/async-jobs', summary: 'Create a draft job', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/async-jobs/{id}', summary: 'Read one job back', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/async-jobs/{id}', summary: 'Replace the input of a draft', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/async-jobs/{id}', summary: 'Throw a job away', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'submit': { method: 'POST', path: '/v1/async-jobs/{id}/submit', summary: 'Ask for the work of a draft', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'list-attempts': { method: 'GET', path: '/v1/async-jobs/{id}/attempts', summary: 'List the runs of one job', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'list-items': { method: 'GET', path: '/v1/async-jobs/{id}/items', summary: 'List the records of one job and how the work on each ended', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'payload': { method: 'GET', path: '/v1/async-jobs/{id}/payload', summary: 'Read the input a job holds', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/async-jobs', summary: 'List the jobs the caller may see', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/async-jobs', summary: 'Create a draft job', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/async-jobs/{id}', summary: 'Read one job back', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/async-jobs/{id}', summary: 'Replace the input of a draft', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/async-jobs/{id}', summary: 'Throw a job away', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'submit': { method: 'POST', path: '/v1/async-jobs/{id}/submit', summary: 'Ask for the work of a draft', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'list-attempts': { method: 'GET', path: '/v1/async-jobs/{id}/attempts', summary: 'List the runs of one job', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'list-items': { method: 'GET', path: '/v1/async-jobs/{id}/items', summary: 'List the records of one job and how the work on each ended', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'payload': { method: 'GET', path: '/v1/async-jobs/{id}/payload', summary: 'Read the input a job holds', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
24
|
};
|
|
24
25
|
export default class AsyncJobs extends Command {
|
|
25
26
|
static description = 'Manage async jobs';
|
|
@@ -41,7 +42,7 @@ export default class AsyncJobs extends Command {
|
|
|
41
42
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
42
43
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
43
44
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
44
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
45
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
45
46
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
46
47
|
page: Flags.string({ description: 'Page number' }),
|
|
47
48
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -172,6 +173,17 @@ export default class AsyncJobs extends Command {
|
|
|
172
173
|
}
|
|
173
174
|
}
|
|
174
175
|
}
|
|
176
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
177
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
178
|
+
for (const param of endpoint.specParams) {
|
|
179
|
+
const value = flags[param.flag];
|
|
180
|
+
if (value === undefined || value === '') {
|
|
181
|
+
if (param.required)
|
|
182
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
queryParams[param.name] = value;
|
|
186
|
+
}
|
|
175
187
|
let data;
|
|
176
188
|
if (endpoint.isMultipart) {
|
|
177
189
|
if (!flags.file)
|
|
@@ -192,6 +204,25 @@ export default class AsyncJobs extends Command {
|
|
|
192
204
|
}
|
|
193
205
|
data = form;
|
|
194
206
|
}
|
|
207
|
+
else if (endpoint.bodyMediaType) {
|
|
208
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
209
|
+
// verbatim, under the content type the endpoint asks for.
|
|
210
|
+
if (flags.file) {
|
|
211
|
+
const fsModule = await import('node:fs');
|
|
212
|
+
try {
|
|
213
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (flags.data) {
|
|
220
|
+
data = flags.data;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
195
226
|
else if (endpoint.hasBody) {
|
|
196
227
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
197
228
|
// input file — skip the read-as-body branch.
|
|
@@ -287,7 +318,7 @@ export default class AsyncJobs extends Command {
|
|
|
287
318
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
288
319
|
}
|
|
289
320
|
else if (data) {
|
|
290
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
321
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
291
322
|
}
|
|
292
323
|
process.stderr.write('\n');
|
|
293
324
|
}
|
|
@@ -301,6 +332,7 @@ export default class AsyncJobs extends Command {
|
|
|
301
332
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
302
333
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
303
334
|
data,
|
|
335
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
304
336
|
contextName: flags.context,
|
|
305
337
|
binary: true,
|
|
306
338
|
});
|
|
@@ -326,6 +358,7 @@ export default class AsyncJobs extends Command {
|
|
|
326
358
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
327
359
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
328
360
|
data,
|
|
361
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
329
362
|
contextName: flags.context,
|
|
330
363
|
binary: true,
|
|
331
364
|
});
|
|
@@ -346,6 +379,7 @@ export default class AsyncJobs extends Command {
|
|
|
346
379
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
347
380
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
348
381
|
data,
|
|
382
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
349
383
|
contextName: flags.context,
|
|
350
384
|
acceptAny: true,
|
|
351
385
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,8 +12,8 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "get"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/audit-logs', summary: 'Get audit log entries', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'get': { method: 'GET', path: '/v1/audit-logs/{id}', summary: 'Get a single audit log entry', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/audit-logs', summary: 'Get audit log entries', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'get': { method: 'GET', path: '/v1/audit-logs/{id}', summary: 'Get a single audit log entry', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
17
|
};
|
|
17
18
|
export default class AuditLog extends Command {
|
|
18
19
|
static description = 'Manage audit log';
|
|
@@ -31,7 +32,7 @@ export default class AuditLog extends Command {
|
|
|
31
32
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
32
33
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
33
34
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
34
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
35
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
35
36
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
36
37
|
page: Flags.string({ description: 'Page number' }),
|
|
37
38
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -162,6 +163,17 @@ export default class AuditLog extends Command {
|
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
}
|
|
166
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
167
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
168
|
+
for (const param of endpoint.specParams) {
|
|
169
|
+
const value = flags[param.flag];
|
|
170
|
+
if (value === undefined || value === '') {
|
|
171
|
+
if (param.required)
|
|
172
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
queryParams[param.name] = value;
|
|
176
|
+
}
|
|
165
177
|
let data;
|
|
166
178
|
if (endpoint.isMultipart) {
|
|
167
179
|
if (!flags.file)
|
|
@@ -182,6 +194,25 @@ export default class AuditLog extends Command {
|
|
|
182
194
|
}
|
|
183
195
|
data = form;
|
|
184
196
|
}
|
|
197
|
+
else if (endpoint.bodyMediaType) {
|
|
198
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
199
|
+
// verbatim, under the content type the endpoint asks for.
|
|
200
|
+
if (flags.file) {
|
|
201
|
+
const fsModule = await import('node:fs');
|
|
202
|
+
try {
|
|
203
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (flags.data) {
|
|
210
|
+
data = flags.data;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
185
216
|
else if (endpoint.hasBody) {
|
|
186
217
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
187
218
|
// input file — skip the read-as-body branch.
|
|
@@ -277,7 +308,7 @@ export default class AuditLog extends Command {
|
|
|
277
308
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
278
309
|
}
|
|
279
310
|
else if (data) {
|
|
280
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
311
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
281
312
|
}
|
|
282
313
|
process.stderr.write('\n');
|
|
283
314
|
}
|
|
@@ -291,6 +322,7 @@ export default class AuditLog extends Command {
|
|
|
291
322
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
292
323
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
293
324
|
data,
|
|
325
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
294
326
|
contextName: flags.context,
|
|
295
327
|
binary: true,
|
|
296
328
|
});
|
|
@@ -316,6 +348,7 @@ export default class AuditLog extends Command {
|
|
|
316
348
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
317
349
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
318
350
|
data,
|
|
351
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
319
352
|
contextName: flags.context,
|
|
320
353
|
binary: true,
|
|
321
354
|
});
|
|
@@ -336,6 +369,7 @@ export default class AuditLog extends Command {
|
|
|
336
369
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
337
370
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
338
371
|
data,
|
|
372
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
339
373
|
contextName: flags.context,
|
|
340
374
|
acceptAny: true,
|
|
341
375
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,24 +12,24 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["ledger-mappings", "notes"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-balances", "get-balances-latest", "list-ledger-mappings", "create-ledger-mappings", "get-ledger-mappings", "update-ledger-mappings", "delete-ledger-mappings", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-daily-balances"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/bank-accounts', summary: 'Get all bank accounts with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/bank-accounts', summary: 'Create a new bank account (with optional notes)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/bank-accounts/{id}', summary: 'Get a bank account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/bank-accounts/{id}', summary: 'Update a bank account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/bank-accounts/{id}', summary: 'Delete a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'get-balances': { method: 'GET', path: '/v1/bank-accounts/{id}/balances', summary: 'Get balance history for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'get-balances-latest': { method: 'GET', path: '/v1/bank-accounts/{id}/balances/latest', summary: 'Get latest balances (OPBD, CLBD, CLAV) for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'list-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Get all ledger mappings for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'create-ledger-mappings': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Create a ledger mapping for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'get-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Get a ledger mapping by ID', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'update-ledger-mappings': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Update a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'delete-ledger-mappings': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Delete a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'list-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Get all notes for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'create-notes': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Create a note for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'get-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Get a specific note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'update-notes': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Update a note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'delete-notes': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Delete a note from a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'list-daily-balances': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/daily-balances', summary: 'Get a bank account\'s daily closing balances for a date range, one row per day and currency', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/bank-accounts', summary: 'Get all bank accounts with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/bank-accounts', summary: 'Create a new bank account (with optional notes)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/bank-accounts/{id}', summary: 'Get a bank account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/bank-accounts/{id}', summary: 'Update a bank account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentRunDays', 'notes'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/bank-accounts/{id}', summary: 'Delete a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'get-balances': { method: 'GET', path: '/v1/bank-accounts/{id}/balances', summary: 'Get balance history for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'get-balances-latest': { method: 'GET', path: '/v1/bank-accounts/{id}/balances/latest', summary: 'Get latest balances (OPBD, CLBD, CLAV) for a bank account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'list-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Get all ledger mappings for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'create-ledger-mappings': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings', summary: 'Create a ledger mapping for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'get-ledger-mappings': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Get a ledger mapping by ID', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'update-ledger-mappings': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Update a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'delete-ledger-mappings': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/ledger-mappings/{mappingId}', summary: 'Delete a ledger mapping', pathParams: ['bankAccountId', 'mappingId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'list-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Get all notes for a bank account', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'create-notes': { method: 'POST', path: '/v1/bank-accounts/{bankAccountId}/notes', summary: 'Create a note for a bank account', pathParams: ['bankAccountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'get-notes': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Get a specific note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'update-notes': { method: 'PATCH', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Update a note for a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'delete-notes': { method: 'DELETE', path: '/v1/bank-accounts/{bankAccountId}/notes/{noteId}', summary: 'Delete a note from a bank account', pathParams: ['bankAccountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'list-daily-balances': { method: 'GET', path: '/v1/bank-accounts/{bankAccountId}/daily-balances', summary: 'Get a bank account\'s daily closing balances for a date range, one row per day and currency', pathParams: ['bankAccountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
33
|
};
|
|
33
34
|
export default class BankAccounts extends Command {
|
|
34
35
|
static description = 'Manage bank accounts';
|
|
@@ -50,7 +51,7 @@ export default class BankAccounts extends Command {
|
|
|
50
51
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
51
52
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
52
53
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
53
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
54
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
54
55
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
55
56
|
'mapping-id': Flags.string({ description: 'Path param: mappingId' }),
|
|
56
57
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
@@ -183,6 +184,17 @@ export default class BankAccounts extends Command {
|
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
}
|
|
187
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
188
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
189
|
+
for (const param of endpoint.specParams) {
|
|
190
|
+
const value = flags[param.flag];
|
|
191
|
+
if (value === undefined || value === '') {
|
|
192
|
+
if (param.required)
|
|
193
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
queryParams[param.name] = value;
|
|
197
|
+
}
|
|
186
198
|
let data;
|
|
187
199
|
if (endpoint.isMultipart) {
|
|
188
200
|
if (!flags.file)
|
|
@@ -203,6 +215,25 @@ export default class BankAccounts extends Command {
|
|
|
203
215
|
}
|
|
204
216
|
data = form;
|
|
205
217
|
}
|
|
218
|
+
else if (endpoint.bodyMediaType) {
|
|
219
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
220
|
+
// verbatim, under the content type the endpoint asks for.
|
|
221
|
+
if (flags.file) {
|
|
222
|
+
const fsModule = await import('node:fs');
|
|
223
|
+
try {
|
|
224
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else if (flags.data) {
|
|
231
|
+
data = flags.data;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
206
237
|
else if (endpoint.hasBody) {
|
|
207
238
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
208
239
|
// input file — skip the read-as-body branch.
|
|
@@ -298,7 +329,7 @@ export default class BankAccounts extends Command {
|
|
|
298
329
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
299
330
|
}
|
|
300
331
|
else if (data) {
|
|
301
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
332
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
302
333
|
}
|
|
303
334
|
process.stderr.write('\n');
|
|
304
335
|
}
|
|
@@ -312,6 +343,7 @@ export default class BankAccounts extends Command {
|
|
|
312
343
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
313
344
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
314
345
|
data,
|
|
346
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
315
347
|
contextName: flags.context,
|
|
316
348
|
binary: true,
|
|
317
349
|
});
|
|
@@ -337,6 +369,7 @@ export default class BankAccounts extends Command {
|
|
|
337
369
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
338
370
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
339
371
|
data,
|
|
372
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
340
373
|
contextName: flags.context,
|
|
341
374
|
binary: true,
|
|
342
375
|
});
|
|
@@ -357,6 +390,7 @@ export default class BankAccounts extends Command {
|
|
|
357
390
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
358
391
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
359
392
|
data,
|
|
393
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
360
394
|
contextName: flags.context,
|
|
361
395
|
acceptAny: true,
|
|
362
396
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,26 +12,26 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["initiate", "providers-supported", "providers-consent-status", "delete-providers-consent", "list", "create", "get", "update", "delete", "log", "list-account-statement-runs", "trigger-account-statement-runs", "get-account-statement-runs", "account-statement-runs-files", "trigger-account-statement-runs-reimport", "account-statement-runs-files-download", "list-all", "list-statements", "statements", "download-statements-xml"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'initiate': { method: 'POST', path: '/v1/bank-integrations/initiate', summary: 'Initiate the OAuth/auth flow for a bank integration', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'providers-supported': { method: 'GET', path: '/v1/bank-integrations/providers/supported', summary: 'List supported bLink providers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'providers-consent-status': { method: 'GET', path: '/v1/bank-integrations/providers/consent-status', summary: 'Get bLink consent status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'delete-providers-consent': { method: 'DELETE', path: '/v1/bank-integrations/providers/{providerId}/consent', summary: 'Revoke bLink consent for a provider', pathParams: ['providerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'list': { method: 'GET', path: '/v1/bank-integrations', summary: 'List all BankIntegrations for the current tenant with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'create': { method: 'POST', path: '/v1/bank-integrations', summary: 'Create a BankIntegration record', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['methods'] },
|
|
20
|
-
'get': { method: 'GET', path: '/v1/bank-integrations/{id}', summary: 'Get a BankIntegration by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'update': { method: 'PATCH', path: '/v1/bank-integrations/{id}', summary: 'Update the display name of a BankIntegration', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'delete': { method: 'DELETE', path: '/v1/bank-integrations/{id}', summary: 'Delete a BankIntegration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'log': { method: 'GET', path: '/v1/bank-integrations/{id}/log', summary: 'Get activity log for a bank integration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'list-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'List bank statement import runs', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'trigger-account-statement-runs': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'Trigger a bank statement import', pathParams: ['bankIntegrationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'get-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}', summary: 'Get import run details', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'account-statement-runs-files': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files', summary: 'Get files for an import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'trigger-account-statement-runs-reimport': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/reimport', summary: 'Trigger reimport of an existing account statement import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fileIds'] },
|
|
29
|
-
'account-statement-runs-files-download': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files/{fileId}/download', summary: 'Download the stored CAMT XML for a statement file', pathParams: ['bankIntegrationId', 'importRunId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'list-all': { method: 'GET', path: '/v1/account-statement-files', summary: 'List statement import files across this tenant’s bank integrations', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'list-statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements', summary: 'List CAMT.053 statements for a bank integration', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}', summary: 'Get CAMT.053 statement detail', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'download-statements-xml': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}/xml', summary: 'Get raw CAMT.053 XML for a statement', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'initiate': { method: 'POST', path: '/v1/bank-integrations/initiate', summary: 'Initiate the OAuth/auth flow for a bank integration', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'providers-supported': { method: 'GET', path: '/v1/bank-integrations/providers/supported', summary: 'List supported bLink providers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'providers-consent-status': { method: 'GET', path: '/v1/bank-integrations/providers/consent-status', summary: 'Get bLink consent status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'delete-providers-consent': { method: 'DELETE', path: '/v1/bank-integrations/providers/{providerId}/consent', summary: 'Revoke bLink consent for a provider', pathParams: ['providerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'list': { method: 'GET', path: '/v1/bank-integrations', summary: 'List all BankIntegrations for the current tenant with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'create': { method: 'POST', path: '/v1/bank-integrations', summary: 'Create a BankIntegration record', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['methods'], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'get': { method: 'GET', path: '/v1/bank-integrations/{id}', summary: 'Get a BankIntegration by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'update': { method: 'PATCH', path: '/v1/bank-integrations/{id}', summary: 'Update the display name of a BankIntegration', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'delete': { method: 'DELETE', path: '/v1/bank-integrations/{id}', summary: 'Delete a BankIntegration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'log': { method: 'GET', path: '/v1/bank-integrations/{id}/log', summary: 'Get activity log for a bank integration', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'list-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'List bank statement import runs', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'trigger-account-statement-runs': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'Trigger a bank statement import', pathParams: ['bankIntegrationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'get-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}', summary: 'Get import run details', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'account-statement-runs-files': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files', summary: 'Get files for an import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'trigger-account-statement-runs-reimport': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/reimport', summary: 'Trigger reimport of an existing account statement import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fileIds'], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'account-statement-runs-files-download': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files/{fileId}/download', summary: 'Download the stored CAMT XML for a statement file', pathParams: ['bankIntegrationId', 'importRunId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'list-all': { method: 'GET', path: '/v1/account-statement-files', summary: 'List statement import files across this tenant’s bank integrations', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'list-statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements', summary: 'List CAMT.053 statements for a bank integration', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}', summary: 'Get CAMT.053 statement detail', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'download-statements-xml': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}/xml', summary: 'Get raw CAMT.053 XML for a statement', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
35
|
};
|
|
35
36
|
export default class BankIntegrations extends Command {
|
|
36
37
|
static description = 'Manage bank integrations';
|
|
@@ -52,7 +53,7 @@ export default class BankIntegrations extends Command {
|
|
|
52
53
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
53
54
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
54
55
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
55
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
56
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
56
57
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
57
58
|
'import-run-id': Flags.string({ description: 'Path param: importRunId' }),
|
|
58
59
|
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
@@ -186,6 +187,17 @@ export default class BankIntegrations extends Command {
|
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
}
|
|
190
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
191
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
192
|
+
for (const param of endpoint.specParams) {
|
|
193
|
+
const value = flags[param.flag];
|
|
194
|
+
if (value === undefined || value === '') {
|
|
195
|
+
if (param.required)
|
|
196
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
queryParams[param.name] = value;
|
|
200
|
+
}
|
|
189
201
|
let data;
|
|
190
202
|
if (endpoint.isMultipart) {
|
|
191
203
|
if (!flags.file)
|
|
@@ -206,6 +218,25 @@ export default class BankIntegrations extends Command {
|
|
|
206
218
|
}
|
|
207
219
|
data = form;
|
|
208
220
|
}
|
|
221
|
+
else if (endpoint.bodyMediaType) {
|
|
222
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
223
|
+
// verbatim, under the content type the endpoint asks for.
|
|
224
|
+
if (flags.file) {
|
|
225
|
+
const fsModule = await import('node:fs');
|
|
226
|
+
try {
|
|
227
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (flags.data) {
|
|
234
|
+
data = flags.data;
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
209
240
|
else if (endpoint.hasBody) {
|
|
210
241
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
211
242
|
// input file — skip the read-as-body branch.
|
|
@@ -301,7 +332,7 @@ export default class BankIntegrations extends Command {
|
|
|
301
332
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
302
333
|
}
|
|
303
334
|
else if (data) {
|
|
304
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
335
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
305
336
|
}
|
|
306
337
|
process.stderr.write('\n');
|
|
307
338
|
}
|
|
@@ -315,6 +346,7 @@ export default class BankIntegrations extends Command {
|
|
|
315
346
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
316
347
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
317
348
|
data,
|
|
349
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
318
350
|
contextName: flags.context,
|
|
319
351
|
binary: true,
|
|
320
352
|
});
|
|
@@ -340,6 +372,7 @@ export default class BankIntegrations extends Command {
|
|
|
340
372
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
341
373
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
342
374
|
data,
|
|
375
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
343
376
|
contextName: flags.context,
|
|
344
377
|
binary: true,
|
|
345
378
|
});
|
|
@@ -360,6 +393,7 @@ export default class BankIntegrations extends Command {
|
|
|
360
393
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
361
394
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
362
395
|
data,
|
|
396
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
363
397
|
contextName: flags.context,
|
|
364
398
|
acceptAny: true,
|
|
365
399
|
});
|