Skip to content

Conversation

@wobsoriano
Copy link
Member

@wobsoriano wobsoriano commented Oct 31, 2025

Description

This PR replaces the persistent key column in the API keys table with a one-time modal that displays the secret immediately after creation. It also removes the clerkClient.apiKeys.getSecretKey() method in backend as we're only going to provide the API key secret once after creation.

Screen.Recording.2025-11-03.at.9.24.27.AM.mov

Resolves USER-3698

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Adds a “Copy API Key” modal shown immediately after creation with one-click copy-and-close.
  • Localization

    • Adds copy-secret and API key label entries across 40+ locales to support the new modal.
  • Refactor

    • API key secrets are only shown at creation (no later retrieval); key column and inline secret controls removed from the table.
  • Tests

    • Tests updated to verify clipboard copy flow immediately after key creation.

@changeset-bot
Copy link

changeset-bot bot commented Oct 31, 2025

🦋 Changeset detected

Latest commit: 4aeab7b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 15 packages
Name Type
@clerk/localizations Minor
@clerk/clerk-js Minor
@clerk/backend Minor
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Oct 31, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Nov 4, 2025 3:09pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 31, 2025

Walkthrough

Secrets for API keys are shown only once immediately after creation via a one-time modal; the persistent Key column and backend/frontend getSecret() method were removed. Created API key responses may include an optional secret field and UI/components were added/updated to support the modal copy flow and localized text.

Changes

