Skip to content

Commit

Permalink
chore(repo): Move error helpers to shared package (#1308)
Browse files Browse the repository at this point in the history
test(chrome-extension): Update shapshots
  • Loading branch information
desiprisg committed Jun 9, 2023
1 parent 2e93816 commit 7af91bc
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 109 deletions.
8 changes: 8 additions & 0 deletions .changeset/beige-tips-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@clerk/nextjs': minor
'@clerk/shared': minor
'@clerk/clerk-react': minor
'@clerk/clerk-expo': minor
---

Export error helpers from the shared package to the framework specific packages
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ exports[`public exports should not include a breaking change 1`] = `
"WithSession",
"WithUser",
"__internal__setErrorThrowerOptions",
"isClerkAPIResponseError",
"isKnownError",
"isMagicLinkError",
"isMetamaskError",
"useAuth",
"useClerk",
"useMagicLink",
Expand Down
101 changes: 12 additions & 89 deletions packages/clerk-js/src/core/resources/Error.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,12 @@
import type { ClerkAPIError, ClerkAPIErrorJSON } from '@clerk/types';

interface ClerkAPIResponseOptions {
data: ClerkAPIErrorJSON[];
status: number;
}

// For a comprehensive Metamask error list, please see
// https://docs.metamask.io/guide/ethereum-provider.html#errors
export interface MetamaskError extends Error {
code: 4001 | 32602 | 32603;
message: string;
data?: unknown;
}

export function isKnownError(error: any) {
return isClerkAPIResponseError(error) || isMetamaskError(error);
}

export function isClerkAPIResponseError(err: any): err is ClerkAPIResponseError {
return 'clerkError' in err;
}

export function isMetamaskError(err: any): err is MetamaskError {
return 'code' in err && [4001, 32602, 32603].includes(err.code) && 'message' in err;
}

export function parseErrors(data: ClerkAPIErrorJSON[] = []): ClerkAPIError[] {
return data.length > 0 ? data.map(parseError) : [];
}

export function parseError(error: ClerkAPIErrorJSON): ClerkAPIError {
return {
code: error.code,
message: error.message,
longMessage: error.long_message,
meta: {
paramName: error?.meta?.param_name,
sessionId: error?.meta?.session_id,
emailAddresses: error?.meta?.email_addresses,
},
};
}

export class ClerkAPIResponseError extends Error {
clerkError: true;

status: number;
message: string;

errors: ClerkAPIError[];

constructor(message: string, { data, status }: ClerkAPIResponseOptions) {
super(message);

Object.setPrototypeOf(this, ClerkAPIResponseError.prototype);

this.status = status;
this.message = message;
this.clerkError = true;
this.errors = parseErrors(data);
}

public toString = () => {
return `[${this.name}]\nMessage:${this.message}\nStatus:${this.status}\nSerialized errors: ${this.errors.map(e =>
JSON.stringify(e),
)}`;
};
}

export class MagicLinkError extends Error {
code: string;

constructor(code: string) {
super(code);
this.code = code;
Object.setPrototypeOf(this, MagicLinkError.prototype);
}
}
// Check if the error is a MagicLinkError.

export function isMagicLinkError(err: Error): err is MagicLinkError {
return err instanceof MagicLinkError;
}

export const MagicLinkErrorCode = {
Expired: 'expired',
Failed: 'failed',
};
export {
isKnownError,
isMagicLinkError,
isMetamaskError,
isClerkAPIResponseError,
MagicLinkErrorCode,
parseError,
parseErrors,
MagicLinkError,
ClerkAPIResponseError,
} from '@clerk/shared';
export type { MetamaskError } from '@clerk/shared';
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui/common/EmailLinkVerify.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { isMagicLinkError, MagicLinkErrorCode } from '@clerk/shared';
import React from 'react';

import { isMagicLinkError, MagicLinkErrorCode } from '../../core/resources/Error';
import type { VerificationStatus } from '../../utils/getClerkQueryParam';
import { completeSignUpFlow } from '../components/SignUp/util';
import { useCoreClerk, useCoreSignUp } from '../contexts';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ClerkAPIResponseError } from '../../../core/resources/Error';
import { ClerkAPIResponseError } from '@clerk/shared';

import { isVerificationExpiredError, VerificationErrorMessage, verificationErrorMessage } from '../verification';

describe('verification utils', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ClerkAPIResponseError } from '@clerk/shared';
import type { MembershipRole, OrganizationResource } from '@clerk/types';
import React from 'react';

import { ClerkAPIResponseError } from '../../../core/resources/Error';
import { Flex, Text } from '../../customizables';
import {
Alert,
Expand Down
3 changes: 3 additions & 0 deletions packages/expo/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export {
WithSession,
withUser,
WithUser,
isClerkAPIResponseError,
isMagicLinkError,
isMetamaskError,
isKnownError,
MagicLinkErrorCode,
} from '@clerk/clerk-react';

Expand Down
8 changes: 7 additions & 1 deletion packages/nextjs/src/client-boundary/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ export {

export type { WithUserProp, WithSessionProp, WithClerkProp } from '@clerk/clerk-react';

export { isMagicLinkError, MagicLinkErrorCode } from '@clerk/clerk-react';
export {
isClerkAPIResponseError,
MagicLinkErrorCode,
isKnownError,
isMetamaskError,
isMagicLinkError,
} from '@clerk/clerk-react';
10 changes: 8 additions & 2 deletions packages/nextjs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ export {
useOrganizationList,
useOrganizations,
useMagicLink,
MagicLinkErrorCode,
isMagicLinkError,
withUser,
withSession,
withClerk,
Expand All @@ -59,6 +57,14 @@ export {

export type { WithUserProp, WithSessionProp, WithClerkProp } from './client-boundary/hooks';

export {
isClerkAPIResponseError,
isMagicLinkError,
isMetamaskError,
isKnownError,
MagicLinkErrorCode,
} from '@clerk/clerk-react';

/**
* Conditionally export components that exhibit different behavior
* when used in /app vs /pages.
Expand Down
21 changes: 8 additions & 13 deletions packages/react/src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
export {
isMagicLinkError,
MagicLinkErrorCode,
isClerkAPIResponseError,
isKnownError,
isMetamaskError,
} from '@clerk/shared';

export const noFrontendApiError = 'Clerk: You must add the frontendApi prop to your <ClerkProvider>';

export const noClerkProviderError = 'Clerk: You must wrap your application in a <ClerkProvider> component.';
Expand All @@ -16,19 +24,6 @@ export const hocChildrenNotAFunctionError = 'Clerk: Child of WithClerk must be a
export const multipleChildrenInButtonComponent = (name: string) =>
`Clerk: You've passed multiple children components to <${name}/>. You can only pass a single child component or text.`;

export const MagicLinkErrorCode = {
Expired: 'expired',
Failed: 'failed',
};

type MagicLinkError = {
code: 'expired' | 'failed';
};

export function isMagicLinkError(err: any): err is MagicLinkError {
return !!err && (err.code === MagicLinkErrorCode.Expired || err.code === MagicLinkErrorCode.Failed);
}

export const invalidStateError =
'Invalid state. Feel free to submit a bug or reach out to support here: https://clerk.com/support';

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export type {
WithSessionProp,
IsomorphicClerkOptions,
} from './types';
export { isMagicLinkError, MagicLinkErrorCode } from './errors';
export { MagicLinkErrorCode, isClerkAPIResponseError, isKnownError, isMetamaskError, isMagicLinkError } from './errors';
export { useMagicLink } from './hooks/useMagicLink';
89 changes: 89 additions & 0 deletions packages/shared/src/errors/Error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { ClerkAPIError, ClerkAPIErrorJSON } from '@clerk/types';

interface ClerkAPIResponseOptions {
data: ClerkAPIErrorJSON[];
status: number;
}

// For a comprehensive Metamask error list, please see
// https://docs.metamask.io/guide/ethereum-provider.html#errors
export interface MetamaskError extends Error {
code: 4001 | 32602 | 32603;
message: string;
data?: unknown;
}

export function isKnownError(error: any) {
return isClerkAPIResponseError(error) || isMetamaskError(error);
}

export function isClerkAPIResponseError(err: any): err is ClerkAPIResponseError {
return 'clerkError' in err;
}

export function isMetamaskError(err: any): err is MetamaskError {
return 'code' in err && [4001, 32602, 32603].includes(err.code) && 'message' in err;
}

export function parseErrors(data: ClerkAPIErrorJSON[] = []): ClerkAPIError[] {
return data.length > 0 ? data.map(parseError) : [];
}

export function parseError(error: ClerkAPIErrorJSON): ClerkAPIError {
return {
code: error.code,
message: error.message,
longMessage: error.long_message,
meta: {
paramName: error?.meta?.param_name,
sessionId: error?.meta?.session_id,
emailAddresses: error?.meta?.email_addresses,
},
};
}

export class ClerkAPIResponseError extends Error {
clerkError: true;

status: number;
message: string;

errors: ClerkAPIError[];

constructor(message: string, { data, status }: ClerkAPIResponseOptions) {
super(message);

Object.setPrototypeOf(this, ClerkAPIResponseError.prototype);

this.status = status;
this.message = message;
this.clerkError = true;
this.errors = parseErrors(data);
}

public toString = () => {
return `[${this.name}]\nMessage:${this.message}\nStatus:${this.status}\nSerialized errors: ${this.errors.map(e =>
JSON.stringify(e),
)}`;
};
}

export class MagicLinkError extends Error {
code: string;

constructor(code: string) {
super(code);
this.code = code;
Object.setPrototypeOf(this, MagicLinkError.prototype);
}
}
// Check if the error is a MagicLinkError.

export function isMagicLinkError(err: Error): err is MagicLinkError {
return err instanceof MagicLinkError;
}

export const MagicLinkErrorCode = {
Expired: 'expired',
Failed: 'failed',
};
2 changes: 2 additions & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
export { buildErrorThrower } from './errors/thrower';
export type { ErrorThrower, ErrorThrowerOptions } from './errors/thrower';

export * from './errors/Error';

/**
* Utils
*/
Expand Down

0 comments on commit 7af91bc

Please sign in to comment.