From f577cb822a866b2d51fcd03e8f9fef8037490220 Mon Sep 17 00:00:00 2001 From: Jacek Date: Fri, 1 Nov 2024 15:14:13 -0500 Subject: [PATCH 1/4] feat(clerk-js): send FAPI version through URLSearchParams --- .../src/core/__tests__/fapiClient.test.ts | 26 ++++++++++++------- packages/clerk-js/src/core/constants.ts | 3 +++ packages/clerk-js/src/core/fapiClient.ts | 4 +++ .../core/resources/__tests__/Token.test.ts | 14 +++++----- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/packages/clerk-js/src/core/__tests__/fapiClient.test.ts b/packages/clerk-js/src/core/__tests__/fapiClient.test.ts index 50e80c8916..39720cbaac 100644 --- a/packages/clerk-js/src/core/__tests__/fapiClient.test.ts +++ b/packages/clerk-js/src/core/__tests__/fapiClient.test.ts @@ -1,9 +1,11 @@ import type { Clerk } from '@clerk/types'; +import { SUPPORTED_FAPI_VERSION } from '../constants'; import { createFapiClient } from '../fapiClient'; const mockedClerkInstance = { frontendApi: 'clerk.example.com', + frontEnvApiVersion: '', version: '42.0.0', session: { id: 'deadbeef', @@ -73,38 +75,40 @@ afterAll(() => { describe('buildUrl(options)', () => { it('returns the full frontend API URL', () => { expect(fapiClient.buildUrl({ path: '/foo' }).href).toBe( - 'https://clerk.example.com/v1/foo?_clerk_js_version=42.0.0', + `https://clerk.example.com/v1/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, ); }); it('returns the full frontend API URL using proxy url', () => { - expect(fapiClientWithProxy.buildUrl({ path: '/foo' }).href).toBe(`${proxyUrl}/v1/foo?_clerk_js_version=42.0.0`); + expect(fapiClientWithProxy.buildUrl({ path: '/foo' }).href).toBe( + `${proxyUrl}/v1/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, + ); }); it('adds _clerk_session_id as a query parameter if provided and path does not start with client', () => { expect(fapiClient.buildUrl({ path: '/foo', sessionId: 'sess_42' }).href).toBe( - 'https://clerk.example.com/v1/foo?_clerk_js_version=42.0.0&_clerk_session_id=sess_42', + `https://clerk.example.com/v1/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0&_clerk_session_id=sess_42`, ); expect(fapiClient.buildUrl({ path: '/client/foo', sessionId: 'sess_42' }).href).toBe( - 'https://clerk.example.com/v1/client/foo?_clerk_js_version=42.0.0', + `https://clerk.example.com/v1/client/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, ); }); it('parses search params is an object with string values', () => { expect(fapiClient.buildUrl({ path: '/foo', search: { test: '1' } }).href).toBe( - 'https://clerk.example.com/v1/foo?test=1&_clerk_js_version=42.0.0', + `https://clerk.example.com/v1/foo?test=1&__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, ); }); it('parses string search params ', () => { expect(fapiClient.buildUrl({ path: '/foo', search: 'test=2' }).href).toBe( - 'https://clerk.example.com/v1/foo?test=2&_clerk_js_version=42.0.0', + `https://clerk.example.com/v1/foo?test=2&__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, ); }); it('parses search params when value contains invalid url symbols', () => { expect(fapiClient.buildUrl({ path: '/foo', search: { bar: 'test=2' } }).href).toBe( - 'https://clerk.example.com/v1/foo?bar=test%3D2&_clerk_js_version=42.0.0', + `https://clerk.example.com/v1/foo?bar=test%3D2&__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, ); }); @@ -116,7 +120,9 @@ describe('buildUrl(options)', () => { array: ['item1', 'item2'], }, }).href, - ).toBe('https://clerk.example.com/v1/foo?array=item1&array=item2&_clerk_js_version=42.0.0'); + ).toBe( + `https://clerk.example.com/v1/foo?array=item1&array=item2&__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0`, + ); }); // The return value isn't as expected. @@ -152,7 +158,7 @@ describe('request', () => { }); expect(fetch).toHaveBeenCalledWith( - 'https://clerk.example.com/v1/foo?_clerk_js_version=42.0.0&_clerk_session_id=deadbeef', + `https://clerk.example.com/v1/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0&_clerk_session_id=deadbeef`, expect.objectContaining({ credentials: 'include', method: 'GET', @@ -167,7 +173,7 @@ describe('request', () => { }); expect(fetch).toHaveBeenCalledWith( - `${proxyUrl}/v1/foo?_clerk_js_version=42.0.0&_clerk_session_id=deadbeef`, + `${proxyUrl}/v1/foo?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=42.0.0&_clerk_session_id=deadbeef`, expect.objectContaining({ credentials: 'include', method: 'GET', diff --git a/packages/clerk-js/src/core/constants.ts b/packages/clerk-js/src/core/constants.ts index a3ef8a6844..1799278e06 100644 --- a/packages/clerk-js/src/core/constants.ts +++ b/packages/clerk-js/src/core/constants.ts @@ -37,3 +37,6 @@ export const SIGN_UP_MODES: Record = { PUBLIC: 'public', RESTRICTED: 'restricted', }; + +// This is the currently support version of the Frontend API +export const SUPPORTED_FAPI_VERSION = '2024-10-01'; diff --git a/packages/clerk-js/src/core/fapiClient.ts b/packages/clerk-js/src/core/fapiClient.ts index 0b557c5d8c..3f6def84c6 100644 --- a/packages/clerk-js/src/core/fapiClient.ts +++ b/packages/clerk-js/src/core/fapiClient.ts @@ -2,6 +2,7 @@ import { camelToSnake, isBrowserOnline, runWithExponentialBackOff } from '@clerk import type { Clerk, ClerkAPIErrorJSON, ClientJSON } from '@clerk/types'; import { buildEmailAddress as buildEmailAddressUtil, buildURL as buildUrlUtil, stringifyQueryParams } from '../utils'; +import { SUPPORTED_FAPI_VERSION } from './constants'; import { clerkNetworkError } from './errors'; export type HTTPMethod = 'CONNECT' | 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT' | 'TRACE'; @@ -91,6 +92,9 @@ export function createFapiClient(clerkInstance: Clerk): FapiClient { const searchParams = new URLSearchParams(search as any); // the above will parse {key: ['val1','val2']} as key: 'val1,val2' and we need to recreate the array bellow + // Append supported FAPI version to the query string + searchParams.append('__clerk_api_version', SUPPORTED_FAPI_VERSION); + if (clerkInstance.version) { searchParams.append('_clerk_js_version', clerkInstance.version); } diff --git a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts index 91116e46ac..e9b3e18cf6 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts @@ -1,3 +1,4 @@ +import { SUPPORTED_FAPI_VERSION } from '../../constants'; import { createFapiClient } from '../../fapiClient'; import { mockDevClerkInstance, mockFetch, mockNetworkFailedFetch } from '../../test/fixtures'; import { BaseResource } from '../internal'; @@ -20,7 +21,7 @@ describe('Token', () => { }); expect(global.fetch).toHaveBeenCalledWith( - 'https://clerk.example.com/v1/path/to/tokens?_clerk_js_version=test-0.0.0', + `https://clerk.example.com/v1/path/to/tokens?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=test-0.0.0`, // TODO(dimkl): omit extra params from fetch request (eg path, url) - remove expect.objectContaining expect.objectContaining({ method: 'POST', @@ -57,7 +58,7 @@ describe('Token', () => { const token = await Token.create('/path/to/tokens'); expect(global.fetch).toHaveBeenCalledWith( - 'https://clerk.example.com/v1/path/to/tokens?_clerk_js_version=test-0.0.0', + `https://clerk.example.com/v1/path/to/tokens?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=test-0.0.0`, // TODO(dimkl): omit extra params from fetch request (eg path, url) - remove expect.objectContaining expect.objectContaining({ method: 'POST', @@ -77,13 +78,12 @@ describe('Token', () => { mockNetworkFailedFetch(); BaseResource.clerk = { getFapiClient: () => createFapiClient(mockDevClerkInstance) } as any; - await expect(Token.create('/path/to/tokens')).rejects.toMatchObject({ - message: - 'ClerkJS: Network error at "https://clerk.example.com/v1/path/to/tokens?_clerk_js_version=test-0.0.0" - TypeError: Failed to fetch. Please try again.', - }); + await expect(Token.create('/path/to/tokens')).rejects.toThrow( + `ClerkJS: Network error at "https://clerk.example.com/v1/path/to/tokens?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=test-0.0.0" - TypeError: Failed to fetch. Please try again.`, + ); expect(global.fetch).toHaveBeenCalledWith( - 'https://clerk.example.com/v1/path/to/tokens?_clerk_js_version=test-0.0.0', + `https://clerk.example.com/v1/path/to/tokens?__clerk_api_version=${SUPPORTED_FAPI_VERSION}&_clerk_js_version=test-0.0.0`, // TODO(dimkl): omit extra params from fetch request (eg path, url) - remove expect.objectContaining expect.objectContaining({ method: 'POST', From b9b7184465a15ede680fbbb6fd8406e4e2db89e5 Mon Sep 17 00:00:00 2001 From: Jacek Date: Fri, 1 Nov 2024 15:31:50 -0500 Subject: [PATCH 2/4] changeset --- .changeset/wild-guests-battle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/wild-guests-battle.md diff --git a/.changeset/wild-guests-battle.md b/.changeset/wild-guests-battle.md new file mode 100644 index 0000000000..cd78e0a229 --- /dev/null +++ b/.changeset/wild-guests-battle.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': minor +--- + +Now sending the Frontend API version through query string params From 0f9ab2e3fcf381efc51d83c972cea40eabcc519c Mon Sep 17 00:00:00 2001 From: Jacek Radko Date: Sat, 2 Nov 2024 14:53:48 -0500 Subject: [PATCH 3/4] Update packages/clerk-js/src/core/__tests__/fapiClient.test.ts --- packages/clerk-js/src/core/__tests__/fapiClient.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/clerk-js/src/core/__tests__/fapiClient.test.ts b/packages/clerk-js/src/core/__tests__/fapiClient.test.ts index 39720cbaac..9aaa045e02 100644 --- a/packages/clerk-js/src/core/__tests__/fapiClient.test.ts +++ b/packages/clerk-js/src/core/__tests__/fapiClient.test.ts @@ -5,7 +5,6 @@ import { createFapiClient } from '../fapiClient'; const mockedClerkInstance = { frontendApi: 'clerk.example.com', - frontEnvApiVersion: '', version: '42.0.0', session: { id: 'deadbeef', From 41107d7ca6dbe0eb0910bbf5b75ce17ac2a66763 Mon Sep 17 00:00:00 2001 From: Jacek Date: Mon, 4 Nov 2024 09:39:36 -0600 Subject: [PATCH 4/4] WIP --- packages/clerk-js/src/core/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/core/constants.ts b/packages/clerk-js/src/core/constants.ts index 5b470536c7..28c6cfd203 100644 --- a/packages/clerk-js/src/core/constants.ts +++ b/packages/clerk-js/src/core/constants.ts @@ -39,5 +39,5 @@ export const SIGN_UP_MODES: Record = { WAITLIST: 'waitlist', }; -// This is the currently support version of the Frontend API -export const SUPPORTED_FAPI_VERSION = '2024-10-01'; +// This is the currently supported version of the Frontend API +export const SUPPORTED_FAPI_VERSION = '2021-02-05';