Cohort / File(s) Summary
Changeset entries
\.changeset/chilly-boxes-warn.md, \.changeset/heavy-books-protect.md, \.changeset/tiny-hounds-pretend.md
Added changeset entries documenting the UX/security change, version bumps, and removal of getSecret().
Backend API
packages/backend/src/api/endpoints/APIKeysApi.ts
Removed public getSecret(apiKeyId: string) endpoint method.
Shared types & JSON
packages/shared/src/types/json.ts, packages/shared/src/types/apiKeys.ts, packages/shared/src/types/appearance.ts, packages/shared/src/types/localization.ts
Added optional secret?: string to ApiKey JSON/resource, added new appearance element keys for the copy modal, and expanded localization type with formFieldLabel__apiKey and apiKeys.copySecret.
Frontend core & resources
packages/clerk-js/src/core/modules/apiKeys/index.ts, packages/clerk-js/src/core/resources/APIKey.ts
Removed getSecret from client API; create/revoke simplified; APIKey resource now has optional secret populated from JSON.
UI pages & tables
packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx, packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
On create, open a CopyApiKeyModal with returned secret; removed per-row secret column, visibility toggle, and copy UI from the table.
New modal components
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx, packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
Added CopyApiKeyModal (one-time secret display + copy) and ApiKeyModal (portal-aware modal wrapper).
Modal migration
packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
Switched Revoke confirmation modal to use new ApiKeyModal wrapper.
UI elements & exports
packages/clerk-js/src/ui/elements/ClipboardInput.tsx, packages/clerk-js/src/ui/elements/Form.tsx, packages/clerk-js/src/ui/customizables/elementDescriptors.ts, packages/shared/src/types/appearance.ts
Extended ClipboardInput props to accept custom icons; exported CommonInputWrapper from Form; added appearance keys for copy modal.
Localization files
packages/localizations/src/*.ts (many locales, e.g., en-US.ts, en-GB.ts, ... )
Added apiKeys.copySecret (formTitle, formHint, formButtonPrimary__copyAndClose) and formFieldLabel__apiKey across locales; en-US includes concrete strings.
Integration tests & utils
integration/tests/machine-auth/component.test.ts, integration/testUtils/usersService.ts
Tests updated to read secret from create response and verify copy via modal/clipboard; usersService reads secret from creation response instead of calling getSecret().
Documentation/comments
packages/shared/src/types/clerk.ts
JSDoc and spacing updates (documentation-only).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as API Keys UI
    participant Backend as Backend API
    participant Modal as CopyApiKeyModal
    participant Clipboard as Clipboard

    User->>UI: Click "Create API Key"
    UI->>Backend: POST /api_keys (create)
    Backend-->>UI: 201 { id, name, secret? }
    UI->>Modal: Open with apiKeyName + secret
    User->>Modal: Click "Copy & Close"
    Modal->>Clipboard: write(secret)
    Clipboard-->>User: secret copied
    Modal->>UI: Close modal
    Note right of UI: Secret not retrievable after creation
Loading
sequenceDiagram
    participant Old as Old Flow (removed)
    participant New as New Flow (current)

    Note over Old: Persistent table + getSecret() allowed viewing later
    Old->>Old: Secret column shows secret
    Old->>Old: API client can call getSecret(id)

    Note over New: One-time modal, no later retrieval
    New->>New: Create API key -> response contains secret
    New->>New: Modal shows secret once -> user copies -> modal closes
    New->>New: No getSecret() API available anymore
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to check closely:
    • CopyApiKeyModal and ApiKeyModal: props, portalRoot styles, focus/aria behavior.
    • Ensure removal of getSecret() has no remaining callers.
    • Type handling for optional secret in create responses and downstream code paths.
    • Integration test clipboard permission handling and reliability.

Poem

🐇 A key appears for just one glance,
A modal hums: "Copy now, take a chance."
I press the button — the secret takes flight,
Then hides away into the night. ✨

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: removing the secret key column from the API keys component and replacing it with a one-time modal.
Linked Issues check ✅ Passed The PR fully addresses the objective in USER-3698 to prevent API key secret retrieval after creation by removing the persistent column and backend method.
Out of Scope Changes check ✅ Passed All changes directly support the primary objective of securing API keys by preventing post-creation secret access; no unrelated modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rob/user-3698-remove-key-column

Comment @coderabbitai help to get the list of available commands and usage tips.

@wobsoriano wobsoriano changed the title chore(clerk-js) [DO NOT REVIEW]: Remove key column in API keys component chore(clerk-js): Remove key column in API keys component Oct 31, 2025
@wobsoriano wobsoriano changed the title chore(clerk-js): Remove key column in API keys component chore(clerk-js,backend): Remove key column in API keys component Nov 2, 2025
@wobsoriano wobsoriano changed the title chore(clerk-js,backend): Remove key column in API keys component chore(clerk-js,backend): Remove secret key column in API keys component Nov 2, 2025
@wobsoriano wobsoriano marked this pull request as ready for review November 2, 2025 16:12
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
integration/testUtils/usersService.ts (1)

209-209: Let me check the usage of the secret from createFakeAPIKey and any context around this change:

Now let me check how the secret from createFakeAPIKey is actually used in tests:

Improve error handling by validating API key secret presence instead of using empty string fallback.

The empty string fallback masks potential API contract violations. Since APIKey.secret is optional but FakeAPIKey.secret is required, consider one of these approaches:

  1. Throw a clear error if secret is missing — Helps catch API issues immediately during tests
  2. Add explicit validation — Document why the fallback exists if it's intentional
  3. Verify secret is always present in create response — Confirm this is guaranteed by Clerk's API

Using an empty string as a fallback could cause confusing auth failures in integration tests that use this fake key, making it harder to debug actual issues.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 51e5a68 and 4fb8000.

📒 Files selected for processing (1)
  • integration/testUtils/usersService.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • integration/testUtils/usersService.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • integration/testUtils/usersService.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • integration/testUtils/usersService.ts
integration/**

📄 CodeRabbit inference engine (.cursor/rules/global.mdc)

Framework integration templates and E2E tests should be placed under the integration/ directory

Files:

  • integration/testUtils/usersService.ts
integration/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

End-to-end tests and integration templates must be located in the 'integration/' directory.

Files:

  • integration/testUtils/usersService.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • integration/testUtils/usersService.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx (1)

39-43: Localize revoke input and handle API errors

  • Replace hard-coded label/placeholder with localization keys.
  • Wrap revoke() in try/catch and use handleError to surface failures.

Example:

-  const revokeField = useFormControl('apiKeyRevokeConfirmation', '', {
-    type: 'text',
-    label: `Type "Revoke" to confirm`,
-    placeholder: 'Revoke',
-    isRequired: true,
-  });
+  const revokeField = useFormControl('apiKeyRevokeConfirmation', '', {
+    type: 'text',
+    label: localizationKeys('formFieldLabel__confirmDeletion'),
+    placeholder: localizationKeys('apiKeys.revokeConfirmation.confirmationText'),
+    isRequired: true,
+  });
@@
-    await clerk.apiKeys.revoke({ apiKeyID: apiKeyId });
+    try {
+      await clerk.apiKeys.revoke({ apiKeyID: apiKeyId });
+    } catch (e) {
+      // Use the standard error utility to report and localize the error
+      // handleError(e);
+      return;
+    }

Note: import and exact handleError path per project conventions. Based on coding guidelines.

Also applies to: 52-63

♻️ Duplicate comments (1)
packages/clerk-js/src/ui/elements/ClipboardInput.tsx (1)

13-15: Fix a11y and form behavior; add return type (same as previously requested)

  • Remove tabIndex={-1} to keep the button focusable.
  • Add aria-label and type='button' to avoid accidental form submit.
  • Add explicit return type for the exported component.
-export const ClipboardInput = (props: ClipboardInputProps) => {
+export const ClipboardInput = (props: ClipboardInputProps): JSX.Element => {
@@
-      <Button
+      <Button
         elementDescriptor={descriptors.formFieldInputCopyToClipboardButton}
         variant='ghost'
-        tabIndex={-1}
         onClick={onCopy}
+        aria-label='Copy to clipboard'
+        type='button'
         sx={{
           position: 'absolute',
           right: 0,
         }}
       >

Optional: defensively coerce value for useClipboard:

-  const { onCopy, hasCopied } = useClipboard(value as string);
+  const { onCopy, hasCopied } = useClipboard(String(value ?? ''));

Also applies to: 30-46

🧹 Nitpick comments (6)
packages/localizations/src/he-IL.ts (1)

20-24: LGTM - Structure is correct for the new copy secret modal.

The nested copySecret object correctly extends the API keys localization with the required fields for the one-time secret display modal. While the values are undefined (no Hebrew translations provided yet), this is consistent with the community-contributed nature of this file where many translations are pending.

Consider providing Hebrew translations for these new fields to improve the user experience for Hebrew-speaking users, though this can be deferred to a future contribution.

packages/localizations/src/es-UY.ts (2)

20-24: Structure looks good; consider adding Spanish translations.

The copySecret nested object follows the established pattern and correctly implements the localization structure for the one-time API key secret display feature. The undefined values are consistent with this file's community-maintained status.

However, since this is a security-critical feature, providing Spanish translations for these fields would significantly improve the user experience for Uruguayan Spanish speakers.

Consider adding translations for:

  • formButtonPrimary__copyAndClose: e.g., "Copiar y cerrar"
  • formHint: Appropriate hint text about the one-time nature of the secret display
  • formTitle: e.g., "Clave secreta de API" or similar
     copySecret: {
-      formButtonPrimary__copyAndClose: undefined,
-      formHint: undefined,
-      formTitle: undefined,
+      formButtonPrimary__copyAndClose: 'Copiar y cerrar',
+      formHint: 'Guardá esta clave de forma segura. Solo se mostrará una vez.',
+      formTitle: 'Clave secreta de API',
     },

230-230: Label field correctly added; translation recommended.

The formFieldLabel__apiKey field is properly positioned and follows the established naming convention. The undefined value is consistent with the file's current state.

Consider adding a Spanish translation to improve UX:

-  formFieldLabel__apiKey: undefined,
+  formFieldLabel__apiKey: 'Clave de API',
integration/tests/machine-auth/component.test.ts (1)

133-147: Consider moving permission cleanup to ensure it runs even on test failure.

The clipboard permissions are granted and cleared within the test flow, but if the test fails before reaching line 146, permissions may not be cleaned up. Consider using a try-finally block or moving the cleanup to an appropriate lifecycle hook.

Example approach:

-    // Grant clipboard permissions before clicking the button
     await context.grantPermissions(['clipboard-read']);
+    
+    try {
+      // Click "Copy & Close" button which will copy the secret and close the modal
+      const copyAndCloseButton = copyModal.locator('.cl-apiKeysCopyModalSubmitButton');
+      await copyAndCloseButton.waitFor({ state: 'attached' });
+      await copyAndCloseButton.click();

-    // Click "Copy & Close" button which will copy the secret and close the modal
-    const copyAndCloseButton = copyModal.locator('.cl-apiKeysCopyModalSubmitButton');
-    await copyAndCloseButton.waitFor({ state: 'attached' });
-    await copyAndCloseButton.click();
+      // Wait for modal to close
+      await copyModal.waitFor({ state: 'detached' });

-    // Wait for modal to close
-    await copyModal.waitFor({ state: 'detached' });
+      // Read clipboard contents to verify the secret was copied
+      const clipboardText = await page.evaluate('navigator.clipboard.readText()');
+      expect(clipboardText).toBe(secret);
+    } finally {
+      await context.clearPermissions();
+    }
-
-    // Read clipboard contents to verify the secret was copied
-    const clipboardText = await page.evaluate('navigator.clipboard.readText()');
-    await context.clearPermissions();
-    expect(clipboardText).toBe(secret);
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (2)

32-36: Use a more descriptive ID for the form control.

The form control ID is set to 'name', but this field displays the API key secret, not a name. Consider using a more descriptive identifier like 'apiKeySecret' or 'apiKey' to improve code clarity and avoid potential conflicts.

Apply this diff:

-  const apiKeyField = useFormControl('name', apiKeySecret, {
+  const apiKeyField = useFormControl('apiKeySecret', apiKeySecret, {
     type: 'text',
     label: localizationKeys('formFieldLabel__apiKey'),
     isRequired: false,
   });

76-84: Consider simplifying the read-only field implementation.

The useFormControl hook provides interactive form field machinery (onChange, onFocus, validation, etc.), but ClipboardInput is inherently read-only and disabled. The form control logic isn't actively used here. Consider whether a simpler approach with just a label and the ClipboardInput would be more appropriate.

Alternative approach:

<Form.ControlRow
  elementDescriptor={descriptors.apiKeysCopyModalInput}
  sx={{ flex: 1 }}
>
  <Form.Label localizationKey={localizationKeys('formFieldLabel__apiKey')} />
  <ClipboardInput
    value={apiKeySecret}
    readOnly
    sx={{ width: '100%' }}
    copyIcon={ClipboardOutline}
    copiedIcon={Check}
  />
</Form.ControlRow>

However, if Form.CommonInputWrapper provides necessary styling or structure for consistency with other forms, the current approach is acceptable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4fb8000 and 03a3651.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (59)
  • integration/tests/machine-auth/component.test.ts (2 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (5 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts (1 hunks)
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts (1 hunks)
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx (2 hunks)
  • packages/clerk-js/src/ui/elements/Form.tsx (1 hunks)
  • packages/localizations/src/ar-SA.ts (2 hunks)
  • packages/localizations/src/be-BY.ts (2 hunks)
  • packages/localizations/src/bg-BG.ts (2 hunks)
  • packages/localizations/src/bn-IN.ts (2 hunks)
  • packages/localizations/src/ca-ES.ts (2 hunks)
  • packages/localizations/src/cs-CZ.ts (2 hunks)
  • packages/localizations/src/da-DK.ts (2 hunks)
  • packages/localizations/src/de-DE.ts (2 hunks)
  • packages/localizations/src/el-GR.ts (2 hunks)
  • packages/localizations/src/en-GB.ts (2 hunks)
  • packages/localizations/src/en-US.ts (2 hunks)
  • packages/localizations/src/es-CR.ts (2 hunks)
  • packages/localizations/src/es-ES.ts (2 hunks)
  • packages/localizations/src/es-MX.ts (2 hunks)
  • packages/localizations/src/es-UY.ts (2 hunks)
  • packages/localizations/src/fa-IR.ts (2 hunks)
  • packages/localizations/src/fi-FI.ts (2 hunks)
  • packages/localizations/src/fr-FR.ts (2 hunks)
  • packages/localizations/src/he-IL.ts (2 hunks)
  • packages/localizations/src/hi-IN.ts (2 hunks)
  • packages/localizations/src/hr-HR.ts (2 hunks)
  • packages/localizations/src/hu-HU.ts (2 hunks)
  • packages/localizations/src/id-ID.ts (2 hunks)
  • packages/localizations/src/is-IS.ts (2 hunks)
  • packages/localizations/src/it-IT.ts (2 hunks)
  • packages/localizations/src/ja-JP.ts (2 hunks)
  • packages/localizations/src/kk-KZ.ts (2 hunks)
  • packages/localizations/src/ko-KR.ts (2 hunks)
  • packages/localizations/src/mn-MN.ts (2 hunks)
  • packages/localizations/src/ms-MY.ts (2 hunks)
  • packages/localizations/src/nb-NO.ts (2 hunks)
  • packages/localizations/src/nl-BE.ts (2 hunks)
  • packages/localizations/src/nl-NL.ts (2 hunks)
  • packages/localizations/src/pl-PL.ts (2 hunks)
  • packages/localizations/src/pt-BR.ts (2 hunks)
  • packages/localizations/src/pt-PT.ts (2 hunks)
  • packages/localizations/src/ro-RO.ts (2 hunks)
  • packages/localizations/src/ru-RU.ts (2 hunks)
  • packages/localizations/src/sk-SK.ts (2 hunks)
  • packages/localizations/src/sr-RS.ts (2 hunks)
  • packages/localizations/src/sv-SE.ts (2 hunks)
  • packages/localizations/src/ta-IN.ts (2 hunks)
  • packages/localizations/src/te-IN.ts (2 hunks)
  • packages/localizations/src/th-TH.ts (2 hunks)
  • packages/localizations/src/tr-TR.ts (2 hunks)
  • packages/localizations/src/uk-UA.ts (2 hunks)
  • packages/localizations/src/vi-VN.ts (2 hunks)
  • packages/localizations/src/zh-CN.ts (2 hunks)
  • packages/localizations/src/zh-TW.ts (2 hunks)
  • packages/shared/src/types/appearance.ts (1 hunks)
  • packages/shared/src/types/localization.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (33)
  • packages/localizations/src/kk-KZ.ts
  • packages/localizations/src/is-IS.ts
  • packages/localizations/src/es-MX.ts
  • packages/localizations/src/mn-MN.ts
  • packages/localizations/src/ru-RU.ts
  • packages/localizations/src/tr-TR.ts
  • packages/localizations/src/en-US.ts
  • packages/localizations/src/pt-BR.ts
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
  • packages/localizations/src/de-DE.ts
  • packages/localizations/src/es-ES.ts
  • packages/localizations/src/hr-HR.ts
  • packages/localizations/src/it-IT.ts
  • packages/localizations/src/uk-UA.ts
  • packages/localizations/src/es-CR.ts
  • packages/localizations/src/th-TH.ts
  • packages/localizations/src/ar-SA.ts
  • packages/localizations/src/zh-TW.ts
  • packages/localizations/src/ms-MY.ts
  • packages/localizations/src/fi-FI.ts
  • packages/localizations/src/pl-PL.ts
  • packages/localizations/src/nb-NO.ts
  • packages/localizations/src/fa-IR.ts
  • packages/localizations/src/ca-ES.ts
  • packages/localizations/src/en-GB.ts
  • packages/localizations/src/ja-JP.ts
  • packages/localizations/src/sr-RS.ts
  • packages/localizations/src/pt-PT.ts
  • packages/localizations/src/hu-HU.ts
  • packages/localizations/src/fr-FR.ts
  • packages/shared/src/types/localization.ts
  • packages/localizations/src/bn-IN.ts
  • packages/localizations/src/nl-BE.ts
🧰 Additional context used
📓 Path-based instructions (14)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • integration/tests/machine-auth/component.test.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • integration/tests/machine-auth/component.test.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • integration/tests/machine-auth/component.test.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/utils.ts
  • packages/localizations/src/zh-CN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/localizations/src/vi-VN.ts
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • integration/tests/machine-auth/component.test.ts
  • packages/localizations/src/id-ID.ts
  • packages/shared/src/types/appearance.ts
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/clerk-js/src/ui/elements/Form.tsx
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
packages/localizations/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Localization files must be placed in 'packages/localizations/'.

Files:

  • packages/localizations/src/zh-CN.ts
  • packages/localizations/src/vi-VN.ts
  • packages/localizations/src/ko-KR.ts
  • packages/localizations/src/el-GR.ts
  • packages/localizations/src/he-IL.ts
  • packages/localizations/src/hi-IN.ts
  • packages/localizations/src/nl-NL.ts
  • packages/localizations/src/id-ID.ts
  • packages/localizations/src/sv-SE.ts
  • packages/localizations/src/cs-CZ.ts
  • packages/localizations/src/bg-BG.ts
  • packages/localizations/src/be-BY.ts
  • packages/localizations/src/da-DK.ts
  • packages/localizations/src/ro-RO.ts
  • packages/localizations/src/es-UY.ts
  • packages/localizations/src/sk-SK.ts
  • packages/localizations/src/te-IN.ts
  • packages/localizations/src/ta-IN.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/clerk-js/src/ui/elements/Form.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
  • packages/clerk-js/src/ui/elements/ClipboardInput.tsx
  • packages/clerk-js/src/ui/elements/Form.tsx
integration/**

📄 CodeRabbit inference engine (.cursor/rules/global.mdc)

Framework integration templates and E2E tests should be placed under the integration/ directory

Files:

  • integration/tests/machine-auth/component.test.ts
integration/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

End-to-end tests and integration templates must be located in the 'integration/' directory.

Files:

  • integration/tests/machine-auth/component.test.ts
integration/**/*.{test,spec}.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Integration tests should use Playwright.

