diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad9acb62..efd0482f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [#1462](https://github.com/okta/okta-auth-js/pull/1462) Fixes ESM build for Node.js - [#1472](https://github.com/okta/okta-auth-js/pull/1472) Added missing remediator `ReEnrollAuthenticatorWarning` + - [#1473](https://github.com/okta/okta-auth-js/pull/1473) Resolves circular dependencies issue for ESM build ### Other diff --git a/lib/myaccount/emailApi.ts b/lib/myaccount/emailApi.ts index 8447b7308..e13918ba4 100644 --- a/lib/myaccount/emailApi.ts +++ b/lib/myaccount/emailApi.ts @@ -1,10 +1,10 @@ import { sendRequest } from './request'; -import { - IAPIFunction, +import { IAPIFunction } from './types'; +import { BaseTransaction, EmailTransaction, EmailChallengeTransaction -} from './types'; +} from './transactions'; /** * @scope: okta.myAccount.email.read @@ -13,12 +13,11 @@ export const getEmails: IAPIFunction = async ( oktaAuth, options? ) => { - const transaction = await sendRequest(oktaAuth, { + const transaction = await sendRequest(oktaAuth, { url: '/idp/myaccount/emails', method: 'GET', - accessToken: options?.accessToken, - transactionClassName: 'EmailTransaction' - }) as EmailTransaction[]; + accessToken: options?.accessToken + }, EmailTransaction); return transaction; }; @@ -34,8 +33,7 @@ export const getEmail: IAPIFunction = async ( url: `/idp/myaccount/emails/${id}`, method: 'GET', accessToken, - transactionClassName: 'EmailTransaction' - }) as EmailTransaction; + }, EmailTransaction); return transaction; }; @@ -52,8 +50,7 @@ export const addEmail: IAPIFunction = async ( method: 'POST', payload, accessToken, - transactionClassName: 'EmailTransaction' - }) as EmailTransaction; + }, EmailTransaction); return transaction; }; @@ -69,7 +66,7 @@ export const deleteEmail: IAPIFunction = async ( url: `/idp/myaccount/emails/${id}`, method: 'DELETE', accessToken - }) as BaseTransaction; + }); return transaction; }; @@ -85,8 +82,7 @@ export const sendEmailChallenge: IAPIFunction = async url: `/idp/myaccount/emails/${id}/challenge`, method: 'POST', accessToken, - transactionClassName: 'EmailChallengeTransaction' - }) as EmailChallengeTransaction; + }, EmailChallengeTransaction); return transaction; }; @@ -102,8 +98,7 @@ export const getEmailChallenge: IAPIFunction = async url: `/idp/myaccount/emails/${emailId}/challenge/${challengeId}`, method: 'POST', accessToken, - transactionClassName: 'EmailChallengeTransaction' - }) as EmailChallengeTransaction; + }, EmailChallengeTransaction); return transaction; }; @@ -120,6 +115,6 @@ export const verifyEmailChallenge: IAPIFunction = async ( method: 'POST', payload, accessToken - }) as BaseTransaction; + }); return transaction; }; diff --git a/lib/myaccount/passwordApi.ts b/lib/myaccount/passwordApi.ts index 0a151119f..d23d62453 100644 --- a/lib/myaccount/passwordApi.ts +++ b/lib/myaccount/passwordApi.ts @@ -1,9 +1,9 @@ import { sendRequest } from './request'; -import { - IAPIFunction, +import { IAPIFunction } from './types'; +import { BaseTransaction, PasswordTransaction -} from './types'; +} from './transactions'; /** * @scope: okta.myAccount.password.read @@ -16,8 +16,7 @@ export const getPassword: IAPIFunction = async ( url: `/idp/myaccount/password`, method: 'GET', accessToken: options?.accessToken, - transactionClassName: 'PasswordTransaction' - }) as PasswordTransaction; + }, PasswordTransaction); return transaction; }; @@ -34,8 +33,7 @@ export const enrollPassword: IAPIFunction = async ( method: 'POST', payload, accessToken, - transactionClassName: 'PasswordTransaction' - }) as PasswordTransaction; + }, PasswordTransaction); return transaction; }; @@ -52,8 +50,7 @@ export const updatePassword: IAPIFunction = async ( method: 'PUT', payload, accessToken, - transactionClassName: 'PasswordTransaction' - }) as PasswordTransaction; + }, PasswordTransaction); return transaction; }; @@ -68,6 +65,6 @@ export const deletePassword: IAPIFunction = async ( url: `/idp/myaccount/password`, method: 'DELETE', accessToken: options?.accessToken, - }) as BaseTransaction; + }); return transaction; }; diff --git a/lib/myaccount/phoneApi.ts b/lib/myaccount/phoneApi.ts index 019f12ce5..5adedb744 100644 --- a/lib/myaccount/phoneApi.ts +++ b/lib/myaccount/phoneApi.ts @@ -1,9 +1,9 @@ import { sendRequest } from './request'; -import { - IAPIFunction, +import { IAPIFunction } from './types'; +import { BaseTransaction, PhoneTransaction -} from './types'; +} from './transactions'; /** * @scope: okta.myAccount.phone.read @@ -12,12 +12,11 @@ export const getPhones: IAPIFunction = async ( oktaAuth, options? ) => { - const transaction = await sendRequest(oktaAuth, { + const transaction = await sendRequest(oktaAuth, { url: '/idp/myaccount/phones', method: 'GET', accessToken: options?.accessToken, - transactionClassName: 'PhoneTransaction' - }) as PhoneTransaction[]; + }, PhoneTransaction); return transaction; }; @@ -33,8 +32,7 @@ export const getPhone: IAPIFunction = async ( url: `/idp/myaccount/phones/${id}`, method: 'GET', accessToken, - transactionClassName: 'PhoneTransaction' - }) as PhoneTransaction; + }, PhoneTransaction); return transaction; }; @@ -51,8 +49,7 @@ export const addPhone: IAPIFunction = async ( method: 'POST', payload, accessToken, - transactionClassName: 'PhoneTransaction' - }) as PhoneTransaction; + }, PhoneTransaction); return transaction; }; @@ -68,7 +65,7 @@ export const deletePhone: IAPIFunction = async ( url: `/idp/myaccount/phones/${id}`, method: 'DELETE', accessToken, - }) as BaseTransaction; + }); return transaction; }; @@ -85,7 +82,7 @@ export const sendPhoneChallenge: IAPIFunction = async ( method: 'POST', payload, accessToken - }) as BaseTransaction; + }); return transaction; }; @@ -102,6 +99,6 @@ export const verifyPhoneChallenge: IAPIFunction = async ( method: 'POST', payload, accessToken - }) as BaseTransaction; + }); return transaction; }; diff --git a/lib/myaccount/profileApi.ts b/lib/myaccount/profileApi.ts index 615e56e25..998a0bfae 100644 --- a/lib/myaccount/profileApi.ts +++ b/lib/myaccount/profileApi.ts @@ -1,9 +1,9 @@ import { sendRequest } from './request'; -import { - IAPIFunction, +import { IAPIFunction } from './types'; +import { ProfileTransaction, ProfileSchemaTransaction -} from './types'; +} from './transactions'; /** * @scope: okta.myAccount.profile.read @@ -13,8 +13,7 @@ export const getProfile: IAPIFunction = async (oktaAuth, opt url: '/idp/myaccount/profile', method: 'GET', accessToken: options?.accessToken, - transactionClassName: 'ProfileTransaction' - }) as ProfileTransaction; + }, ProfileTransaction); return transaction; }; @@ -31,8 +30,7 @@ export const updateProfile: IAPIFunction = async ( method: 'PUT', payload, accessToken, - transactionClassName: 'ProfileTransaction' - }) as ProfileTransaction; + }, ProfileTransaction); return transaction; }; @@ -47,7 +45,6 @@ export const getProfileSchema: IAPIFunction = async ( url: '/idp/myaccount/profile/schema', method: 'GET', accessToken: options?.accessToken, - transactionClassName: 'ProfileSchemaTransaction' - }) as ProfileSchemaTransaction; + }, ProfileSchemaTransaction); return transaction; }; diff --git a/lib/myaccount/request.ts b/lib/myaccount/request.ts index df0fcc9ea..6218a6525 100644 --- a/lib/myaccount/request.ts +++ b/lib/myaccount/request.ts @@ -1,42 +1,29 @@ import { - BaseTransaction, - EmailTransaction, - EmailStatusTransaction, - EmailChallengeTransaction, - ProfileTransaction, - ProfileSchemaTransaction, - PhoneTransaction, - PasswordTransaction -} from './transactions'; + default as BaseTransaction, + TransactionType, + TransactionLinks +} from './transactions/Base'; import { httpRequest } from '../http'; import { AuthSdkError } from '../errors'; import { MyAccountRequestOptions as RequestOptions } from './types'; import { OktaAuthOAuthInterface } from '../oidc/types'; -export type TransactionLink = { - href: string; - hints?: { - allow?: string[]; - }; -} - -type TransactionLinks = { - self: TransactionLink; - [property: string]: TransactionLink; -} - type SendRequestOptions = RequestOptions & { url: string; method: string; - transactionClassName?: string; } /* eslint-disable complexity */ -export async function sendRequest ( +export async function sendRequest< + T extends BaseTransaction = BaseTransaction, + N extends 'plural' | 'single' = 'single', + NT = N extends 'plural' ? T[] : T +> ( oktaAuth: OktaAuthOAuthInterface, - options: SendRequestOptions -): Promise { - const { + options: SendRequestOptions, + TransactionClass: TransactionType = BaseTransaction as TransactionType, +): Promise { + const { accessToken: accessTokenObj } = oktaAuth.tokenManager.getTokensSync(); @@ -57,28 +44,19 @@ export async function sendRequest ( ...(payload && { args: payload }) }); - const map = { - EmailTransaction, - EmailStatusTransaction, - EmailChallengeTransaction, - ProfileTransaction, - ProfileSchemaTransaction, - PhoneTransaction, - PasswordTransaction - }; - const TransactionClass = map[options.transactionClassName!] || BaseTransaction; - + let ret: T | T[]; if (Array.isArray(res)) { - return res.map(item => new TransactionClass(oktaAuth, { + ret = res.map(item => new TransactionClass(oktaAuth, { res: item, accessToken })); + } else { + ret = new TransactionClass(oktaAuth, { + res, + accessToken + }); } - - return new TransactionClass(oktaAuth, { - res, - accessToken - }); + return ret as NT; } /* eslint-enable complexity */ @@ -87,28 +65,28 @@ export type GenerateRequestFnFromLinksOptions = { accessToken: string; methodName: string; links: TransactionLinks; - transactionClassName?: string; } -type IRequestFnFromLinks = (payload?) => Promise; +type IRequestFnFromLinks = (payload?) => Promise; -export function generateRequestFnFromLinks ({ - oktaAuth, - accessToken, - methodName, - links, - transactionClassName -}: GenerateRequestFnFromLinksOptions): IRequestFnFromLinks { +export function generateRequestFnFromLinks( + { + oktaAuth, + accessToken, + methodName, + links, + }: GenerateRequestFnFromLinksOptions, + TransactionClass: TransactionType = BaseTransaction as TransactionType, +): IRequestFnFromLinks { for (const method of ['GET', 'POST', 'PUT', 'DELETE']) { if (method.toLowerCase() === methodName) { const link = links.self; - return (async (payload?) => sendRequest(oktaAuth, { + return (async (payload?) => sendRequest(oktaAuth, { accessToken, url: link.href, method, payload, - transactionClassName - })); + }, TransactionClass)); } } @@ -117,11 +95,10 @@ export function generateRequestFnFromLinks ({ throw new AuthSdkError(`No link is found with methodName: ${methodName}`); } - return (async (payload?) => sendRequest(oktaAuth, { + return (async (payload?) => sendRequest(oktaAuth, { accessToken, url: link.href, method: link.hints!.allow![0], payload, - transactionClassName - })); + }, TransactionClass)); } diff --git a/lib/myaccount/transactions/Base.ts b/lib/myaccount/transactions/Base.ts index 1b3852703..05f3988e7 100644 --- a/lib/myaccount/transactions/Base.ts +++ b/lib/myaccount/transactions/Base.ts @@ -1,5 +1,16 @@ import { OktaAuthHttpInterface } from '../../http/types'; -import { TransactionLink } from '../request'; + +export type TransactionLink = { + href: string; + hints?: { + allow?: string[]; + }; +} + +export type TransactionLinks = { + self: TransactionLink; + [property: string]: TransactionLink; +} type TransactionOptions = { // TODO: move res type to http module @@ -10,6 +21,7 @@ type TransactionOptions = { }; accessToken: string; }; + export default class BaseTransaction { // Deprecated headers?: Record; @@ -32,3 +44,8 @@ export default class BaseTransaction { }); } } + +export interface TransactionType extends Function { + new (oktaAuth: OktaAuthHttpInterface, options: TransactionOptions): T; + prototype: T; +} diff --git a/lib/myaccount/transactions/EmailChallengeTransaction.ts b/lib/myaccount/transactions/EmailChallengeTransaction.ts index eaa18b8ed..48c5cd2bb 100644 --- a/lib/myaccount/transactions/EmailChallengeTransaction.ts +++ b/lib/myaccount/transactions/EmailChallengeTransaction.ts @@ -35,9 +35,8 @@ export default class EmailChallengeTransaction extends BaseTransaction { accessToken, methodName: 'poll', links: _links, - transactionClassName: 'EmailStatusTransaction' - }); - return await fn() as EmailStatusTransaction; + }, EmailStatusTransaction); + return await fn(); }; this.verify = async (payload) => { const fn = generateRequestFnFromLinks({ @@ -45,8 +44,8 @@ export default class EmailChallengeTransaction extends BaseTransaction { accessToken, methodName: 'verify', links: _links, - }); - return await fn(payload) as EmailChallengeTransaction; + }, EmailChallengeTransaction); + return await fn(payload); }; } } diff --git a/lib/myaccount/transactions/EmailTransaction.ts b/lib/myaccount/transactions/EmailTransaction.ts index 9744f1efa..50e8adba4 100644 --- a/lib/myaccount/transactions/EmailTransaction.ts +++ b/lib/myaccount/transactions/EmailTransaction.ts @@ -1,4 +1,5 @@ -import { EmailChallengeTransaction, EmailStatusTransaction } from '.'; +import EmailChallengeTransaction from './EmailChallengeTransaction'; +import EmailStatusTransaction from './EmailStatusTransaction'; import { EmailProfile, EmailRole, Status, VerificationPayload } from '../types'; import BaseTransaction from './Base'; import { generateRequestFnFromLinks } from '../request'; @@ -34,9 +35,8 @@ export default class EmailTransaction extends BaseTransaction { accessToken, methodName: 'get', links: _links, - transactionClassName: 'EmailTransaction' - }); - return await fn() as EmailTransaction; + }, EmailTransaction); + return await fn(); }; this.delete = async () => { const fn = generateRequestFnFromLinks({ @@ -45,7 +45,7 @@ export default class EmailTransaction extends BaseTransaction { methodName: 'delete', links: _links }); - return await fn() as BaseTransaction; + return await fn(); }; this.challenge = async () => { const fn = generateRequestFnFromLinks({ @@ -53,9 +53,8 @@ export default class EmailTransaction extends BaseTransaction { accessToken, methodName: 'challenge', links: _links, - transactionClassName: 'EmailChallengeTransaction' - }); - return await fn() as EmailChallengeTransaction; + }, EmailChallengeTransaction); + return await fn(); }; if (_links.poll) { this.poll = async () => { @@ -64,9 +63,8 @@ export default class EmailTransaction extends BaseTransaction { accessToken, methodName: 'poll', links: _links, - transactionClassName: 'EmailStatusTransaction' - }); - return await fn() as EmailStatusTransaction; + }, EmailStatusTransaction); + return await fn(); }; } if (_links.verify) { @@ -77,7 +75,7 @@ export default class EmailTransaction extends BaseTransaction { methodName: 'verify', links: _links, }); - return await fn(payload) as BaseTransaction; + return await fn(payload); }; } } diff --git a/lib/myaccount/transactions/PasswordTransaction.ts b/lib/myaccount/transactions/PasswordTransaction.ts index c342aa13c..72bd30314 100644 --- a/lib/myaccount/transactions/PasswordTransaction.ts +++ b/lib/myaccount/transactions/PasswordTransaction.ts @@ -35,9 +35,8 @@ export default class PasswordTransaction extends BaseTransaction { accessToken, methodName: 'enroll', links: _links, - transactionClassName: 'PasswordTransaction' - }); - return await fn(payload) as PasswordTransaction; + }, PasswordTransaction); + return await fn(payload); }; } else { @@ -47,9 +46,8 @@ export default class PasswordTransaction extends BaseTransaction { accessToken, methodName: 'get', links: _links, - transactionClassName: 'PasswordTransaction' - }); - return await fn() as PasswordTransaction; + }, PasswordTransaction); + return await fn(); }; this.update = async (payload) => { @@ -58,9 +56,8 @@ export default class PasswordTransaction extends BaseTransaction { accessToken, methodName: 'put', links: _links, - transactionClassName: 'PasswordTransaction' - }); - return await fn(payload) as PasswordTransaction; + }, PasswordTransaction); + return await fn(payload); }; this.delete = async () => { @@ -70,7 +67,7 @@ export default class PasswordTransaction extends BaseTransaction { methodName: 'delete', links: _links }); - return await fn() as BaseTransaction; + return await fn(); }; } } diff --git a/lib/myaccount/transactions/PhoneTransaction.ts b/lib/myaccount/transactions/PhoneTransaction.ts index 13b7d6ac5..61a0358d4 100644 --- a/lib/myaccount/transactions/PhoneTransaction.ts +++ b/lib/myaccount/transactions/PhoneTransaction.ts @@ -30,9 +30,8 @@ export default class PhoneTransaction extends BaseTransaction { accessToken, methodName: 'get', links: _links, - transactionClassName: 'PhoneTransaction' - }); - return await fn() as PhoneTransaction; + }, PhoneTransaction); + return await fn(); }; this.delete = async () => { const fn = generateRequestFnFromLinks({ @@ -41,7 +40,7 @@ export default class PhoneTransaction extends BaseTransaction { methodName: 'delete', links: _links }); - return await fn() as BaseTransaction; + return await fn(); }; this.challenge = async (payload) => { const fn = generateRequestFnFromLinks({ @@ -50,7 +49,7 @@ export default class PhoneTransaction extends BaseTransaction { methodName: 'challenge', links: _links }); - return await fn(payload) as BaseTransaction; + return await fn(payload); }; if (_links.verify) { this.verify = async (payload) => { @@ -60,7 +59,7 @@ export default class PhoneTransaction extends BaseTransaction { methodName: 'verify', links: _links }); - return await fn(payload) as BaseTransaction; + return await fn(payload); } ; } } diff --git a/lib/myaccount/types.ts b/lib/myaccount/types.ts index cfcea1d42..69b315c72 100644 --- a/lib/myaccount/types.ts +++ b/lib/myaccount/types.ts @@ -6,7 +6,7 @@ import { PKCETransactionMeta } from '../oidc/types'; -export { +export type { EmailTransaction, EmailStatusTransaction, EmailChallengeTransaction, diff --git a/lib/oidc/mixin/index.ts b/lib/oidc/mixin/index.ts index ac1845972..ec8d4f6b7 100644 --- a/lib/oidc/mixin/index.ts +++ b/lib/oidc/mixin/index.ts @@ -28,7 +28,7 @@ import { Endpoints, } from '../types'; import PKCE from '../util/pkce'; -import { createEndpoints, createTokenAPI } from '../factory'; +import { createEndpoints, createTokenAPI } from '../factory/api'; import { TokenManager } from '../TokenManager'; import { getOAuthUrls, isLoginRedirect } from '../util'; diff --git a/test/spec/myaccount/request.ts b/test/spec/myaccount/request.ts index 72b128974..48e2cb439 100644 --- a/test/spec/myaccount/request.ts +++ b/test/spec/myaccount/request.ts @@ -143,8 +143,7 @@ describe('generateRequestFnFromLinks function', () => { accessToken: 'fake-token', methodName: 'get', links: mockLinks, - transactionClassName: 'EmailTransaction' - }); + }, EmailTransaction); await getFn(); expect(mocked.http.httpRequest).toHaveBeenCalledWith(auth, { url: 'http://my-okta-domain/idp/myaccount/emails/00T196qTp3LIMZQ0L0g3', @@ -195,8 +194,7 @@ describe('generateRequestFnFromLinks function', () => { accessToken: 'fake-token', methodName: 'challenge', links: mockLinks, - transactionClassName: 'EmailChallengeTransaction' - }); + }, EmailChallengeTransaction); await challengeFn(); expect(mocked.http.httpRequest).toHaveBeenCalledWith(auth, { method: 'POST',