Skip to content

feat(clerk-js): Introduce debugLogger #6452

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

Merged
merged 7 commits into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions .changeset/all-cougars-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/clerk-js': patch
'@clerk/types': patch
---

Introduce debugLogger for internal debugging support
2 changes: 2 additions & 0 deletions .typedoc/__tests__/__snapshots__/file-structure.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
"types/sign-up-resource.mdx",
"types/signed-in-session-resource.mdx",
"types/state-selectors.mdx",
"types/telemetry-log-entry.mdx",
"types/use-auth-return.mdx",
"types/use-session-list-return.mdx",
"types/use-session-return.mdx",
Expand All @@ -148,6 +149,7 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
"shared/derive-state.mdx",
"shared/extract-dev-browser-jwt-from-url.mdx",
"shared/fast-deep-merge-and-replace.mdx",
"shared/generate-uuid.mdx",
"shared/get-clerk-js-major-version-or-tag.mdx",
"shared/get-cookie-suffix.mdx",
"shared/get-env-variable.mdx",
Expand Down
8 changes: 4 additions & 4 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "625KB" },
{ "path": "./dist/clerk.js", "maxSize": "626KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "117KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "119KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "113KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "114KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
{ "path": "./dist/vendors*.js", "maxSize": "41KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
{ "path": "./dist/stripe-vendors*.js", "maxSize": "1KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
Expand Down
52 changes: 48 additions & 4 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ import type {
Web3Provider,
} from '@clerk/types';

import type { DebugLoggerInterface } from '@/utils/debug';
import { debugLogger, initDebugLogger } from '@/utils/debug';

import type { MountComponentRenderer } from '../ui/Components';
import {
ALLOWED_PROTOCOLS,
Expand Down Expand Up @@ -159,6 +162,11 @@ type SetActiveHook = (intent?: 'sign-out') => void | Promise<void>;

export type ClerkCoreBroadcastChannelEvent = { type: 'signout' };

/**
* Interface for the debug logger with all available logging methods
*/
// DebugLoggerInterface imported from '@/utils/debug'

declare global {
interface Window {
Clerk?: Clerk;
Expand Down Expand Up @@ -197,8 +205,8 @@ export class Clerk implements ClerkInterface {
public static sdkMetadata: SDKMetadata = {
name: __PKG_NAME__,
version: __PKG_VERSION__,
environment: process.env.NODE_ENV || 'production',
};

private static _billing: CommerceBillingNamespace;
private static _apiKeys: APIKeysNamespace;
private _checkout: ClerkInterface['__experimental_checkout'] | undefined;
Expand All @@ -210,6 +218,8 @@ export class Clerk implements ClerkInterface {
public __internal_country?: string | null;
public telemetry: TelemetryCollector | undefined;
public readonly __internal_state: State = new State();
// Deprecated: use global singleton from `@/utils/debug`
public debugLogger?: DebugLoggerInterface;

protected internal_last_error: ClerkAPIError | null = null;
// converted to protected environment to support `updateEnvironment` type assertion
Expand Down Expand Up @@ -404,6 +414,7 @@ export class Clerk implements ClerkInterface {
public getFapiClient = (): FapiClient => this.#fapiClient;

public load = async (options?: ClerkOptions): Promise<void> => {
debugLogger.info('load() start', {}, 'clerk');
if (this.loaded) {
return;
}
Expand Down Expand Up @@ -448,10 +459,18 @@ export class Clerk implements ClerkInterface {
} else {
await this.#loadInNonStandardBrowser();
}
} catch (e) {
if (this.environment?.clientDebugMode) {
initDebugLogger({
enabled: true,
telemetryCollector: this.telemetry,
});
}
debugLogger.info('load() complete', {}, 'clerk');
} catch (error) {
this.#publicEventBus.emit(clerkEvents.Status, 'error');
debugLogger.error('load() failed', { error }, 'clerk');
// bubble up the error
throw e;
throw error;
}
};

Expand All @@ -477,6 +496,16 @@ export class Clerk implements ClerkInterface {
const opts = callbackOrOptions && typeof callbackOrOptions === 'object' ? callbackOrOptions : options || {};

const redirectUrl = opts?.redirectUrl || this.buildAfterSignOutUrl();
debugLogger.debug(
'signOut() start',
{
hasClient: Boolean(this.client),
multiSessionCount: this.client?.signedInSessions.length ?? 0,
redirectUrl,
sessionTarget: opts?.sessionId ?? null,
},
'clerk',
);
const signOutCallback = typeof callbackOrOptions === 'function' ? callbackOrOptions : undefined;

const executeSignOut = async () => {
Expand Down Expand Up @@ -520,6 +549,7 @@ export class Clerk implements ClerkInterface {

await executeSignOut();

debugLogger.info('signOut() complete', { redirectUrl: stripOrigin(redirectUrl) }, 'clerk');
return;
}

Expand All @@ -531,6 +561,7 @@ export class Clerk implements ClerkInterface {

if (shouldSignOutCurrent) {
await executeSignOut();
debugLogger.info('signOut() complete', { redirectUrl: stripOrigin(redirectUrl) }, 'clerk');
}
};

Expand Down Expand Up @@ -1202,13 +1233,25 @@ export class Clerk implements ClerkInterface {
const { organization, beforeEmit, redirectUrl, navigate: setActiveNavigate } = params;
let { session } = params;
this.__internal_setActiveInProgress = true;

debugLogger.debug(
'setActive() start',
{
hasClient: Boolean(this.client),
sessionTarget: typeof session === 'string' ? session : (session?.id ?? session ?? null),
organizationTarget:
typeof organization === 'string' ? organization : (organization?.id ?? organization ?? null),
redirectUrl: redirectUrl ?? null,
},
'clerk',
);
try {
if (!this.client) {
debugLogger.warn('Clerk setActive called before client is loaded', {}, 'clerk');
throw new Error('setActive is being called before the client is loaded. Wait for init.');
}

if (session === undefined && !this.session) {
debugLogger.warn('Clerk setActive precondition not met: no target session and no active session', {}, 'clerk');
throw new Error(
'setActive should either be called with a session param or there should be already an active session.',
);
Expand Down Expand Up @@ -1414,6 +1457,7 @@ export class Clerk implements ClerkInterface {
const customNavigate =
options?.replace && this.#options.routerReplace ? this.#options.routerReplace : this.#options.routerPush;

debugLogger.info(`Clerk is navigating to: ${toURL}`);
if (this.#options.routerDebug) {
console.log(`Clerk is navigating to: ${toURL}`);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/clerk-js/src/core/fapiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { retry } from '@clerk/shared/retry';
import { camelToSnake } from '@clerk/shared/underscore';
import type { ClerkAPIErrorJSON, ClientJSON, InstanceType } from '@clerk/types';

import { debugLogger } from '@/utils/debug';

import { buildEmailAddress as buildEmailAddressUtil, buildURL as buildUrlUtil, stringifyQueryParams } from '../utils';
import { SUPPORTED_FAPI_VERSION } from './constants';
import { clerkNetworkError } from './errors';
Expand Down Expand Up @@ -250,12 +252,16 @@ export function createFapiClient(options: FapiClientOptions): FapiClient {
response = new Response('{}', requestInit); // Mock an empty json response
}
} catch (e) {
debugLogger.error('network error', { error: e, url: urlStr, method }, 'fapiClient');
clerkNetworkError(urlStr, e);
}

// 204 No Content responses do not have a body so we should not try to parse it
const json: FapiResponseJSON<T> | null = response.status !== 204 ? await response.json() : null;
const fapiResponse: FapiResponse<T> = Object.assign(response, { payload: json });
if (!response.ok) {
debugLogger.error('request failed', { method, path: requestInit.path, status: response.status }, 'fapiClient');
}
await runAfterResponseCallbacks(requestInit, fapiResponse);
return fapiResponse;
}
Expand Down
Loading
Loading