Files:

  • integration/tests/machine-auth/component.test.ts
packages/clerk-js/src/ui/customizables/elementDescriptors.ts

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

Append new element descriptors to APPEARANCE_KEYS in packages/clerk-js/src/ui/customizables/elementDescriptors.ts

Files:

  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
🧠 Learnings (1)
📚 Learning: 2025-07-18T15:25:18.331Z
Learnt from: CR
Repo: clerk/javascript PR: 0
File: .cursor/rules/clerk-js-ui.mdc:0-0
Timestamp: 2025-07-18T15:25:18.331Z
Learning: Applies to packages/clerk-js/src/ui/customizables/elementDescriptors.ts : Append new element descriptors to APPEARANCE_KEYS in packages/clerk-js/src/ui/customizables/elementDescriptors.ts

Applied to files:

  • packages/clerk-js/src/ui/customizables/elementDescriptors.ts
🧬 Code graph analysis (4)
packages/clerk-js/src/ui/components/ApiKeys/utils.ts (1)
packages/clerk-js/src/ui/styledSystem/types.ts (1)
  • ThemableCssProp (58-58)
packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx (1)
packages/clerk-js/src/ui/components/ApiKeys/utils.ts (1)
  • getApiKeyModalContainerStyles (8-29)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (6)
packages/clerk-js/src/ui/utils/useFormControl.ts (1)
  • useFormControl (97-189)
