@aderis-erp/cli 1.1.3 → 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/README.md +1 -0
- 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.d.ts +58 -0
- package/dist/commands/api-clients.js +1375 -0
- 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.d.ts +4 -0
- package/dist/commands/credit-card-accounts.js +64 -25
- package/dist/commands/currencies.d.ts +56 -0
- package/dist/commands/currencies.js +1361 -0
- package/dist/commands/custody-accounts.d.ts +56 -0
- package/dist/commands/custody-accounts.js +1369 -0
- package/dist/commands/{integration-identities.d.ts → dashboards.d.ts} +3 -3
- package/dist/commands/dashboards.js +1381 -0
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +57 -0
- package/dist/commands/{integration-identities.js → document-checksums.js} +48 -21
- 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.d.ts +56 -0
- package/dist/commands/financial-instrument-types.js +1369 -0
- package/dist/commands/financial-instruments.d.ts +56 -0
- package/dist/commands/financial-instruments.js +1369 -0
- 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/{workflows.d.ts → kpis.d.ts} +1 -1
- package/dist/commands/kpis.js +1371 -0
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.d.ts +56 -0
- package/dist/commands/notifications.js +1360 -0
- 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.d.ts +56 -0
- package/dist/commands/settings.js +1361 -0
- 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 +50 -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 +82 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.d.ts +56 -0
- package/dist/commands/{workflows.js → work-summary.js} +49 -18
- package/dist/lib/auth/index.js +5 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.d.ts +42 -0
- package/dist/lib/production-guard.js +94 -0
- package/oclif.manifest.json +2142 -333
- 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,9 +12,9 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list-entities", "get-entities", "update-entities"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list-entities': { method: 'GET', path: '/v1/config/entities', summary: 'List all entity-type configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'get-entities': { method: 'GET', path: '/v1/config/entities/{entityType}', summary: 'Get one entity-type config', pathParams: ['entityType'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'update-entities': { method: 'PATCH', path: '/v1/config/entities/{entityType}', summary: 'Adjust one entity-type config (admin only)', pathParams: ['entityType'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
18
|
};
|
|
18
19
|
export default class EntityConfigurations extends Command {
|
|
19
20
|
static description = 'Manage entity configurations';
|
|
@@ -28,7 +29,7 @@ export default class EntityConfigurations extends Command {
|
|
|
28
29
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
29
30
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
30
31
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
31
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
32
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
32
33
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
33
34
|
page: Flags.string({ description: 'Page number' }),
|
|
34
35
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -159,6 +160,17 @@ export default class EntityConfigurations extends Command {
|
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
}
|
|
163
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
164
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
165
|
+
for (const param of endpoint.specParams) {
|
|
166
|
+
const value = flags[param.flag];
|
|
167
|
+
if (value === undefined || value === '') {
|
|
168
|
+
if (param.required)
|
|
169
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
queryParams[param.name] = value;
|
|
173
|
+
}
|
|
162
174
|
let data;
|
|
163
175
|
if (endpoint.isMultipart) {
|
|
164
176
|
if (!flags.file)
|
|
@@ -179,6 +191,25 @@ export default class EntityConfigurations extends Command {
|
|
|
179
191
|
}
|
|
180
192
|
data = form;
|
|
181
193
|
}
|
|
194
|
+
else if (endpoint.bodyMediaType) {
|
|
195
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
196
|
+
// verbatim, under the content type the endpoint asks for.
|
|
197
|
+
if (flags.file) {
|
|
198
|
+
const fsModule = await import('node:fs');
|
|
199
|
+
try {
|
|
200
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else if (flags.data) {
|
|
207
|
+
data = flags.data;
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
182
213
|
else if (endpoint.hasBody) {
|
|
183
214
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
184
215
|
// input file — skip the read-as-body branch.
|
|
@@ -274,7 +305,7 @@ export default class EntityConfigurations extends Command {
|
|
|
274
305
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
275
306
|
}
|
|
276
307
|
else if (data) {
|
|
277
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
308
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
278
309
|
}
|
|
279
310
|
process.stderr.write('\n');
|
|
280
311
|
}
|
|
@@ -288,6 +319,7 @@ export default class EntityConfigurations extends Command {
|
|
|
288
319
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
289
320
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
290
321
|
data,
|
|
322
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
291
323
|
contextName: flags.context,
|
|
292
324
|
binary: true,
|
|
293
325
|
});
|
|
@@ -313,6 +345,7 @@ export default class EntityConfigurations extends Command {
|
|
|
313
345
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
314
346
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
315
347
|
data,
|
|
348
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
316
349
|
contextName: flags.context,
|
|
317
350
|
binary: true,
|
|
318
351
|
});
|
|
@@ -333,6 +366,7 @@ export default class EntityConfigurations extends Command {
|
|
|
333
366
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
334
367
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
335
368
|
data,
|
|
369
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
336
370
|
contextName: flags.context,
|
|
337
371
|
acceptAny: true,
|
|
338
372
|
});
|
|
@@ -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,7 +12,7 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["fields"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'fields': { method: 'GET', path: '/v1/event-mapping-rules/fields', summary: 'List the fields an event mapping’s conditions may test', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'fields': { method: 'GET', path: '/v1/event-mapping-rules/fields', summary: 'List the fields an event mapping’s conditions may test', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
15
16
|
};
|
|
16
17
|
export default class EventMappingRules extends Command {
|
|
17
18
|
static description = 'Manage event mapping rules';
|
|
@@ -26,7 +27,7 @@ export default class EventMappingRules extends Command {
|
|
|
26
27
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
27
28
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
28
29
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
29
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
30
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
30
31
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
31
32
|
page: Flags.string({ description: 'Page number' }),
|
|
32
33
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -157,6 +158,17 @@ export default class EventMappingRules extends Command {
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
}
|
|
161
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
162
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
163
|
+
for (const param of endpoint.specParams) {
|
|
164
|
+
const value = flags[param.flag];
|
|
165
|
+
if (value === undefined || value === '') {
|
|
166
|
+
if (param.required)
|
|
167
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
queryParams[param.name] = value;
|
|
171
|
+
}
|
|
160
172
|
let data;
|
|
161
173
|
if (endpoint.isMultipart) {
|
|
162
174
|
if (!flags.file)
|
|
@@ -177,6 +189,25 @@ export default class EventMappingRules extends Command {
|
|
|
177
189
|
}
|
|
178
190
|
data = form;
|
|
179
191
|
}
|
|
192
|
+
else if (endpoint.bodyMediaType) {
|
|
193
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
194
|
+
// verbatim, under the content type the endpoint asks for.
|
|
195
|
+
if (flags.file) {
|
|
196
|
+
const fsModule = await import('node:fs');
|
|
197
|
+
try {
|
|
198
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (flags.data) {
|
|
205
|
+
data = flags.data;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
180
211
|
else if (endpoint.hasBody) {
|
|
181
212
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
182
213
|
// input file — skip the read-as-body branch.
|
|
@@ -272,7 +303,7 @@ export default class EventMappingRules extends Command {
|
|
|
272
303
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
273
304
|
}
|
|
274
305
|
else if (data) {
|
|
275
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
306
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
276
307
|
}
|
|
277
308
|
process.stderr.write('\n');
|
|
278
309
|
}
|
|
@@ -286,6 +317,7 @@ export default class EventMappingRules extends Command {
|
|
|
286
317
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
287
318
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
288
319
|
data,
|
|
320
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
289
321
|
contextName: flags.context,
|
|
290
322
|
binary: true,
|
|
291
323
|
});
|
|
@@ -311,6 +343,7 @@ export default class EventMappingRules extends Command {
|
|
|
311
343
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
312
344
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
313
345
|
data,
|
|
346
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
314
347
|
contextName: flags.context,
|
|
315
348
|
binary: true,
|
|
316
349
|
});
|
|
@@ -331,6 +364,7 @@ export default class EventMappingRules extends Command {
|
|
|
331
364
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
332
365
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
333
366
|
data,
|
|
367
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
334
368
|
contextName: flags.context,
|
|
335
369
|
acceptAny: true,
|
|
336
370
|
});
|
|
@@ -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,11 +12,11 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["events", "list", "create", "update", "delete"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'events': { method: 'GET', path: '/v1/event-processor-mappings/events', summary: 'List all valid event types', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'list': { method: 'GET', path: '/v1/event-processor-mappings', summary: 'List all event type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'create': { method: 'POST', path: '/v1/event-processor-mappings', summary: 'Create event type processor mappings', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['eventTypes', 'includes'] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/event-processor-mappings/{id}', summary: 'Update an event type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['includes'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/event-processor-mappings/{id}', summary: 'Delete an event type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'events': { method: 'GET', path: '/v1/event-processor-mappings/events', summary: 'List all valid event types', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'list': { method: 'GET', path: '/v1/event-processor-mappings', summary: 'List all event type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'create': { method: 'POST', path: '/v1/event-processor-mappings', summary: 'Create event type processor mappings', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['eventTypes', 'includes'], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/event-processor-mappings/{id}', summary: 'Update an event type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['includes'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/event-processor-mappings/{id}', summary: 'Delete an event type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
20
|
};
|
|
20
21
|
export default class EventProcessorMappings extends Command {
|
|
21
22
|
static description = 'Manage event processor mappings';
|
|
@@ -36,7 +37,7 @@ export default class EventProcessorMappings extends Command {
|
|
|
36
37
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
37
38
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
38
39
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
39
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
40
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
40
41
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
41
42
|
page: Flags.string({ description: 'Page number' }),
|
|
42
43
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -167,6 +168,17 @@ export default class EventProcessorMappings extends Command {
|
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
}
|
|
171
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
172
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
173
|
+
for (const param of endpoint.specParams) {
|
|
174
|
+
const value = flags[param.flag];
|
|
175
|
+
if (value === undefined || value === '') {
|
|
176
|
+
if (param.required)
|
|
177
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
queryParams[param.name] = value;
|
|
181
|
+
}
|
|
170
182
|
let data;
|
|
171
183
|
if (endpoint.isMultipart) {
|
|
172
184
|
if (!flags.file)
|
|
@@ -187,6 +199,25 @@ export default class EventProcessorMappings extends Command {
|
|
|
187
199
|
}
|
|
188
200
|
data = form;
|
|
189
201
|
}
|
|
202
|
+
else if (endpoint.bodyMediaType) {
|
|
203
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
204
|
+
// verbatim, under the content type the endpoint asks for.
|
|
205
|
+
if (flags.file) {
|
|
206
|
+
const fsModule = await import('node:fs');
|
|
207
|
+
try {
|
|
208
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (flags.data) {
|
|
215
|
+
data = flags.data;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
190
221
|
else if (endpoint.hasBody) {
|
|
191
222
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
192
223
|
// input file — skip the read-as-body branch.
|
|
@@ -282,7 +313,7 @@ export default class EventProcessorMappings extends Command {
|
|
|
282
313
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
283
314
|
}
|
|
284
315
|
else if (data) {
|
|
285
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
316
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
286
317
|
}
|
|
287
318
|
process.stderr.write('\n');
|
|
288
319
|
}
|
|
@@ -296,6 +327,7 @@ export default class EventProcessorMappings extends Command {
|
|
|
296
327
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
297
328
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
298
329
|
data,
|
|
330
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
299
331
|
contextName: flags.context,
|
|
300
332
|
binary: true,
|
|
301
333
|
});
|
|
@@ -321,6 +353,7 @@ export default class EventProcessorMappings extends Command {
|
|
|
321
353
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
322
354
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
323
355
|
data,
|
|
356
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
324
357
|
contextName: flags.context,
|
|
325
358
|
binary: true,
|
|
326
359
|
});
|
|
@@ -341,6 +374,7 @@ export default class EventProcessorMappings extends Command {
|
|
|
341
374
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
342
375
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
343
376
|
data,
|
|
377
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
344
378
|
contextName: flags.context,
|
|
345
379
|
acceptAny: true,
|
|
346
380
|
});
|
package/dist/commands/files.js
CHANGED
|
@@ -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,18 +12,18 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "download-all", "download", "get", "references", "update", "discard", "move", "retention", "hold", "reclassify"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/files', summary: 'List files (paginated, permission-scoped)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/files', summary: 'Upload a file (streaming, memory-efficient)', pathParams: [], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'download-all': { method: 'GET', path: '/v1/files/download/*', summary: 'Download file directly by storage key', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'download': { method: 'GET', path: '/v1/files/{id}/download', summary: 'Get a signed download URL for a file', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'get': { method: 'GET', path: '/v1/files/{id}', summary: 'Get a file by id (permission-scoped)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'references': { method: 'POST', path: '/v1/files/references', summary: 'Register a file reference to an existing storage object', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'update': { method: 'PATCH', path: '/v1/files/{fileId}', summary: 'Update file metadata (type, parent, sortOrder)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'references'] },
|
|
21
|
-
'discard': { method: 'POST', path: '/v1/files/{fileId}/discard', summary: 'Discard a file (sets status DISCARDED; stays readable by id)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'move': { method: 'POST', path: '/v1/files/{fileId}/move', summary: 'Move file between storage zones', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'retention': { method: 'POST', path: '/v1/files/{fileId}/retention', summary: 'Set or override retention period on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'hold': { method: 'POST', path: '/v1/files/{fileId}/hold', summary: 'Set or release legal hold on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'reclassify': { method: 'POST', path: '/v1/files/{fileId}/reclassify', summary: 'Reclassify a file and reprocess it through the inbox pipeline', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/files', summary: 'List files (paginated, permission-scoped)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/files', summary: 'Upload a file (streaming, memory-efficient)', pathParams: [], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'download-all': { method: 'GET', path: '/v1/files/download/*', summary: 'Download file directly by storage key', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'download': { method: 'GET', path: '/v1/files/{id}/download', summary: 'Get a signed download URL for a file', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'get': { method: 'GET', path: '/v1/files/{id}', summary: 'Get a file by id (permission-scoped)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'references': { method: 'POST', path: '/v1/files/references', summary: 'Register a file reference to an existing storage object', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'update': { method: 'PATCH', path: '/v1/files/{fileId}', summary: 'Update file metadata (type, parent, sortOrder)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'references'], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'discard': { method: 'POST', path: '/v1/files/{fileId}/discard', summary: 'Discard a file (sets status DISCARDED; stays readable by id)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'move': { method: 'POST', path: '/v1/files/{fileId}/move', summary: 'Move file between storage zones', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'retention': { method: 'POST', path: '/v1/files/{fileId}/retention', summary: 'Set or override retention period on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'hold': { method: 'POST', path: '/v1/files/{fileId}/hold', summary: 'Set or release legal hold on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'reclassify': { method: 'POST', path: '/v1/files/{fileId}/reclassify', summary: 'Reclassify a file and reprocess it through the inbox pipeline', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
27
|
};
|
|
27
28
|
export default class Files extends Command {
|
|
28
29
|
static description = 'Manage files';
|
|
@@ -44,7 +45,7 @@ export default class Files extends Command {
|
|
|
44
45
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
45
46
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
46
47
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
47
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
48
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
48
49
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
49
50
|
page: Flags.string({ description: 'Page number' }),
|
|
50
51
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -175,6 +176,17 @@ export default class Files extends Command {
|
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
180
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
181
|
+
for (const param of endpoint.specParams) {
|
|
182
|
+
const value = flags[param.flag];
|
|
183
|
+
if (value === undefined || value === '') {
|
|
184
|
+
if (param.required)
|
|
185
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
queryParams[param.name] = value;
|
|
189
|
+
}
|
|
178
190
|
let data;
|
|
179
191
|
if (endpoint.isMultipart) {
|
|
180
192
|
if (!flags.file)
|
|
@@ -195,6 +207,25 @@ export default class Files extends Command {
|
|
|
195
207
|
}
|
|
196
208
|
data = form;
|
|
197
209
|
}
|
|
210
|
+
else if (endpoint.bodyMediaType) {
|
|
211
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
212
|
+
// verbatim, under the content type the endpoint asks for.
|
|
213
|
+
if (flags.file) {
|
|
214
|
+
const fsModule = await import('node:fs');
|
|
215
|
+
try {
|
|
216
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (flags.data) {
|
|
223
|
+
data = flags.data;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
198
229
|
else if (endpoint.hasBody) {
|
|
199
230
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
200
231
|
// input file — skip the read-as-body branch.
|
|
@@ -290,7 +321,7 @@ export default class Files extends Command {
|
|
|
290
321
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
291
322
|
}
|
|
292
323
|
else if (data) {
|
|
293
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
324
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
294
325
|
}
|
|
295
326
|
process.stderr.write('\n');
|
|
296
327
|
}
|
|
@@ -304,6 +335,7 @@ export default class Files extends Command {
|
|
|
304
335
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
305
336
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
306
337
|
data,
|
|
338
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
307
339
|
contextName: flags.context,
|
|
308
340
|
binary: true,
|
|
309
341
|
});
|
|
@@ -329,6 +361,7 @@ export default class Files extends Command {
|
|
|
329
361
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
330
362
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
331
363
|
data,
|
|
364
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
332
365
|
contextName: flags.context,
|
|
333
366
|
binary: true,
|
|
334
367
|
});
|
|
@@ -349,6 +382,7 @@ export default class Files extends Command {
|
|
|
349
382
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
350
383
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
351
384
|
data,
|
|
385
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
352
386
|
contextName: flags.context,
|
|
353
387
|
acceptAny: true,
|
|
354
388
|
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class FinancialInstrumentTransactions extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'sort-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
private runUpsert;
|
|
31
|
+
/**
|
|
32
|
+
* The API's own import: the whole array goes up in one request and comes
|
|
33
|
+
* back as an import run, which records what happened to every record. A bad
|
|
34
|
+
* record lands in errorLog and the rest are still applied, and the run stays
|
|
35
|
+
* readable afterwards with: aderis imports get <id>.
|
|
36
|
+
*/
|
|
37
|
+
private runServerImport;
|
|
38
|
+
/** Renders an import run: its counts, then whatever the server refused. */
|
|
39
|
+
private printImportRun;
|
|
40
|
+
private runExport;
|
|
41
|
+
private runCamt053Import;
|
|
42
|
+
private runNestedUpsert;
|
|
43
|
+
private parseFilterValue;
|
|
44
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
45
|
+
private printPageSummary;
|
|
46
|
+
/**
|
|
47
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
48
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
49
|
+
*/
|
|
50
|
+
private warnShortPage;
|
|
51
|
+
private sanitizeOutput;
|
|
52
|
+
private getColumns;
|
|
53
|
+
private getValue;
|
|
54
|
+
private printTable;
|
|
55
|
+
private printCsv;
|
|
56
|
+
}
|