Skip to content

Commit 7a64501

Browse files
authored
Merge branch 'main' into rob/api-keys-stable
2 parents 096545b + 26692e1 commit 7a64501

39 files changed

Lines changed: 622 additions & 1300 deletions

.changeset/eight-paws-exercise.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.changeset/fifty-paths-tie.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/ui': patch
3+
---
4+
5+
Adjust padding and display logo on `OrganizationList` header
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/backend': patch
3+
---
4+
5+
Export `OrganizationInvitationAcceptedWebhookEvent` type.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@clerk/testing": patch
3+
---
4+
5+
Fix `signIn()` timing out with concurrent Playwright workers by de-duplicating route handler registration and adding retry with exponential backoff for transient FAPI errors (429, 502, 503, 504).
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.github/workflows/e2e-staging.yml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ concurrency:
3939
jobs:
4040
permissions-check:
4141
name: Check Permissions
42+
if: ${{ github.event_name != 'repository_dispatch' }}
4243
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
4344
steps:
4445
- name: Check org membership
@@ -70,12 +71,35 @@ jobs:
7071
validate-instances:
7172
name: Validate Staging Instances
7273
needs: [permissions-check]
74+
if: ${{ always() && (needs.permissions-check.result == 'success' || needs.permissions-check.result == 'skipped') }}
7375
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
7476
steps:
77+
- name: Normalize inputs
78+
id: inputs
79+
env:
80+
EVENT_NAME: ${{ github.event_name }}
81+
INPUT_REF: ${{ github.event.inputs.ref }}
82+
PAYLOAD_REF: ${{ github.event.client_payload.ref }}
83+
run: |
84+
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
85+
echo "ref=${INPUT_REF:-main}" >> $GITHUB_OUTPUT
86+
else
87+
echo "ref=${PAYLOAD_REF:-main}" >> $GITHUB_OUTPUT
88+
fi
89+
90+
- name: Validate ref
91+
env:
92+
REF: ${{ steps.inputs.outputs.ref }}
93+
run: |
94+
if [[ ! "$REF" =~ ^(main|release/.*)$ ]]; then
95+
echo "::error::Ref '$REF' is not allowed. Only 'main' and 'release/*' branches are permitted."
96+
exit 1
97+
fi
98+
7599
- name: Checkout Repo
76100
uses: actions/checkout@v4
77101
with:
78-
ref: ${{ github.event.inputs.ref || github.event.client_payload.ref || 'main' }}
102+
ref: ${{ steps.inputs.outputs.ref }}
79103
sparse-checkout: scripts/validate-staging-instances.mjs
80104
fetch-depth: 1
81105

@@ -88,6 +112,7 @@ jobs:
88112
integration-tests:
89113
name: Integration Tests (${{ matrix.test-name }}, ${{ matrix.test-project }})
90114
needs: [permissions-check]
115+
if: ${{ always() && (needs.permissions-check.result == 'success' || needs.permissions-check.result == 'skipped') }}
91116
runs-on: 'blacksmith-8vcpu-ubuntu-2204'
92117
defaults:
93118
run:

eslint.config.mjs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import eslint from '@eslint/js';
22
import configPrettier from 'eslint-config-prettier';
33
import configTurbo from 'eslint-config-turbo/flat';
44
import pluginImport from 'eslint-plugin-import';
5-
import pluginJest from 'eslint-plugin-jest';
65
import pluginJsDoc from 'eslint-plugin-jsdoc';
76
import pluginJsxA11y from 'eslint-plugin-jsx-a11y';
87
import pluginPlaywright from 'eslint-plugin-playwright';
@@ -497,16 +496,12 @@ export default tseslint.config([
497496
name: 'repo/test',
498497
files: TEST_FILES,
499498
languageOptions: {
500-
globals: pluginJest.environments.globals.globals,
501-
},
502-
plugins: {
503-
jest: pluginJest,
499+
globals: globals.vitest,
504500
},
505501
rules: {
506502
'@typescript-eslint/await-thenable': 'off',
507503
'@typescript-eslint/no-non-null-assertion': 'off',
508504
'@typescript-eslint/unbound-method': 'off',
509-
'jest/unbound-method': 'error',
510505
},
511506
},
512507
{
@@ -546,7 +541,6 @@ export default tseslint.config([
546541
name: 'packages - vitest',
547542
files: ['packages/*/src/**/*.test.{ts,tsx}'],
548543
rules: {
549-
'jest/unbound-method': 'off',
550544
'@typescript-eslint/unbound-method': 'off',
551545
},
552546
},

integration/templates/expo-web/package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
"lint": "expo lint",
1010
"start": "pnpm dlx serve dist --single"
1111
},
12-
"jest": {
13-
"preset": "jest-expo"
14-
},
1512
"dependencies": {
1613
"@expo/vector-icons": "^14.0.2",
1714
"@react-navigation/native": "^6.0.2",
@@ -37,11 +34,8 @@
3734
"devDependencies": {
3835
"@babel/core": "^7.20.0",
3936
"@babel/runtime": "7.26.0",
40-
"@types/jest": "^29.5.12",
4137
"@types/react": "18.3.12",
4238
"@types/react-test-renderer": "^18.0.7",
43-
"jest": "^29.2.1",
44-
"jest-expo": "~51.0.3",
4539
"react-test-renderer": "18.2.0",
4640
"typescript": "~5.7.3"
4741
}

integration/templates/react-cra/package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
"scripts": {
66
"build": "react-scripts build",
77
"eject": "react-scripts eject",
8-
"start": "BROWSER=none react-scripts start",
9-
"test": "react-scripts test"
8+
"start": "BROWSER=none react-scripts start"
109
},
1110
"browserslist": {
1211
"production": [
@@ -22,8 +21,7 @@
2221
},
2322
"eslintConfig": {
2423
"extends": [
25-
"react-app",
26-
"react-app/jest"
24+
"react-app"
2725
]
2826
},
2927
"dependencies": {

integration/testUtils/__tests__/retryableClerkClient.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,29 @@ describe('withRetry', () => {
135135
expect(mock).toHaveBeenCalledTimes(2);
136136
});
137137

138+
it('uses exponential backoff as floor when retryAfter is 0', async () => {
139+
vi.spyOn(Math, 'random').mockReturnValue(0);
140+
const error = makeClerkAPIError(429, { retryAfter: 0 });
141+
const mock = vi
142+
.fn()
143+
.mockImplementationOnce(() => Promise.resolve().then(() => Promise.reject(error)))
144+
.mockResolvedValueOnce({ id: 'user_123' });
145+
const client = makeMockClient({ getUser: mock });
146+
const wrapped = withRetry(client);
147+
148+
const promise = (wrapped.users as any).getUser('user_123');
149+
150+
// retryAfter=0 should NOT cause a 0ms delay; exponential backoff (1000ms for attempt 0) is used as floor
151+
await vi.advanceTimersByTimeAsync(999);
152+
expect(mock).toHaveBeenCalledTimes(1);
153+
154+
await vi.advanceTimersByTimeAsync(1);
155+
await vi.advanceTimersByTimeAsync(0);
156+
157+
await expect(promise).resolves.toEqual({ id: 'user_123' });
158+
expect(mock).toHaveBeenCalledTimes(2);
159+
});
160+
138161
it('caps retryAfter delay at MAX_RETRY_DELAY_MS (30s)', async () => {
139162
const error = makeClerkAPIError(429, { retryAfter: 60 });
140163
const mock = vi

0 commit comments

Comments
 (0)