From b8aa2f469fa444bab88d0113bd757bbddb40f4d6 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 27 May 2026 12:34:44 -0500 Subject: [PATCH 1/4] test(repo): exercise snapi breaking-change detector (DO NOT MERGE) --- .changeset/test-snapi-detection-do-not-merge.md | 2 ++ packages/backend/src/webhooks.ts | 4 ++++ packages/shared/src/file.ts | 10 +++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 .changeset/test-snapi-detection-do-not-merge.md diff --git a/.changeset/test-snapi-detection-do-not-merge.md b/.changeset/test-snapi-detection-do-not-merge.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/test-snapi-detection-do-not-merge.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/backend/src/webhooks.ts b/packages/backend/src/webhooks.ts index 0cebb68e345..05bcc9f4c75 100644 --- a/packages/backend/src/webhooks.ts +++ b/packages/backend/src/webhooks.ts @@ -12,6 +12,10 @@ export type VerifyWebhookOptions = { * The signing secret for the webhook. It's recommended to use the [`CLERK_WEBHOOK_SIGNING_SECRET` environment variable](https://clerk.com/docs/guides/development/clerk-environment-variables#webhooks) instead. */ signingSecret?: string; + /** + * Optional tolerance, in seconds, for accepting webhooks whose timestamp falls outside the default replay window. + */ + timestampToleranceSeconds?: number; }; // Standard Webhooks header names diff --git a/packages/shared/src/file.ts b/packages/shared/src/file.ts index 88c4f85c3d5..302f2adc249 100644 --- a/packages/shared/src/file.ts +++ b/packages/shared/src/file.ts @@ -3,8 +3,10 @@ * * Probably paired with: * + * + * Renamed from `readJSONFile` to align naming with the rest of the parse-* helpers. */ -export function readJSONFile(file: File): Promise { +export function parseJSONFile(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.addEventListener('load', function () { @@ -28,6 +30,8 @@ const MimeTypeToExtensionMap = Object.freeze({ export type SupportedMimeType = keyof typeof MimeTypeToExtensionMap; -export const extension = (mimeType: SupportedMimeType): string => { - return MimeTypeToExtensionMap[mimeType]; +export type MimeTypeExtension = (typeof MimeTypeToExtensionMap)[SupportedMimeType]; + +export const extension = (mimeType: SupportedMimeType, fallback?: string): string => { + return MimeTypeToExtensionMap[mimeType] ?? fallback ?? ''; }; From c8cb9bd5a84d1ecf042221d937969576850f5ea1 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 27 May 2026 12:58:19 -0500 Subject: [PATCH 2/4] test(repo): add detectable breaking + additive change on @clerk/backend/jwt Adds two more snapi-visible changes on an explicit (non-wildcard) subpath: - BREAKING: drop hasValidSignature from the @clerk/backend/jwt barrel - ADDITIVE: export a new JwtAlgorithm type from the same barrel The existing changes to @clerk/shared/file land under the './*' wildcard export, which the current snapi build skips, so this PR otherwise wouldn't surface anything breaking once the snapi pin is bumped. --- packages/backend/src/__tests__/exports.test.ts | 1 - packages/backend/src/jwt/index.ts | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/__tests__/exports.test.ts b/packages/backend/src/__tests__/exports.test.ts index 7892bf9f554..2d66890eaff 100644 --- a/packages/backend/src/__tests__/exports.test.ts +++ b/packages/backend/src/__tests__/exports.test.ts @@ -74,7 +74,6 @@ describe('subpath /jwt exports', () => { expect(Object.keys(jwtExports).sort()).toMatchInlineSnapshot(` [ "decodeJwt", - "hasValidSignature", "signJwt", "verifyJwt", ] diff --git a/packages/backend/src/jwt/index.ts b/packages/backend/src/jwt/index.ts index 4875a9689eb..8c8ee7747e2 100644 --- a/packages/backend/src/jwt/index.ts +++ b/packages/backend/src/jwt/index.ts @@ -1,10 +1,12 @@ import { withLegacyReturn, withLegacySyncReturn } from './legacyReturn'; import { signJwt as _signJwt } from './signJwt'; -import { decodeJwt as _decodeJwt, hasValidSignature as _hasValidSignature, verifyJwt as _verifyJwt } from './verifyJwt'; +import { decodeJwt as _decodeJwt, verifyJwt as _verifyJwt } from './verifyJwt'; export type { VerifyJwtOptions } from './verifyJwt'; export type { SignJwtOptions } from './signJwt'; +export type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512'; + // Introduce compatibility layer to avoid more breaking changes // TODO(dimkl): This (probably be drop in the next major version) @@ -12,4 +14,3 @@ export const verifyJwt = withLegacyReturn(_verifyJwt); export const decodeJwt = withLegacySyncReturn(_decodeJwt); export const signJwt = withLegacyReturn(_signJwt); -export const hasValidSignature = withLegacyReturn(_hasValidSignature); From bb03ddc0ff4046e331e68cde88b1ef9eb1458edb Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 27 May 2026 12:54:24 -0500 Subject: [PATCH 3/4] ci(repo): keep snapi baseline cache warm and bump snapi pin - drop the paths: filter on the push trigger so publish-baseline runs on every main/release-branch commit, keeping the cache that check-api restores hot. - bump SNAPI_PACKAGE to the current snapi main HEAD; the previous pin predates subpath snapshot support, so changes on subpath exports (e.g. @clerk/backend/webhooks) were never detected. --- .changeset/fix-snapi-api-changes-workflow.md | 2 ++ .github/workflows/api-changes.yml | 11 +---------- 2 files changed, 3 insertions(+), 10 deletions(-) create mode 100644 .changeset/fix-snapi-api-changes-workflow.md diff --git a/.changeset/fix-snapi-api-changes-workflow.md b/.changeset/fix-snapi-api-changes-workflow.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/fix-snapi-api-changes-workflow.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/api-changes.yml b/.github/workflows/api-changes.yml index 1b15c256ed0..d95e332440e 100644 --- a/.github/workflows/api-changes.yml +++ b/.github/workflows/api-changes.yml @@ -6,15 +6,6 @@ on: - main - release/v4 - release/core-2 - paths: - - 'packages/backend/**' - - 'packages/clerk-js/**' - - 'packages/nextjs/**' - - 'packages/react/**' - - 'packages/shared/**' - - 'packages/ui/**' - - 'snapi.config.json' - - '.github/workflows/api-changes.yml' pull_request: types: [opened, synchronize, reopened, ready_for_review] branches: @@ -39,7 +30,7 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: - SNAPI_PACKAGE: https://pkg.pr.new/clerk/snapi/@clerk/snapi@d3ee0217f35a3b1ebb3ce73d252d12761b01f374 + SNAPI_PACKAGE: https://pkg.pr.new/clerk/snapi/@clerk/snapi@d42ed8b7857f9254bbb2a6e9ead44d5e7b1aa60c SNAPI_FILTERS: >- --filter=@clerk/backend --filter=@clerk/clerk-js From ba8a50de8703c5302df07f54103ce61d9793a9d3 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 27 May 2026 14:29:47 -0500 Subject: [PATCH 4/4] ci(repo): pass SNAPI_ANTHROPIC_API_KEY to snapi detect step --- .changeset/snapi-enable-ai-reviewer.md | 2 ++ .github/workflows/api-changes.yml | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 .changeset/snapi-enable-ai-reviewer.md diff --git a/.changeset/snapi-enable-ai-reviewer.md b/.changeset/snapi-enable-ai-reviewer.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/snapi-enable-ai-reviewer.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/api-changes.yml b/.github/workflows/api-changes.yml index d95e332440e..8d838b8ccdf 100644 --- a/.github/workflows/api-changes.yml +++ b/.github/workflows/api-changes.yml @@ -148,6 +148,8 @@ jobs: --output "$GITHUB_WORKSPACE/.api-snapshots-baseline" - name: Detect API changes + env: + SNAPI_ANTHROPIC_API_KEY: ${{ secrets.SNAPI_ANTHROPIC_API_KEY }} run: | pnpm dlx --package "$SNAPI_PACKAGE" snapi detect \ --baseline .api-snapshots-baseline \