diff --git a/.changeset/gentle-radios-shout.md b/.changeset/gentle-radios-shout.md new file mode 100644 index 00000000000..ac36e81f0c2 --- /dev/null +++ b/.changeset/gentle-radios-shout.md @@ -0,0 +1,16 @@ +--- +'@clerk/clerk-sdk-node': patch +'@clerk/backend': major +'@clerk/nextjs': patch +--- + +The following paginated APIs now return `{ data, totalCount }` instead of simple arrays, in order to make building paginated UIs easier: +- `clerkClient.users.getOrganizationMembershipList(...)` +- `clerkClient.organization.getOrganizationList(...)` +- `clerkClient.organization.getOrganizationInvitationList(...)` + +Revert changing the `{ data, errors }` return value of the following helpers to throw the `errors` or return the `data` (keep v4 format): + +- `import { verifyToken } from '@clerk/backend'` +- `import { signJwt, hasValidSignature, decodeJwt, verifyJwt } from '@clerk/backend/jwt'` +- BAPI `clerkClient` methods eg (`clerkClient.users.getUserList(...)`) diff --git a/integration/cleanup/cleanup.setup.ts b/integration/cleanup/cleanup.setup.ts index f66715cf3fa..fbf63d3f2f7 100644 --- a/integration/cleanup/cleanup.setup.ts +++ b/integration/cleanup/cleanup.setup.ts @@ -19,17 +19,12 @@ setup('cleanup instances ', async () => { for (const entry of entries) { console.log(`Cleanup for ${entry!.secretKey.replace(/(sk_test_)(.+)(...)/, '$1***$3')}`); const clerkClient = createClerkClient({ secretKey: entry!.secretKey, apiUrl: entry?.apiUrl }); - const { data: users, errors } = await clerkClient.users.getUserList({ + const users = await clerkClient.users.getUserList({ orderBy: '-created_at', query: 'clerkcookie', limit: 100, }); - if (errors) { - console.log(errors); - return; - } - const batches = batchElements(skipUsersThatWereCreatedToday(users), 5); for (const batch of batches) { console.log(`Starting batch...`); diff --git a/integration/testUtils/usersService.ts b/integration/testUtils/usersService.ts index 7b41a3f9cc5..e764ad391fe 100644 --- a/integration/testUtils/usersService.ts +++ b/integration/testUtils/usersService.ts @@ -39,7 +39,7 @@ export const createUserService = (clerkClient: ReturnType) => { }, createFakeOrganization: async (userId: string) => { const name = faker.animal.dog(); - const { data: organization } = await clerkClient.organizations.createOrganization({ + const organization = await clerkClient.organizations.createOrganization({ name: faker.animal.dog(), createdBy: userId, }); diff --git a/integration/tests/protect.test.ts b/integration/tests/protect.test.ts index 88f422a890d..94b81cc0c83 100644 --- a/integration/tests/protect.test.ts +++ b/integration/tests/protect.test.ts @@ -15,11 +15,10 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withCustomRoles] })('authoriz test.beforeAll(async () => { const m = createTestUtils({ app }); fakeAdmin = m.services.users.createFakeUser(); - const { data: admin } = await m.services.users.createBapiUser(fakeAdmin); + const admin = await m.services.users.createBapiUser(fakeAdmin); fakeOrganization = await m.services.users.createFakeOrganization(admin.id); fakeViewer = m.services.users.createFakeUser(); - const { data: viewer } = await m.services.users.createBapiUser(fakeViewer); - + const viewer = await m.services.users.createBapiUser(fakeViewer); await m.services.clerk.organizations.createOrganizationMembership({ organizationId: fakeOrganization.organization.id, role: 'org:viewer' as OrganizationMembershipRole, diff --git a/packages/backend/src/api/__tests__/factory.test.ts b/packages/backend/src/api/__tests__/factory.test.ts index 227cea88909..e6c3f531ff6 100644 --- a/packages/backend/src/api/__tests__/factory.test.ts +++ b/packages/backend/src/api/__tests__/factory.test.ts @@ -4,14 +4,7 @@ import sinon from 'sinon'; // @ts-ignore import userJson from '../../fixtures/user.json'; import runtime from '../../runtime'; -import { - assertErrorResponse, - assertResponse, - jsonError, - jsonNotOk, - jsonOk, - jsonPaginatedOk, -} from '../../util/testUtils'; +import { jsonError, jsonNotOk, jsonOk, jsonPaginatedOk } from '../../util/testUtils'; import { createBackendApiClient } from '../factory'; export default (QUnit: QUnit) => { @@ -35,16 +28,12 @@ export default (QUnit: QUnit) => { const response = await apiClient.users.getUser('user_deadbeef'); - assertResponse(assert, response); - const { data: payload, totalCount } = response; - - assert.equal(payload.firstName, 'John'); - assert.equal(payload.lastName, 'Doe'); - assert.equal(payload.emailAddresses[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload.phoneNumbers[0].phoneNumber, '+311-555-2368'); - assert.equal(payload.externalAccounts[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload.publicMetadata.zodiac_sign, 'leo'); - assert.equal(totalCount, undefined); + assert.equal(response.firstName, 'John'); + assert.equal(response.lastName, 'Doe'); + assert.equal(response.emailAddresses[0].emailAddress, 'john.doe@clerk.test'); + assert.equal(response.phoneNumbers[0].phoneNumber, '+311-555-2368'); + assert.equal(response.externalAccounts[0].emailAddress, 'john.doe@clerk.test'); + assert.equal(response.publicMetadata.zodiac_sign, 'leo'); assert.ok( fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { @@ -63,16 +52,13 @@ export default (QUnit: QUnit) => { fakeFetch.onCall(0).returns(jsonOk([userJson])); const response = await apiClient.users.getUserList({ offset: 2, limit: 5 }); - assertResponse(assert, response); - const { data: payload, totalCount } = response; - assert.equal(payload[0].firstName, 'John'); - assert.equal(payload[0].lastName, 'Doe'); - assert.equal(payload[0].emailAddresses[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload[0].phoneNumbers[0].phoneNumber, '+311-555-2368'); - assert.equal(payload[0].externalAccounts[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload[0].publicMetadata.zodiac_sign, 'leo'); - assert.equal(totalCount, 1); + assert.equal(response[0].firstName, 'John'); + assert.equal(response[0].lastName, 'Doe'); + assert.equal(response[0].emailAddresses[0].emailAddress, 'john.doe@clerk.test'); + assert.equal(response[0].phoneNumbers[0].phoneNumber, '+311-555-2368'); + assert.equal(response[0].externalAccounts[0].emailAddress, 'john.doe@clerk.test'); + assert.equal(response[0].publicMetadata.zodiac_sign, 'leo'); assert.ok( fakeFetch.calledOnceWith('https://api.clerk.test/v1/users?offset=2&limit=5', { @@ -88,32 +74,18 @@ export default (QUnit: QUnit) => { test('executes a successful backend API request for a paginated response', async assert => { fakeFetch = sinon.stub(runtime, 'fetch'); - fakeFetch.onCall(0).returns(jsonPaginatedOk([userJson], 3)); + fakeFetch.onCall(0).returns(jsonPaginatedOk([{ id: '1' }], 3)); - const response = await apiClient.users.getUserList({ offset: 2, limit: 5 }); - assertResponse(assert, response); - const { data: payload, totalCount } = response; - - assert.equal(payload[0].firstName, 'John'); - assert.equal(payload[0].lastName, 'Doe'); - assert.equal(payload[0].emailAddresses[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload[0].phoneNumbers[0].phoneNumber, '+311-555-2368'); - assert.equal(payload[0].externalAccounts[0].emailAddress, 'john.doe@clerk.test'); - assert.equal(payload[0].publicMetadata.zodiac_sign, 'leo'); + const { data: response, totalCount } = await apiClient.users.getOrganizationMembershipList({ + offset: 2, + limit: 5, + userId: 'user_123', + }); + + assert.equal(response[0].id, '1'); // payload.length is different from response total_count to check that totalCount use the total_count from response - assert.equal(payload.length, 1); assert.equal(totalCount, 3); - - assert.ok( - fakeFetch.calledOnceWith('https://api.clerk.test/v1/users?offset=2&limit=5', { - method: 'GET', - headers: { - Authorization: 'Bearer deadbeef', - 'Content-Type': 'application/json', - 'User-Agent': '@clerk/backend@0.0.0-test', - }, - }), - ); + assert.equal(response.length, 1); }); test('executes a successful backend API request to create a new resource', async assert => { @@ -127,10 +99,8 @@ export default (QUnit: QUnit) => { star_sign: 'Leon', }, }); - assertResponse(assert, response); - const { data: payload } = response; - assert.equal(payload.firstName, 'John'); + assert.equal(response.firstName, 'John'); assert.ok( fakeFetch.calledOnceWith('https://api.clerk.test/v1/users', { @@ -162,16 +132,14 @@ export default (QUnit: QUnit) => { fakeFetch = sinon.stub(runtime, 'fetch'); fakeFetch.onCall(0).returns(jsonNotOk({ errors: [mockErrorPayload], clerk_trace_id: traceId })); - const response = await apiClient.users.getUser('user_deadbeef'); - assertErrorResponse(assert, response); + const errResponse = await apiClient.users.getUser('user_deadbeef').catch(err => err); - assert.equal(response.clerkTraceId, traceId); - assert.equal(response.status, 422); - assert.equal(response.statusText, '422'); - assert.equal(response.errors[0].code, 'whatever_error'); - assert.equal(response.errors[0].message, 'whatever error'); - assert.equal(response.errors[0].longMessage, 'some long message'); - assert.equal(response.errors[0].meta.paramName, 'some param'); + assert.equal(errResponse.clerkTraceId, traceId); + assert.equal(errResponse.status, 422); + assert.equal(errResponse.errors[0].code, 'whatever_error'); + assert.equal(errResponse.errors[0].message, 'whatever error'); + assert.equal(errResponse.errors[0].longMessage, 'some long message'); + assert.equal(errResponse.errors[0].meta.paramName, 'some param'); assert.ok( fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { @@ -189,12 +157,10 @@ export default (QUnit: QUnit) => { fakeFetch = sinon.stub(runtime, 'fetch'); fakeFetch.onCall(0).returns(jsonError({ errors: [] })); - const response = await apiClient.users.getUser('user_deadbeef'); - assertErrorResponse(assert, response); + const errResponse = await apiClient.users.getUser('user_deadbeef').catch(err => err); - assert.equal(response.status, 500); - assert.equal(response.statusText, '500'); - assert.equal(response.clerkTraceId, 'mock_cf_ray'); + assert.equal(errResponse.status, 500); + assert.equal(errResponse.clerkTraceId, 'mock_cf_ray'); assert.ok( fakeFetch.calledOnceWith('https://api.clerk.test/v1/users/user_deadbeef', { diff --git a/packages/backend/src/api/endpoints/OrganizationApi.ts b/packages/backend/src/api/endpoints/OrganizationApi.ts index b26592ccb62..f549a4ef441 100644 --- a/packages/backend/src/api/endpoints/OrganizationApi.ts +++ b/packages/backend/src/api/endpoints/OrganizationApi.ts @@ -8,6 +8,7 @@ import type { OrganizationInvitationStatus, OrganizationMembership, } from '../resources'; +import type { PaginatedResourceResponse } from '../resources/Deserializer'; import type { OrganizationMembershipRole } from '../resources/Enums'; import { AbstractAPI } from './AbstractApi'; @@ -95,7 +96,7 @@ type RevokeOrganizationInvitationParams = { export class OrganizationAPI extends AbstractAPI { public async getOrganizationList(params?: GetOrganizationListParams) { - return this.request({ + return this.request>({ method: 'GET', path: basePath, queryParams: params, @@ -234,7 +235,7 @@ export class OrganizationAPI extends AbstractAPI { const { organizationId, status, limit, offset } = params; this.requireId(organizationId); - return this.request({ + return this.request>({ method: 'GET', path: joinPaths(basePath, organizationId, 'invitations'), queryParams: { status, limit, offset }, diff --git a/packages/backend/src/api/endpoints/UserApi.ts b/packages/backend/src/api/endpoints/UserApi.ts index cd0e8ff450e..b798298da13 100644 --- a/packages/backend/src/api/endpoints/UserApi.ts +++ b/packages/backend/src/api/endpoints/UserApi.ts @@ -3,6 +3,7 @@ import type { ClerkPaginationRequest, OAuthProvider } from '@clerk/types'; import runtime from '../../runtime'; import { joinPaths } from '../../util/path'; import type { OauthAccessToken, OrganizationMembership, User } from '../resources'; +import type { PaginatedResourceResponse } from '../resources/Deserializer'; import { AbstractAPI } from './AbstractApi'; const basePath = '/users'; @@ -199,7 +200,7 @@ export class UserAPI extends AbstractAPI { const { userId, limit, offset } = params; this.requireId(userId); - return this.request({ + return this.request>({ method: 'GET', path: joinPaths(basePath, userId, 'organization_memberships'), queryParams: { limit, offset }, diff --git a/packages/backend/src/api/request.ts b/packages/backend/src/api/request.ts index 38d6645b38c..fbff09bc419 100644 --- a/packages/backend/src/api/request.ts +++ b/packages/backend/src/api/request.ts @@ -1,4 +1,4 @@ -import { parseError } from '@clerk/shared/error'; +import { ClerkAPIResponseError, parseError } from '@clerk/shared/error'; import type { ClerkAPIError, ClerkAPIErrorJSON } from '@clerk/types'; import snakecaseKeys from 'snakecase-keys'; @@ -55,7 +55,7 @@ type BuildRequestOptions = { userAgent?: string; }; export function buildRequest(options: BuildRequestOptions) { - return async (requestOptions: ClerkBackendApiRequestOptions): Promise> => { + const requestFn = async (requestOptions: ClerkBackendApiRequestOptions): Promise> => { const { secretKey, apiUrl = API_URL, apiVersion = API_VERSION, userAgent = USER_AGENT } = options; const { path, method, queryParams, headerParams, bodyParams, formData } = requestOptions; @@ -149,6 +149,8 @@ export function buildRequest(options: BuildRequestOptions) { }; } }; + + return withLegacyRequestReturn(requestFn); } // Returns either clerk_trace_id if present in response json, otherwise defaults to CF-Ray header @@ -169,3 +171,31 @@ function parseErrors(data: unknown): ClerkAPIError[] { } return []; } + +type LegacyRequestFunction = (requestOptions: ClerkBackendApiRequestOptions) => Promise; + +// TODO(dimkl): Will be probably be dropped in next major version +function withLegacyRequestReturn(cb: any): LegacyRequestFunction { + return async (...args) => { + // @ts-ignore + const { data, errors, totalCount, status, statusText, clerkTraceId } = await cb(...args); + if (errors) { + // instead of passing `data: errors`, we have set the `error.errors` because + // the errors returned from callback is already parsed and passing them as `data` + // will not be able to assign them to the instance + const error = new ClerkAPIResponseError(statusText || '', { + data: [], + status, + clerkTraceId, + }); + error.errors = errors; + throw error; + } + + if (typeof totalCount !== 'undefined') { + return { data, totalCount }; + } + + return data; + }; +} diff --git a/packages/backend/src/api/resources/Deserializer.ts b/packages/backend/src/api/resources/Deserializer.ts index 81a43c171ff..89dfd840058 100644 --- a/packages/backend/src/api/resources/Deserializer.ts +++ b/packages/backend/src/api/resources/Deserializer.ts @@ -24,19 +24,16 @@ type ResourceResponse = { data: T; }; -type PaginatedResponse = { - data: T; - totalCount?: number; +export type PaginatedResourceResponse = ResourceResponse & { + totalCount: number; }; -export function deserialize(payload: unknown): PaginatedResponse | ResourceResponse { +export function deserialize(payload: unknown): PaginatedResourceResponse | ResourceResponse { let data, totalCount: number | undefined; if (Array.isArray(payload)) { - data = payload.map(item => jsonToObject(item)) as U; - totalCount = payload.length; - - return { data, totalCount }; + const data = payload.map(item => jsonToObject(item)) as U; + return { data }; } else if (isPaginated(payload)) { data = payload.data.map(item => jsonToObject(item)) as U; totalCount = payload.total_count; diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index ea277052e8c..b8fe19fa87b 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -4,12 +4,15 @@ import type { SDKMetadata } from '@clerk/types'; import type { ApiClient, CreateBackendApiOptions } from './api'; import { createBackendApiClient } from './api'; +import { withLegacyReturn } from './jwt/legacyReturn'; import type { CreateAuthenticateRequestOptions } from './tokens/factory'; import { createAuthenticateRequest } from './tokens/factory'; +import { verifyToken as _verifyToken } from './tokens/verify'; export type { Organization, Session, User, WebhookEvent, WebhookEventType } from './api/resources'; export type { VerifyTokenOptions } from './tokens/verify'; -export { verifyToken } from './tokens/verify'; + +export const verifyToken = withLegacyReturn(_verifyToken); export type ClerkOptions = CreateBackendApiOptions & Partial< diff --git a/packages/backend/src/jwt/index.ts b/packages/backend/src/jwt/index.ts index a3cc2c5d109..4875a9689eb 100644 --- a/packages/backend/src/jwt/index.ts +++ b/packages/backend/src/jwt/index.ts @@ -1,5 +1,15 @@ -export { hasValidSignature, decodeJwt, verifyJwt } from './verifyJwt'; -export { signJwt } from './signJwt'; +import { withLegacyReturn, withLegacySyncReturn } from './legacyReturn'; +import { signJwt as _signJwt } from './signJwt'; +import { decodeJwt as _decodeJwt, hasValidSignature as _hasValidSignature, verifyJwt as _verifyJwt } from './verifyJwt'; export type { VerifyJwtOptions } from './verifyJwt'; export type { SignJwtOptions } from './signJwt'; + +// Introduce compatibility layer to avoid more breaking changes +// TODO(dimkl): This (probably be drop in the next major version) + +export const verifyJwt = withLegacyReturn(_verifyJwt); +export const decodeJwt = withLegacySyncReturn(_decodeJwt); + +export const signJwt = withLegacyReturn(_signJwt); +export const hasValidSignature = withLegacyReturn(_hasValidSignature); diff --git a/packages/backend/src/jwt/legacyReturn.ts b/packages/backend/src/jwt/legacyReturn.ts new file mode 100644 index 00000000000..8437afe828e --- /dev/null +++ b/packages/backend/src/jwt/legacyReturn.ts @@ -0,0 +1,23 @@ +import type { JwtReturnType } from './types'; + +// TODO(dimkl): Will be probably be dropped in next major version +export function withLegacyReturn Promise>>(cb: T) { + return async (...args: Parameters): Promise>['data']>> | never => { + const { data, errors } = await cb(...args); + if (errors) { + throw errors[0]; + } + return data; + }; +} + +// TODO(dimkl): Will be probably be dropped in next major version +export function withLegacySyncReturn JwtReturnType>(cb: T) { + return (...args: Parameters): NonNullable>['data']> | never => { + const { data, errors } = cb(...args); + if (errors) { + throw errors[0]; + } + return data; + }; +} diff --git a/packages/backend/src/jwt/signJwt.ts b/packages/backend/src/jwt/signJwt.ts index e8f42f949df..82177cb4879 100644 --- a/packages/backend/src/jwt/signJwt.ts +++ b/packages/backend/src/jwt/signJwt.ts @@ -42,7 +42,9 @@ export async function signJwt( const algorithm = getCryptoAlgorithm(options.algorithm); if (!algorithm) { - throw new Error(`Unsupported algorithm ${options.algorithm}`); + return { + errors: [new SignJWTError(`Unsupported algorithm ${options.algorithm}`)], + }; } const cryptoKey = await importKey(key, algorithm, 'sign'); diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index 0bb63f966ac..44d0dabd7aa 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -1,4 +1,3 @@ -import { ClerkAPIResponseError } from '@clerk/shared/error'; import type { ActClaim, CheckAuthorizationWithCustomPermissions, @@ -11,7 +10,6 @@ import type { import type { CreateBackendApiOptions } from '../api'; import { createBackendApiClient } from '../api'; -import type { ClerkBackendApiResponse } from '../api/request'; import type { AuthenticateContext } from './authenticateContext'; type AuthObjectDebugData = Record; @@ -72,27 +70,6 @@ const createDebug = (data: AuthObjectDebugData | undefined) => { }; }; -// This helper is introduced as compat layer between the v4 and v5 implementations to keep the -// exposed top-level getToken API the same since it's critical and there are already a lot of -// breaking changes. -// TODO: Revamp AuthObject `getToken()` to return { data, errors } in next major version -const throwResponseErrors = (response: ClerkBackendApiResponse): never => { - // used to by-pass type-safety for the `{ status, statusText, clerkTraceId } = response` line below - if (!response.errors) { - throw new Error('no error to throw'); - } - - const { status, statusText, clerkTraceId } = response; - const error = new ClerkAPIResponseError(statusText || '', { - data: [], - status: Number(status || ''), - clerkTraceId, - }); - error.errors = response.errors; - - throw error; -}; - /** * @internal */ @@ -113,14 +90,7 @@ export function signedInAuthObject( const getToken = createGetToken({ sessionId, sessionToken: authenticateContext.sessionToken || '', - fetcher: async (...args) => { - const response = await apiClient.sessions.getToken(...args); - if (response.errors) { - return throwResponseErrors(response); - } - - return response.data.jwt; - }, + fetcher: async (...args) => (await apiClient.sessions.getToken(...args)).jwt, }); return { diff --git a/packages/backend/src/tokens/handshake.ts b/packages/backend/src/tokens/handshake.ts index ca0259e1528..dfdbbec20b6 100644 --- a/packages/backend/src/tokens/handshake.ts +++ b/packages/backend/src/tokens/handshake.ts @@ -1,7 +1,7 @@ import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; import type { VerifyJwtOptions } from '../jwt'; -import { decodeJwt, hasValidSignature } from '../jwt'; import { assertHeaderAlgorithm, assertHeaderType } from '../jwt/assertions'; +import { decodeJwt, hasValidSignature } from '../jwt/verifyJwt'; import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys'; import type { VerifyTokenOptions } from './verify'; diff --git a/packages/backend/src/tokens/request.ts b/packages/backend/src/tokens/request.ts index 1f6ed10ad7d..da94bd11c37 100644 --- a/packages/backend/src/tokens/request.ts +++ b/packages/backend/src/tokens/request.ts @@ -3,7 +3,7 @@ import { parsePublishableKey } from '@clerk/shared/keys'; import { constants } from '../constants'; import type { TokenCarrier } from '../errors'; import { TokenVerificationError, TokenVerificationErrorReason } from '../errors'; -import { decodeJwt } from '../jwt'; +import { decodeJwt } from '../jwt/verifyJwt'; import { assertValidSecretKey } from '../util/assertValidSecretKey'; import { isDevelopmentFromSecretKey } from '../util/shared'; import type { AuthenticateContext } from './authenticateContext'; diff --git a/packages/backend/src/tokens/verify.ts b/packages/backend/src/tokens/verify.ts index d79de1cccc9..523cee883be 100644 --- a/packages/backend/src/tokens/verify.ts +++ b/packages/backend/src/tokens/verify.ts @@ -2,8 +2,8 @@ import type { JwtPayload } from '@clerk/types'; import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors'; import type { VerifyJwtOptions } from '../jwt'; -import { decodeJwt, verifyJwt } from '../jwt'; import type { JwtReturnType } from '../jwt/types'; +import { decodeJwt, verifyJwt } from '../jwt/verifyJwt'; import type { LoadClerkJWKFromRemoteOptions } from './keys'; import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys'; diff --git a/packages/backend/src/util/decorateObjectWithResources.ts b/packages/backend/src/util/decorateObjectWithResources.ts index e2bc104af55..924c2e6e00d 100644 --- a/packages/backend/src/util/decorateObjectWithResources.ts +++ b/packages/backend/src/util/decorateObjectWithResources.ts @@ -33,10 +33,12 @@ export const decorateObjectWithResources = async ( loadOrganization && orgId ? organizations.getOrganization({ organizationId: orgId }) : Promise.resolve(undefined), ]); - const session = sessionResp && !sessionResp.errors ? sessionResp.data : undefined; - const user = userResp && !userResp.errors ? userResp.data : undefined; - const organization = organizationResp && !organizationResp.errors ? organizationResp.data : undefined; - return Object.assign(obj, stripPrivateDataFromObject({ session, user, organization })); + const resources = stripPrivateDataFromObject({ + session: sessionResp, + user: userResp, + organization: organizationResp, + }); + return Object.assign(obj, resources); }; /** diff --git a/packages/nextjs/src/app-router/server/currentUser.ts b/packages/nextjs/src/app-router/server/currentUser.ts index adcf72e2860..6ab56eb297c 100644 --- a/packages/nextjs/src/app-router/server/currentUser.ts +++ b/packages/nextjs/src/app-router/server/currentUser.ts @@ -7,8 +7,5 @@ export async function currentUser(): Promise { const { userId } = auth(); if (!userId) return null; - const { data, errors } = await clerkClient.users.getUser(userId); - if (errors) return null; - - return data; + return clerkClient.users.getUser(userId); } diff --git a/packages/nextjs/src/server/buildClerkProps.ts b/packages/nextjs/src/server/buildClerkProps.ts index 4c5d623cbc0..0248a461233 100644 --- a/packages/nextjs/src/server/buildClerkProps.ts +++ b/packages/nextjs/src/server/buildClerkProps.ts @@ -51,11 +51,7 @@ export const buildClerkProps: BuildClerkProps = (req, initState = {}) => { if (!authStatus || authStatus !== AuthStatus.SignedIn) { authObject = signedOutAuthObject(options); } else { - const { data: jwt, errors } = decodeJwt(authToken as string); - - if (errors) { - throw errors[0]; - } + const jwt = decodeJwt(authToken as string); // @ts-expect-error - TODO @nikos: Align types authObject = signedInAuthObject({ ...options, sessionToken: jwt.raw.text }, jwt.payload); diff --git a/packages/nextjs/src/server/createGetAuth.ts b/packages/nextjs/src/server/createGetAuth.ts index 553a63780e3..61756ea574c 100644 --- a/packages/nextjs/src/server/createGetAuth.ts +++ b/packages/nextjs/src/server/createGetAuth.ts @@ -46,10 +46,7 @@ export const createGetAuth = ({ logger.debug('Options debug', options); if (authStatus === AuthStatus.SignedIn) { - const { data: jwt, errors } = decodeJwt(authToken as string); - if (errors) { - throw errors[0]; - } + const jwt = decodeJwt(authToken as string); logger.debug('JWT debug', jwt.raw.text); // @ts-expect-error - TODO @nikos: Align types @@ -68,11 +65,5 @@ export const getAuth = createGetAuth({ export const parseJwt = (req: RequestLike) => { const cookieToken = getCookie(req, constants.Cookies.Session); const headerToken = getHeader(req, 'authorization')?.replace('Bearer ', ''); - const { data, errors } = decodeJwt(cookieToken || headerToken || ''); - - if (errors) { - throw errors[0]; - } - - return data; + return decodeJwt(cookieToken || headerToken || ''); }; diff --git a/packages/sdk-node/examples/express/src/runtime-keys-middleware.ts b/packages/sdk-node/examples/express/src/runtime-keys-middleware.ts index 11a442f7122..385eb861bf4 100644 --- a/packages/sdk-node/examples/express/src/runtime-keys-middleware.ts +++ b/packages/sdk-node/examples/express/src/runtime-keys-middleware.ts @@ -23,10 +23,12 @@ app.get('/', async (req: WithAuthProp, res: Response) => { console.log(debug()); if (!userId) return res.json({ auth: req.auth, user: null }); - const { data, errors } = await clerk.users.getUser(userId); - if (errors) return res.json({ auth: req.auth, user: null }); - - return res.json({ auth: req.auth, user: data });; + try{ + const user = await clerk.users.getUser(userId); + return res.json({ auth: req.auth, user }); + }catch(error){ + return res.json({ auth: req.auth, user: null }); + } }); // @ts-ignore diff --git a/packages/sdk-node/examples/node/src/organizations.ts b/packages/sdk-node/examples/node/src/organizations.ts index d225b83c3ca..a56a28eedec 100644 --- a/packages/sdk-node/examples/node/src/organizations.ts +++ b/packages/sdk-node/examples/node/src/organizations.ts @@ -1,29 +1,22 @@ import { organizations, users } from '@clerk/clerk-sdk-node'; console.log('Get user to create organization'); -const { data, errors } = await users.getUserList(); -if (errors) { - throw new Error(errors); -} - -const creator = data[0]; +const userList = await users.getUserList(); +const creator = userList[0]; console.log('Create organization'); -const { data: organization } = await organizations.createOrganization({ +const organization = await organizations.createOrganization({ name: 'test-organization', createdBy: creator.id, }); console.log(organization); console.log('Update organization metadata'); -const { data: updatedOrganizationMetadata, errors: uomErrors } = await organizations.updateOrganizationMetadata( +const updatedOrganizationMetadata = await organizations.updateOrganizationMetadata( organization.id, { publicMetadata: { test: 1 }, }, ); -if (uomErrors) { - throw new Error(uomErrors); -} console.log(updatedOrganizationMetadata); diff --git a/packages/sdk-node/examples/node/src/sessions.ts b/packages/sdk-node/examples/node/src/sessions.ts index 1b4c3e56fcd..dea3d5a4c0c 100644 --- a/packages/sdk-node/examples/node/src/sessions.ts +++ b/packages/sdk-node/examples/node/src/sessions.ts @@ -9,25 +9,25 @@ const sessionIdtoRevoke = process.env.SESSION_ID_TO_REVOKE || ''; const sessionToken = process.env.SESSION_TOKEN || ''; console.log('Get session list'); -const { data: sessionList } = await sessions.getSessionList(); +const sessionList = await sessions.getSessionList(); console.log(sessionList); console.log('Get session list filtered by userId'); -const { data: filteredSessions1 } = await sessions.getSessionList({ userId }); +const filteredSessions1 = await sessions.getSessionList({ userId }); console.log(filteredSessions1); console.log('Get session list filtered by clientId'); -const { data: filteredSessions2 } = await sessions.getSessionList({ clientId }); +const filteredSessions2 = await sessions.getSessionList({ clientId }); console.log(filteredSessions2); console.log('Get single session'); -const { data: session } = await sessions.getSession(sessionId); +const session = await sessions.getSession(sessionId); console.log(session); console.log('Revoke session'); -const { data: revokedSession } = await sessions.revokeSession(sessionIdtoRevoke); +const revokedSession = await sessions.revokeSession(sessionIdtoRevoke); console.log(revokedSession); console.log('Verify session'); -const { data: verifiedSession } = await sessions.verifySession(sessionId, sessionToken); +const verifiedSession = await sessions.verifySession(sessionId, sessionToken); console.log(verifiedSession); diff --git a/packages/sdk-node/examples/node/src/users.ts b/packages/sdk-node/examples/node/src/users.ts index 9ee3a2f0f15..72264f64529 100644 --- a/packages/sdk-node/examples/node/src/users.ts +++ b/packages/sdk-node/examples/node/src/users.ts @@ -3,7 +3,7 @@ import { users } from '@clerk/clerk-sdk-node'; console.log('Create user'); -const { data: createdUser, errors: createUserErrors } = await users.createUser({ +const createdUser = await users.createUser({ emailAddress: ['test@example.com'], phoneNumber: ['+15555555555'], externalId: 'a-unique-id', @@ -21,31 +21,22 @@ const { data: createdUser, errors: createUserErrors } = await users.createUser({ }, password: '123456+ABCd', }); -if (createUserErrors) { - throw new Error(createUserErrors); -} console.log(createdUser); const createdUserId = createdUser.id as string; console.log('Get single user'); -const { data: user, errors: userErrors } = await users.getUser(createdUserId); -if (userErrors) { - throw new Error(userErrors); -} +const user = await users.getUser(createdUserId); console.log(user); await users.deleteUser(createdUserId); console.log('Get user list'); -const { data: userList, errors: userListErrors } = await users.getUserList(); -if (userListErrors) { - throw new Error(userListErrors); -} +const userList = await users.getUserList(); console.log(userList); console.log('Update user'); -const { user: updatedUser, errors: updateUserErrors } = await users.updateUser(createdUserId, { +const updatedUser = await users.updateUser(createdUserId, { firstName: 'Kyle', lastName: 'Reese', publicMetadata: { @@ -53,14 +44,9 @@ const { user: updatedUser, errors: updateUserErrors } = await users.updateUser(c ascendant: 'scorpio', }, }); -if (updateUserErrors) { - throw new Error(updateUserErrors); -} console.log(updatedUser); console.log('Get total count of users'); -const { data: count, errors: countErrors } = await users.getCount(); -if (countErrors) { - throw new Error(countErrors); -} +const count = await users.getCount(); + console.log(count);