packages/clerk-js/src/ui/elements/Modal.tsx (1)
  • Modal (25-108)
packages/clerk-js/src/ui/components/ApiKeys/utils.ts (1)
  • getApiKeyModalContainerStyles (8-29)
packages/clerk-js/src/ui/elements/FormContainer.tsx (1)
  • FormContainer (20-61)
packages/clerk-js/src/ui/elements/ClipboardInput.tsx (1)
  • ClipboardInput (13-48)
packages/clerk-js/src/ui/elements/FormButtons.tsx (1)
  • FormButtons (16-36)
packages/clerk-js/src/ui/elements/ClipboardInput.tsx (2)
packages/clerk-js/src/ui/styledSystem/types.ts (1)
  • PropsOfComponent (58-58)
packages/clerk-js/src/ui/customizables/index.ts (1)
  • Flex (16-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (35)
packages/localizations/src/nl-NL.ts (2)

20-24: LGTM! New localization structure added correctly.

The new copySecret nested object under apiKeys is properly structured and follows the established pattern of using undefined for untranslated strings in this community-maintained locale file. This addition supports the new one-time API key secret display modal feature.


228-228: LGTM! Form field label added correctly.

The new formFieldLabel__apiKey field is properly placed among the other form field labels and follows the consistent pattern of using undefined for missing translations in this community-maintained locale.

packages/localizations/src/te-IN.ts (2)

20-24: LGTM! New API key copy secret localization structure added correctly.

The new copySecret nested object follows the correct structure and naming conventions. The undefined values are appropriate for this community-contributed locale, allowing fallback to the default language until Telugu translations are provided.


228-228: LGTM! API key form field label added correctly.

The new formFieldLabel__apiKey field is correctly placed in the form field labels section and follows the established naming convention. The undefined value is appropriate for this community-contributed locale.

packages/localizations/src/be-BY.ts (2)

20-24: LGTM! Localization structure correctly added for one-time secret display.

The copySecret nested object is properly structured to support the new one-time API key secret display modal. The field names follow established conventions, and undefined values are appropriate for this community-maintained locale pending translation.


230-230: LGTM! API key form field label correctly added.

The formFieldLabel__apiKey field is properly placed among other form field labels and follows the established naming convention. The undefined value is appropriate for this community-maintained locale.

packages/localizations/src/ta-IN.ts (2)

20-24: Structure for "copy secret" modal added correctly.

The nested copySecret object with its three fields follows the existing naming conventions and aligns with the PR's objective to support one-time secret display functionality. The undefined values indicate that Tamil translations are pending, which is acceptable for this community-contributed locale file (as noted in the file's disclaimer).


