Skip to content

Commit 2c06a5f

Browse files
authored
chore(clerk-js,shared): Remove experimental tags from API keys (#8059)
1 parent 22d945d commit 2c06a5f

14 files changed

Lines changed: 88 additions & 48 deletions

File tree

.changeset/empty-lights-dress.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@clerk/nuxt': minor
3+
---
4+
5+
API keys is now generally available.
6+
7+
```vue
8+
<script setup>
9+
// Components are automatically imported
10+
</script>
11+
12+
<template>
13+
<APIKeys />
14+
</template>
15+
```

.changeset/stable-api-keys.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
"@clerk/shared": minor
3+
"@clerk/react": minor
4+
"@clerk/clerk-js": minor
5+
"@clerk/ui": minor
6+
---
7+
8+
API keys is now generally available.
9+
10+
### `<APIKeys />` component
11+
12+
```tsx
13+
import { APIKeys } from '@clerk/react';
14+
15+
export default function Page() {
16+
return <APIKeys />;
17+
}
18+
```
19+
20+
### `useAPIKeys()` hook
21+
22+
```tsx
23+
import { useAPIKeys } from '@clerk/react';
24+
25+
export default function CustomAPIKeys() {
26+
const { data, isLoading, page, pageCount, fetchNext, fetchPrevious } = useAPIKeys({
27+
pageSize: 10,
28+
initialPage: 1,
29+
});
30+
31+
if (isLoading) return <div>Loading...</div>;
32+
33+
return (
34+
<ul>
35+
{data?.map((key) => (
36+
<li key={key.id}>{key.name}</li>
37+
))}
38+
</ul>
39+
);
40+
}
41+
```

packages/clerk-js/src/core/clerk.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,15 +1345,11 @@ export class Clerk implements ClerkInterface {
13451345
};
13461346

13471347
/**
1348-
* @experimental This API is in early access and may change in future releases.
1349-
*
1350-
* Mount a API keys component at the target element.
1348+
* Mount an API keys component at the target element.
13511349
* @param targetNode Target to mount the APIKeys component.
13521350
* @param props Configuration parameters.
13531351
*/
13541352
public mountAPIKeys = (node: HTMLDivElement, props?: APIKeysProps) => {
1355-
logger.warnOnce('Clerk: <APIKeys /> component is in early access and not yet recommended for production use.');
1356-
13571353
if (disabledAllAPIKeysFeatures(this, this.environment)) {
13581354
if (this.#instanceType === 'development') {
13591355
throw new ClerkRuntimeError(warnings.cannotRenderAPIKeysComponent, {
@@ -1398,9 +1394,7 @@ export class Clerk implements ClerkInterface {
13981394
};
13991395

14001396
/**
1401-
* @experimental This API is in early access and may change in future releases.
1402-
*
1403-
* Unmount a API keys component from the target element.
1397+
* Unmount an API keys component from the target element.
14041398
* If there is no component mounted at the target node, results in a noop.
14051399
*
14061400
* @param targetNode Target node to unmount the APIKeys component from.

packages/clerk-js/src/core/modules/apiKeys/index.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import { convertPageToOffsetSearchParams } from '@/utils/convertPageToOffsetSear
1515
import { APIKey, BaseResource } from '../../resources/internal';
1616

1717
export class APIKeys implements APIKeysNamespace {
18+
static readonly #pathRoot = '/api_keys';
19+
1820
/**
1921
* Returns the base options for the FAPI proxy requests.
2022
*/
21-
private async getBaseFapiProxyOptions(): Promise<FapiRequestInit> {
23+
async #getBaseFapiProxyOptions(): Promise<FapiRequestInit> {
2224
const token = await BaseResource.clerk.session?.getToken();
2325
if (!token) {
2426
throw new ClerkRuntimeError('No valid session token available', { code: 'no_session_token' });
@@ -27,7 +29,7 @@ export class APIKeys implements APIKeysNamespace {
2729
return {
2830
// Set to an empty string because FAPI Proxy does not include the version in the path.
2931
pathPrefix: '',
30-
// Set the session token as a Bearer token in the Authorization header for authentication.
32+
// FAPI Proxy looks for the session token in the Authorization header.
3133
headers: {
3234
Authorization: `Bearer ${token}`,
3335
'Content-Type': 'application/json',
@@ -37,11 +39,19 @@ export class APIKeys implements APIKeysNamespace {
3739
};
3840
}
3941

42+
/**
43+
* Retrieves a paginated list of API keys.
44+
*
45+
* The subject (owner) is resolved in the following order:
46+
* 1. Explicit `subject` param (user or organization ID)
47+
* 2. Active organization ID
48+
* 3. Current user ID
49+
*/
4050
async getAll(params?: GetAPIKeysParams): Promise<ClerkPaginatedResponse<APIKeyResource>> {
4151
return BaseResource._fetch({
42-
...(await this.getBaseFapiProxyOptions()),
52+
...(await this.#getBaseFapiProxyOptions()),
4353
method: 'GET',
44-
path: '/api_keys',
54+
path: APIKeys.#pathRoot,
4555
search: convertPageToOffsetSearchParams({
4656
...params,
4757
subject: params?.subject ?? BaseResource.clerk.organization?.id ?? BaseResource.clerk.user?.id ?? '',
@@ -59,8 +69,8 @@ export class APIKeys implements APIKeysNamespace {
5969

6070
async create(params: CreateAPIKeyParams): Promise<APIKeyResource> {
6171
const json = (await BaseResource._fetch<ApiKeyJSON>({
62-
...(await this.getBaseFapiProxyOptions()),
63-
path: '/api_keys',
72+
...(await this.#getBaseFapiProxyOptions()),
73+
path: APIKeys.#pathRoot,
6474
method: 'POST',
6575
body: JSON.stringify({
6676
type: 'api_key',
@@ -76,9 +86,9 @@ export class APIKeys implements APIKeysNamespace {
7686

7787
async revoke(params: RevokeAPIKeyParams): Promise<APIKeyResource> {
7888
const json = (await BaseResource._fetch<ApiKeyJSON>({
79-
...(await this.getBaseFapiProxyOptions()),
89+
...(await this.#getBaseFapiProxyOptions()),
8090
method: 'POST',
81-
path: `/api_keys/${params.apiKeyID}/revoke`,
91+
path: `${APIKeys.#pathRoot}/${params.apiKeyID}/revoke`,
8292
body: JSON.stringify({
8393
revocation_reason: params.revocationReason,
8494
}),

packages/nuxt/src/module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ export default defineNuxtModule<ModuleOptions>({
182182
'RedirectToCreateOrganization',
183183
'Show',
184184
'Waitlist',
185+
// API Keys
186+
'APIKeys',
185187
];
186188
otherComponents.forEach(component => {
187189
void addComponent({

packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
5757
"__experimental_useCheckout",
5858
"__experimental_usePaymentElement",
5959
"getToken",
60+
"useAPIKeys",
6061
"useAuth",
6162
"useClerk",
6263
"useEmailLink",

packages/react/src/experimental.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export type {
99
} from '@clerk/shared/types';
1010

1111
export {
12-
__experimental_useAPIKeys as useAPIKeys,
1312
__experimental_PaymentElementProvider as PaymentElementProvider,
1413
__experimental_usePaymentElement as usePaymentElement,
1514
__experimental_PaymentElement as PaymentElement,

packages/react/src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export {
1010
useUser,
1111
useSession,
1212
useReverification,
13+
useAPIKeys,
1314
__experimental_useCheckout,
1415
__experimental_CheckoutProvider,
1516
__experimental_usePaymentElement,

packages/shared/src/react/hooks/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { assertContextExists, createContextAndHook } from './createContextAndHook';
2-
export { useAPIKeys as __experimental_useAPIKeys } from './useAPIKeys';
2+
export { useAPIKeys } from './useAPIKeys';
33
export { useOrganization } from './useOrganization';
44
export { useOrganizationCreationDefaults } from './useOrganizationCreationDefaults';
55
export type {

packages/shared/src/react/hooks/useAPIKeys.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { createCacheKeys } from './createCacheKeys';
77
import { usePagesOrInfinite, useWithSafeValues } from './usePagesOrInfinite';
88

99
/**
10-
* @internal
10+
* @interface
1111
*/
1212
export type UseAPIKeysParams = PaginatedHookConfig<
1313
GetAPIKeysParams & {
@@ -21,16 +21,14 @@ export type UseAPIKeysParams = PaginatedHookConfig<
2121
>;
2222

2323
/**
24-
* @internal
24+
* @interface
2525
*/
2626
export type UseAPIKeysReturn<T extends UseAPIKeysParams> = PaginatedResources<
2727
APIKeyResource,
2828
T extends { infinite: true } ? true : false
2929
>;
3030

3131
/**
32-
* @internal
33-
*
3432
* The `useAPIKeys()` hook provides access to paginated API keys for the current user or organization.
3533
*
3634
* @example

0 commit comments

Comments
 (0)