@aderis-erp/cli 1.0.13 → 1.0.15
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 +21 -21
- package/dist/commands/account-transaction-allocations.js +21 -21
- package/dist/commands/account-transactions.js +23 -23
- package/dist/commands/accounts.js +23 -23
- package/dist/commands/agent-platform.js +23 -22
- package/dist/commands/analytics.d.ts +40 -0
- package/dist/commands/{documents.js → analytics.js} +33 -43
- package/dist/commands/audit-log.js +24 -24
- package/dist/commands/auth/login.js +11 -2
- package/dist/commands/auth/logout.d.ts +2 -0
- package/dist/commands/auth/logout.js +19 -6
- package/dist/commands/auth/status.js +26 -12
- package/dist/commands/auth/tenant.js +12 -3
- package/dist/commands/auth.js +32 -17
- package/dist/commands/bank-accounts.js +21 -21
- package/dist/commands/bank-integrations.js +21 -21
- package/dist/commands/business-partners.js +29 -26
- package/dist/commands/chat.js +21 -21
- package/dist/commands/config/add.d.ts +9 -0
- package/dist/commands/config/add.js +64 -2
- package/dist/commands/config/current.js +9 -4
- package/dist/commands/config/list.js +9 -4
- package/dist/commands/config/set-api-key.d.ts +10 -0
- package/dist/commands/config/set-api-key.js +49 -0
- package/dist/commands/config/use.js +3 -4
- package/dist/commands/credit-card-accounts.js +21 -21
- package/dist/commands/delivery-notes.js +28 -25
- package/dist/commands/dunning-configs.js +21 -21
- package/dist/commands/dunning-reminders.js +21 -21
- package/dist/commands/dunning-runs.js +21 -21
- package/dist/commands/email-transactions.js +21 -21
- package/dist/commands/employees.js +23 -23
- package/dist/commands/entity-configurations.js +21 -21
- package/dist/commands/event-processor-mappings.js +21 -21
- package/dist/commands/{documents.d.ts → files.d.ts} +1 -1
- package/dist/commands/{files-internal.js → files.js} +39 -33
- package/dist/commands/health.js +21 -21
- package/dist/commands/inbox.d.ts +1 -0
- package/dist/commands/inbox.js +25 -23
- package/dist/commands/integrations.js +21 -21
- package/dist/commands/item-categories.js +21 -21
- package/dist/commands/items.js +23 -23
- package/dist/commands/journal-lines.js +21 -21
- package/dist/commands/journals.js +27 -24
- package/dist/commands/ledgers.js +25 -22
- package/dist/commands/office-locations.js +21 -21
- package/dist/commands/payment-methods.js +21 -21
- package/dist/commands/payment-runs.js +23 -22
- package/dist/commands/payment-terms.js +21 -21
- package/dist/commands/payments.js +21 -21
- package/dist/commands/price-lists.js +21 -21
- package/dist/commands/processor-mappings.js +21 -21
- package/dist/commands/processors.js +21 -21
- package/dist/commands/purchase-order-types.js +21 -21
- package/dist/commands/purchase-orders.d.ts +1 -0
- package/dist/commands/purchase-orders.js +32 -25
- package/dist/commands/reports.js +21 -21
- package/dist/commands/salary-types.js +21 -21
- package/dist/commands/sales-invoices.js +33 -31
- package/dist/commands/sales-orders.js +23 -23
- package/dist/commands/saved-views.js +21 -21
- package/dist/commands/scheduled-processor-mappings.d.ts +40 -0
- package/dist/commands/scheduled-processor-mappings.js +1178 -0
- package/dist/commands/schedules.js +21 -21
- package/dist/commands/switch.js +10 -3
- package/dist/commands/{files-internal.d.ts → tag-configurations.d.ts} +1 -1
- package/dist/commands/tag-configurations.js +1178 -0
- package/dist/commands/tags.js +21 -21
- package/dist/commands/tax-codes.js +21 -21
- package/dist/commands/tax-matrix.js +21 -21
- package/dist/commands/tenants.js +23 -23
- package/dist/commands/text-templates.js +21 -21
- package/dist/commands/tools.js +21 -21
- package/dist/commands/vat-declarations.js +21 -21
- package/dist/commands/vendor-invoices.js +25 -25
- package/dist/commands/webhooks.js +21 -21
- package/dist/commands/workflows.js +21 -21
- package/dist/lib/api-client.d.ts +8 -0
- package/dist/lib/api-client.js +31 -6
- package/dist/lib/auth.d.ts +8 -0
- package/dist/lib/auth.js +51 -7
- package/dist/lib/base-api-command.js +6 -4
- package/dist/lib/config.d.ts +31 -1
- package/dist/lib/config.js +31 -0
- package/oclif.manifest.json +1099 -443
- package/package.json +2 -2
package/dist/lib/api-client.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import {
|
|
3
|
-
import { getBaseUrls, getCurrentContext } from './config.js';
|
|
2
|
+
import { getAuthHeaders } from './auth.js';
|
|
3
|
+
import { getAuthType, getBaseUrls, getCurrentContext } from './config.js';
|
|
4
|
+
/**
|
|
5
|
+
* Normalize a --sort-by value: comma-separated fields, each optionally suffixed
|
|
6
|
+
* with `:ASC` or `:DESC`. Fields without an explicit direction default to DESC
|
|
7
|
+
* when the leaf name ends in `At`, `Date`, or `Time` (dates read newest-first);
|
|
8
|
+
* everything else defaults to ASC. Returned as an array so axios expands it
|
|
9
|
+
* into repeated `sortBy=a:ASC&sortBy=b:DESC` params.
|
|
10
|
+
*/
|
|
11
|
+
export function normalizeSortBy(input) {
|
|
12
|
+
return input
|
|
13
|
+
.split(',')
|
|
14
|
+
.map((part) => part.trim())
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.map((part) => {
|
|
17
|
+
if (part.includes(':'))
|
|
18
|
+
return part;
|
|
19
|
+
const leaf = part.split('.').pop() ?? part;
|
|
20
|
+
const dateLike = /(?:At|Date|Time)$/.test(leaf);
|
|
21
|
+
return `${part}:${dateLike ? 'DESC' : 'ASC'}`;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
4
24
|
export class ApiError extends Error {
|
|
5
25
|
status;
|
|
6
26
|
data;
|
|
@@ -19,14 +39,15 @@ export async function createApiClient(contextName, options = false) {
|
|
|
19
39
|
if (!context) {
|
|
20
40
|
throw new Error('No context configured. Run: aderis auth login --new');
|
|
21
41
|
}
|
|
22
|
-
const
|
|
42
|
+
const authHeaders = await getAuthHeaders(context.name);
|
|
23
43
|
const { api: baseURL } = getBaseUrls(context.environment);
|
|
24
44
|
const client = axios.create({
|
|
25
45
|
baseURL,
|
|
26
46
|
headers: {
|
|
27
47
|
Accept: binary ? '*/*' : (acceptAny ? '*/*' : 'application/json'),
|
|
28
|
-
Authorization: `Bearer ${token}`,
|
|
29
48
|
'Content-Type': 'application/json',
|
|
49
|
+
// Either `Authorization: Bearer <token>` or `x-api-key: <key>`.
|
|
50
|
+
...authHeaders,
|
|
30
51
|
},
|
|
31
52
|
// Serialize arrays as repeated params (key=v1&key=v2) instead of bracket format (key[]=v1)
|
|
32
53
|
paramsSerializer: { indexes: null },
|
|
@@ -36,9 +57,13 @@ export async function createApiClient(contextName, options = false) {
|
|
|
36
57
|
// Response interceptor for error handling
|
|
37
58
|
client.interceptors.response.use((response) => response, (error) => {
|
|
38
59
|
if (error.response) {
|
|
39
|
-
// Handle 401 with a clear message
|
|
60
|
+
// Handle 401 with a clear message, pointing at the right remedy for the
|
|
61
|
+
// context's auth type — re-login only helps OAuth contexts.
|
|
40
62
|
if (error.response.status === 401) {
|
|
41
|
-
|
|
63
|
+
const message = getAuthType(context) === 'api_key'
|
|
64
|
+
? `API key for context "${context.name}" was rejected. Check the key with: aderis config set-api-key --context ${context.name}`
|
|
65
|
+
: 'Session expired. Please run: aderis auth login';
|
|
66
|
+
throw new ApiError(message, 401, error.response.data);
|
|
42
67
|
}
|
|
43
68
|
const message = extractErrorMessage(error.response.data);
|
|
44
69
|
throw new ApiError(message, error.response.status, error.response.data);
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -4,6 +4,14 @@ export declare function login(context: Context, options?: {
|
|
|
4
4
|
}): Promise<TokenData>;
|
|
5
5
|
export declare function refreshTokens(contextName: string): Promise<TokenData>;
|
|
6
6
|
export declare function getValidToken(contextName: string): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Build the auth headers for a context: a bearer token for `oauth2` contexts
|
|
9
|
+
* (refreshing it first if needed) or `x-api-key` for `api_key` contexts.
|
|
10
|
+
*
|
|
11
|
+
* This is the single place that decides how credentials reach the API — callers
|
|
12
|
+
* should never read `tokens` or `api_key` off a context to build headers.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAuthHeaders(contextName: string): Promise<Record<string, string>>;
|
|
7
15
|
export declare function testAuth(contextName: string): Promise<{
|
|
8
16
|
email: string;
|
|
9
17
|
name?: string;
|
package/dist/lib/auth.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as crypto from 'node:crypto';
|
|
|
4
4
|
import * as http from 'node:http';
|
|
5
5
|
import { URL, URLSearchParams } from 'node:url';
|
|
6
6
|
import open from 'open';
|
|
7
|
-
import { getBaseUrls, getContext, saveCachedTenants, saveTokens, } from './config.js';
|
|
7
|
+
import { getAuthType, getBaseUrls, getContext, missingCredentialsMessage, saveCachedTenants, saveTokens, } from './config.js';
|
|
8
8
|
function buildValidatedUrl(baseUrl, path) {
|
|
9
9
|
try {
|
|
10
10
|
// Minimal path validation
|
|
@@ -132,6 +132,23 @@ function renderAuthPage(type, title, message) {
|
|
|
132
132
|
</body>
|
|
133
133
|
</html>`;
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Guard for flows that only exist for OAuth contexts (browser login, token
|
|
137
|
+
* refresh, Frontegg tenant switching). API keys are issued per tenant, so there
|
|
138
|
+
* is nothing to log into or switch.
|
|
139
|
+
*/
|
|
140
|
+
function requireOAuthContext(context, action) {
|
|
141
|
+
if (getAuthType(context) === 'api_key') {
|
|
142
|
+
throw new Error(`${action} requires OAuth. Context "${context.name}" authenticates with an API key, which is already scoped to one tenant.`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** `client_id` is optional on Context (API-key contexts have none), so OAuth flows must assert it. */
|
|
146
|
+
function requireClientId(context) {
|
|
147
|
+
if (!context.client_id) {
|
|
148
|
+
throw new Error(`Context "${context.name}" has no OAuth client ID. Recreate it with: aderis config add`);
|
|
149
|
+
}
|
|
150
|
+
return context.client_id;
|
|
151
|
+
}
|
|
135
152
|
function generatePKCE() {
|
|
136
153
|
const verifier = crypto.randomBytes(32).toString('base64url');
|
|
137
154
|
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
|
|
@@ -143,7 +160,7 @@ function generateState() {
|
|
|
143
160
|
function buildAuthorizeUrl(context, pkce, state, options = {}) {
|
|
144
161
|
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
145
162
|
const url = new URL(`${authUrl}/oauth/authorize`);
|
|
146
|
-
url.searchParams.set('client_id', context
|
|
163
|
+
url.searchParams.set('client_id', requireClientId(context));
|
|
147
164
|
url.searchParams.set('redirect_uri', REDIRECT_URI);
|
|
148
165
|
url.searchParams.set('response_type', 'code');
|
|
149
166
|
url.searchParams.set('state', state);
|
|
@@ -155,6 +172,7 @@ function buildAuthorizeUrl(context, pkce, state, options = {}) {
|
|
|
155
172
|
return url.toString();
|
|
156
173
|
}
|
|
157
174
|
export async function login(context, options = {}) {
|
|
175
|
+
requireOAuthContext(context, 'Browser login');
|
|
158
176
|
const pkce = generatePKCE();
|
|
159
177
|
const state = generateState();
|
|
160
178
|
const authorizationUrl = buildAuthorizeUrl(context, pkce, state, options);
|
|
@@ -252,7 +270,7 @@ async function exchangeCodeForTokens(context, code, codeVerifier) {
|
|
|
252
270
|
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
253
271
|
const params = new URLSearchParams();
|
|
254
272
|
params.set('grant_type', 'authorization_code');
|
|
255
|
-
params.set('client_id', context
|
|
273
|
+
params.set('client_id', requireClientId(context));
|
|
256
274
|
params.set('code', code);
|
|
257
275
|
params.set('redirect_uri', REDIRECT_URI);
|
|
258
276
|
params.set('code_verifier', codeVerifier);
|
|
@@ -279,13 +297,14 @@ export async function refreshTokens(contextName) {
|
|
|
279
297
|
if (!context) {
|
|
280
298
|
throw new Error(`Context "${contextName}" not found`);
|
|
281
299
|
}
|
|
300
|
+
requireOAuthContext(context, 'Token refresh');
|
|
282
301
|
if (!context.tokens?.refresh_token) {
|
|
283
302
|
throw new Error('No refresh token available. Please login again.');
|
|
284
303
|
}
|
|
285
304
|
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
286
305
|
const params = new URLSearchParams();
|
|
287
306
|
params.set('grant_type', 'refresh_token');
|
|
288
|
-
params.set('client_id', context
|
|
307
|
+
params.set('client_id', requireClientId(context));
|
|
289
308
|
params.set('refresh_token', context.tokens.refresh_token);
|
|
290
309
|
if (context.client_secret) {
|
|
291
310
|
params.set('client_secret', context.client_secret);
|
|
@@ -321,6 +340,9 @@ export async function getValidToken(contextName) {
|
|
|
321
340
|
if (!context) {
|
|
322
341
|
throw new Error(`Context "${contextName}" not found`);
|
|
323
342
|
}
|
|
343
|
+
if (getAuthType(context) === 'api_key') {
|
|
344
|
+
throw new Error(`Context "${contextName}" authenticates with an API key and has no access token. Use getAuthHeaders() instead.`);
|
|
345
|
+
}
|
|
324
346
|
if (!context.tokens?.access_token) {
|
|
325
347
|
throw new Error('Not logged in. Please run: aderis auth login');
|
|
326
348
|
}
|
|
@@ -334,17 +356,36 @@ export async function getValidToken(contextName) {
|
|
|
334
356
|
}
|
|
335
357
|
return context.tokens.access_token;
|
|
336
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* Build the auth headers for a context: a bearer token for `oauth2` contexts
|
|
361
|
+
* (refreshing it first if needed) or `x-api-key` for `api_key` contexts.
|
|
362
|
+
*
|
|
363
|
+
* This is the single place that decides how credentials reach the API — callers
|
|
364
|
+
* should never read `tokens` or `api_key` off a context to build headers.
|
|
365
|
+
*/
|
|
366
|
+
export async function getAuthHeaders(contextName) {
|
|
367
|
+
const context = getContext(contextName);
|
|
368
|
+
if (!context) {
|
|
369
|
+
throw new Error(`Context "${contextName}" not found`);
|
|
370
|
+
}
|
|
371
|
+
if (getAuthType(context) === 'api_key') {
|
|
372
|
+
if (!context.api_key) {
|
|
373
|
+
throw new Error(missingCredentialsMessage(context));
|
|
374
|
+
}
|
|
375
|
+
return { 'x-api-key': context.api_key };
|
|
376
|
+
}
|
|
377
|
+
return { Authorization: `Bearer ${await getValidToken(contextName)}` };
|
|
378
|
+
}
|
|
337
379
|
export async function testAuth(contextName) {
|
|
338
380
|
const context = getContext(contextName);
|
|
339
381
|
if (!context) {
|
|
340
382
|
throw new Error(`Context "${contextName}" not found`);
|
|
341
383
|
}
|
|
342
|
-
const token = await getValidToken(contextName);
|
|
343
384
|
const { api: apiUrl } = getBaseUrls(context.environment);
|
|
344
385
|
const response = await axios.get(buildValidatedUrl(apiUrl, '/v1/auth/me'), {
|
|
345
386
|
headers: {
|
|
346
387
|
Accept: 'application/json',
|
|
347
|
-
|
|
388
|
+
...(await getAuthHeaders(contextName)),
|
|
348
389
|
},
|
|
349
390
|
});
|
|
350
391
|
return response.data;
|
|
@@ -354,6 +395,7 @@ export async function listTenants(contextName) {
|
|
|
354
395
|
if (!context) {
|
|
355
396
|
throw new Error(`Context "${contextName}" not found`);
|
|
356
397
|
}
|
|
398
|
+
requireOAuthContext(context, 'Listing tenants');
|
|
357
399
|
const token = await getValidToken(contextName);
|
|
358
400
|
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
359
401
|
let response;
|
|
@@ -389,7 +431,8 @@ export async function getCurrentTenant(contextName) {
|
|
|
389
431
|
if (!context) {
|
|
390
432
|
throw new Error(`Context "${contextName}" not found`);
|
|
391
433
|
}
|
|
392
|
-
|
|
434
|
+
// API-key contexts carry no JWT, so there is no tenant to decode locally.
|
|
435
|
+
if (getAuthType(context) === 'api_key' || !context.tokens?.access_token) {
|
|
393
436
|
return null;
|
|
394
437
|
}
|
|
395
438
|
const decoded = jwt.decode(context.tokens.access_token);
|
|
@@ -415,6 +458,7 @@ export async function switchTenant(contextName, tenantId) {
|
|
|
415
458
|
if (!context) {
|
|
416
459
|
throw new Error(`Context "${contextName}" not found`);
|
|
417
460
|
}
|
|
461
|
+
requireOAuthContext(context, 'Switching tenants');
|
|
418
462
|
if (!context.tokens?.refresh_token) {
|
|
419
463
|
throw new Error('No refresh token available. Please login again.');
|
|
420
464
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { ApiError, apiRequest } from './api-client.js';
|
|
3
|
-
import { getCurrentContext } from './config.js';
|
|
3
|
+
import { getCurrentContext, hasCredentials, missingCredentialsMessage } from './config.js';
|
|
4
4
|
export class BaseApiCommand extends Command {
|
|
5
5
|
static globalFlags = {
|
|
6
6
|
context: Flags.string({
|
|
7
|
+
aliases: ['config'],
|
|
7
8
|
char: 'c',
|
|
8
|
-
description: 'Context to use
|
|
9
|
+
description: 'Context to use, overriding the current context (alias: --config)',
|
|
10
|
+
env: 'ADERIS_CONTEXT',
|
|
9
11
|
}),
|
|
10
12
|
output: Flags.string({
|
|
11
13
|
char: 'o',
|
|
@@ -66,8 +68,8 @@ export class BaseApiCommand extends Command {
|
|
|
66
68
|
if (!context) {
|
|
67
69
|
this.error('No context configured. Run: aderis auth login --new');
|
|
68
70
|
}
|
|
69
|
-
if (!context
|
|
70
|
-
this.error(
|
|
71
|
+
if (!hasCredentials(context)) {
|
|
72
|
+
this.error(missingCredentialsMessage(context));
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
printTable(data) {
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import Conf from 'conf';
|
|
2
2
|
export type Environment = 'dev' | 'live' | 'staging';
|
|
3
|
+
/**
|
|
4
|
+
* How a context authenticates against the API.
|
|
5
|
+
*
|
|
6
|
+
* - `oauth2`: browser PKCE login, sends `Authorization: Bearer <access_token>`
|
|
7
|
+
* - `api_key`: a long-lived key, sends `x-api-key: <key>`
|
|
8
|
+
*
|
|
9
|
+
* Contexts created before API-key support have no `auth_type` field; they are
|
|
10
|
+
* treated as `oauth2`, so always read it through {@link getAuthType}.
|
|
11
|
+
*/
|
|
12
|
+
export type AuthType = 'api_key' | 'oauth2';
|
|
3
13
|
export interface BaseUrls {
|
|
4
14
|
api: string;
|
|
5
15
|
auth: string;
|
|
@@ -17,8 +27,11 @@ export interface CachedTenant {
|
|
|
17
27
|
tenantId: string;
|
|
18
28
|
}
|
|
19
29
|
export interface Context {
|
|
30
|
+
api_key?: string;
|
|
31
|
+
auth_type?: AuthType;
|
|
20
32
|
cachedTenants?: CachedTenant[];
|
|
21
|
-
|
|
33
|
+
/** Only required for `oauth2` contexts; API-key contexts have no OAuth client. */
|
|
34
|
+
client_id?: string;
|
|
22
35
|
client_secret?: string;
|
|
23
36
|
environment: Environment;
|
|
24
37
|
name: string;
|
|
@@ -44,5 +57,22 @@ export declare function saveCachedTenants(contextName: string, tenants: CachedTe
|
|
|
44
57
|
export declare function getCachedTenants(contextName: string): CachedTenant[] | undefined;
|
|
45
58
|
export declare function getTokens(contextName: string): null | TokenData;
|
|
46
59
|
export declare function clearTokens(contextName: string): void;
|
|
60
|
+
export declare function saveApiKey(contextName: string, apiKey: string): void;
|
|
61
|
+
export declare function clearApiKey(contextName: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Auth type of a context, defaulting to `oauth2` for contexts stored before
|
|
64
|
+
* API-key support existed.
|
|
65
|
+
*/
|
|
66
|
+
export declare function getAuthType(context: Context): AuthType;
|
|
67
|
+
/** Whether a context holds the credential its auth type needs to call the API. */
|
|
68
|
+
export declare function hasCredentials(context: Context): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The error to show when a context can't authenticate. Kept here so every
|
|
71
|
+
* command — including the ~60 generated ones — points at the right remedy for
|
|
72
|
+
* the context's auth type instead of always suggesting `auth login`.
|
|
73
|
+
*/
|
|
74
|
+
export declare function missingCredentialsMessage(context: Context): string;
|
|
75
|
+
/** Redact a key for display: first and last 4 characters only. */
|
|
76
|
+
export declare function maskApiKey(apiKey: string): string;
|
|
47
77
|
export declare function getBaseUrls(environment: Environment): BaseUrls;
|
|
48
78
|
export { config };
|
package/dist/lib/config.js
CHANGED
|
@@ -133,6 +133,37 @@ export function getTokens(contextName) {
|
|
|
133
133
|
export function clearTokens(contextName) {
|
|
134
134
|
updateContext(contextName, { tokens: undefined });
|
|
135
135
|
}
|
|
136
|
+
export function saveApiKey(contextName, apiKey) {
|
|
137
|
+
updateContext(contextName, { api_key: apiKey, auth_type: 'api_key' });
|
|
138
|
+
}
|
|
139
|
+
export function clearApiKey(contextName) {
|
|
140
|
+
updateContext(contextName, { api_key: undefined });
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Auth type of a context, defaulting to `oauth2` for contexts stored before
|
|
144
|
+
* API-key support existed.
|
|
145
|
+
*/
|
|
146
|
+
export function getAuthType(context) {
|
|
147
|
+
return context.auth_type ?? 'oauth2';
|
|
148
|
+
}
|
|
149
|
+
/** Whether a context holds the credential its auth type needs to call the API. */
|
|
150
|
+
export function hasCredentials(context) {
|
|
151
|
+
return getAuthType(context) === 'api_key' ? Boolean(context.api_key) : Boolean(context.tokens);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The error to show when a context can't authenticate. Kept here so every
|
|
155
|
+
* command — including the ~60 generated ones — points at the right remedy for
|
|
156
|
+
* the context's auth type instead of always suggesting `auth login`.
|
|
157
|
+
*/
|
|
158
|
+
export function missingCredentialsMessage(context) {
|
|
159
|
+
return getAuthType(context) === 'api_key'
|
|
160
|
+
? `No API key set for context "${context.name}". Run: aderis config set-api-key --context ${context.name}`
|
|
161
|
+
: `Not logged in to context "${context.name}". Run: aderis auth login --context ${context.name}`;
|
|
162
|
+
}
|
|
163
|
+
/** Redact a key for display: first and last 4 characters only. */
|
|
164
|
+
export function maskApiKey(apiKey) {
|
|
165
|
+
return apiKey.length <= 8 ? '*'.repeat(apiKey.length) : `${apiKey.slice(0, 4)}${'*'.repeat(8)}${apiKey.slice(-4)}`;
|
|
166
|
+
}
|
|
136
167
|
export function getBaseUrls(environment) {
|
|
137
168
|
return BASE_URLS[environment];
|
|
138
169
|
}
|