229-229: API key label field added correctly.

The formFieldLabel__apiKey field follows the established naming pattern and is positioned logically within the form field labels section. The undefined value indicates that a Tamil translation is pending, consistent with other untranslated fields in this community-contributed locale file.

packages/localizations/src/he-IL.ts (1)

228-228: LGTM - Correctly adds API key form field label.

The formFieldLabel__apiKey field is properly placed within the form field labels section and follows the established naming convention. Like other fields in this community-contributed localization file, the Hebrew translation is pending (undefined).

packages/localizations/src/id-ID.ts (2)

20-24: LGTM! Structure follows established patterns.

The new copySecret object is correctly structured and follows the same pattern as other nested objects in this file (e.g., revokeConfirmation at lines 48-53). The undefined values are appropriate for this community-maintained localization file awaiting Indonesian translations.


228-228: LGTM! Correctly placed and named.

The new formFieldLabel__apiKey field follows the established naming convention and is appropriately placed among other form field labels. The undefined value is consistent with this community-maintained localization file.

packages/localizations/src/el-GR.ts (2)

20-24: LGTM! Structure is consistent with localization patterns.

The new copySecret nested group follows the established structure and naming conventions. The undefined values are appropriate for this community-contributed locale—translations can be provided by Greek-speaking contributors in the future.


229-229: LGTM! Consistent placement and naming.

The formFieldLabel__apiKey field is correctly placed alongside other form field labels and follows the established naming convention. The undefined value is expected for this community-contributed locale.

packages/localizations/src/da-DK.ts (2)

20-24: Structural changes look good.

The addition of the copySecret object under apiKeys aligns with the PR objective to display API key secrets one-time after creation. The field names follow proper naming conventions and the structure matches the expected localization pattern.

Note: The undefined values mean Danish users will see fallback strings (likely English) for these new features, which is acceptable for a community-contributed localization file per the disclaimer at the top of the file.


229-229: Field addition is correct.

The formFieldLabel__apiKey field is properly placed among other form field labels and follows the established naming convention. This supports the new API key UI elements introduced in this PR.

packages/localizations/src/sv-SE.ts (2)

20-24: LGTM! Structure is correct for the new API key secret copy feature.

The nested copySecret group follows the established localization pattern and aligns with the PR's one-time secret display functionality. The undefined values are acceptable for this community-maintained locale file per the disclaimer at the top—Swedish users will see fallback translations until community contributors provide Swedish text.


229-229: LGTM! New form field label follows conventions.

The formFieldLabel__apiKey key follows the established naming pattern and is correctly positioned among other form field labels. The undefined value is consistent with this community-maintained file.

packages/localizations/src/hi-IN.ts (2)

20-24: LGTM! Structure is correct for the one-time API key secret modal.

