@aderis-erp/cli 1.0.2 → 1.0.4
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 +6 -0
- package/dist/commands/access-groups 3.d.ts +40 -0
- package/dist/commands/{access-groups 2.js → access-groups 3.js } +106 -40
- package/dist/commands/access-groups.d.ts +40 -0
- package/dist/commands/access-groups.js +1074 -0
- package/dist/commands/account-transactions.d.ts +42 -0
- package/dist/commands/account-transactions.js +1088 -0
- package/dist/commands/accounts 2.d.ts +41 -0
- package/dist/commands/accounts 2.js +1078 -0
- package/dist/commands/accounts.d.ts +41 -0
- package/dist/commands/accounts.js +1080 -0
- package/dist/commands/agent-runs.d.ts +40 -0
- package/dist/commands/agent-runs.js +1071 -0
- package/dist/commands/async-endpoints-internal 3.d.ts +40 -0
- package/dist/commands/{processing-logs.js → async-endpoints-internal 3.js } +110 -46
- package/dist/commands/async-endpoints-internal.d.ts +40 -0
- package/dist/commands/async-endpoints-internal.js +1064 -0
- package/dist/commands/audit-log 3.d.ts +40 -0
- package/dist/commands/audit-log 3.js +1066 -0
- package/dist/commands/audit-log.d.ts +40 -0
- package/dist/commands/audit-log.js +1068 -0
- package/dist/commands/auth/login.d.ts +14 -0
- package/dist/commands/auth/login.js +116 -0
- package/dist/commands/auth/logout.d.ts +10 -0
- package/dist/commands/auth/logout.js +58 -0
- package/dist/commands/auth/status.d.ts +12 -0
- package/dist/commands/auth/status.js +101 -0
- package/dist/commands/auth/tenant.d.ts +19 -0
- package/dist/commands/auth/tenant.js +184 -0
- package/dist/commands/auth.d.ts +37 -0
- package/dist/commands/auth.js +871 -0
- package/dist/commands/bank-accounts.d.ts +42 -0
- package/dist/commands/bank-accounts.js +1088 -0
- package/dist/commands/bank-integrations.d.ts +1 -0
- package/dist/commands/bank-integrations.js +122 -54
- package/dist/commands/business-partners 3.d.ts +41 -0
- package/dist/commands/business-partners 3.js +1078 -0
- package/dist/commands/business-partners---contacts 3.d.ts +42 -0
- package/dist/commands/business-partners---contacts 3.js +1072 -0
- package/dist/commands/business-partners---contacts.d.ts +1 -0
- package/dist/commands/business-partners---contacts.js +114 -46
- package/dist/commands/business-partners.d.ts +1 -0
- package/dist/commands/business-partners.js +114 -46
- package/dist/commands/config/add.d.ts +13 -0
- package/dist/commands/config/add.js +120 -0
- package/dist/commands/config/current.d.ts +9 -0
- package/dist/commands/config/current.js +43 -0
- package/dist/commands/config/delete.d.ts +12 -0
- package/dist/commands/config/delete.js +67 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.js +50 -0
- package/dist/commands/config/use.d.ts +9 -0
- package/dist/commands/config/use.js +40 -0
- package/dist/commands/credit-card-accounts 3.d.ts +42 -0
- package/dist/commands/credit-card-accounts 3.js +1084 -0
- package/dist/commands/credit-card-accounts.d.ts +1 -0
- package/dist/commands/credit-card-accounts.js +119 -51
- package/dist/commands/documents.d.ts +1 -0
- package/dist/commands/documents.js +110 -42
- package/dist/commands/dunning-configs 3.d.ts +40 -0
- package/dist/commands/dunning-configs 3.js +1072 -0
- package/dist/commands/dunning-configs.d.ts +1 -0
- package/dist/commands/dunning-configs.js +109 -41
- package/dist/commands/dunning-reminders.d.ts +1 -0
- package/dist/commands/dunning-reminders.js +112 -44
- package/dist/commands/dunning-runs 3.d.ts +40 -0
- package/dist/commands/{pubsub.js → dunning-runs 3.js } +108 -43
- package/dist/commands/dunning-runs.d.ts +1 -0
- package/dist/commands/dunning-runs.js +105 -37
- package/dist/commands/employees.d.ts +1 -0
- package/dist/commands/employees.js +136 -68
- package/dist/commands/event-processor-mappings 3.d.ts +40 -0
- package/dist/commands/event-processor-mappings 3.js +1071 -0
- package/dist/commands/event-processor-mappings.d.ts +1 -0
- package/dist/commands/event-processor-mappings.js +109 -41
- package/dist/commands/files-internal 3.d.ts +40 -0
- package/dist/commands/files-internal 3.js +1073 -0
- package/dist/commands/files-internal.d.ts +1 -0
- package/dist/commands/files-internal.js +113 -45
- package/dist/commands/health 3.d.ts +40 -0
- package/dist/commands/health 3.js +1067 -0
- package/dist/commands/health.d.ts +1 -0
- package/dist/commands/health.js +109 -41
- package/dist/commands/{pubsub.d.ts → inbox 3.d.ts } +2 -1
- package/dist/commands/inbox 3.js +1065 -0
- package/dist/commands/inbox.d.ts +1 -0
- package/dist/commands/inbox.js +110 -40
- package/dist/commands/integrations 3.d.ts +41 -0
- package/dist/commands/integrations 3.js +1067 -0
- package/dist/commands/integrations.d.ts +1 -0
- package/dist/commands/integrations.js +107 -39
- package/dist/commands/item-categories 3.d.ts +40 -0
- package/dist/commands/item-categories 3.js +1072 -0
- package/dist/commands/item-categories.d.ts +1 -0
- package/dist/commands/item-categories.js +109 -41
- package/dist/commands/items 3.d.ts +40 -0
- package/dist/commands/items 3.js +1072 -0
- package/dist/commands/items.d.ts +1 -0
- package/dist/commands/items.js +109 -41
- package/dist/commands/journal-lines.d.ts +1 -0
- package/dist/commands/journal-lines.js +105 -37
- package/dist/commands/journals 3.d.ts +42 -0
- package/dist/commands/journals 3.js +1088 -0
- package/dist/commands/journals.d.ts +1 -0
- package/dist/commands/journals.js +123 -55
- package/dist/commands/ledgers.d.ts +1 -0
- package/dist/commands/ledgers.js +120 -52
- package/dist/commands/office-locations 3.d.ts +40 -0
- package/dist/commands/office-locations 3.js +1072 -0
- package/dist/commands/office-locations.d.ts +1 -0
- package/dist/commands/office-locations.js +109 -41
- package/dist/commands/payment-method-ledger-mappings 3.d.ts +41 -0
- package/dist/commands/payment-method-ledger-mappings 3.js +1066 -0
- package/dist/commands/payment-method-ledger-mappings.d.ts +1 -0
- package/dist/commands/payment-method-ledger-mappings.js +109 -41
- package/dist/commands/payment-methods 3.d.ts +40 -0
- package/dist/commands/payment-methods 3.js +1072 -0
- package/dist/commands/payment-methods.d.ts +1 -0
- package/dist/commands/payment-methods.js +109 -41
- package/dist/commands/payment-runs 3.d.ts +42 -0
- package/dist/commands/payment-runs 3.js +1087 -0
- package/dist/commands/payment-runs.d.ts +1 -0
- package/dist/commands/payment-runs.js +122 -54
- package/dist/commands/payment-terms 3.d.ts +40 -0
- package/dist/commands/payment-terms 3.js +1073 -0
- package/dist/commands/payment-terms.d.ts +1 -0
- package/dist/commands/payment-terms.js +110 -42
- package/dist/commands/price-lists 3.d.ts +41 -0
- package/dist/commands/price-lists 3.js +1078 -0
- package/dist/commands/price-lists.d.ts +1 -0
- package/dist/commands/price-lists.js +114 -46
- package/dist/commands/processor-mappings 2.d.ts +40 -0
- package/dist/commands/processor-mappings 2.js +1070 -0
- package/dist/commands/processor-mappings.d.ts +1 -0
- package/dist/commands/processor-mappings.js +108 -40
- package/dist/commands/processors.d.ts +1 -0
- package/dist/commands/processors.js +113 -45
- package/dist/commands/reconciliation 3.d.ts +40 -0
- package/dist/commands/reconciliation 3.js +1069 -0
- package/dist/commands/reconciliation.d.ts +1 -0
- package/dist/commands/reconciliation.js +110 -42
- package/dist/commands/reports.d.ts +1 -0
- package/dist/commands/reports.js +110 -39
- package/dist/commands/salary-types 3.d.ts +40 -0
- package/dist/commands/salary-types 3.js +1072 -0
- package/dist/commands/salary-types.d.ts +1 -0
- package/dist/commands/salary-types.js +1074 -0
- package/dist/commands/sales-invoices 3.d.ts +43 -0
- package/dist/commands/sales-invoices 3.js +1100 -0
- package/dist/commands/sales-invoices.d.ts +1 -0
- package/dist/commands/sales-invoices.js +134 -66
- package/dist/commands/sales-orders 3.d.ts +43 -0
- package/dist/commands/sales-orders 3.js +1098 -0
- package/dist/commands/sales-orders.d.ts +1 -0
- package/dist/commands/sales-orders.js +133 -64
- package/dist/commands/switch.d.ts +1 -0
- package/dist/commands/switch.js +58 -3
- package/dist/commands/{processing-logs.d.ts → tags 3.d.ts } +2 -1
- package/dist/commands/tags 3.js +1072 -0
- package/dist/commands/tags.d.ts +1 -0
- package/dist/commands/tags.js +109 -41
- package/dist/commands/tax-codes 3.d.ts +40 -0
- package/dist/commands/tax-codes 3.js +1075 -0
- package/dist/commands/tax-codes.d.ts +1 -0
- package/dist/commands/tax-codes.js +112 -44
- package/dist/commands/tax-matrix.d.ts +1 -0
- package/dist/commands/tax-matrix.js +109 -41
- package/dist/commands/tenants.d.ts +1 -0
- package/dist/commands/tenants.js +109 -41
- package/dist/commands/text-templates 3.d.ts +40 -0
- package/dist/commands/text-templates 3.js +1072 -0
- package/dist/commands/text-templates.d.ts +1 -0
- package/dist/commands/text-templates.js +109 -41
- package/dist/commands/tools.d.ts +1 -0
- package/dist/commands/tools.js +106 -38
- package/dist/commands/vendor-invoices.d.ts +1 -0
- package/dist/commands/vendor-invoices.js +139 -69
- package/dist/commands/webhooks 3.d.ts +40 -0
- package/dist/commands/webhooks 3.js +1074 -0
- package/dist/commands/webhooks.d.ts +1 -0
- package/dist/commands/webhooks.js +111 -43
- package/dist/commands/workflows.d.ts +1 -0
- package/dist/commands/workflows.js +107 -39
- package/dist/lib/api-client.d.ts +5 -1
- package/dist/lib/api-client.js +19 -5
- package/dist/lib/auth.d.ts +16 -1
- package/dist/lib/auth.js +170 -45
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +7 -1
- package/oclif.manifest.json +7464 -653
- package/package.json +2 -2
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, saveTokens } from './config.js';
|
|
7
|
+
import { getBaseUrls, getContext, saveCachedTenants, saveTokens, } from './config.js';
|
|
8
8
|
function buildValidatedUrl(baseUrl, path) {
|
|
9
9
|
try {
|
|
10
10
|
// Minimal path validation
|
|
@@ -140,19 +140,24 @@ function generatePKCE() {
|
|
|
140
140
|
function generateState() {
|
|
141
141
|
return crypto.randomBytes(16).toString('hex');
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
function buildAuthorizeUrl(context, pkce, state, options = {}) {
|
|
144
144
|
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
145
|
+
const url = new URL(`${authUrl}/oauth/authorize`);
|
|
146
|
+
url.searchParams.set('client_id', context.client_id);
|
|
147
|
+
url.searchParams.set('redirect_uri', REDIRECT_URI);
|
|
148
|
+
url.searchParams.set('response_type', 'code');
|
|
149
|
+
url.searchParams.set('state', state);
|
|
150
|
+
url.searchParams.set('code_challenge', pkce.challenge);
|
|
151
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
152
|
+
url.searchParams.set('scope', 'openid profile email offline_access');
|
|
153
|
+
if (options.prompt)
|
|
154
|
+
url.searchParams.set('prompt', options.prompt);
|
|
155
|
+
return url.toString();
|
|
156
|
+
}
|
|
157
|
+
export async function login(context, options = {}) {
|
|
145
158
|
const pkce = generatePKCE();
|
|
146
159
|
const state = generateState();
|
|
147
|
-
|
|
148
|
-
const authorizationUrl = new URL(`${authUrl}/oauth/authorize`);
|
|
149
|
-
authorizationUrl.searchParams.set('client_id', context.client_id);
|
|
150
|
-
authorizationUrl.searchParams.set('redirect_uri', REDIRECT_URI);
|
|
151
|
-
authorizationUrl.searchParams.set('response_type', 'code');
|
|
152
|
-
authorizationUrl.searchParams.set('state', state);
|
|
153
|
-
authorizationUrl.searchParams.set('code_challenge', pkce.challenge);
|
|
154
|
-
authorizationUrl.searchParams.set('code_challenge_method', 'S256');
|
|
155
|
-
authorizationUrl.searchParams.set('scope', 'openid profile email offline_access');
|
|
160
|
+
const authorizationUrl = buildAuthorizeUrl(context, pkce, state, options);
|
|
156
161
|
return new Promise((resolve, reject) => {
|
|
157
162
|
const connections = new Set();
|
|
158
163
|
let timeoutId;
|
|
@@ -215,11 +220,21 @@ export async function login(context) {
|
|
|
215
220
|
}
|
|
216
221
|
connections.clear();
|
|
217
222
|
server.close();
|
|
223
|
+
process.off('SIGINT', onSigint);
|
|
224
|
+
};
|
|
225
|
+
const onSigint = () => {
|
|
226
|
+
closeServer();
|
|
227
|
+
// Exit with the standard SIGINT code so the parent shell sees the
|
|
228
|
+
// expected termination status instead of a hung process. This is a CLI;
|
|
229
|
+
// process.exit is the correct way to bail from a SIGINT.
|
|
230
|
+
// eslint-disable-next-line unicorn/no-process-exit, n/no-process-exit
|
|
231
|
+
process.exit(130);
|
|
218
232
|
};
|
|
233
|
+
process.once('SIGINT', onSigint);
|
|
219
234
|
server.listen(CALLBACK_PORT, () => {
|
|
220
235
|
console.log(`Opening browser for authentication...`);
|
|
221
|
-
console.log(`If the browser doesn't open, visit: ${authorizationUrl
|
|
222
|
-
open(authorizationUrl
|
|
236
|
+
console.log(`If the browser doesn't open, visit: ${authorizationUrl}`);
|
|
237
|
+
open(authorizationUrl);
|
|
223
238
|
});
|
|
224
239
|
server.on('error', (err) => {
|
|
225
240
|
closeServer();
|
|
@@ -357,12 +372,16 @@ export async function listTenants(contextName) {
|
|
|
357
372
|
throw error;
|
|
358
373
|
}
|
|
359
374
|
// Normalize the response - Frontegg may use different field names
|
|
360
|
-
|
|
375
|
+
const tenants = response.data.map((t) => ({
|
|
361
376
|
createdAt: t.createdAt,
|
|
362
377
|
isDefault: t.isDefault,
|
|
363
378
|
name: t.name || t.tenantName || t.tenantId,
|
|
364
379
|
tenantId: t.tenantId,
|
|
365
380
|
}));
|
|
381
|
+
// Cache for use when the access token is expired (e.g. session-expired branch
|
|
382
|
+
// of `aderis switch`, where we want to show the picker before re-authenticating).
|
|
383
|
+
saveCachedTenants(contextName, tenants.map((t) => ({ name: t.name, tenantId: t.tenantId })));
|
|
384
|
+
return tenants;
|
|
366
385
|
}
|
|
367
386
|
export async function getCurrentTenant(contextName) {
|
|
368
387
|
const context = getContext(contextName);
|
|
@@ -398,38 +417,14 @@ export async function switchTenant(contextName, tenantId) {
|
|
|
398
417
|
if (!context.tokens?.refresh_token) {
|
|
399
418
|
throw new Error('No refresh token available. Please login again.');
|
|
400
419
|
}
|
|
401
|
-
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
402
|
-
const token = await getValidToken(contextName);
|
|
403
420
|
try {
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
});
|
|
412
|
-
// Step 2: Refresh tokens to get new tokens for the switched tenant
|
|
413
|
-
const response = await axios.post(buildValidatedUrl(authUrl, '/oauth/token'), new URLSearchParams({
|
|
414
|
-
client_id: context.client_id,
|
|
415
|
-
grant_type: 'refresh_token',
|
|
416
|
-
refresh_token: context.tokens.refresh_token,
|
|
417
|
-
}).toString(), {
|
|
418
|
-
headers: {
|
|
419
|
-
Accept: 'application/json',
|
|
420
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
421
|
-
},
|
|
422
|
-
});
|
|
423
|
-
const tokens = response.data;
|
|
424
|
-
const decoded = jwt.decode(tokens.access_token);
|
|
425
|
-
const tokenData = {
|
|
426
|
-
access_token: tokens.access_token,
|
|
427
|
-
expires_at: tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined,
|
|
428
|
-
refresh_token: tokens.refresh_token || context.tokens.refresh_token,
|
|
429
|
-
tenant_id: decoded?.tenantId || decoded?.tenant_id,
|
|
430
|
-
};
|
|
431
|
-
saveTokens(contextName, tokenData);
|
|
432
|
-
return tokenData;
|
|
421
|
+
// Delegate to the two-round PKCE flow. Round 1 issues a token for whatever
|
|
422
|
+
// tenant Frontegg's session cookie currently holds (which forces Frontegg
|
|
423
|
+
// to refresh its session state), then we PUT the requested tenant, and
|
|
424
|
+
// round 2 — reached via meta-refresh on the same browser tab — issues a
|
|
425
|
+
// token scoped to the new tenant. No re-authentication is required because
|
|
426
|
+
// the user's Frontegg session cookie is still valid.
|
|
427
|
+
return await loginAndSwitchTenant(context, tenantId);
|
|
433
428
|
}
|
|
434
429
|
catch (error) {
|
|
435
430
|
if (axios.isAxiosError(error) && (error.response?.status === 401 || error.response?.status === 400)) {
|
|
@@ -438,3 +433,133 @@ export async function switchTenant(contextName, tenantId) {
|
|
|
438
433
|
throw error;
|
|
439
434
|
}
|
|
440
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* Combined login + tenant switch flow that uses a single browser tab.
|
|
438
|
+
*
|
|
439
|
+
* Two PKCE rounds run against one local callback server. After the first round
|
|
440
|
+
* completes (which gives us tokens we can use to PUT the new active tenant),
|
|
441
|
+
* the server responds with HTML that meta-refreshes the same browser tab to a
|
|
442
|
+
* second `/oauth/authorize` URL. The second round mints tokens scoped to the
|
|
443
|
+
* new active tenant.
|
|
444
|
+
*
|
|
445
|
+
* Used by `aderis switch` when the user's session is expired AND they want to
|
|
446
|
+
* end up on a different tenant — avoids the previous two-separate-tab UX.
|
|
447
|
+
*/
|
|
448
|
+
export async function loginAndSwitchTenant(context, tenantId) {
|
|
449
|
+
const { auth: authUrl } = getBaseUrls(context.environment);
|
|
450
|
+
const pkce1 = generatePKCE();
|
|
451
|
+
const state1 = generateState();
|
|
452
|
+
const pkce2 = generatePKCE();
|
|
453
|
+
const state2 = generateState();
|
|
454
|
+
const authorizeUrl1 = buildAuthorizeUrl(context, pkce1, state1);
|
|
455
|
+
const authorizeUrl2 = buildAuthorizeUrl(context, pkce2, state2);
|
|
456
|
+
return new Promise((resolve, reject) => {
|
|
457
|
+
const connections = new Set();
|
|
458
|
+
const timeoutRef = {};
|
|
459
|
+
const closeServer = () => {
|
|
460
|
+
if (timeoutRef.id)
|
|
461
|
+
clearTimeout(timeoutRef.id);
|
|
462
|
+
for (const socket of connections) {
|
|
463
|
+
socket.destroy();
|
|
464
|
+
}
|
|
465
|
+
connections.clear();
|
|
466
|
+
server.close();
|
|
467
|
+
process.off('SIGINT', onSigint);
|
|
468
|
+
};
|
|
469
|
+
const onSigint = () => {
|
|
470
|
+
closeServer();
|
|
471
|
+
// eslint-disable-next-line unicorn/no-process-exit, n/no-process-exit
|
|
472
|
+
process.exit(130);
|
|
473
|
+
};
|
|
474
|
+
process.once('SIGINT', onSigint);
|
|
475
|
+
const server = http.createServer(async (req, res) => {
|
|
476
|
+
const url = new URL(req.url || '', `http://localhost:${CALLBACK_PORT}`);
|
|
477
|
+
if (url.pathname !== '/oauth/callback') {
|
|
478
|
+
res.writeHead(404);
|
|
479
|
+
res.end('Not Found');
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const code = url.searchParams.get('code');
|
|
483
|
+
const returnedState = url.searchParams.get('state');
|
|
484
|
+
const error = url.searchParams.get('error');
|
|
485
|
+
const errorDescription = url.searchParams.get('error_description');
|
|
486
|
+
if (error || !code || !returnedState) {
|
|
487
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
488
|
+
res.end(renderAuthPage('error', 'Authentication Failed', errorDescription || error || 'Invalid response'));
|
|
489
|
+
closeServer();
|
|
490
|
+
reject(new Error(errorDescription || error || 'Invalid authorization response'));
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
if (returnedState === state1) {
|
|
495
|
+
// Round 1: fresh login → tokens for whatever tenant Frontegg considers
|
|
496
|
+
// active for this user. PUT to set the requested tenant, then redirect
|
|
497
|
+
// the SAME browser tab to authorize URL #2 so Frontegg re-mints tokens.
|
|
498
|
+
const tokens1 = await exchangeCodeForTokens(context, code, pkce1.verifier);
|
|
499
|
+
saveTokens(context.name, tokens1);
|
|
500
|
+
await axios.put(buildValidatedUrl(authUrl, '/identity/resources/users/v1/tenant'), { tenantId }, {
|
|
501
|
+
headers: {
|
|
502
|
+
Accept: 'application/json',
|
|
503
|
+
Authorization: `Bearer ${tokens1.access_token}`,
|
|
504
|
+
'Content-Type': 'application/json',
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
508
|
+
res.end(`<!DOCTYPE html>
|
|
509
|
+
<html><head>
|
|
510
|
+
<meta charset="UTF-8">
|
|
511
|
+
<meta http-equiv="refresh" content="0; url=${authorizeUrl2}">
|
|
512
|
+
<title>Switching tenant…</title>
|
|
513
|
+
</head><body><p>Switching tenant…</p></body></html>`);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (returnedState === state2) {
|
|
517
|
+
// Round 2: tokens scoped to the new tenant.
|
|
518
|
+
const tokens2 = await exchangeCodeForTokens(context, code, pkce2.verifier);
|
|
519
|
+
saveTokens(context.name, tokens2);
|
|
520
|
+
if (tokens2.tenant_id !== tenantId) {
|
|
521
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
522
|
+
res.end(renderAuthPage('error', 'Tenant Switch Failed', `Frontegg returned a token for tenant ${tokens2.tenant_id} instead of ${tenantId}.`));
|
|
523
|
+
closeServer();
|
|
524
|
+
reject(new Error(`Tenant switch did not propagate. Frontegg returned tenant ${tokens2.tenant_id} instead of ${tenantId}. Please try again in a few seconds.`));
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
res.writeHead(200, { Connection: 'close', 'Content-Type': 'text/html' });
|
|
528
|
+
res.end(renderAuthPage('success', 'Tenant Switched', `You have been logged in to <strong>${context.name}</strong> on the selected tenant.`));
|
|
529
|
+
setImmediate(() => {
|
|
530
|
+
closeServer();
|
|
531
|
+
resolve(tokens2);
|
|
532
|
+
});
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
536
|
+
res.end(renderAuthPage('error', 'Authentication Failed', 'Invalid state parameter.'));
|
|
537
|
+
closeServer();
|
|
538
|
+
reject(new Error('Invalid state in callback'));
|
|
539
|
+
}
|
|
540
|
+
catch (error_) {
|
|
541
|
+
res.writeHead(500, { 'Content-Type': 'text/html' });
|
|
542
|
+
res.end(renderAuthPage('error', 'Authentication Failed', error_ instanceof Error ? error_.message : 'Unknown error'));
|
|
543
|
+
closeServer();
|
|
544
|
+
reject(error_);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
server.on('connection', (socket) => {
|
|
548
|
+
connections.add(socket);
|
|
549
|
+
socket.on('close', () => connections.delete(socket));
|
|
550
|
+
});
|
|
551
|
+
server.listen(CALLBACK_PORT, () => {
|
|
552
|
+
console.log('Opening browser for authentication…');
|
|
553
|
+
console.log(`If the browser doesn't open, visit: ${authorizeUrl1}`);
|
|
554
|
+
open(authorizeUrl1);
|
|
555
|
+
});
|
|
556
|
+
server.on('error', (err) => {
|
|
557
|
+
closeServer();
|
|
558
|
+
reject(new Error(`Failed to start local server: ${err.message}`));
|
|
559
|
+
});
|
|
560
|
+
timeoutRef.id = setTimeout(() => {
|
|
561
|
+
closeServer();
|
|
562
|
+
reject(new Error('Authentication timed out'));
|
|
563
|
+
}, 5 * 60 * 1000);
|
|
564
|
+
});
|
|
565
|
+
}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -12,7 +12,12 @@ export interface TokenData {
|
|
|
12
12
|
refresh_token?: string;
|
|
13
13
|
tenant_id?: string;
|
|
14
14
|
}
|
|
15
|
+
export interface CachedTenant {
|
|
16
|
+
name: string;
|
|
17
|
+
tenantId: string;
|
|
18
|
+
}
|
|
15
19
|
export interface Context {
|
|
20
|
+
cachedTenants?: CachedTenant[];
|
|
16
21
|
client_id: string;
|
|
17
22
|
client_secret?: string;
|
|
18
23
|
environment: Environment;
|
|
@@ -34,6 +39,8 @@ export declare function addContext(context: Context): void;
|
|
|
34
39
|
export declare function updateContext(name: string, updates: Partial<Context>): void;
|
|
35
40
|
export declare function deleteContext(name: string): void;
|
|
36
41
|
export declare function saveTokens(contextName: string, tokens: TokenData): void;
|
|
42
|
+
export declare function saveCachedTenants(contextName: string, tenants: CachedTenant[]): void;
|
|
43
|
+
export declare function getCachedTenants(contextName: string): CachedTenant[] | undefined;
|
|
37
44
|
export declare function getTokens(contextName: string): null | TokenData;
|
|
38
45
|
export declare function clearTokens(contextName: string): void;
|
|
39
46
|
export declare function getBaseUrls(environment: Environment): BaseUrls;
|
package/dist/lib/config.js
CHANGED
|
@@ -20,7 +20,7 @@ export const BASE_URLS = {
|
|
|
20
20
|
export const DEFAULT_CLIENT_IDS = {
|
|
21
21
|
dev: '74fd96f8-cf4b-49d8-b713-2a121ea22910',
|
|
22
22
|
live: '970d9568-84c9-4613-b966-30d7e1d93828',
|
|
23
|
-
test: '',
|
|
23
|
+
test: 'bf0e5dd6-419f-4d64-8951-2c385533651f',
|
|
24
24
|
};
|
|
25
25
|
const CONFIG_DIR = path.join(os.homedir(), '.aderis');
|
|
26
26
|
// Ensure config directory exists
|
|
@@ -100,6 +100,12 @@ export function saveTokens(contextName, tokens) {
|
|
|
100
100
|
tokens,
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
export function saveCachedTenants(contextName, tenants) {
|
|
104
|
+
updateContext(contextName, { cachedTenants: tenants });
|
|
105
|
+
}
|
|
106
|
+
export function getCachedTenants(contextName) {
|
|
107
|
+
return getContext(contextName)?.cachedTenants;
|
|
108
|
+
}
|
|
103
109
|
export function getTokens(contextName) {
|
|
104
110
|
const context = getContext(contextName);
|
|
105
111
|
return context?.tokens || null;
|