Skip to content

Commit 97c9ab3

Browse files
authored
refactor(shared,upgrade): Update exported error typeguard functions from error.ts, port from core 2 (#7509)
Signed-off-by: Kenton Duprey <[email protected]>
1 parent 8a49ea7 commit 97c9ab3

File tree

11 files changed

+55
-48
lines changed

11 files changed

+55
-48
lines changed

.changeset/sweet-singers-beg.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/shared': patch
3+
---
4+
5+
Refactor internal Clerk error handling functions

.changeset/tall-games-design.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/shared': major
3+
'@clerk/upgrade': minor
4+
---
5+
6+
Update `ClerkAPIError.kind` value to match class name

packages/shared/src/error.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
export { errorToJSON, parseError, parseErrors } from './errors/parseError';
22

3-
export { ClerkAPIError } from './errors/clerkApiError';
4-
export { ClerkAPIResponseError } from './errors/clerkApiResponseError';
5-
export { ClerkError } from './errors/clerkError';
3+
export { ClerkAPIError, isClerkAPIError } from './errors/clerkApiError';
4+
export { ClerkAPIResponseError, isClerkAPIResponseError } from './errors/clerkApiResponseError';
5+
export { ClerkError, isClerkError } from './errors/clerkError';
66

77
export { buildErrorThrower, type ErrorThrower, type ErrorThrowerOptions } from './errors/errorThrower';
88

99
export { EmailLinkError, EmailLinkErrorCode, EmailLinkErrorCodeStatus } from './errors/emailLinkError';
1010

1111
export type { MetamaskError } from './errors/metamaskError';
1212

13-
export { ClerkRuntimeError } from './errors/clerkRuntimeError';
13+
export { ClerkRuntimeError, isClerkRuntimeError } from './errors/clerkRuntimeError';
1414

1515
export { ClerkWebAuthnError } from './errors/webAuthNError';
1616

1717
export {
1818
is4xxError,
1919
isCaptchaError,
20-
isClerkAPIResponseError,
21-
isClerkRuntimeError,
2220
isEmailLinkError,
2321
isKnownError,
2422
isMetamaskError,

packages/shared/src/errors/clerkApiError.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import type { ClerkAPIError as ClerkAPIErrorInterface, ClerkAPIErrorJSON } from '../types';
22
import { createErrorTypeGuard } from './createErrorTypeGuard';
33

4-
export type ClerkApiErrorMeta = Record<string, unknown>;
4+
export type ClerkAPIErrorMeta = Record<string, unknown>;
55

66
/**
77
* This error contains the specific error message, code, and any additional metadata that was returned by the Clerk API.
88
*/
9-
export class ClerkAPIError<Meta extends ClerkApiErrorMeta = any> implements ClerkAPIErrorInterface {
10-
static kind = 'ClerkApiError';
9+
export class ClerkAPIError<Meta extends ClerkAPIErrorMeta = any> implements ClerkAPIErrorInterface {
10+
static kind = 'ClerkAPIError';
1111
readonly code: string;
1212
readonly message: string;
1313
readonly longMessage: string | undefined;
@@ -36,6 +36,6 @@ export class ClerkAPIError<Meta extends ClerkApiErrorMeta = any> implements Cler
3636
}
3737

3838
/**
39-
* Type guard to check if a value is a ClerkApiError instance.
39+
* Type guard to check if a value is a ClerkAPIError instance.
4040
*/
41-
export const isClerkApiError = createErrorTypeGuard(ClerkAPIError);
41+
export const isClerkAPIError = createErrorTypeGuard(ClerkAPIError);

packages/shared/src/errors/clerkApiResponseError.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ export class ClerkAPIResponseError extends ClerkError implements ClerkAPIRespons
4747
}
4848

4949
/**
50-
* Type guard to check if an error is a ClerkApiResponseError.
50+
* Type guard to check if an error is a ClerkAPIResponseError.
5151
* Can be called as a standalone function or as a method on an error object.
5252
*
5353
* @example
5454
* // As a standalone function
55-
* if (isClerkApiResponseError(error)) { ... }
55+
* if (isClerkAPIResponseError(error)) { ... }
5656
*
5757
* // As a method (when attached to error object)
58-
* if (error.isClerkApiResponseError()) { ... }
58+
* if (error.isClerkAPIResponseError()) { ... }
5959
*/
60-
export const isClerkApiResponseError = createErrorTypeGuard(ClerkAPIResponseError);
60+
export const isClerkAPIResponseError = createErrorTypeGuard(ClerkAPIResponseError);

packages/shared/src/errors/createErrorTypeGuard.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ export function createErrorTypeGuard<T extends new (...args: any[]) => Value>(
2727
if (!target) {
2828
throw new TypeError(`${ErrorClass.kind || ErrorClass.name} type guard requires an error object`);
2929
}
30+
// Use duck-typing with 'kind' property to handle cross-bundle scenarios
31+
// where instanceof fails due to different class instances
32+
if (ErrorClass.kind && typeof target === 'object' && target !== null && 'constructor' in target) {
33+
const targetConstructor = (target as { constructor?: { kind?: string } }).constructor;
34+
if (targetConstructor?.kind === ErrorClass.kind) {
35+
return true;
36+
}
37+
}
3038
return target instanceof ErrorClass;
3139
}
3240

packages/shared/src/errors/globalHookError.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isClerkApiResponseError } from './clerkApiResponseError';
1+
import { isClerkAPIResponseError } from './clerkApiResponseError';
22
import type { ClerkError } from './clerkError';
33
import { isClerkRuntimeError } from './clerkRuntimeError';
44

@@ -9,7 +9,7 @@ import { isClerkRuntimeError } from './clerkRuntimeError';
99
*/
1010
export function createClerkGlobalHookError(error: ClerkError) {
1111
const predicates = {
12-
isClerkApiResponseError,
12+
isClerkAPIResponseError,
1313
isClerkRuntimeError,
1414
} as const;
1515

packages/shared/src/errors/helpers.ts

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { ClerkAPIResponseError } from './clerkApiResponseError';
2+
import { isClerkAPIResponseError } from './clerkApiResponseError';
23
import type { ClerkRuntimeError } from './clerkRuntimeError';
4+
import { isClerkRuntimeError } from './clerkRuntimeError';
35
import type { EmailLinkError } from './emailLinkError';
46
import type { MetamaskError } from './metamaskError';
57

@@ -55,35 +57,6 @@ export function isKnownError(error: any): error is ClerkAPIResponseError | Clerk
5557
return isClerkAPIResponseError(error) || isMetamaskError(error) || isClerkRuntimeError(error);
5658
}
5759

58-
/**
59-
* Checks if the provided error is a ClerkAPIResponseError.
60-
*
61-
* @internal
62-
*/
63-
export function isClerkAPIResponseError(err: any): err is ClerkAPIResponseError {
64-
return err && 'clerkError' in err;
65-
}
66-
67-
/**
68-
* Checks if the provided error object is an instance of ClerkRuntimeError.
69-
*
70-
* @param err - The error object to check.
71-
* @returns True if the error is a ClerkRuntimeError, false otherwise.
72-
*
73-
* @example
74-
* const error = new ClerkRuntimeError('An error occurred');
75-
* if (isClerkRuntimeError(error)) {
76-
* // Handle ClerkRuntimeError
77-
* console.error('ClerkRuntimeError:', error.message);
78-
* } else {
79-
* // Handle other errors
80-
* console.error('Other error:', error.message);
81-
* }
82-
*/
83-
export function isClerkRuntimeError(err: any): err is ClerkRuntimeError {
84-
return 'clerkRuntimeError' in err;
85-
}
86-
8760
/**
8861
* Checks if the provided error is a Clerk runtime error indicating a reverification was cancelled.
8962
*

packages/ui/src/components/Checkout/CheckoutPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const FetchStatus = ({
6262
const internalFetchStatus = useMemo(() => {
6363
if (errors.global) {
6464
const errorCodes = errors.global.flatMap(e => {
65-
if (e.isClerkApiResponseError()) {
65+
if (e.isClerkAPIResponseError()) {
6666
return e.errors.map(e => e.code);
6767
}
6868
});

packages/ui/src/components/Checkout/parts.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const InvalidPlanScreen = () => {
4242
const { errors } = useCheckout();
4343

4444
const InvalidPlanError = errors?.global
45-
?.filter(e => e.isClerkApiResponseError())
45+
?.filter(e => e.isClerkAPIResponseError())
4646
.flatMap(e => e.errors)
4747
.find(e => e.code === 'invalid_plan_change');
4848

0 commit comments

Comments
 (0)