The new copySecret nested object under apiKeys follows the correct structure for the one-time secret display feature. The undefined values are consistent with this file's pattern as a community-contributed locale where translations are not fully provided.


228-228: LGTM! Correctly adds the API key field label.

The new formFieldLabel__apiKey field is properly placed at the root level, following the naming convention and pattern used throughout the file. The undefined value is appropriate for this community-contributed locale.

packages/localizations/src/ko-KR.ts (2)

20-24: LGTM! Structure and placement are correct.

The new copySecret object is properly nested within apiKeys and follows the established naming conventions. The undefined values are expected for this community-contributed localization file as noted in the disclaimer.


229-229: LGTM! Consistent placement and naming.

The new formFieldLabel__apiKey key is correctly placed at the root level alongside other formFieldLabel__* keys, following the established pattern in this localization file.

packages/localizations/src/cs-CZ.ts (2)

20-24: Structure is correct; translations pending.

The new copySecret localization group is properly structured and follows established naming conventions. The undefined values are consistent with the file's disclaimer indicating this is a community-maintained localization that may have incomplete translations.

Note: Czech translations for the new API key secret copy modal are missing. While this is acceptable given the community-maintained nature of this locale, consider tracking these for future translation completion to ensure Czech users have a complete experience.


233-233: Field addition is correct; translation missing.

The new formFieldLabel__apiKey field is properly placed and follows the established naming convention for form field labels. The undefined value is consistent with this locale's pattern for untranslated strings.

As with the copySecret group, consider adding this to the translation backlog for Czech locale completion.

packages/localizations/src/ro-RO.ts (2)

20-24: LGTM: Copy secret modal localization structure added correctly.

The new copySecret nested object follows the established pattern and supports the one-time API key secret display feature. Using undefined values is appropriate for this community-contributed localization file, as stated in the file header disclaimer.


235-235: LGTM: API key form field label added correctly.

The new formFieldLabel__apiKey property is properly placed among other form field labels and follows the established naming convention. The undefined value is appropriate given this is a community-contributed localization file.

packages/localizations/src/vi-VN.ts (2)

233-233: LGTM: Form field label key added in correct location.

The formFieldLabel__apiKey field is properly placed within the form field labels section with appropriate naming convention. The undefined value is consistent with other untranslated strings in this community-contributed locale file.


20-24: Localization structure correctly aligned with source locale.

The copySecret nested group in vi-VN.ts has the correct structure matching the English locale, with appropriately named fields (formButtonPrimary__copyAndClose, formHint, formTitle). The undefined values are expected for this community-contributed file where Vietnamese translations are pending—the application will automatically fall back to English text for these strings.

packages/localizations/src/bg-BG.ts (1)

20-24: Locales surface aligned for copy-secret flow

Keys and shapes look correct; OK to ship with undefined placeholders (falls back to default locale). Please ensure all locales include these keys consistently.

Also applies to: 229-229

packages/localizations/src/zh-CN.ts (1)

20-24: Locales surface aligned for copy-secret flow

Additions match shared typings and other locales. Good to merge.

Also applies to: 228-229

packages/localizations/src/sk-SK.ts (1)

20-24: Locales surface aligned for copy-secret flow

Keys are correct and consistent. Approved.

Also applies to: 229-229

packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx (1)

75-76: Centralized modal container styling LGTM

Using getApiKeyModalContainerStyles improves consistency. Good change.

packages/shared/src/types/appearance.ts (1)

633-636: Appearance types updated for API key copy modal

New element entries look correct and align with UI usage.

packages/clerk-js/src/ui/customizables/elementDescriptors.ts (1)

498-501: Descriptors synced with new appearance keys

Additions are correct and camelCase. Good to go.

packages/clerk-js/src/ui/components/ApiKeys/utils.ts (1)

1-29: LGTM!

The utility function is well-structured with clear JSDoc documentation. The conditional styling logic correctly handles both custom modal root and default scenarios, and the type safety is properly maintained with ThemableCssProp.

packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1)

49-96: Excellent accessibility and security implementation.

The modal correctly uses role='alertdialog' for accessibility and canCloseModal={false} to ensure users cannot accidentally dismiss the one-time secret display without explicitly copying it. All user-facing text is properly localized, and element descriptors follow the camelCase convention for consistent theming.

@blacksmith-sh
Copy link

blacksmith-sh bot commented Nov 3, 2025

Found 9 test failures on Blacksmith runners:

Test View Logs
[chrome] › integration/tests/
dynamic-keys.test.ts:68:7 › dynamic keys @nextjs › redirects to signInUrl on await a</code><br /><code>uth.protect()
View Logs
[chrome] › integration/tests/machine-auth/
component.test.ts:29:7 › api keys component @machine › long-running--withMachine.next.a
ppRouter › can create api keys
View Logs
[chrome] › integration/tests/
pricing-table.test.ts:163:9 › pricing table @billing › long-running--withBilling.astro.
node › when signed in flow › can downgrade to previous plan
View Logs
[chrome] › integration/tests/
pricing-table.test.ts:163:9 › pricing table @billing › long-running--withBilling.next.a
ppRouter › when signed in flow › can downgrade to previous plan
View Logs
[chrome] › integration/tests/
pricing-table.test.ts:163:9 › pricing table @billing › long-running--withBilling.vue.vi
te › when signed in flow › can downgrade to previous plan
View Logs
[chrome] › integration/tests/
pricing-table.test.ts:588:9 › pricing table @billing › long-running--withBilling.next.a
ppRouter › in UserProfile › adds payment method via checkout and resets stripe setup in
tent after failed payment
View Logs
[chrome] › integration/tests/
pricing-table.test.ts:658:9 › pricing table @billing › long-running--withBilling.next.a
ppRouter › in UserProfile › adds two payment methods and sets the last as default
View Logs
[chrome] › integration/tests/
session-tasks-eject-flow.test.ts:88:7 › session tasks eject flow @nextjs › redirects to
completion page after resolving task
View Logs
[chrome] › integration/tests/
session-tasks-multi-session.test.ts:33:9 › session tasks multi-session flow @nextjs › l
ong-running--next.appRouter.withSessionTasks › when switching sessions, navigate to tas
k
View Logs


