Skip to content

Commit

Permalink
chore(*): Improve @clerk/backend DX [Part 1 - Refactoring] (#2360)
Browse files Browse the repository at this point in the history
* chore(backend): Sort imports in edge-runtime runner

* chore(backend): Move tests & convert runtime folder to module

* chore(backend): Merge test utils to util/testUtils.ts module

* fix(backend): Improve node esm support

* chore(repo): Add changeset
  • Loading branch information
dimkl committed Dec 15, 2023
1 parent 2a67f72 commit d08ec6d
Show file tree
Hide file tree
Showing 28 changed files with 111 additions and 84 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-numbers-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/backend': minor
---

Improve ESM support in `@clerk/backend` for Node by using .mjs for #crypto subpath import
5 changes: 4 additions & 1 deletion packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
"edge-light": "./dist/runtime/browser/crypto.mjs",
"worker": "./dist/runtime/browser/crypto.mjs",
"browser": "./dist/runtime/browser/crypto.mjs",
"node": "./dist/runtime/node/crypto.js",
"node": {
"require": "./dist/runtime/node/crypto.js",
"import": "./dist/runtime/node/crypto.mjs"
},
"default": "./dist/runtime/browser/crypto.mjs"
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type QUnit from 'qunit';

import * as publicExports from './index';
import * as publicExports from '../index';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type QUnit from 'qunit';
import sinon from 'sinon';

import { redirect } from './redirections';
import { redirect } from '../redirections';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type QUnit from 'qunit';

import { buildOrigin, buildRequestUrl } from './utils';
import { buildOrigin, buildRequestUrl } from '../utils';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import type QUnit from 'qunit';
import sinon from 'sinon';

import emailJson from '../fixtures/responses/email.json';
import userJson from '../fixtures/responses/user.json';
import runtime from '../runtime';
import { assertErrorResponse, assertResponse } from '../util/assertResponse';
import { jsonError, jsonNotOk, jsonOk, jsonPaginatedOk } from '../util/mockFetch';
import { createBackendApiClient } from './factory';
// @ts-ignore
import emailJson from '../../fixtures/email.json';
// @ts-ignore
import userJson from '../../fixtures/user.json';
import runtime from '../../runtime';
import {
assertErrorResponse,
assertResponse,
jsonError,
jsonNotOk,
jsonOk,
jsonPaginatedOk,
} from '../../util/testUtils';
import { createBackendApiClient } from '../factory';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/backend/src/runtime/node/crypto.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { webcrypto } from 'node:crypto';
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type QUnit from 'qunit';

import { makeAuthObjectSerializable, signedOutAuthObject } from './authObjects';
import { makeAuthObjectSerializable, signedOutAuthObject } from '../authObjects';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type QUnit from 'qunit';

import type { ApiClient } from '../api';
import { createAuthenticateRequest } from './factory';
import type { ApiClient } from '../../api';
import { createAuthenticateRequest } from '../factory';

const TEST_PK = 'pk_test_Y2xlcmsuaW5jbHVkZWQua2F0eWRpZC05Mi5sY2wuZGV2JA';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import type QUnit from 'qunit';
import sinon from 'sinon';

import runtime from '../runtime';
import { jsonError, jsonOk } from '../util/mockFetch';
import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from './errors';
import { mockJwks, mockJwtPayload, mockPEMJwk, mockPEMJwtKey, mockPEMKey, mockRsaJwk, mockRsaJwkKid } from './fixtures';
import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from './keys';
import runtime from '../../runtime';
import { jsonError, jsonOk } from '../../util/testUtils';
import { TokenVerificationError, TokenVerificationErrorAction, TokenVerificationErrorReason } from '../errors';
import {
mockJwks,
mockJwtPayload,
mockPEMJwk,
mockPEMJwtKey,
mockPEMKey,
mockRsaJwk,
mockRsaJwkKid,
} from '../fixtures';
import { loadClerkJWKFromLocal, loadClerkJWKFromRemote } from '../keys';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type QUnit from 'qunit';
import sinon from 'sinon';

import runtime from '../runtime';
import { jsonOk } from '../util/mockFetch';
import { AuthErrorReason, type AuthReason, AuthStatus, type RequestState } from './authStatus';
import { TokenVerificationErrorReason } from './errors';
import { mockInvalidSignatureJwt, mockJwks, mockJwt, mockJwtPayload, mockMalformedJwt } from './fixtures';
import type { AuthenticateRequestOptions } from './request';
import { authenticateRequest, loadOptionsFromHeaders } from './request';
import runtime from '../../runtime';
import { jsonOk } from '../../util/testUtils';
import { AuthErrorReason, type AuthReason, AuthStatus, type RequestState } from '../authStatus';
import { TokenVerificationErrorReason } from '../errors';
import { mockInvalidSignatureJwt, mockJwks, mockJwt, mockJwtPayload, mockMalformedJwt } from '../fixtures';
import type { AuthenticateRequestOptions } from '../request';
import { authenticateRequest, loadOptionsFromHeaders } from '../request';

function assertSignedOut(
assert,
Expand Down Expand Up @@ -181,12 +181,8 @@ export default (QUnit: QUnit) => {

test('returns signed out state if jwk fails to load from remote', async assert => {
fakeFetch.onCall(0).returns(jsonOk({}));
const requestState = await authenticateRequest(
mockRequestWithHeaderAuth(),
mockOptions({
skipJwksCache: false,
}),
);

const requestState = await authenticateRequest(mockRequestWithHeaderAuth(), mockOptions());

const errMessage =
'The JWKS endpoint did not contain any signing keys. Contact support@clerk.com. Contact support@clerk.com (reason=jwk-remote-failed-to-load, token-carrier=header)';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type QUnit from 'qunit';
import sinon from 'sinon';

import runtime from '../runtime';
import { jsonOk } from '../util/mockFetch';
import { mockJwks, mockJwt, mockJwtPayload } from './fixtures';
import { verifyToken } from './verify';
import runtime from '../../runtime';
import { jsonOk } from '../../util/testUtils';
import { mockJwks, mockJwt, mockJwtPayload } from '../fixtures';
import { verifyToken } from '../verify';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
assertHeaderType,
assertIssuedAtClaim,
assertSubClaim,
} from './assertions';
} from '../assertions';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type QUnit from 'qunit';

import { pemEncodedPublicKey, pemEncodedSignKey, publicJwks, signingJwks } from '../fixtures';
import { importKey } from './cryptoKeys';
import { pemEncodedPublicKey, pemEncodedSignKey, publicJwks, signingJwks } from '../../fixtures';
import { importKey } from '../cryptoKeys';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
pemEncodedSignKey,
publicJwks,
signingJwks,
} from '../fixtures';
import { signJwt } from './signJwt';
import { verifyJwt } from './verifyJwt';
} from '../../fixtures';
import { signJwt } from '../signJwt';
import { verifyJwt } from '../verifyJwt';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
publicJwks,
signedJwt,
someOtherPublicKey,
} from '../fixtures';
import { decodeJwt, hasValidSignature, verifyJwt } from './verifyJwt';
} from '../../fixtures';
import { decodeJwt, hasValidSignature, verifyJwt } from '../verifyJwt';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
5 changes: 4 additions & 1 deletion packages/backend/src/tokens/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ export async function loadClerkJWKFromRemote({

if (!jwk) {
const cacheValues = getCacheValues();
const jwkKeys = cacheValues.map(jwk => jwk.kid).join(', ');
const jwkKeys = cacheValues
.map(jwk => jwk.kid)
.sort()
.join(', ');

throw new TokenVerificationError({
action: TokenVerificationErrorAction.ContactSupport,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type QUnit from 'qunit';

import { joinPaths } from './path';
import { joinPaths } from '../path';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type QUnit from 'qunit';

import { checkCrossOrigin } from './request';
import { checkCrossOrigin } from '../request';

export default (QUnit: QUnit) => {
const { module, test } = QUnit;
Expand Down
9 changes: 0 additions & 9 deletions packages/backend/src/util/assertResponse.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { constants } from '../constants';

type ApiResponse<T> = { data: T | null; errors: null | any[] };
type SuccessApiResponse<T> = { data: T; errors: null };
type ErrorApiResponse = { data: null; errors: any[]; clerkTraceId: string; status: number; statusText: string };
export function assertResponse<T>(assert: Assert, resp: ApiResponse<T>): asserts resp is SuccessApiResponse<T> {
assert.equal(resp.errors, null);
}
export function assertErrorResponse<T>(assert: Assert, resp: ApiResponse<T>): asserts resp is ErrorApiResponse {
assert.notEqual(resp.errors, null);
}

export function jsonOk(body: unknown, status = 200) {
// Mock response object that satisfies the window.Response interface
const mockResponse = {
Expand Down
7 changes: 4 additions & 3 deletions packages/backend/tests/edge-runtime/run.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { EdgeRuntime } from 'edge-runtime';
import { exit } from 'node:process';
import fs from 'node:fs';
import * as url from 'url';
import { exit } from 'node:process';

import { EdgeRuntime } from 'edge-runtime';
import * as path from 'path';
import * as url from 'url';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

Expand Down
47 changes: 24 additions & 23 deletions packages/backend/tests/suites.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
// Import all suites
// TODO: Automate this step using dynamic imports
import factoryTest from './dist/api/factory.test.js';
import exportsTest from './dist/exports.test.js';
import redirectTest from './dist/redirections.test.js';
import authObjectsTest from './dist/tokens/authObjects.test.js';
import tokenFactoryTest from './dist/tokens/factory.test.js';
import jwtAssertionsTest from './dist/tokens/jwt/assertions.test.js';
import cryptoKeysTest from './dist/tokens/jwt/cryptoKeys.test.js';
import signJwtTest from './dist/tokens/jwt/signJwt.test.js';
import verifyJwtTest from './dist/tokens/jwt/verifyJwt.test.js';
import keysTest from './dist/tokens/keys.test.js';
import requestTest from './dist/tokens/request.test.js';
import verifyTest from './dist/tokens/verify.test.js';
import pathTest from './dist/util/path.test.js';
import utilRequestTest from './dist/util/request.test.js';
import utilsTest from './dist/utils.test.js';

import authObjectsTest from './dist/tokens/__tests__/authObjects.test.js';
import cryptoKeysTest from './dist/tokens/jwt/__tests__/cryptoKeys.test.js';
import exportsTest from './dist/__tests__/exports.test.js';
import factoryTest from './dist/api/__tests__/factory.test.js';
import jwtAssertionsTest from './dist/tokens/jwt/__tests__/assertions.test.js';
import keysTest from './dist/tokens/__tests__/keys.test.js';
import pathTest from './dist/util/__tests__/path.test.js';
import redirectTest from './dist/__tests__/redirections.test.js';
import requestTest from './dist/tokens/__tests__/request.test.js';
import signJwtTest from './dist/tokens/jwt/__tests__/signJwt.test.js';
import tokenFactoryTest from './dist/tokens/__tests__/factory.test.js';
import utilRequestTest from './dist/util/__tests__/request.test.js';
import utilsTest from './dist/__tests__/utils.test.js';
import verifyJwtTest from './dist/tokens/jwt/__tests__/verifyJwt.test.js';
import verifyTest from './dist/tokens/__tests__/verify.test.js';

// Add them to the suite array
const suites = [
authObjectsTest,
cryptoKeysTest,
exportsTest,
factoryTest,
jwtAssertionsTest,
requestTest,
utilRequestTest,
keysTest,
verifyTest,
pathTest,
verifyJwtTest,
signJwtTest,
cryptoKeysTest,
factoryTest,
redirectTest,
utilsTest,
requestTest,
signJwtTest,
tokenFactoryTest,
utilRequestTest,
utilsTest,
verifyJwtTest,
verifyTest,
];

export default suites;
2 changes: 1 addition & 1 deletion packages/backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
"isolatedModules": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "/src/runtime/*", "src/**/*.spec.ts", "src/**/*.test.ts", "src/tests"]
"exclude": ["node_modules", "dist", "/src/runtime/*", "src/**/__tests__/*.test.ts", "src/tests"]
}
4 changes: 2 additions & 2 deletions packages/backend/tsconfig.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"@clerk/shared/*": ["../shared/dist/*.js"]
}
},
"include": ["src/**/*.test.ts"],
"exclude": ["node_modules", "dist", "src/__tests__"]
"include": ["src/**/__tests__"],
"exclude": ["node_modules", "dist"]
}

0 comments on commit d08ec6d

Please sign in to comment.