diff --git a/packages/clerk-js/src/core/fapiClient.ts b/packages/clerk-js/src/core/fapiClient.ts index 506b732abe3..3976232544c 100644 --- a/packages/clerk-js/src/core/fapiClient.ts +++ b/packages/clerk-js/src/core/fapiClient.ts @@ -24,7 +24,7 @@ type FapiQueryStringParameters = { }; export type FapiResponse = Response & { - payload: FapiResponseJSON | null; + payload: FapiResponseJSON; }; export type FapiRequestCallback = ( diff --git a/packages/clerk-js/src/core/resources/Base.ts b/packages/clerk-js/src/core/resources/Base.ts index 7f032cd8c40..d8d297cd4ed 100644 --- a/packages/clerk-js/src/core/resources/Base.ts +++ b/packages/clerk-js/src/core/resources/Base.ts @@ -1,8 +1,13 @@ -import { isValidBrowserOnline } from '@clerk/shared/browser'; -import type { ClerkAPIErrorJSON, ClerkResourceJSON, ClerkResourceReloadParams, DeletedObjectJSON } from '@clerk/types'; +import type { + ClerkAPIErrorJSON, + ClerkPaginatedResponse, + ClerkResourceJSON, + ClerkResourceReloadParams, + DeletedObjectJSON, +} from '@clerk/types'; import { clerkMissingFapiClientInResources } from '../errors'; -import type { FapiClient, FapiRequestInit, FapiResponse, FapiResponseJSON, HTTPMethod } from '../fapiClient'; +import type { FapiClient, FapiRequestInit, FapiResponseJSON, HTTPMethod } from '../fapiClient'; import type { Clerk } from './internal'; import { ClerkAPIResponseError, Client } from './internal'; @@ -24,26 +29,20 @@ export abstract class BaseResource { return BaseResource.clerk.getFapiClient(); } - protected static async _fetch( - requestInit: FapiRequestInit, - opts: BaseFetchOptions = {}, - ): Promise | null> { + protected static async _fetch< + J extends + | ClerkResourceJSON + | ClerkResourceJSON[] + | DeletedObjectJSON + | DeletedObjectJSON[] + | ClerkPaginatedResponse + | null, + >(requestInit: FapiRequestInit, opts: BaseFetchOptions = {}): Promise> { if (!BaseResource.fapiClient) { clerkMissingFapiClientInResources(); } - let fapiResponse: FapiResponse; - - try { - fapiResponse = await BaseResource.fapiClient.request(requestInit); - } catch (e) { - if (!isValidBrowserOnline()) { - console.warn(e); - return null; - } else { - throw e; - } - } + const fapiResponse = await BaseResource.fapiClient.request(requestInit); const { payload, status, statusText, headers } = fapiResponse; @@ -66,14 +65,10 @@ export abstract class BaseResource { await BaseResource.clerk.handleUnauthenticated(); } - if (status >= 400) { - throw new ClerkAPIResponseError(statusText, { - data: payload?.errors as ClerkAPIErrorJSON[], - status: status, - }); - } - - return null; + throw new ClerkAPIResponseError(statusText, { + data: payload?.errors as ClerkAPIErrorJSON[], + status: status, + }); } protected static _updateClient(responseJSON: FapiResponseJSON | null): void { diff --git a/packages/clerk-js/src/core/resources/Image.ts b/packages/clerk-js/src/core/resources/Image.ts index 19c07e0a070..829a1eb635e 100644 --- a/packages/clerk-js/src/core/resources/Image.ts +++ b/packages/clerk-js/src/core/resources/Image.ts @@ -27,7 +27,7 @@ export class Image extends BaseResource implements ImageResource { body: fd, headers, }) - )?.response as unknown as ImageJSON; + )?.response; return new Image(json); } @@ -38,7 +38,7 @@ export class Image extends BaseResource implements ImageResource { path, method: 'DELETE', }) - )?.response as unknown as ImageJSON; + )?.response; return new Image(json); } diff --git a/packages/clerk-js/src/core/resources/Organization.ts b/packages/clerk-js/src/core/resources/Organization.ts index ddb9b8f1cef..f3128b13b86 100644 --- a/packages/clerk-js/src/core/resources/Organization.ts +++ b/packages/clerk-js/src/core/resources/Organization.ts @@ -86,7 +86,7 @@ export class Organization extends BaseResource implements OrganizationResource { method: 'POST', body: { name, slug } as any, }) - )?.response as unknown as OrganizationJSON; + )?.response; return new Organization(json); } @@ -97,7 +97,7 @@ export class Organization extends BaseResource implements OrganizationResource { path: `/organizations/${organizationId}`, method: 'GET', }) - )?.response as unknown as OrganizationJSON; + )?.response; return new Organization(json); } @@ -126,14 +126,13 @@ export class Organization extends BaseResource implements OrganizationResource { getDomains = async ( getDomainParams?: GetDomainsParams, ): Promise> => { - return await BaseResource._fetch({ + return await BaseResource._fetch>({ path: `/organizations/${this.id}/domains`, method: 'GET', search: convertPageToOffset(getDomainParams) as any, }) .then(res => { - const { data: invites, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + const { data: invites, total_count } = res.response; return { total_count, @@ -152,21 +151,20 @@ export class Organization extends BaseResource implements OrganizationResource { path: `/organizations/${this.id}/domains/${domainId}`, method: 'GET', }) - )?.response as unknown as OrganizationDomainJSON; + )?.response; return new OrganizationDomain(json); }; getMembershipRequests = async ( getRequestParam?: GetMembershipRequestParams, ): Promise> => { - return await BaseResource._fetch({ + return await BaseResource._fetch>({ path: `/organizations/${this.id}/membership_requests`, method: 'GET', search: convertPageToOffset(getRequestParam) as any, }) .then(res => { - const { data: requests, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + const { data: requests, total_count } = res.response; return { total_count, @@ -197,7 +195,7 @@ export class Organization extends BaseResource implements OrganizationResource { deprecated('offset', 'Use `initialPage` instead in Organization.limit.', 'organization:getMemberships:offset'); } - return await BaseResource._fetch({ + return await BaseResource._fetch({ path: `/organizations/${this.id}/memberships`, method: 'GET', search: isDeprecatedParams @@ -206,7 +204,7 @@ export class Organization extends BaseResource implements OrganizationResource { }) .then(res => { if (isDeprecatedParams) { - const organizationMembershipsJSON = res?.response as unknown as OrganizationMembershipJSON[]; + const organizationMembershipsJSON = res.response; return organizationMembershipsJSON.map(orgMem => new OrganizationMembership(orgMem)) as any; } @@ -233,13 +231,13 @@ export class Organization extends BaseResource implements OrganizationResource { getPendingInvitationsParams?: GetPendingInvitationsParams, ): Promise => { deprecated('getPendingInvitations', 'Use the `getInvitations` method instead.'); - return await BaseResource._fetch({ + return await BaseResource._fetch({ path: `/organizations/${this.id}/invitations/pending`, method: 'GET', search: getPendingInvitationsParams as any, }) .then(res => { - const pendingInvitations = res?.response as unknown as OrganizationInvitationJSON[]; + const pendingInvitations = res?.response; return pendingInvitations.map(pendingInvitation => new OrganizationInvitation(pendingInvitation)); }) .catch(() => []); @@ -248,14 +246,13 @@ export class Organization extends BaseResource implements OrganizationResource { getInvitations = async ( getInvitationsParams?: GetInvitationsParams, ): Promise> => { - return await BaseResource._fetch({ + return await BaseResource._fetch>({ path: `/organizations/${this.id}/invitations`, method: 'GET', search: convertPageToOffset(getInvitationsParams) as any, }) .then(res => { - const { data: requests, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + const { data: requests, total_count } = res.response; return { total_count, @@ -269,11 +266,11 @@ export class Organization extends BaseResource implements OrganizationResource { }; addMember = async ({ userId, role }: AddMemberParams) => { - const newMember = await BaseResource._fetch({ + const newMember = await BaseResource._fetch({ method: 'POST', path: `/organizations/${this.id}/memberships`, body: { userId, role } as any, - }).then(res => new OrganizationMembership(res?.response as OrganizationMembershipJSON)); + }).then(res => new OrganizationMembership(res.response)); OrganizationMembership.clerk.__unstable__membershipUpdate(newMember); return newMember; }; @@ -287,20 +284,20 @@ export class Organization extends BaseResource implements OrganizationResource { }; updateMember = async ({ userId, role }: UpdateMembershipParams): Promise => { - const updatedMember = await BaseResource._fetch({ + const updatedMember = await BaseResource._fetch({ method: 'PATCH', path: `/organizations/${this.id}/memberships/${userId}`, body: { role } as any, - }).then(res => new OrganizationMembership(res?.response as OrganizationMembershipJSON)); + }).then(res => new OrganizationMembership(res.response)); OrganizationMembership.clerk.__unstable__membershipUpdate(updatedMember); return updatedMember; }; removeMember = async (userId: string): Promise => { - const deletedMember = await BaseResource._fetch({ + const deletedMember = await BaseResource._fetch({ method: 'DELETE', path: `/organizations/${this.id}/memberships/${userId}`, - }).then(res => new OrganizationMembership(res?.response as OrganizationMembershipJSON)); + }).then(res => new OrganizationMembership(res.response)); OrganizationMembership.clerk.__unstable__membershipUpdate(deletedMember); return deletedMember; }; @@ -311,10 +308,10 @@ export class Organization extends BaseResource implements OrganizationResource { setLogo = async ({ file }: SetOrganizationLogoParams): Promise => { if (file === null) { - return await BaseResource._fetch({ + return await BaseResource._fetch({ path: `/organizations/${this.id}/logo`, method: 'DELETE', - }).then(res => new Organization(res?.response as OrganizationJSON)); + }).then(res => new Organization(res.response)); } let body; @@ -329,12 +326,12 @@ export class Organization extends BaseResource implements OrganizationResource { body.append('file', file); } - return await BaseResource._fetch({ + return await BaseResource._fetch({ path: `/organizations/${this.id}/logo`, method: 'PUT', body, headers, - }).then(res => new Organization(res?.response as OrganizationJSON)); + }).then(res => new Organization(res.response)); }; protected fromJSON(data: OrganizationJSON | null): this { @@ -370,7 +367,7 @@ export class Organization extends BaseResource implements OrganizationResource { }, { forceUpdateClient: true }, ) - )?.response as unknown as OrganizationJSON; + ).response; return this.fromJSON(json); } diff --git a/packages/clerk-js/src/core/resources/OrganizationDomain.ts b/packages/clerk-js/src/core/resources/OrganizationDomain.ts index 420349002f2..0c0b03cc66d 100644 --- a/packages/clerk-js/src/core/resources/OrganizationDomain.ts +++ b/packages/clerk-js/src/core/resources/OrganizationDomain.ts @@ -35,7 +35,7 @@ export class OrganizationDomain extends BaseResource implements OrganizationDoma method: 'POST', body: { name } as any, }) - )?.response as unknown as OrganizationDomainJSON; + ).response; return new OrganizationDomain(json); } diff --git a/packages/clerk-js/src/core/resources/OrganizationInvitation.ts b/packages/clerk-js/src/core/resources/OrganizationInvitation.ts index d89c8038434..45a1172629d 100644 --- a/packages/clerk-js/src/core/resources/OrganizationInvitation.ts +++ b/packages/clerk-js/src/core/resources/OrganizationInvitation.ts @@ -30,7 +30,7 @@ export class OrganizationInvitation extends BaseResource implements Organization method: 'POST', body: { email_address: emailAddress, role } as any, }) - )?.response as unknown as OrganizationInvitationJSON; + ).response; const newInvitation = new OrganizationInvitation(json); this.clerk.__unstable__invitationUpdate(newInvitation); return newInvitation; @@ -42,12 +42,12 @@ export class OrganizationInvitation extends BaseResource implements Organization ): Promise { const { emailAddresses, role } = params; const json = ( - await BaseResource._fetch({ + await BaseResource._fetch({ path: `/organizations/${organizationId}/invitations/bulk`, method: 'POST', body: { email_address: emailAddresses, role } as any, }) - )?.response as unknown as OrganizationInvitationJSON[]; + ).response; // const newInvitation = new OrganizationInvitation(json); // TODO: Figure out what this is... // this.clerk.__unstable__invitationUpdate(newInvitation); diff --git a/packages/clerk-js/src/core/resources/OrganizationMembership.ts b/packages/clerk-js/src/core/resources/OrganizationMembership.ts index 0a4c188f6e5..e6dd0bc1ea6 100644 --- a/packages/clerk-js/src/core/resources/OrganizationMembership.ts +++ b/packages/clerk-js/src/core/resources/OrganizationMembership.ts @@ -52,7 +52,7 @@ export class OrganizationMembership extends BaseResource implements Organization ); } - return await BaseResource._fetch({ + return await BaseResource._fetch({ path: '/me/organization_memberships', method: 'GET', search: isDeprecatedParams @@ -61,7 +61,7 @@ export class OrganizationMembership extends BaseResource implements Organization }) .then(res => { if (isDeprecatedParams) { - const organizationMembershipsJSON = res?.response as unknown as OrganizationMembershipJSON[]; + const organizationMembershipsJSON = res.response; return organizationMembershipsJSON.map(orgMem => new OrganizationMembership(orgMem)) as any; } diff --git a/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts b/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts index 879ba46719f..9a26bd644f4 100644 --- a/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts +++ b/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts @@ -26,14 +26,13 @@ export class OrganizationSuggestion extends BaseResource implements Organization static async retrieve( params?: GetUserOrganizationSuggestionsParams, ): Promise> { - return await BaseResource._fetch({ + return await BaseResource._fetch>({ path: '/me/organization_suggestions', method: 'GET', search: convertPageToOffset(params) as any, }) .then(res => { - const { data: suggestions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + const { data: suggestions, total_count } = res.response; return { total_count, diff --git a/packages/clerk-js/src/core/resources/Token.ts b/packages/clerk-js/src/core/resources/Token.ts index 9471cb468ca..8fa748363ec 100644 --- a/packages/clerk-js/src/core/resources/Token.ts +++ b/packages/clerk-js/src/core/resources/Token.ts @@ -9,13 +9,13 @@ export class Token extends BaseResource implements TokenResource { jwt: JWT; static async create(path: string, body: any = {}): Promise { - const json = (await BaseResource._fetch({ + const json = await BaseResource._fetch({ path, method: 'POST', body, - })) as unknown as TokenJSON; + }); - return new Token(json, path); + return new Token(json.response, path); } constructor(data: TokenJSON, pathRoot?: string) { diff --git a/packages/clerk-js/src/core/resources/User.ts b/packages/clerk-js/src/core/resources/User.ts index 3733a324297..262374bb3e6 100644 --- a/packages/clerk-js/src/core/resources/User.ts +++ b/packages/clerk-js/src/core/resources/User.ts @@ -165,7 +165,7 @@ export class User extends BaseResource implements UserResource { additional_scope: additionalScopes, } as any, }) - )?.response as unknown as ExternalAccountJSON; + ).response; return new ExternalAccount(json, this.path() + '/external_accounts'); }; @@ -176,19 +176,19 @@ export class User extends BaseResource implements UserResource { path: '/me/totp', method: 'POST', }) - )?.response as unknown as TOTPJSON; + ).response; return new TOTP(json); }; verifyTOTP = async ({ code }: VerifyTOTPParams): Promise => { const json = ( - await BaseResource._fetch({ + await BaseResource._fetch({ path: '/me/totp/attempt_verification', method: 'POST', body: { code } as any, }) - )?.response as unknown as TOTPJSON; + ).response; return new TOTP(json); }; @@ -199,7 +199,7 @@ export class User extends BaseResource implements UserResource { path: '/me/totp', method: 'DELETE', }) - )?.response as unknown as DeletedObjectJSON; + ).response; return new DeletedObject(json); }; @@ -210,7 +210,7 @@ export class User extends BaseResource implements UserResource { path: this.path() + '/backup_codes/', method: 'POST', }) - )?.response as unknown as BackupCodeJSON; + ).response; return new BackupCode(json); }; @@ -282,7 +282,7 @@ export class User extends BaseResource implements UserResource { path: `${this.path()}/organization_memberships/${organizationId}`, method: 'DELETE', }) - )?.response as unknown as DeletedObjectJSON; + ).response; return new DeletedObject(json); }; diff --git a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts index 40e4fa7fc06..64976ebc8e7 100644 --- a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts +++ b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts @@ -24,14 +24,13 @@ export class UserOrganizationInvitation extends BaseResource implements UserOrga static async retrieve( params?: GetUserOrganizationInvitationsParams, ): Promise> { - return await BaseResource._fetch({ + return await BaseResource._fetch>({ path: '/me/organization_invitations', method: 'GET', search: convertPageToOffset(params) as any, }) .then(res => { - const { data: invites, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + const { data: invites, total_count } = res.response; return { total_count, diff --git a/packages/clerk-js/src/core/services/authentication/SessionCookieService.ts b/packages/clerk-js/src/core/services/authentication/SessionCookieService.ts index ad75670e4b9..c29f42bccd7 100644 --- a/packages/clerk-js/src/core/services/authentication/SessionCookieService.ts +++ b/packages/clerk-js/src/core/services/authentication/SessionCookieService.ts @@ -1,4 +1,4 @@ -import { is4xxError, isClerkAPIResponseError, isNetworkError } from '@clerk/shared/error'; +import { is4xxError, isClerkAPIResponseError, isKnownError, isNetworkError } from '@clerk/shared/error'; import type { Clerk, EnvironmentResource, SessionResource, TokenResource } from '@clerk/types'; import type { CookieHandler } from '../../../utils'; @@ -95,6 +95,11 @@ export class SessionCookieService { } private handleGetTokenError(e: any) { + //return if network error + if (isNetworkError(e)) { + return; + } + //throw if not a clerk error if (!isClerkAPIResponseError(e)) { clerkCoreErrorTokenRefreshFailed(e.message || e); @@ -106,10 +111,6 @@ export class SessionCookieService { return; } - if (isNetworkError(e)) { - return; - } - clerkCoreErrorTokenRefreshFailed(e.toString()); } } diff --git a/packages/shared/src/error.ts b/packages/shared/src/error.ts index 38cb1927d33..5ec0102872d 100644 --- a/packages/shared/src/error.ts +++ b/packages/shared/src/error.ts @@ -13,10 +13,11 @@ export function is4xxError(e: any): boolean { return !!status && status >= 400 && status < 500; } +export const NETWORK_ERROR_STRING = 'networkerror'; export function isNetworkError(e: any): boolean { // TODO: revise during error handling epic const message = (`${e.message}${e.name}` || '').toLowerCase().replace(/\s+/g, ''); - return message.includes('networkerror'); + return message.includes(NETWORK_ERROR_STRING); } interface ClerkAPIResponseOptions {