Fix in Cursor

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (2)

31-35: Simplify: useFormControl appears unnecessary for read-only display.

The form control state is initialized with apiKeySecret but never modified, and the ClipboardInput receives its value directly (line 76) rather than from the form control state. Since this is a read-only display, consider removing useFormControl and passing only the label to Form.CommonInputWrapper.

If the label is the only needed metadata, refactor to:

- const apiKeyField = useFormControl('name', apiKeySecret, {
-   type: 'text',
-   label: localizationKeys('formFieldLabel__apiKey'),
-   isRequired: false,
- });
+ const label = localizationKeys('formFieldLabel__apiKey');

Then update the wrapper:

-                <Form.CommonInputWrapper {...apiKeyField.props}>
+                <Form.CommonInputWrapper label={label}>
                   <ClipboardInput
                     value={apiKeySecret}
                     readOnly
                     sx={{ width: '100%' }}
                     copyIcon={ClipboardOutline}
                     copiedIcon={Check}
                   />
                 </Form.CommonInputWrapper>

Note: Verify that Form.CommonInputWrapper accepts a simple label prop. If it requires the full form control props structure, this change may not be applicable and the current pattern is acceptable despite appearing redundant.


31-31: Use a more descriptive form control ID.

The form control ID is set to 'name', which doesn't clearly describe the field's purpose. Consider using 'apiKeySecret' or 'apiKey' for better semantic clarity.

Apply this diff:

- const apiKeyField = useFormControl('name', apiKeySecret, {
+ const apiKeyField = useFormControl('apiKeySecret', apiKeySecret, {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 17bbb98 and 9209f76.

📒 Files selected for processing (3)
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/src/ui/components/ApiKeys/RevokeAPIKeyConfirmationModal.tsx
🧰 Additional context used
📓 Path-based instructions (9)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
🧬 Code graph analysis (2)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx (1)
packages/clerk-js/src/ui/elements/Modal.tsx (1)
  • Modal (25-108)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (6)
packages/clerk-js/src/ui/utils/useFormControl.ts (1)
  • useFormControl (97-189)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx (1)
  • ApiKeyModal (36-44)
packages/clerk-js/src/ui/elements/FormContainer.tsx (1)
  • FormContainer (20-61)
packages/clerk-js/src/ui/elements/Form.tsx (1)
  • Form (309-322)
packages/clerk-js/src/ui/elements/ClipboardInput.tsx (1)
  • ClipboardInput (13-48)
packages/clerk-js/src/ui/elements/FormButtons.tsx (1)
  • FormButtons (16-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (2)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1)

48-94: Security and UX implementation aligns with PR objectives.

The modal correctly implements one-time secret display:

  • canCloseModal={false} prevents accidental dismissal before copying
  • role='alertdialog' provides appropriate accessibility semantics
  • handleSubmit ensures the secret is copied before closing
  • Read-only ClipboardInput prevents modification

This aligns with the security enhancement described in USER-3698.

packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx (1)

1-44: LGTM! Clean portal-scoped modal wrapper implementation.

The ApiKeyModal component provides a well-structured abstraction for rendering modals within scoped containers (e.g., UserProfile, OrganizationProfile):

  • getScopedPortalContainerStyles correctly handles both document-root and scoped portal scenarios with appropriate positioning (absolute vs. fixed) and backdrop styling.
  • JSDoc clearly documents the rationale for custom container styles.
  • Props are properly typed by extending Modal props.
  • Style merging via array syntax allows consumer-provided containerSx to override defaults.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (2)

71-76: Reuse of list cache key for mutation causes cache conflicts and stale list data.

This issue was flagged in a previous review but remains unaddressed. Using cacheKey for both the list query and the create mutation can cause:

  1. Cache shape conflicts (list returns array/paginated data, create returns a single API key object)
  2. The newly created API key won't appear in the list until manual refresh

Apply this fix:

+import { useSWRConfig } from 'swr';
+
 export const APIKeysPage = ({ subject, perPage, revokeModalRoot }: APIKeysPageProps) => {
   // ... existing code ...
   const clerk = useClerk();
   const {
     data: createdApiKey,
     trigger: createApiKey,
     isMutating,
-  } = useSWRMutation(cacheKey, (_key, { arg }: { arg: CreateAPIKeyParams }) => clerk.apiKeys.create(arg));
+  } = useSWRMutation(`${cacheKey}/create`, (_key, { arg }: { arg: CreateAPIKeyParams }) => clerk.apiKeys.create(arg));
+  const { mutate } = useSWRConfig();

Then in handleCreateApiKey, revalidate the list after successful creation:

   const handleCreateApiKey = async (params: OnCreateParams) => {
     try {
       await createApiKey({
         ...params,
         subject,
       });
+      await mutate(cacheKey); // Refresh the list
       card.setError(undefined);
       setIsCopyModalOpen(true);
     } catch (err: any) {

160-167: Gate modal opening on secret presence—secret field is optional and can be undefined.

The secret field in APIKeyResource is defined as optional (secret?: string; in APIKey.ts). When handleCreateApiKey succeeds, the modal opens unconditionally without verifying that the secret was returned from the backend. If the API response omits the secret field, CopyApiKeyModal displays an empty field and the user cannot retrieve their newly created API key.

Update handleCreateApiKey to verify the secret exists before opening the modal:

  const handleCreateApiKey = async (params: OnCreateParams) => {
    try {
-     await createApiKey({
+     const result = await createApiKey({
        ...params,
        subject,
      });
      card.setError(undefined);
-     setIsCopyModalOpen(true);
+     if (result?.secret) {
+       setIsCopyModalOpen(true);
+     } else {
+       card.setError('API key created but secret not available');
+     }
    } catch (err: any) {
🧹 Nitpick comments (1)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (1)

82-97: Signature change correct; consider comprehensive error handling.

The removal of closeCardFn parameter aligns with the new modal flow.

However, error handling only covers the 409 conflict case. Other API errors may not set a user-visible error message.

Consider handling generic errors:

     } catch (err: any) {
       if (isClerkAPIResponseError(err)) {
         if (err.status === 409) {
           card.setError('API Key name already exists');
+        } else {
+          card.setError(err.errors?.[0]?.message || 'Failed to create API key');
         }
+      } else {
+        card.setError('An unexpected error occurred');
       }
     }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a0838b1 and b5254e8.

📒 Files selected for processing (3)
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (4 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
🧰 Additional context used
📓 Path-based instructions (9)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx
  • packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
🧬 Code graph analysis (1)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (3)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1)
  • CopyApiKeyModal (24-98)
packages/shared/src/types/clerk.ts (1)
  • CreateAPIKeyParams (1973-1979)
packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx (1)
  • OnCreateParams (23-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/clerk-js/src/ui/components/ApiKeys/CreateApiKeyForm.tsx (2)

30-30: LGTM - Signature simplification aligns with new modal flow.

Removing closeCardFn from the onCreate callback is correct. The form no longer needs to close the card on successful creation since the parent now opens a copy modal instead.


165-172: LGTM - Call site correctly updated.

The onCreate call correctly passes only the params object, matching the updated signature.

packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx (1)

45-49: LGTM - Proper lazy loading.

The CopyApiKeyModal is correctly lazy-loaded with appropriate webpack chunk naming, consistent with the existing modal pattern.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (3)

32-36: Simplify by removing unnecessary useFormControl.

The useFormControl hook is not needed here since the ClipboardInput is read-only and receives the apiKeySecret value directly. The form control adds unnecessary state management overhead without providing validation, transformation, or user interaction capabilities.

Apply this diff to simplify:

-  const apiKeyField = useFormControl('name', apiKeySecret, {
-    type: 'text',
-    label: localizationKeys('formFieldLabel__apiKey'),
-    isRequired: false,
-  });
-

And update the Form.ControlRow to remove the wrapper:

-              <Form.ControlRow
-                elementDescriptor={descriptors.apiKeysCopyModalInput}
-                sx={{ flex: 1 }}
-              >
-                <Form.CommonInputWrapper {...apiKeyField.props}>
-                  <ClipboardInput
-                    value={apiKeySecret}
-                    readOnly
-                    sx={{ width: '100%' }}
-                    copyIcon={ClipboardOutline}
-                    copiedIcon={Check}
-                  />
-                </Form.CommonInputWrapper>
-              </Form.ControlRow>
+              <Form.ControlRow
+                elementDescriptor={descriptors.apiKeysCopyModalInput}
+                sx={{ flex: 1 }}
+              >
+                <ClipboardInput
+                  value={apiKeySecret}
+                  readOnly
+                  sx={{ width: '100%' }}
+                  copyIcon={ClipboardOutline}
+                  copiedIcon={Check}
+                />
+              </Form.ControlRow>

And remove the import:

-import { useFormControl } from '@/ui/utils/useFormControl';

38-47: Clarify duplicate copy mechanism and setTimeout delay.

Two observations:

  1. Duplicate clipboard management: Both the component-level useClipboard (line 38) and the ClipboardInput (line 80) manage clipboard operations independently. Users can copy via the ClipboardInput's copy button OR the form's submit button, both triggering separate copy actions. Consider whether both copy mechanisms are intentional or if the submit button should only close the modal (since ClipboardInput already provides copy functionality).

  2. Unexplained delay: The setTimeout with a 100ms delay before closing the action card (line 44-46) lacks explanation. Document why this delay is necessary (e.g., animation timing, state cleanup) or consider removing it if it's not required.


60-72: Consider adding ARIA attributes for enhanced accessibility.

The role='alertdialog' is appropriate for a modal requiring user action. To further improve accessibility, consider adding aria-labelledby and aria-describedby attributes pointing to the form title and hint elements.

Example enhancement:

       <Card.Root
         role='alertdialog'
+        aria-labelledby='copy-api-key-title'
+        aria-describedby='copy-api-key-hint'
         elementDescriptor={descriptors.apiKeysCopyModal}
       >

And ensure the FormContainer's header elements have corresponding IDs (may require adjustments to FormContainer component to accept id props).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b5254e8 and 4aeab7b.

📒 Files selected for processing (1)
  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx
🧬 Code graph analysis (1)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (5)
packages/clerk-js/src/ui/utils/useFormControl.ts (1)
  • useFormControl (97-189)
packages/clerk-js/src/ui/components/ApiKeys/ApiKeyModal.tsx (1)
  • ApiKeyModal (36-44)
packages/clerk-js/src/ui/elements/FormContainer.tsx (1)
  • FormContainer (20-61)
packages/clerk-js/src/ui/elements/ClipboardInput.tsx (1)
  • ClipboardInput (13-48)
packages/clerk-js/src/ui/elements/FormButtons.tsx (1)
  • FormButtons (16-36)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/clerk-js/src/ui/components/ApiKeys/CopyApiKeyModal.tsx (1)

53-99: Well-structured implementation of one-time secret display.

The modal correctly implements the PR objective of showing API key secrets only once:

  • canCloseModal={false} prevents accidental dismissal
  • Explicit user action (copy and close) required
  • Proper localization and theming throughout
  • Clean component structure with appropriate hooks

The implementation aligns with security best practices for sensitive credential display.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants