Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2001287
feat(shared,types): Add clerk trace id to existing errors
nikosdouvlis Oct 1, 2025
6e90c2a
introduce global error types
nikosdouvlis Oct 2, 2025
e5bc3a5
chore(backend): Add `slug_disabled` to `OrganizationSettings` (#6902)
LauraBeatris Oct 2, 2025
05aaf71
docs(repo): Add link replacements for broken types (#6908)
SarahSoutoul Oct 2, 2025
efe70b5
fix(clerk-js): SignUpVerificationCodeForm back navigation for combine…
alexcarpenter Oct 3, 2025
4e053d2
feat(clerk-js): Adding oidc logout to frontendApiRedirectPathsNoUserI…
Ben2W Oct 3, 2025
93ffbfa
feat(clerk-expo): Add support for experimental Signal hooks (#6900)
dstaley Oct 3, 2025
7659e86
ci(repo): Version packages (#6893)
clerk-cookie Oct 3, 2025
82016bf
ci(repo): Add clerk/react v6 branch to CI (#6912)
dstaley Oct 3, 2025
757637c
chore(repo): Update dependency tailwindcss to ^3.4.18 (#6924)
renovate[bot] Oct 5, 2025
54c3378
chore(repo): Update dependency @types/react to v18.3.25 (#6923)
renovate[bot] Oct 5, 2025
9c669be
fix(astro): Update dependency nanoid to v5.1.6 (#6926)
renovate[bot] Oct 5, 2025
d25efea
feat(clerk-js,clerk-react,types): Add support for additional props (#…
dstaley Oct 6, 2025
da16c00
chore(astro): Update dependency astro to ^5.14.1 (#6919)
renovate[bot] Oct 6, 2025
8b6b33b
feat(clerk-js,types): Display organization slug based on environment …
LauraBeatris Oct 6, 2025
aa46aca
Revert "fix(nuxt): Prevent Nuxt route middlewares from seeing interme…
wobsoriano Oct 6, 2025
e0ee76d
chore(react-router): Accept `organizationSyncOptions` option in middl…
wobsoriano Oct 6, 2025
2253988
ci(repo): Version packages (#6929)
clerk-cookie Oct 6, 2025
2a1b9ad
fix(clerk-js): Add private _create method for use inside runAsyncReso…
dstaley Oct 6, 2025
5dc0451
chore(repo): Update dependency zx to v8.8.4 (#6925)
renovate[bot] Oct 7, 2025
7f23db3
chore(repo): Update common TypeScript types (#6922)
renovate[bot] Oct 7, 2025
74e71f3
fix(vue): Prevent boolean prop coercion for SignIn component props (#…
wobsoriano Oct 7, 2025
645fc37
chore(backend): Add helper type for auth helpers without request para…
wobsoriano Oct 7, 2025
6c2722f
chore(localizations): Update account deletion confirmation copy (#6937)
jescalan Oct 7, 2025
05f7ee8
feat(backend): Add support for User `locale` (#6938)
tmilewski Oct 7, 2025
0388e89
chore(localizations): Update pt-BR localization (#6881)
hypeARM Oct 8, 2025
5f49059
chore(backend): Add missing `adminDeleteEnabled` param to Organizatio…
ccaspanello Oct 8, 2025
fe53c98
chore(repo): Migrate Nuxt E2E template to v4 (#6942)
wobsoriano Oct 8, 2025
e565234
fix(backend): Export missing Billing types (#6944)
mauricioabreu Oct 8, 2025
f6bd8da
add runtime error scaffold
nikosdouvlis Oct 9, 2025
c6344fa
move error/future to top-level experimental-error
nikosdouvlis Oct 9, 2025
35704ab
wire ClerkGlobalHookError to hook `errors.global`
nikosdouvlis Oct 9, 2025
6029e99
refactor(errors): introduce typed ClerkApiResponseError class
nikosdouvlis Oct 12, 2025
e5bbabe
refactor(errors): consolidate error interfaces into errors.ts and rem…
nikosdouvlis Oct 12, 2025
ccc5b1e
move state and signInFuture types to shared/types
nikosdouvlis Oct 13, 2025
fabe03f
move state and signInFuture types to shared/types
nikosdouvlis Oct 13, 2025
7cc57df
Merge branch 'main' into nikos/errors-part-3
nikosdouvlis Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/warm-steaks-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/backend': minor
---

Export missing Billing types
4 changes: 4 additions & 0 deletions packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ export type {
PaginatedResponseJSON,
TestingTokenJSON,
WebhooksSvixJSON,
BillingPayerJSON,
BillingPlanJSON,
BillingSubscriptionJSON,
BillingSubscriptionItemJSON,
BillingPaymentAttemptWebhookEventJSON,
BillingSubscriptionItemWebhookEventJSON,
BillingSubscriptionWebhookEventJSON,
} from './api/resources/JSON';

/**
Expand Down
34 changes: 18 additions & 16 deletions packages/clerk-js/src/core/resources/SignIn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import { inBrowser } from '@clerk/shared/browser';
import { ClerkWebAuthnError } from '@clerk/shared/error';
import { Poller } from '@clerk/shared/poller';
import type {
SignInFutureBackupCodeVerifyParams,
SignInFutureCreateParams,
SignInFutureEmailCodeSendParams,
SignInFutureEmailCodeVerifyParams,
SignInFutureEmailLinkSendParams,
SignInFutureFinalizeParams,
SignInFutureMFAPhoneCodeVerifyParams,
SignInFuturePasswordParams,
SignInFuturePhoneCodeSendParams,
SignInFuturePhoneCodeVerifyParams,
SignInFutureResetPasswordSubmitParams,
SignInFutureResource,
SignInFutureSSOParams,
SignInFutureTicketParams,
SignInFutureTOTPVerifyParams,
SignInFutureWeb3Params,
} from '@clerk/shared/types';
import { deepCamelToSnake, deepSnakeToCamel } from '@clerk/shared/underscore';
import {
isWebAuthnAutofillSupported as isWebAuthnAutofillSupportedOnWindow,
Expand Down Expand Up @@ -31,22 +49,6 @@ import type {
SamlConfig,
SignInCreateParams,
SignInFirstFactor,
SignInFutureBackupCodeVerifyParams,
SignInFutureCreateParams,
SignInFutureEmailCodeSendParams,
SignInFutureEmailCodeVerifyParams,
SignInFutureEmailLinkSendParams,
SignInFutureFinalizeParams,
SignInFutureMFAPhoneCodeVerifyParams,
SignInFuturePasswordParams,
SignInFuturePhoneCodeSendParams,
SignInFuturePhoneCodeVerifyParams,
SignInFutureResetPasswordSubmitParams,
SignInFutureResource,
SignInFutureSSOParams,
SignInFutureTicketParams,
SignInFutureTOTPVerifyParams,
SignInFutureWeb3Params,
SignInIdentifier,
SignInJSON,
SignInJSONSnapshot,
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/hooks/useClerkSignal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SignInSignalValue, SignUpSignalValue } from '@clerk/types';
import type { SignInSignalValue, SignUpSignalValue } from '@clerk/shared/types';
import { useCallback, useSyncExternalStore } from 'react';

import { useIsomorphicClerkContext } from '../contexts/IsomorphicClerkContext';
Expand Down
22 changes: 21 additions & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@
"default": "./dist/dom/index.js"
}
},
"./experimental-error": {
"import": {
"types": "./dist/experimental-error/index.d.mts",
"default": "./dist/experimental-error/index.mjs"
},
"require": {
"types": "./dist/experimental-error/index.d.ts",
"default": "./dist/experimental-error/index.js"
}
},
"./types": {
"import": {
"types": "./dist/types/index.d.mts"
},
"require": {
"types": "./dist/types/index.d.ts"
}
},
"./package.json": "./package.json"
},
"main": "./dist/index.js",
Expand All @@ -87,6 +105,7 @@
"deriveState",
"dom",
"error",
"experimental-error",
"file",
"globs",
"handleValueOrFn",
Expand Down Expand Up @@ -123,7 +142,8 @@
"eventBus",
"netlifyCacheHandler",
"clerkEventBus",
"phoneCodeChannel"
"phoneCodeChannel",
"types"
],
"scripts": {
"build": "tsup",
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/errors/apiResponseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {

import { parseErrors } from './parseError';

interface ClerkAPIResponseOptions {
export interface ClerkAPIResponseOptions {
data: ClerkAPIErrorJSON[];
status: number;
clerkTraceId?: string;
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/errors/parseError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function parseError(error: ClerkAPIErrorJSON): ClerkAPIError {
code: error.code,
message: error.message,
longMessage: error.long_message,
clerkTraceId: error.clerk_trace_id,
meta: {
paramName: error?.meta?.param_name,
sessionId: error?.meta?.session_id,
Expand Down
31 changes: 31 additions & 0 deletions packages/shared/src/experimental-error/clerkApiError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { ClerkAPIErrorJSON } from '@clerk/types';

import { parseError } from '../errors/parseError';

export type ClerkApiErrorMeta = Record<string, unknown> | undefined;

/**
* This error contains the specific error message, code, and any additional metadata that was returned by the Clerk API.
*/
export class ClerkApiError<Meta extends ClerkApiErrorMeta = undefined> {
readonly name = 'ClerkApiError';
readonly code: string;
readonly message: string;
readonly longMessage: string | undefined;
readonly meta: Meta;

constructor(json: ClerkAPIErrorJSON) {
const parsedError = parseError(json);
this.code = parsedError.code;
this.message = parsedError.message;
this.longMessage = parsedError.longMessage;
this.meta = json.meta as Meta;
}
}

/**
* Type guard to check if a value is a ClerkApiError instance.
*/
export function isClerkApiError(error: Error): error is ClerkApiError {
return error instanceof ClerkApiError;
}
50 changes: 50 additions & 0 deletions packages/shared/src/experimental-error/clerkApiErrorResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* eslint-disable jsdoc/require-jsdoc */
import type { ClerkApiErrorResponseJSON } from '@clerk/types';

import { ClerkApiError } from './clerkApiError';
import { ClerkError } from './clerkError';

type ClerkApiResponseErrorParams = ClerkApiErrorResponseJSON & {
retryAfter?: number;
};

/**
* A ClerkError subclass that represents the shell response of a Clerk API error.
* This error contains an array of ClerkApiError instances, each representing a specific error that occurred.
*/
export class ClerkApiResponseError<E extends ClerkApiError = ClerkApiError> extends ClerkError {
readonly name = 'ClerkApiResponseError';
readonly retryAfter?: number;
readonly errors: E[];
readonly clerkTraceId: string | undefined;

constructor(data: ClerkApiResponseErrorParams) {
const errorMesages = data.errors.map(e => e.message).join(', ');
const message = `Api errors occurred: ${errorMesages}. Check the \`errors\` property for more details about the specific errors.`;
super({ message, code: 'clerk_api_error' });
this.errors = data.errors.map(e => new ClerkApiError(e)) as E[];
this.clerkTraceId = data.clerk_trace_id;
this.retryAfter = data.retryAfter;
}
}

/**
* Type guard to check if an error is a ClerkApiResponseError.
* Can be called as a standalone function or as a method on an error object.
*
* @example
* // As a standalone function
* if (isClerkApiResponseError(error)) { ... }
*
* // As a method (when attached to error object)
* if (error.isClerkApiResponseError()) { ... }
*/
export function isClerkApiResponseError(error: Error): error is ClerkApiResponseError;
export function isClerkApiResponseError(this: Error): this is ClerkApiResponseError;
export function isClerkApiResponseError(this: Error | void, error?: Error): error is ClerkApiResponseError {
const target = error ?? this;
if (!target) {
throw new TypeError('isClerkApiResponseError requires an error object');
}
return target instanceof ClerkApiResponseError;
}
Empty file.
64 changes: 64 additions & 0 deletions packages/shared/src/experimental-error/clerkError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export interface ClerkErrorParams {
/**
* A message that describes the error. This is typically intented to be showed to the developers.
* It should not be shown to the user or parsed directly as the message contents are not guaranteed
* to be stable - use the `code` property instead.
*/
message: string;
/**
* A machine-stable code that identifies the error.
*/
code: string;
/**
* A user-friendly message that describes the error and can be displayed to the user.
* This message defaults to English but can be usually translated to the user's language
* by matching the `code` property to a localized message.
*/
longMessage?: string;
/**
* The cause of the error, typically an `Error` instance that was caught and wrapped by the Clerk error handler.
*/
cause?: Error;
/**
* A URL to the documentation for the error.
*/
docsUrl?: string;
}

/**
* A temporary placeholder, this will eventually be replaced with a
* build-time flag that will actually perform DCE.
*/
const __DEV__ = true;

export class ClerkError extends Error {
readonly clerkError = true as const;
readonly name: string = 'ClerkError';
readonly code: string;
readonly longMessage: string | undefined;
readonly docsUrl: string | undefined;
readonly cause: Error | undefined;

constructor(opts: ClerkErrorParams) {
const formatMessage = (msg: string, code: string, docsUrl: string | undefined) => {
msg = `${this.name}: ${msg.trim()}\n\n(code="${code}")\n\n`;
if (__DEV__) {
msg += `\n\nDocs: ${docsUrl}`;
}
return msg;
};

super(formatMessage(opts.message, opts.code, opts.docsUrl), { cause: opts.cause });
Object.setPrototypeOf(this, ClerkError.prototype);

this.code = opts.code;
this.docsUrl = opts.docsUrl;
}
}

/**
* Type guard to check if a value is a ClerkError instance.
*/
export function isClerkError(val: unknown): val is ClerkError {
return !!val && typeof val === 'object' && 'clerkError' in val && val.clerkError === true;
}
32 changes: 32 additions & 0 deletions packages/shared/src/experimental-error/clerkRuntimeError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable jsdoc/require-jsdoc */
import type { ClerkErrorParams } from './clerkError';
import { ClerkError } from './clerkError';

export class ClerkRuntimeError extends ClerkError {
readonly name = 'ClerkRuntimeError';

constructor(params: ClerkErrorParams) {
super(params);
}
}

/**
* Type guard to check if an error is a ClerkRuntimeError.
* Can be called as a standalone function or as a method on an error object.
*
* @example
* // As a standalone function
* if (isClerkRuntimeError(error)) { ... }
*
* // As a method (when attached to error object)
* if (error.isClerkRuntimeError()) { ... }
*/
export function isClerkRuntimeError(error: Error): error is ClerkRuntimeError;
export function isClerkRuntimeError(this: Error): this is ClerkRuntimeError;
export function isClerkRuntimeError(this: Error | void, error?: Error): error is ClerkRuntimeError {
const target = error ?? this;
if (!target) {
throw new TypeError('isClerkRuntimeError requires an error object');
}
return target instanceof ClerkRuntimeError;
}
23 changes: 23 additions & 0 deletions packages/shared/src/experimental-error/globalHookError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { isClerkApiResponseError } from './clerkApiErrorResponse';
import type { ClerkError } from './clerkError';
import { isClerkRuntimeError } from './clerkRuntimeError';

/**
* Creates a ClerkGlobalHookError object from a ClerkError instance.
* It's a wrapper for all the different instances of Clerk errors that can
* be returned when using Clerk hooks.
*/
export function createClerkGlobalHookError(error: ClerkError) {
const predicates = {
isClerkApiResponseError,
isClerkRuntimeError,
} as const;

for (const [name, fn] of Object.entries(predicates)) {
Object.assign(error, { [name]: fn });
}

return error as ClerkError & typeof predicates;
}

export type ClerkGlobalHookError = ReturnType<typeof createClerkGlobalHookError>;
7 changes: 7 additions & 0 deletions packages/shared/src/experimental-error/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { ClerkApiError, isClerkApiError } from './clerkApiError';
export type { ClerkApiErrorMeta } from './clerkApiError';
export { ClerkApiResponseError, isClerkApiResponseError } from './clerkApiErrorResponse';
export { ClerkError, isClerkError, type ClerkErrorParams } from './clerkError';
export { ClerkRuntimeError, isClerkRuntimeError } from './clerkRuntimeError';
export { createClerkGlobalHookError } from './globalHookError';
export type { ClerkGlobalHookError } from './globalHookError';
31 changes: 31 additions & 0 deletions packages/shared/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export type {
Errors,
FieldError,
FieldErrors,
NullableSignInSignal,
NullableSignUpSignal,
SignInSignal,
SignInSignalValue,
SignUpSignal,
SignUpSignalValue,
State,
} from './state';

export type {
SignInFutureBackupCodeVerifyParams,
SignInFutureCreateParams,
SignInFutureEmailCodeSendParams,
SignInFutureEmailCodeVerifyParams,
SignInFutureEmailLinkSendParams,
SignInFutureFinalizeParams,
SignInFutureMFAPhoneCodeVerifyParams,
SignInFuturePasswordParams,
SignInFuturePhoneCodeSendParams,
SignInFuturePhoneCodeVerifyParams,
SignInFutureResetPasswordSubmitParams,
SignInFutureResource,
SignInFutureSSOParams,
SignInFutureTicketParams,
SignInFutureTOTPVerifyParams,
SignInFutureWeb3Params,
} from './signInResource';
Loading