Skip to content
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/clean-kings-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/clerk-js': patch
'@clerk/shared': patch
---

Add a custom logger to allow logging a message or warning to the console once per session, in order to avoid consecutive identical logs due to component rerenders.
3 changes: 2 additions & 1 deletion packages/clerk-js/src/utils/__tests__/url.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { logger } from '@clerk/shared/logger';
import type { SignUpResource } from '@clerk/types';

import {
Expand Down Expand Up @@ -473,7 +474,7 @@ describe('isAllowedRedirectOrigin', () => {
['https://test.clerk.com/foo?hello=1', [/https:\/\/www\.clerk\.com/], false],
];

const warnMock = jest.spyOn(global.console, 'warn').mockImplementation();
const warnMock = jest.spyOn(logger, 'warnOnce');

beforeEach(() => warnMock.mockClear());
afterAll(() => warnMock.mockRestore());
Expand Down
6 changes: 4 additions & 2 deletions packages/clerk-js/src/utils/assertNoLegacyProp.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { logger } from '@clerk/shared/logger';

export function assertNoLegacyProp(props: Record<string, any>) {
const legacyProps = ['redirectUrl', 'afterSignInUrl', 'afterSignUpUrl', 'after_sign_in_url', 'after_sign_up_url'];
const legacyProp = Object.keys(props).find(key => legacyProps.includes(key));

if (legacyProp && props[legacyProp]) {
// TODO: @nikos update with the docs link
console.warn(
logger.warnOnce(
`Clerk: The prop "${legacyProp}" is deprecated and should be replaced with the new "fallbackRedirectUrl" or "forceRedirectUrl" props instead.`,
);
}
Expand All @@ -18,7 +20,7 @@ export function warnForNewPropShadowingLegacyProp(
) {
if (newValue && legacyValue) {
// TODO: @nikos update with the docs link
console.warn(
logger.warnOnce(
`Clerk: The "${newKey}" prop ("${newValue}") has priority over the legacy "${legacyKey}" (or "redirectUrl") ("${legacyValue}"), which will be completely ignored in this case. "${legacyKey}" (or "redirectUrl" prop) should be replaced with the new "fallbackRedirectUrl" or "forceRedirectUrl" props instead.`,
);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/clerk-js/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { globs } from '@clerk/shared/globs';
import { createDevOrStagingUrlCache } from '@clerk/shared/keys';
import { logger } from '@clerk/shared/logger';
import { camelToSnake } from '@clerk/shared/underscore';
import { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '@clerk/shared/url';
import type { SignUpResource } from '@clerk/types';
Expand Down Expand Up @@ -116,7 +117,7 @@ export function buildURL(params: BuildURLParams, options: BuildURLOptions<boolea
// Merge search params from hashSearch string
const searchParamsFromHashSearchString = getQueryParams(hashSearch || '');
for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {
dummyUrlForHash.searchParams.append(key, val as string);
dummyUrlForHash.searchParams.append(key, val);
}

// Merge search params from the hashSearchParams object
Expand Down Expand Up @@ -354,7 +355,7 @@ export const isAllowedRedirectOrigin =
.some(origin => origin.test(trimTrailingSlash(url.origin)));

if (!isAllowed) {
console.warn(
logger.warnOnce(
`Clerk: Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`,
);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"constants",
"apiUrlFromPublishableKey",
"scripts",
"telemetry"
"telemetry",
"logger"
],
"scripts": {
"build": "tsup",
Expand Down
33 changes: 33 additions & 0 deletions packages/shared/src/__tests__/logger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { logger } from '../logger';

describe('logger', () => {
describe('warnOnce', () => {
const warnMock = jest.spyOn(global.console, 'warn').mockImplementation();

beforeEach(() => warnMock.mockClear());
afterAll(() => warnMock.mockRestore());

test('warns only once per session', () => {
logger.warnOnce('testwarn');
logger.warnOnce('testwarn');
logger.warnOnce('testwarn');

expect(warnMock).toHaveBeenCalledTimes(1);
});
});

describe('logOnce', () => {
const logMock = jest.spyOn(global.console, 'log').mockImplementation();

beforeEach(() => logMock.mockClear());
afterAll(() => logMock.mockRestore());

test('logs only once per session', () => {
logger.logOnce('testlog');
logger.logOnce('testlog');
logger.logOnce('testlog');

expect(logMock).toHaveBeenCalledTimes(1);
});
});
});
1 change: 1 addition & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ export * from './proxy';
export * from './underscore';
export * from './url';
export * from './object';
export * from './logger';
export { createWorkerTimers } from './workerTimers';
export { DEV_BROWSER_JWT_KEY, extractDevBrowserJWTFromURL, setDevBrowserJWTInURL } from './devBrowser';
24 changes: 24 additions & 0 deletions packages/shared/src/logger.ts
Comment thread
LekoArts marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const loggedMessages: Set<string> = new Set();

export const logger = {
Comment thread
desiprisg marked this conversation as resolved.
/**
* A custom logger that ensures messages are logged only once.
* Reduces noise and duplicated messages when logs are in a hot codepath.
*/
warnOnce: (msg: string) => {
if (loggedMessages.has(msg)) {
return;
}
Comment thread
desiprisg marked this conversation as resolved.

loggedMessages.add(msg);
console.warn(msg);
},
logOnce: (msg: string) => {
if (loggedMessages.has(msg)) {
return;
}

console.log(msg);
loggedMessages.add(msg);
},
};
1 change: 1 addition & 0 deletions packages/shared/subpaths.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const subpathNames = [
'constants',
'apiUrlFromPublishableKey',
'telemetry',
'logger',
];

export const subpathFoldersBarrel = ['react'];
Expand Down