Skip to content

Commit

Permalink
Merge branch 'main' into stefanos/fraud-377-expose-more-options-for-t…
Browse files Browse the repository at this point in the history
…urnstile-appearance
  • Loading branch information
anagstef authored Feb 25, 2025
2 parents c81d99d + 460325c commit 6008795
Show file tree
Hide file tree
Showing 52 changed files with 848 additions and 561 deletions.
2 changes: 2 additions & 0 deletions .changeset/chilled-bananas-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
28 changes: 28 additions & 0 deletions .changeset/fair-insects-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
"@clerk/astro": minor
---

Introduce `protect-fallback` slot to avoid naming conflicts with Astro's server islands [`fallback` slot](https://docs.astro.build/en/guides/server-islands/#server-island-fallback-content).

When using Clerk's `<Protect>` component with `server:defer`, you can now use both slots:
- `fallback`: Default loading content
- `protect-fallback`: Shows when a user doesn't have the `role` or `permission` to access the protected content

Regular usage without server islands:

```astro
<Protect role="admin">
<p slot="fallback">Not an admin</p>
<p>You're an admin</p>
</Protect>
```

Example with server islands:

```astro
<Protect server:defer role="admin">
<p slot="fallback">Loading...</p>
<p slot="protect-fallback">Not an admin</p>
<p>You're an admin</p>
</Protect>
```
2 changes: 2 additions & 0 deletions .changeset/healthy-ladybugs-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
5 changes: 5 additions & 0 deletions .changeset/lemon-zebras-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/nuxt": patch
---

Fixes an issue where duplicated imports caused warnings in the console.
27 changes: 27 additions & 0 deletions .changeset/metal-bobcats-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
'@clerk/shared': major
---
This new version introduces the following breaking changes:
- Introduced a new `retry` utility function to replace the deprecated `callWithRetry`.
- Removed the `callWithRetry` function and its associated tests.
- Renamed `runWithExponentialBackOff` to `retry` for consistency.

Migration steps:
- Replace any usage of `callWithRetry` with the new `retry` function.
- Update import statements from:
```typescript
import { callWithRetry } from '@clerk/shared/callWithRetry';
```
to:
```typescript
import { retry } from '@clerk/shared/retry';
```
- Replace any usage of `runWithExponentialBackOff` with `retry`.
- Update import statements from:
```typescript
import { runWithExponentialBackOff } from '@clerk/shared/utils';
```
to:
```typescript
import { retry } from '@clerk/shared/retry';
```
5 changes: 5 additions & 0 deletions .changeset/moody-owls-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': patch
---

Improve compatibility with Safari 12 by removing modern JavaScript syntax.
5 changes: 5 additions & 0 deletions .changeset/new-pots-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-react': patch
---

Refactors `IsomorphicClerk` types to reduce unnecessary duplication between it and `Clerk`. Also relies more on the source types from `Clerk` to ensure `IsomorphicClerk` types match.
5 changes: 5 additions & 0 deletions .changeset/poor-cobras-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@clerk/clerk-js': minor
---

Track usage of modal UI Components as part of telemetry.
2 changes: 2 additions & 0 deletions .changeset/rude-meals-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/shaggy-pandas-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 2 additions & 0 deletions .changeset/sour-walls-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
20 changes: 20 additions & 0 deletions integration/templates/astro-node/src/pages/server-islands.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
import { Protect } from "@clerk/astro/components";
import Layout from "../layouts/Layout.astro";
---

<Layout title="Page is only accessible by members">
<div class="w-full flex justify-center flex-col">
<Protect server:defer role="admin">
<p slot="fallback">Loading</p>
<Fragment slot="protect-fallback">
<h1 class="text-2xl text-center">Not an admin</h1>
<a
class="text-sm text-center text-gray-100 transition hover:text-gray-400"
href="/only-members">Go to Members Page</a
>
</Fragment>
<h1 class="text-2xl text-center">I'm an admin</h1>
</Protect>
</div>
</Layout>
26 changes: 26 additions & 0 deletions integration/tests/astro/components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,4 +481,30 @@ testAgainstRunningApps({ withPattern: ['astro.node.withCustomRoles'] })('basic f
// Components should be rendered on hard reload
await u.po.userButton.waitForMounted();
});

test('server islands protect component shows correct states', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });

await u.page.goToRelative('/server-islands');
// The loading slot for server islands will appear very quickly.
// Wait for next state (default slot) to be ready
await expect(u.page.getByText('Loading')).toBeHidden();
await expect(u.page.getByText('Not an admin')).toBeVisible();

// Sign in as admin user
await u.page.goToRelative('/sign-in');
await u.po.signIn.waitForMounted();
await u.po.signIn.signInWithEmailAndInstantPassword({
email: fakeAdmin2.email,
password: fakeAdmin2.password,
});
await u.po.expect.toBeSignedIn();
await u.po.organizationSwitcher.waitForMounted();
await u.po.organizationSwitcher.waitForAnOrganizationToSelected();

// Visit page again
await u.page.goToRelative('/server-islands');
await expect(u.page.getByText('Loading')).toBeHidden();
await expect(u.page.getByText("I'm an admin")).toBeVisible();
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"license": "MIT",
"scripts": {
"build": "FORCE_COLOR=1 turbo build --concurrency=${TURBO_CONCURRENCY:-80%}",
"build:declarations": "FORCE_COLOR=1 turbo build:declarations --concurrency=${TURBO_CONCURRENCY:-80%} --filter=@clerk/nextjs --filter=@clerk/clerk-react --filter=@clerk/shared --filter=@clerk/types",
"bundlewatch": "turbo bundlewatch",
"changeset": "changeset",
"changeset:empty": "pnpm changeset --empty",
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"nanostores": "0.11.3"
},
"devDependencies": {
"astro": "^5.2.6"
"astro": "^5.3.0"
},
"peerDependencies": {
"astro": "^4.15.0 || ^5.0.0"
Expand Down
11 changes: 10 additions & 1 deletion packages/astro/src/astro-components/control/Protect.astro
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ type Props = ProtectProps & {
const { isStatic, ...props } = Astro.props;
const ProtectComponent = isStaticOutput(isStatic) ? ProtectCSR : ProtectSSR;
// Note: Astro server islands also use a "fallback" slot for loading states
// See: https://docs.astro.build/en/guides/server-islands/#server-island-fallback-content
// We use "protect-fallback" as our preferred slot name to avoid conflicts
const hasProtectFallback = Astro.slots.has('protect-fallback');
---

<ProtectComponent {...props}>
<slot />
<slot name="fallback" slot="fallback" />
{hasProtectFallback ? (
<slot name="protect-fallback" slot="protect-fallback" />
) : (
<slot name="fallback" slot="fallback" />
)}
</ProtectComponent>
14 changes: 13 additions & 1 deletion packages/astro/src/astro-components/control/ProtectSSR.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ const isUnauthorized =
(typeof Astro.props.condition === "function" &&
!Astro.props.condition(has)) ||
((Astro.props.role || Astro.props.permission) && !has(Astro.props));
const hasProtectFallback = Astro.slots.has('protect-fallback');
---

{isUnauthorized ? <slot name="fallback" /> : <slot />}
{
isUnauthorized ? (
hasProtectFallback ? (
<slot name="protect-fallback" />
) : (
<slot name="fallback" />
)
) : (
<slot />
)
}
1 change: 0 additions & 1 deletion packages/backend/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export const API_VERSION = 'v1';

export const USER_AGENT = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;
export const MAX_CACHE_LAST_UPDATED_AT_SECONDS = 5 * 60;
export const JWKS_CACHE_TTL_MS = 1000 * 60 * 60;
export const SUPPORTED_BAPI_VERSION = '2024-10-01';

const Attributes = {
Expand Down
8 changes: 4 additions & 4 deletions packages/backend/src/tokens/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '../errors';
import { runtime } from '../runtime';
import { joinPaths } from '../util/path';
import { callWithRetry } from '../util/shared';
import { retry } from '../util/shared';

type JsonWebKeyWithKid = JsonWebKey & { kid: string };

Expand Down Expand Up @@ -115,7 +115,7 @@ export type LoadClerkJWKFromRemoteOptions = {
*
* Loads a key from JWKS retrieved from the well-known Frontend API endpoint of the issuer.
* The result is also cached on the module level to avoid network requests in subsequent invocations.
* The cache lasts 1 hour by default.
* The cache lasts up to 5 minutes.
*
* @param {Object} options
* @param {string} options.kid - The id of the key that the JWT was signed with
Expand All @@ -137,8 +137,8 @@ export async function loadClerkJWKFromRemote({
reason: TokenVerificationErrorReason.RemoteJWKFailedToLoad,
});
}
const fetcher = () => fetchJWKSFromBAPI(apiUrl, secretKey, apiVersion);
const { keys } = await callWithRetry<{ keys: JsonWebKeyWithKid[] }>(fetcher);
const fetcher = () => fetchJWKSFromBAPI(apiUrl, secretKey, apiVersion) as Promise<{ keys: JsonWebKeyWithKid[] }>;
const { keys } = await retry(fetcher);

if (!keys || !keys.length) {
throw new TokenVerificationError({
Expand Down
4 changes: 2 additions & 2 deletions packages/backend/src/util/shared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { addClerkPrefix, getScriptUrl, getClerkJsMajorVersionOrTag } from '@clerk/shared/url';
export { callWithRetry } from '@clerk/shared/callWithRetry';
export { retry } from '@clerk/shared/retry';
export {
isDevelopmentFromSecretKey,
isProductionFromSecretKey,
Expand All @@ -10,8 +10,8 @@ export {
export { deprecated, deprecatedProperty } from '@clerk/shared/deprecated';

import { buildErrorThrower } from '@clerk/shared/error';
import { createDevOrStagingUrlCache } from '@clerk/shared/keys';
// TODO: replace packageName with `${PACKAGE_NAME}@${PACKAGE_VERSION}` from tsup.config.ts
export const errorThrower = buildErrorThrower({ packageName: '@clerk/backend' });

import { createDevOrStagingUrlCache } from '@clerk/shared/keys';
export const { isDevOrStagingUrl } = createDevOrStagingUrlCache();
2 changes: 0 additions & 2 deletions packages/backend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"declaration": true,
"declarationMap": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"importHelpers": true,
Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"files": [
{ "path": "./dist/clerk.js", "maxSize": "560kB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "75kB" },
{ "path": "./dist/clerk.headless.js", "maxSize": "48kB" },
{ "path": "./dist/clerk.headless.js", "maxSize": "48.2KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "89KB" },
{ "path": "./dist/vendors*.js", "maxSize": "25KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "35.2KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "35.5KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
{ "path": "./dist/impersonationfab*.js", "maxSize": "5KB" },
{ "path": "./dist/organizationprofile*.js", "maxSize": "12KB" },
Expand Down
4 changes: 2 additions & 2 deletions packages/clerk-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
},
"devDependencies": {
"@rsdoctor/rspack-plugin": "^0.4.13",
"@rspack/cli": "^1.2.3",
"@rspack/core": "^1.2.3",
"@rspack/cli": "^1.2.5",
"@rspack/core": "^1.2.5",
"@rspack/plugin-react-refresh": "^1.0.1",
"@svgr/webpack": "^6.5.1",
"@types/webpack-env": "^1.18.8",
Expand Down
11 changes: 11 additions & 0 deletions packages/clerk-js/rspack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ const typescriptLoaderProd = () => {
},
},
},
{
test: /\.m?js$/,
use: {
loader: 'builtin:swc-loader',
options: {
env: {
targets: packageJSON.browserslist,
},
},
},
},
];
};

Expand Down
Loading

0 comments on commit 6008795

Please sign in to comment.