-
Notifications
You must be signed in to change notification settings - Fork 331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(repo): Move error helpers to shared package #1308
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 |
---|---|---|
@@ -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'; | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,5 @@ export type { | |
WithSessionProp, | ||
IsomorphicClerkOptions, | ||
} from './types'; | ||
export { isMagicLinkError, MagicLinkErrorCode } from './errors'; | ||
export { MagicLinkErrorCode, isClerkAPIResponseError, isKnownError, isMetamaskError, isMagicLinkError } from './errors'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Why not export them directly from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It just seemed cleaner to have all error related stuff in one place. Does the other way around seem better to you? |
||
export { useMagicLink } from './hooks/useMagicLink'; |
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', | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ Why not use them directly from the
@clerk/shared
and drop this file?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We export them twice so I thought it was better to have the logic here.