Skip to content

feat(repo): Introduce oxlint #6105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

feat(repo): Introduce oxlint #6105

wants to merge 5 commits into from

Conversation

tmilewski
Copy link
Member

@tmilewski tmilewski commented Jun 11, 2025

Description

This PR introduces Oxlint 1.0 as Oxlint is unbelievably faster than ESLint:

Run ESLint Oxlint Speedup
1 45.327s 1.872s 95.9%
2 41.749s 1.823s 95.6%

Commands:

  • ESLint: turbo lint --filter=\!@clerk/localizations --force --only
  • Oxlint: turbo lint:oxlint --filter=\!@clerk/localizations --force --only

(NOTE: @clerk/localizations wouldn't complete with ESLint.)

PR Notes:

  • This PR adds Oxlint to complement ESLint.
  • The Turbo lint task now depends on lint:oxlint so, if there's an error, it fails fast.
  • Whenever we feel confident enough, we can remove ESLint rules covered by Oxlint via eslint-plugin-oxlint.

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

    • Introduced Oxlint as a linter across the codebase with a shared configuration and scripts for consistent code quality checks.
    • Added new linting commands to project and package scripts for easy linting with Oxlint.
    • Enhanced URL validation to explicitly check for null byte characters.
  • Bug Fixes

    • Improved type handling in React components to support broader return types.
  • Chores

    • Added lint suppression comments to address specific linting rule violations.
    • Updated task runner configuration to integrate new linting workflows.
    • Minor cleanup in error handling and script formatting.

@tmilewski tmilewski self-assigned this Jun 11, 2025
Copy link

changeset-bot bot commented Jun 11, 2025

🦋 Changeset detected

Latest commit: 82f10bb

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

Copy link

vercel bot commented Jun 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
clerk-js-sandbox ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 6:28pm

Copy link
Contributor

coderabbitai bot commented Jun 11, 2025

📝 Walkthrough

Walkthrough

This update introduces OXLint as a new linting tool across the repository. A root configuration file for OXLint is added, and package scripts are updated to include OXLint commands for individual packages. Inline lint rule suppression comments are inserted in source files to address specific OXLint warnings. The monorepo's task runner configuration is updated to incorporate the new linting workflow.

Changes

File(s) Change Summary
.oxlintrc.json Added comprehensive OXLint configuration specifying rules, environments, plugins, overrides, and ignores.
package.json Added OXLint as a devDependency and new script "oxlint": "oxlint --quiet".
turbo.json Added new "lint" task dependent on "lint:oxlint" with updated input/exclude patterns.
packages/*/package.json Added "lint:oxlint" script running OXLint on src (and/or other relevant files) for each package.
packages/astro/src/astro-components/control/ProtectCSR.astro Inserted inline comments to disable "no-unused-expressions" lint rule on specific lines.
packages/astro/src/react/controlComponents.tsx Changed return types of several components to React.ReactNode and adjusted JSX fragment usage; added lint suppression comment.
packages/backend/src/runtime/node/crypto.js Added inline comment to disable @typescript-eslint/no-require-imports lint rule.
packages/clerk-js/headless/index.js
packages/clerk-js/no-rhc/index.js
packages/clerk-js/svgTransform.js
Added inline comments disabling @typescript-eslint/no-require-imports lint rule for require statements.
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts
packages/clerk-js/src/core/resources/Organization.ts
packages/clerk-js/src/core/resources/OrganizationMembership.ts
packages/clerk-js/src/core/resources/OrganizationSuggestion.ts
packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts
Added inline comments disabling "no-unsafe-optional-chaining" lint rule on lines with optional chaining and type assertions.
packages/clerk-js/src/utils/url.ts Added explicit null byte check in pathname and comment to disable control character lint rule for regex.
packages/shared/scripts/postinstall.mjs Removed unused error parameter from catch block.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e51599 and 82f10bb.

📒 Files selected for processing (13)
  • packages/agent-toolkit/package.json (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/chrome-extension/package.json (1 hunks)
  • packages/dev-cli/package.json (1 hunks)
  • packages/expo-passkeys/package.json (1 hunks)
  • packages/express/package.json (1 hunks)
  • packages/fastify/package.json (1 hunks)
  • packages/localizations/package.json (1 hunks)
  • packages/tanstack-react-start/package.json (1 hunks)
  • packages/testing/package.json (1 hunks)
  • packages/themes/package.json (1 hunks)
  • packages/types/package.json (1 hunks)
  • packages/vue/package.json (1 hunks)
✅ Files skipped from review due to trivial changes (6)
  • packages/backend/package.json
  • packages/localizations/package.json
  • packages/themes/package.json
  • packages/testing/package.json
  • packages/agent-toolkit/package.json
  • packages/vue/package.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/expo-passkeys/package.json
  • packages/fastify/package.json
  • packages/dev-cli/package.json
  • packages/chrome-extension/package.json
  • packages/express/package.json
  • packages/tanstack-react-start/package.json
  • packages/types/package.json
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

pkg-pr-new bot commented Jun 11, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@6105

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@6105

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@6105

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@6105

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@6105

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@6105

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@6105

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@6105

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@6105

@clerk/express

npm i https://pkg.pr.new/@clerk/express@6105

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@6105

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@6105

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@6105

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@6105

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@6105

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@6105

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@6105

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@6105

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@6105

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@6105

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@6105

@clerk/types

npm i https://pkg.pr.new/@clerk/types@6105

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@6105

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@6105

commit: 82f10bb

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: 3

♻️ Duplicate comments (9)
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1)

48-50: 🛠️ Refactor suggestion

Same unchecked optional-chaining risk as above

The pattern repeats here. Either assert res?.response is present or refine _fetch’s typing; don’t just mute the rule.

packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (1)

31-34: 🛠️ Refactor suggestion

Unchecked res?.response may throw – handle explicitly

See previous comments: the destructuring will blow up when response is absent. Failing fast with a clear error (or improving _fetch typing) is preferable to blanket-disabling the lint.

packages/clerk-js/src/core/resources/Organization.ts (5)

124-126: 🛠️ Refactor suggestion

Same concern as above – unsafe optional chaining muted instead of handled.


152-154: 🛠️ Refactor suggestion

Same pattern – please address globally.


174-176: 🛠️ Refactor suggestion

As above.


197-199: 🛠️ Refactor suggestion

As above.


246-248: 🛠️ Refactor suggestion

As above.

packages/astro/src/astro-components/control/ProtectCSR.astro (1)

52-54: Mirror the refactor for the fallback slot

-// oxlint-disable-next-line no-unused-expressions
-isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', '');
+this.fallbackSlot?.toggleAttribute('hidden', !isUnauthorized);
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (1)

69-72: Duplicate of the issue above for getStatements

Same nullable-response risk and lint suppression here; please apply the same fix.

🧹 Nitpick comments (19)
packages/clerk-js/svgTransform.js (1)

1-3: Streamline lint suppression directives
Since the plan is to fully migrate off ESLint, consider replacing the ESLint disable comment with Oxlint’s equivalent for no-var-requires to keep consistency across the codebase:

- // eslint-disable-next-line @typescript-eslint/no-var-requires
+ // oxlint-disable-next-line @typescript-eslint/no-var-requires
packages/backend/src/runtime/node/crypto.js (1)

1-2: Consistency: Add OXLint disable directive
To align with other modules adopting Oxlint, consider adding an // oxlint-disable-next-line @typescript-eslint/no-require-imports alongside the existing ESLint directive for uniform suppression.

packages/astro/src/astro-components/control/ProtectCSR.astro (1)

47-49: Use toggleAttribute to avoid side-effect ternaries & lint disable

Ternary expressions used only for side-effects trigger no-unused-expressions.
A clearer, lint-friendly alternative:

-// oxlint-disable-next-line no-unused-expressions
-isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden');
+this.defaultSlot?.toggleAttribute('hidden', isUnauthorized);
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (1)

90-91: Stale disable comment

// oxlint-disable-next-line no-unsafe-optional-chaining refers to an optional-chaining rule, but the next line no longer uses ?.. Remove the comment to avoid dead-code noise.

-// oxlint-disable-next-line no-unsafe-optional-chaining
 const { data: payments, total_count } = res as unknown as ClerkPaginatedResponse<CommercePaymentJSON>;
packages/clerk-js/src/utils/url.ts (2)

247-252: Mixed ESLint/OXLint directives – pick one linter or keep both consistently

You added // oxlint-disable-next-line no-control-regex but kept the old ESLint directive two lines below.
If ESLint will eventually be removed, drop the ESLint comment; if both linters stay, duplicate directives are fine but noisy. Choose and keep consistent.

🧰 Tools
🪛 Biome (1.9.4)

[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


262-266: Redundant null-byte check – regex already covers it

url.pathname.includes('\0') is functionally equivalent to the /\0/ pattern you added to disallowedPatterns, so we now check the same thing twice. Prefer a single source of truth (regex or explicit string check) to avoid drift.

-// Check for null bytes in pathname
-if (url.pathname.includes('\0')) {
-  return true;
-}
packages/astro/src/react/controlComponents.tsx (3)

52-60: Unused PropsWithChildren import

After switching to React.PropsWithChildren, the PropsWithChildren import at line 3 is now unused. Remove it to keep the file lint-clean.


88-109: Protect destructuring refactor is fine, but duplicate vars could be inlined

const unauthorized = …, const authorized = children; are immediately returned; consider inlining to reduce indirection, but this is purely stylistic.


145-146: Use OXLint directive instead of ESLint if ESLint is being phased out

The comment still disables react-hooks/exhaustive-deps for ESLint. If OXLint replaces ESLint, convert or remove this directive to avoid orphaned comments.

packages/shared/scripts/postinstall.mjs (2)

50-54: Silent catch may mask corruption of telemetry config

Silently ignoring JSON.parse errors means a corrupted config.json is perpetually discarded and rewritten, destroying any existing (possibly user-edited) settings.

   try {
     config = JSON.parse(await fs.readFile(configFile, 'utf8'));
-} catch {
-  // File can't be read and parsed, continue
+} catch {
+  // File can't be read or parsed → keep defaults but surface a debug log
+  if (process.env.DEBUG?.includes('clerk-postinstall')) {
+    console.warn('[clerk] telemetry config unreadable – resetting to defaults');
+  }
 }

This keeps the install noise at zero yet allows opt-in diagnostics when needed.


70-74: Same concern for the outer try…catch

A suppressed error here hides unexpected I/O issues (e.g. permission problems).
At minimum, consider logging behind a DEBUG guard as above.

package.json (1)

25-25: Script name diverges from package-level convention

Every workspace package exposes lint:oxlint, but the root exposes plain oxlint.
For symmetry (and muscle-memory), add an alias:

   "lint:publint": "FORCE_COLOR=1 turbo lint:publint",
+  "lint:oxlint": "pnpm oxlint",
   "nuke": "node ./scripts/nuke.mjs",
   "oxlint": "oxlint --quiet",
.oxlintrc.json (7)

1-6: Consider extending shared or ESLint configs.

Instead of enumerating all plugins and disabling the entire correctness category, you could leverage an extends field to reuse baseline rules from a shared or ESLint config and then override only the exceptions.


105-133: Revisit TypeScript rule exceptions.

Disabling @typescript-eslint/no-explicit-any and turning off "no-throw-literal" may mask unsafe patterns. Consider re-enabling them with fine-grained allowances or documenting why they’re off.


241-261: Consolidate TypeScript overrides.

Many rules are toggled off for TS files. Consider grouping these toggles under a shared base config or merging with the main overrides to reduce duplication.


263-277: Review JS override for unused vars.

You’ve redefined no-unused-vars for JS files. If this matches the root config, you can inherit it instead of duplicating.


278-283: Simplify ES2018 environment override.

If all TS targets run on ES2018, merge this env block with the earlier TS override to cut down on fragmentation.


308-313: Confirm exception for upgrade package.

Disabling react/no-unescaped-entities in packages/upgrade looks like a quick workaround. Consider adding a TODO or filing an issue if this isn’t a permanent exception.


314-381: Abstract integration test globals.

Listing 70+ globals inline bloats the config. Consider moving them to a shared globals.json or leveraging a preset environment to simplify maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b23d4ae and dd2716a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • .oxlintrc.json (1 hunks)
  • package.json (2 hunks)
  • packages/agent-toolkit/package.json (1 hunks)
  • packages/astro/package.json (1 hunks)
  • packages/astro/src/astro-components/control/ProtectCSR.astro (1 hunks)
  • packages/astro/src/react/controlComponents.tsx (4 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/runtime/node/crypto.js (1 hunks)
  • packages/chrome-extension/package.json (1 hunks)
  • packages/clerk-js/headless/index.js (1 hunks)
  • packages/clerk-js/no-rhc/index.js (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (3 hunks)
  • packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1 hunks)
  • packages/clerk-js/src/core/resources/Organization.ts (6 hunks)
  • packages/clerk-js/src/core/resources/OrganizationMembership.ts (1 hunks)
  • packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (1 hunks)
  • packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (1 hunks)
  • packages/clerk-js/src/utils/url.ts (2 hunks)
  • packages/clerk-js/svgTransform.js (1 hunks)
  • packages/dev-cli/package.json (1 hunks)
  • packages/elements/package.json (1 hunks)
  • packages/expo-passkeys/package.json (1 hunks)
  • packages/expo/package.json (1 hunks)
  • packages/express/package.json (1 hunks)
  • packages/fastify/package.json (1 hunks)
  • packages/localizations/package.json (1 hunks)
  • packages/nextjs/package.json (1 hunks)
  • packages/nuxt/package.json (1 hunks)
  • packages/react-router/package.json (1 hunks)
  • packages/react/package.json (1 hunks)
  • packages/remix/package.json (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/scripts/postinstall.mjs (1 hunks)
  • packages/tanstack-react-start/package.json (1 hunks)
  • packages/testing/package.json (1 hunks)
  • packages/themes/package.json (1 hunks)
  • packages/types/package.json (1 hunks)
  • packages/upgrade/package.json (1 hunks)
  • packages/vue/package.json (1 hunks)
  • turbo.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationSuggestionJSON (464-471)
packages/clerk-js/src/core/resources/OrganizationMembership.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationMembershipJSON (387-398)
packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • UserOrganizationInvitationJSON (483-493)
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (2)
  • CommerceSubscriptionJSON (684-698)
  • CommerceStatementJSON (655-662)
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • CommercePaymentSourceJSON (636-646)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: semgrep/ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (44)
packages/clerk-js/headless/index.js (1)

1-2: Confirm Oxlint disable directive effectiveness
Ensure OXLint recognizes this // oxlint-disable-next-line @typescript-eslint/no-require-imports directive and properly suppresses the rule on the following require statement.

packages/clerk-js/svgTransform.js (1)

2-2: Approve OXLint suppression for require imports
The inline // oxlint-disable-line @typescript-eslint/no-require-imports correctly suppresses the rule on the require('path') line.

packages/clerk-js/no-rhc/index.js (1)

1-2: Confirm Oxlint disable directive effectiveness
Ensure OXLint recognizes this // oxlint-disable-next-line @typescript-eslint/no-require-imports directive and properly suppresses the rule on the subsequent require statement.

packages/clerk-js/src/core/resources/OrganizationMembership.ts (1)

42-44: Verify rule ID for Oxlint directive
The inline // oxlint-disable-line no-unsafe-optional-chaining omits the @typescript-eslint prefix. Confirm whether Oxlint’s rule identifier is no-unsafe-optional-chaining or should be @typescript-eslint/no-unsafe-optional-chaining to ensure the suppression takes effect.

packages/astro/src/react/controlComponents.tsx (1)

62-70: Return type update looks good

Changing the return type to React.ReactNode and dropping the fragment wrapper is correct and simplifies the component. Nice cleanup.

packages/nextjs/package.json (1)

69-70: Script added correctly

lint:oxlint script is wired properly and scoped to src. No issues spotted.

packages/shared/package.json (1)

137-138: Consistent workspace script – good

lint:oxlint mirrors the pattern used elsewhere, keeping tooling uniform across packages.

packages/tanstack-react-start/package.json (1)

64-64: Introduce lint:oxlint script
Added the lint:oxlint command to run Oxlint quietly on the src directory, in line with the PR’s goal to integrate Oxlint alongside ESLint for faster lint feedback.

packages/agent-toolkit/package.json (1)

44-44: Add Oxlint linting step
The new lint:oxlint script runs Oxlint in quiet mode against src, standardizing the lint workflow across packages as described in the PR summary.

packages/backend/package.json (1)

98-98: Enable Oxlint for the backend package
Introduced the lint:oxlint script to run Oxlint quietly on src, aligning with the monorepo-wide Oxlint rollout.

packages/themes/package.json (1)

38-39: Add and format lint:oxlint entry
Inserted the lint:oxlint script (quiet mode on src) and added the necessary comma on the preceding line, ensuring consistency with other packages’ lint configurations.

packages/astro/package.json (1)

85-85: Configure Oxlint for Astro integration
Added lint:oxlint to target both src and env.d.ts, matching the PR’s aim to include Oxlint across all packages. Verify this matches the root .oxlintrc.json settings.

packages/types/package.json (1)

39-39: Add lint:oxlint script for OXLint
The new lint:oxlint script matches the pattern used across other packages and correctly targets the src directory with --quiet.

packages/elements/package.json (1)

68-68: Add lint:oxlint script for OXLint
This mirrors the addition in other packages and ensures OXLint runs quietly against src. Looks consistent and correct.

packages/remix/package.json (1)

72-72: Add lint:oxlint script for OXLint
The new script is consistent with the monorepo’s OXLint adoption and will run quietly on the src folder.

packages/expo/package.json (1)

75-75: Add lint:oxlint script for OXLint
This addition aligns with the other package scripts and correctly invokes OXLint in quiet mode on src.

packages/nuxt/package.json (1)

64-64: Add lint:oxlint script for OXLint
The script follows the established pattern for OXLint in the monorepo, targeting src with --quiet.

packages/clerk-js/package.json (1)

49-49: Add lint:oxlint script
The new lint:oxlint command aligns with the monorepo’s linting strategy and correctly targets the src directory.

packages/chrome-extension/package.json (1)

43-43: Add lint:oxlint script
Introducing lint:oxlint here mirrors other packages and ensures consistent lint checks on the src folder.

packages/expo-passkeys/package.json (1)

29-29: Add lint:oxlint script
This addition standardizes Oxlint usage across packages and correctly points at the source directory.

packages/fastify/package.json (1)

60-60: Add lint:oxlint script
Adding Oxlint here aligns with the updated Turbo pipeline and ensures fast feedback for Fastify sources.

packages/dev-cli/package.json (1)

23-23: Add lint:oxlint script
The new script complements the existing ESLint step and brings Oxlint checks into the CLI package.

packages/react/package.json (1)

73-73: Addition of OXLint lint script
The new lint:oxlint entry aligns with existing lint scripts and ensures OXLint runs against src. Confirm that this directory exists and that your root .oxlintrc.json covers this package.

packages/express/package.json (1)

62-62: Add lint:oxlint for Express package
The lint:oxlint script is correctly introduced alongside other lint targets. Verify that src is present and .oxlintrc.json rules apply here.

packages/vue/package.json (1)

53-53: Introduce OXLint script to Vue package
Looks good and consistent with other packages. Ensure the src folder exists and is picked up by OXLint per your root config.

packages/react-router/package.json (1)

77-77: OXLint integration for React Router
The new lint:oxlint script matches the repo convention. Double-check that .oxlintrc.json rules cover this package’s src directory.

packages/testing/package.json (1)

73-73: Enable OXLint for testing utilities
Adding lint:oxlint here maintains consistency. Confirm src exists under packages/testing and the root config applies.

packages/localizations/package.json (1)

103-106: lint:oxlint script added – looks correct

The command restricts the run to src and uses --quiet, mirroring the pattern adopted in other packages. ✅

packages/upgrade/package.json (1)

22-24: Consistent lint:oxlint script

Same convention as the rest of the monorepo; nothing further.

package.json (1)

124-124: Pinning with ^ risks auto-upgrading a tool that can fail CI

Given OXLint is new and the monorepo is large, consider a fixed version ("1.0.0" without the caret) until the team is confident with its release cadence.

turbo.json (1)

104-124: New top-level lint task overlaps with existing root lint script

package.json#scripts.lint already points to node ./scripts/lint.mjs.
That script may call turbo internally, but the identical task name inside turbo.json can cause confusion when reading the config or invoking turbo run lint.

Double-check that:

  1. scripts/lint.mjs still behaves as intended (does it now recurse into the new task and double-run?).
  2. CI pipelines and docs aren’t relying on turbo run lint meaning “ESLint only”.

If aliasing is intentional, add a comment here or in the script for clarity.

.oxlintrc.json (13)

7-11: Verify environment settings.

Confirm that enabling "builtin", "es2021", and "commonjs" covers all your target runtimes; otherwise you may miss globals (e.g., browser or Node 18+ features).


12-40: Review ignore patterns for edge cases.

The "!.*.js" negation and various globs might unintentionally include hidden files or skip generated artifacts. Please test that build outputs and source files are correctly included/excluded as intended.


41-104: Audit core rule overrides.

Strict JS rules are good, but you’ve set "no-unexpected-multiline" to "off". Ensure this exception is intentional, as it can allow confusing control flows.


134-138: Approve import plugin rules.

Import checks (namespace, default, no-named-as-default, no-duplicates) are well configured to catch common module issues.


139-171: Validate accessibility rule coverage.

Your JSX A11y rules are comprehensive, but warnings like html-has-lang and no-autofocus can be tightened or relaxed per your design system. Confirm these align with your accessibility policy.


172-196: Confirm React rule choices.

Disabling react/react-in-jsx-scope requires React 17+. Ensure all packages use a compatible React version.


197-239: Approve stylistic and hook rules.

Curly/style rules, import sorting, and React hooks settings are sensibly set to off or warn per your team conventions.


284-290: Check non-null assertion rule overlap.

You enforce @typescript-eslint/no-non-null-assertion here, but also have no-unsafe-optional-chaining globally. Verify there’s no conflict or redundant coverage.


291-296: Approve Jest environment override.

Scoping the Jest env to test file patterns is correct.


297-306: Verify restricted imports in expo-passkeys.

Blocking node:* imports makes sense—double-check if any other core modules should be prohibited in that package.


382-416: Validate JSDoc plugin setup.

Your JSDoc rules for shared/src are thorough. Make sure they align with your actual documentation standards and that the team is prepared to maintain these additional checks.


417-423: Approve YAML overrides.

Disabling whitespace and unused-vars checks for YAML is appropriate.


424-429: Confirm compiled code exceptions.

Excluding unused-expression checks for the compiled path-to-regexp file is fine; ensure future regenerations don’t introduce new rule violations outside this scope.

Comment on lines 34 to 36
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Guard against undefined responses instead of silencing the lint rule

res?.response can legally be undefined if _fetch returns undefined (e.g. network failure).
Destructuring from an undefined value will throw at runtime, so disabling no-unsafe-optional-chaining hides a potential crash.

-const { data: suggestions, total_count } =
-  res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+if (!res?.response) {
+  throw new Error('OrganizationSuggestion.retrieve: empty response');
+}
+const { data: suggestions, total_count } =
+  res.response as ClerkPaginatedResponse<OrganizationSuggestionJSON>;

Alternatively, tighten the _fetch return type so callers no longer need ?. or double as casts.


🏁 Script executed:

#!/bin/bash
set -e
echo "Searching for _fetch occurrences in core resources:"
rg "_fetch" -n packages/clerk-js/src/core/resources/
echo ""
echo "Showing OrganizationSuggestion.ts around the fetch call:"
rg -n -C5 "res?.response" -n packages/clerk-js/src/core/resources/OrganizationSuggestion.ts

Length of output: 9301


🏁 Script executed:

#!/bin/bash
set -e
echo "Displaying lines 1-80 of OrganizationSuggestion.ts for context:"
sed -n '1,80p' packages/clerk-js/src/core/resources/OrganizationSuggestion.ts

Length of output: 2453


🏁 Script executed:

#!/bin/bash
set -e
echo "Locating _fetch signature in Base.ts:"
rg "static async _fetch" -n packages/clerk-js/src/core/resources/Base.ts
echo ""
echo "Displaying BaseResource._fetch implementation (lines 1–200):"
sed -n '1,200p' packages/clerk-js/src/core/resources/Base.ts

Length of output: 6892


Guard against undefined res.response before destructuring

Destructuring from an undefined response will crash at runtime if _fetch returns null (e.g. offline/browser network failure). Replace the unsafe optional chaining and cast with an explicit null check:

packages/clerk-js/src/core/resources/OrganizationSuggestion.ts – in retrieve:

-return await BaseResource._fetch({
-  path: '/me/organization_suggestions',
-  method: 'GET',
-  search: convertPageToOffsetSearchParams(params),
-}).then(res => {
-  const { data: suggestions, total_count } =
-    res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
-
-  return {
-    total_count,
-    data: suggestions.map(suggestion => new OrganizationSuggestion(suggestion)),
-  };
-});
+return await BaseResource._fetch({
+  path: '/me/organization_suggestions',
+  method: 'GET',
+  search: convertPageToOffsetSearchParams(params),
+}).then(res => {
+  if (!res || !res.response) {
+    throw new Error('OrganizationSuggestion.retrieve: empty or null response');
+  }
+  const { data: suggestions, total_count } =
+    res.response as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
+
+  return {
+    total_count,
+    data: suggestions.map(suggestion => new OrganizationSuggestion(suggestion)),
+  };
+});

This change throws a clear error on missing responses instead of risking an uncaught TypeError.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
return await BaseResource._fetch({
path: '/me/organization_suggestions',
method: 'GET',
search: convertPageToOffsetSearchParams(params),
}).then(res => {
if (!res || !res.response) {
throw new Error('OrganizationSuggestion.retrieve: empty or null response');
}
const { data: suggestions, total_count } =
res.response as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
return {
total_count,
data: suggestions.map(suggestion => new OrganizationSuggestion(suggestion)),
};
});
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/OrganizationSuggestion.ts around lines
34 to 36, the code destructures properties from res?.response using unsafe
optional chaining and double casting, which can cause a runtime crash if
res.response is undefined due to network failure. To fix this, add an explicit
null or undefined check for res.response before destructuring, and throw a clear
error if it is missing, removing the unsafe optional chaining and double casting
to ensure safer and more predictable behavior.

Comment on lines 100 to 104
).then(res => {
// oxlint-disable-next-line no-unsafe-optional-chaining
const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;

return {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prefer runtime guard or stronger typings over oxlint-disable-next-line

If _fetch guarantees a response, drop ? and the disable comment; if not, guard first.
Repeated across this file — consider a helper to unpack paginated responses to avoid boilerplate & scattered ignores.

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/Organization.ts around lines 100 to 104,
the code uses optional chaining with a disable comment to bypass linting on
unsafe access to res.response. To fix this, first confirm if _fetch always
returns a response; if so, remove the optional chaining and the disable comment.
If not guaranteed, add a runtime check to safely access res.response before
destructuring. Additionally, refactor by creating a helper function to extract
and validate paginated responses to reduce repeated boilerplate and avoid
scattered lint disables throughout the file.

Comment on lines 51 to 54
}).then(res => {
const { data: subscriptions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>;
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

res?.response can still blow up at runtime – better to assert non-null than silence OXLint

You’re suppressing no-unsafe-optional-chaining, but if _fetch ever returns undefined the destructuring on the next line (const { data, total_count } = …) will throw anyway.
Either assert non-null (e.g. invariant(res)) or propagate an error before destructuring instead of keeping the optional chain and disabling the rule.

-const { data: subscriptions, total_count } =
-  res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+if (!res) {
+  throw new Error('getSubscriptions: unexpected empty response');
+}
+const { data: subscriptions, total_count } =
+  (res.response as ClerkPaginatedResponse<CommerceSubscriptionJSON>);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}).then(res => {
const { data: subscriptions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>;
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
}).then(res => {
if (!res) {
throw new Error('getSubscriptions: unexpected empty response');
}
const { data: subscriptions, total_count } =
(res.response as ClerkPaginatedResponse<CommerceSubscriptionJSON>);
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts around lines
51 to 54, the code uses optional chaining on res.response but disables the
no-unsafe-optional-chaining lint rule, which can still cause runtime errors if
res is undefined. To fix this, add a non-null assertion or explicitly check that
res is not null or undefined before destructuring its response property, and
remove the lint disable comment. This ensures safe access and prevents runtime
crashes.

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: 5

♻️ Duplicate comments (4)
packages/expo-passkeys/package.json (1)

29-29: Lint script addition aligns with other packages
The new lint:oxlint script matches the pattern used across the repo. Ensure your CI and Turbo workflows pick up this command and that the root .oxlintrc.json applies correctly in this package.

packages/themes/package.json (1)

38-39: Lint script addition aligns with other packages
The lint:oxlint entry follows the established convention. Verify that the root-level OXLint config and any package-specific overrides behave as expected here.

packages/nuxt/package.json (1)

64-64: Lint script addition aligns with other packages
This matches the lint:oxlint convention introduced elsewhere. Confirm that the CI/Turbo pipeline invokes it correctly for the Nuxt package.

packages/testing/package.json (1)

73-73: Lint script addition aligns with other packages
The new lint:oxlint entry is consistent with the monorepo’s linting approach. Ensure test packages also respect the shared .oxlintrc.json rules.

🧹 Nitpick comments (10)
packages/shared/scripts/postinstall.mjs (1)

50-54: Silent catch blocks hinder troubleshooting

Both catch {} blocks swallow all errors without even a debug-level log.
Silent failures make telemetry-notice issues extremely hard to diagnose.

Consider at least logging behind an env flag:

-} catch {
-  // File can't be read and parsed, continue
+} catch (err) {
+  if (process.env.CLERK_POSTINSTALL_DEBUG === '1') {
+    console.warn('[clerk/postinstall] telemetry config read failed:', err);
+  }
 }

This keeps install output clean while giving maintainers a way to surface issues on demand.

packages/clerk-js/src/utils/url.ts (2)

247-252: Null-byte check duplicated & extra pragma noise

/[\x00-\x1F]/ already matches \0, so the separate /\0/ entry (and its extra no-control-regex disable) is redundant. Consolidating reduces rule-disable clutter.

-// oxlint-disable-next-line no-control-regex
-/\0/, // Null bytes
-...
-// eslint-disable-next-line no-control-regex
-/[\x00-\x1F]/, // Control characters
+// eslint-disable-next-line no-control-regex
+/[\x00-\x1F]/, // Control + null bytes
🧰 Tools
🪛 Biome (1.9.4)

[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


263-266: Redundant explicit pathname '\0' check

The regex (after consolidation) already catches null bytes in the pathname; this extra includes('\0') branch can be removed for brevity unless you have a benchmark demonstrating a measurable gain.

packages/astro/src/astro-components/control/ProtectCSR.astro (1)

47-53: Avoid side-effect ternaries and drop the lint suppression

The ternary is used solely for its side effect, which is precisely what no-unused-expressions tries to prevent.
Keeping the suppression leaves hard-to-scan logic and increases reviewer cognitive load.

-// oxlint-disable-next-line no-unused-expressions
-isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden');
+if (isUnauthorized) {
+  this.defaultSlot.setAttribute('hidden', '');
+} else {
+  this.defaultSlot.removeAttribute('hidden');
+}

Apply the same pattern to fallbackSlot below and drop both oxlint-disable comments.

package.json (1)

25-25: Script name inconsistency

Most packages expose lint:oxlint, but the root adds plain oxlint.
For discoverability and parity with sub-packages, consider renaming:

-"oxlint": "oxlint --quiet",
+"lint:oxlint": "oxlint --quiet",

Update CI or Turbo tasks if they call the old name.

turbo.json (1)

104-124: Circular-ish dependency risk: lintlint:oxlint (which waits for ^build)

lint now waits for lint:oxlint; lint:oxlint waits for all upstream build tasks.
If any package’s build depends on lint, you’ll create a cycle.
Double-check the task graph; if safe today, document the constraint to avoid future cycles.

.oxlintrc.json (4)

3-3: Consider adding the JSDoc plugin globally.

You currently only load "jsdoc" under a specific override. If your codebase relies on JSDoc annotations broadly, you may want to include "jsdoc" in the top‐level plugins array to catch issues outside packages/shared.


7-11: Add a browser/global environment flag.

Root env includes builtin, es2021, and commonjs but omits browser. Linting React and web packages without a browser env may lead to false positives for globals like window or document. Consider either adding "browser": true here or in frontend-specific overrides.


12-40: Expand and validate your ignore patterns.

  • Missing common lockfiles like yarn.lock or package-lock.json.
  • The negation pattern "!.*.js" can be confusing; verify it has the intended effect.
  • You may also want to ignore .husky/ or other tooling directories if present.

141-180: Align JSX-A11y severity levels.

Some accessibility rules (e.g., jsx-a11y/html-has-lang) are warnings while others are errors. Consider standardizing severity (all as errors or warnings) based on your accessibility compliance goals.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b23d4ae and dd2716a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • .oxlintrc.json (1 hunks)
  • package.json (2 hunks)
  • packages/agent-toolkit/package.json (1 hunks)
  • packages/astro/package.json (1 hunks)
  • packages/astro/src/astro-components/control/ProtectCSR.astro (1 hunks)
  • packages/astro/src/react/controlComponents.tsx (4 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/runtime/node/crypto.js (1 hunks)
  • packages/chrome-extension/package.json (1 hunks)
  • packages/clerk-js/headless/index.js (1 hunks)
  • packages/clerk-js/no-rhc/index.js (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (3 hunks)
  • packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1 hunks)
  • packages/clerk-js/src/core/resources/Organization.ts (6 hunks)
  • packages/clerk-js/src/core/resources/OrganizationMembership.ts (1 hunks)
  • packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (1 hunks)
  • packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (1 hunks)
  • packages/clerk-js/src/utils/url.ts (2 hunks)
  • packages/clerk-js/svgTransform.js (1 hunks)
  • packages/dev-cli/package.json (1 hunks)
  • packages/elements/package.json (1 hunks)
  • packages/expo-passkeys/package.json (1 hunks)
  • packages/expo/package.json (1 hunks)
  • packages/express/package.json (1 hunks)
  • packages/fastify/package.json (1 hunks)
  • packages/localizations/package.json (1 hunks)
  • packages/nextjs/package.json (1 hunks)
  • packages/nuxt/package.json (1 hunks)
  • packages/react-router/package.json (1 hunks)
  • packages/react/package.json (1 hunks)
  • packages/remix/package.json (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/scripts/postinstall.mjs (1 hunks)
  • packages/tanstack-react-start/package.json (1 hunks)
  • packages/testing/package.json (1 hunks)
  • packages/themes/package.json (1 hunks)
  • packages/types/package.json (1 hunks)
  • packages/upgrade/package.json (1 hunks)
  • packages/vue/package.json (1 hunks)
  • turbo.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • UserOrganizationInvitationJSON (483-493)
packages/clerk-js/src/core/resources/OrganizationMembership.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationMembershipJSON (387-398)
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (2)
  • CommerceSubscriptionJSON (684-698)
  • CommerceStatementJSON (655-662)
packages/clerk-js/src/core/resources/Organization.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (4)
  • OrganizationMembershipRequestJSON (473-481)
  • OrganizationMembershipJSON (387-398)
  • OrganizationInvitationJSON (400-411)
  • CommerceSubscriptionJSON (684-698)
packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationSuggestionJSON (464-471)
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • CommercePaymentSourceJSON (636-646)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (47)
packages/clerk-js/headless/index.js (1)

1-1: Approve lint suppression
The added // oxlint-disable-next-line @typescript-eslint/no-require-imports directive is correct for this CommonJS module export, matching the new OXLint rules and existing annotations across the codebase.

packages/clerk-js/no-rhc/index.js (1)

1-1: Approve lint suppression
This // oxlint-disable-next-line @typescript-eslint/no-require-imports comment properly disables the require-imports rule for the subsequent CommonJS export, keeping consistency with other packages.

packages/clerk-js/svgTransform.js (1)

2-2: Approve lint disable for require-imports
The inline // oxlint-disable-line @typescript-eslint/no-require-imports on the require('path') import is appropriate and aligns with project-wide lint exemptions for legacy CommonJS patterns.

packages/backend/src/runtime/node/crypto.js (1)

1-1: Approve lint suppression
Disabling @typescript-eslint/no-require-imports here accurately accommodates the CommonJS require usage under the new OXLint configuration.

packages/clerk-js/src/core/resources/OrganizationMembership.ts (1)

43-43: Approve unsafe-optional-chaining suppression
The // oxlint-disable-line no-unsafe-optional-chaining directive is justified for the cast on res?.response and maintains parity with similar suppressions in other resource files.

packages/astro/src/react/controlComponents.tsx (4)

52-60: Type widening to React.ReactNode is sensible

Returning children directly (without fragment wrapping) and widening the return type improves flexibility and removes unnecessary JSX. Looks good.


62-70: Symmetric change in ClerkLoading also LGTM

Consistent with the above update; no issues spotted.


88-109: Simplified authorized / unauthorized branches read clearer

Removing unnecessary fragments keeps the JSX minimal.


145-146: Empty dependency array suppression: verify intent

Suppressing react-hooks/exhaustive-deps is fine if handleRedirectCallback must run exactly once, but ensure that props (clerk, handleRedirectCallbackParams) are immutable for the component’s lifetime; otherwise the effect may miss updates.

packages/shared/package.json (1)

137-137: Added lint:oxlint script for OXLint integration
This aligns with the monorepo’s new linting workflow and mirrors other packages.

packages/react-router/package.json (1)

77-77: Introduce lint:oxlint script
Matches the pattern used across other packages to run OXLint in quiet mode on src.

packages/backend/package.json (1)

98-98: Add lint:oxlint to scripts
Consistent with the new OXLint-based linting setup; ready to catch issues faster.

packages/nextjs/package.json (1)

69-69: Add lint:oxlint script
Ensures NextJS package participates in the unified OXLint workflow.

packages/agent-toolkit/package.json (1)

44-44: Include lint:oxlint command
Aligns agent-toolkit with the repo-wide OXLint configuration.

packages/remix/package.json (1)

72-72: Approve: Add lint:oxlint script.
This aligns with the repo-wide OXLint integration and matches other packages.

packages/types/package.json (1)

39-39: Approve: Add lint:oxlint script.
Consistent with the new OXLint setup across workspace packages.

packages/expo/package.json (1)

75-75: Approve: Add lint:oxlint script.
Follows the monorepo convention for OXLint and keeps parity with ESLint scripts.

packages/upgrade/package.json (1)

23-23: Approve: Add lint:oxlint script.
Integrates OXLint into the upgrade package as intended.

packages/react/package.json (1)

73-73: Approve: Add lint:oxlint script.
Matches the new linting workflow and other package.json scripts.

packages/tanstack-react-start/package.json (1)

64-64: Add lint:oxlint script
Consistently adds OXLint linting for the src directory, aligning with the new linting workflow.

packages/clerk-js/package.json (1)

49-49: Add lint:oxlint script
Introduces OXLint linting for the src directory, matching the monorepo’s standardized lint setup.

packages/astro/package.json (1)

85-85: Add lint:oxlint script
Runs OXLint quietly on both src and env.d.ts, consistent with other packages’ lint configurations.

packages/dev-cli/package.json (1)

23-23: Add lint:oxlint script
Adds OXLint linting for the src directory, aligning this CLI tool with the repo’s new lint pipeline.

packages/fastify/package.json (1)

60-60: Add lint:oxlint script
Introduces OXLint linting for the src directory, ensuring consistent lint coverage across packages.

packages/chrome-extension/package.json (1)

43-43: Introduce lint:oxlint script for OXLint integration
This addition aligns the Chrome extension package with the new monorepo-wide OXLint setup. Ensure that oxlint is installed and resolvable in this workspace (hoisted devDependency or local install).

packages/localizations/package.json (1)

104-105: Add lint:oxlint alongside existing scripts
Consistent with other packages, this enables OXLint in quiet mode on the src directory. The trailing comma on the lint:attw entry is also correct.

packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1)

49-49: Suppress OXLint’s no-unsafe-optional-chaining rule locally
The inline // oxlint-disable-line no-unsafe-optional-chaining is necessary to avoid false positives on this known-safe access.

packages/vue/package.json (1)

53-53: Introduce lint:oxlint script to Vue package
This mirrors the monorepo’s new OXLint configuration and ensures the Vue package is linted by Oxlint as well.

packages/express/package.json (1)

62-62: Add lint:oxlint script for Express SDK
Aligns the Express package with the project’s OXLint integration, enabling faster lint failures in CI.

packages/elements/package.json (1)

68-68:

❓ Verification inconclusive

Ensure OXLint CLI availability
Confirm that the oxlint binary is resolvable within this package’s context (via workspace hoisting). If you rely on root-level devDependencies, add a verification step or document the requirement.

Run:

to verify the CLI is available and returns the expected version.


🏁 Script executed:

pnpm -C packages/elements oxlint --version

Length of output: 129


🏁 Script executed:

#!/bin/bash
# Search for OXLint in all package.json files to verify where it’s declared
rg -g 'package.json' -n '"oxlint"'

Length of output: 123


Ensure OXLint CLI availability in packages/elements
File: packages/elements/package.json
Lines: 68

    "lint:oxlint": "oxlint --quiet src",

The lint:oxlint script assumes the oxlint binary is available in this package. Although it’s declared in the root package.json, PNPM workspaces may hoist it—but you need to confirm.

  • Run:
    pnpm -C packages/elements exec -- oxlint --version
    to verify it prints the expected version (e.g. 1.0.0).
  • If that fails, either add
    "devDependencies": {
      "oxlint": "^1.0.0"
    }
    to packages/elements/package.json, or document that this script requires the root’s devDependencies.
package.json (1)

124-124: Pin OXLint to an explicit minor/patch to avoid unexpected breakage

"^1.0.0" will pull in future breaking minors if the semver discipline slips.
Given OXLint is new, pin to 1.0.x or exact 1.0.0 until confidence grows.

.oxlintrc.json (16)

2-2: Verify the $schema path is correct.

Ensure that ./node_modules/oxlint/configuration_schema.json matches the installed OXLint package layout and version. An incorrect schema path could break IDE integrations or CLI validation.


4-6: Double‐check disabling the entire “correctness” category.

Turning off the "correctness" category may inadvertently suppress critical runtime checks. Confirm that you’re re-enabling all needed correctness rules individually, and that none are unintentionally disabled by the category override.


42-104: Review core rule disables and warnings.

You’ve turned off no-unexpected-multiline (line 82) and set some rules to "warn". Confirm these exceptions align with your team’s quality targets. If these are temporary, consider adding TODOs for follow-up.


105-140: Audit TypeScript and import rules.

  • @typescript-eslint/no-explicit-any is globally "off"; ensure this aligns with your strategy for type safety.
  • Ensure import rules (import/namespace, import/default, etc.) cover your existing code patterns without causing false positives.

181-240: Verify React and Unicorn rule choices.

  • react/react-in-jsx-scope is correctly off for modern React.
  • A few unicorn rules (e.g., no-nested-ternary) are disabled—confirm these are deliberate trade-offs.

241-262: Approve TypeScript override adjustments.

Disabling certain base rules in TS files while enforcing no-var and prefer-spread is a solid approach to avoid false positives.


263-277: Approve JS override for unused vars.

Customizing no-unused-vars for JS/JSX to match the TS pattern maintains consistency across file types.


278-283: Reevaluate the ES2018 override.

Root env is already es2021; you may not need an extra ES2018 override unless targeting specific build outputs. Confirm its necessity.


284-290: Approve TS non-null assertion rule.

Turning off base no-unused-vars and enforcing @typescript-eslint/no-non-null-assertion at error level is consistent.


291-296: Approve Jest environment for tests.

Enabling jest globals in test files is correct.


297-307: Approve node: import restriction.*

Disallowing node:* imports in expo-passkeys aligns with platform constraints.


308-313: Approve React unescaped entities override.

Disabling react/no-unescaped-entities for packages/upgrade is acceptable if this package relies on literal HTML entities.


314-381: Confirm integration test globals are complete.

You’ve declared an extensive list of globals—verify that no important global (e.g., process, __dirname, or Buffer) is missing and consider adding a Node env override if required.


382-416: Approve JSDoc rules for shared sources.

Scoped JSDoc linting in packages/shared helps enforce documentation standards without impacting the rest of the repo.


417-423: Approve YAML file overrides.

Disabling whitespace and unused-vars rules for YAML is standard to prevent false positives.


424-429: Approve compiled code override.

Exempting no-unused-expressions in compiled sources is appropriate to avoid linting generated artifacts.

Comment on lines 34 to 36
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Unsafe optional-chaining still leads to a potential runtime crash

res?.response may be undefined, yet the next line immediately destructures data & total_count.
If res or res.response is missing the code will throw “Cannot destructure property 'data' of 'undefined'” at runtime.
Disabling the lint rule masks a real bug rather than a false-positive.

-const { data: suggestions, total_count } =
-  res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+const response = res?.response as ClerkPaginatedResponse<OrganizationSuggestionJSON> | undefined;
+if (!response) {
+  throw new Error('Unexpected empty response from /me/organization_suggestions');
+}
+const { data: suggestions, total_count } = response;

Remove the oxlint-disable-line once the code is actually safe.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
const response = res?.response as ClerkPaginatedResponse<OrganizationSuggestionJSON> | undefined;
if (!response) {
throw new Error('Unexpected empty response from /me/organization_suggestions');
}
const { data: suggestions, total_count } = response;
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/OrganizationSuggestion.ts around lines
34 to 36, the code uses optional chaining on res?.response but immediately
destructures data and total_count without ensuring res.response is defined,
risking a runtime crash. To fix this, add a check to confirm res and
res.response are defined before destructuring, or provide a safe fallback value
to avoid destructuring undefined. Remove the oxlint-disable-line comment once
this safety is ensured.

Comment on lines 32 to 34
const { data: invites, total_count } =
res?.response as unknown as ClerkPaginatedResponse<UserOrganizationInvitationJSON>;
res?.response as unknown as ClerkPaginatedResponse<UserOrganizationInvitationJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Same unsafe pattern – destructuring on possibly undefined value

Identical to the issue in OrganizationSuggestion.ts: res?.response can be undefined, causing a crash during destructuring. Please add an explicit guard instead of suppressing the rule.

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts around
lines 32 to 34, the code destructures properties from res?.response without
checking if it is defined, which can cause a runtime error. To fix this, add an
explicit guard to verify that res?.response is not undefined before
destructuring. If it is undefined, handle that case appropriately to avoid
crashes instead of suppressing the lint rule.

Comment on lines 70 to 72
const { data: statements, total_count } =
res?.response as unknown as ClerkPaginatedResponse<CommerceStatementJSON>;
res?.response as unknown as ClerkPaginatedResponse<CommerceStatementJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Apply the same safety fix to getStatements and getPaymentAttempts

Both blocks repeat the unsafe pattern. Refactor them similarly or extract a helper (parsePaginated(res)) to DRY it out.

Also applies to: 90-92

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts around lines
70-72 and 90-92, the code uses unsafe optional chaining and type assertions to
extract paginated response data from res.response. Refactor both getStatements
and getPaymentAttempts to safely parse the paginated response by either applying
the same safety checks or extracting a helper function like parsePaginated(res)
that handles the type assertion and optional chaining safely, then use this
helper in both methods to avoid code duplication and improve safety.

Comment on lines 51 to 54
}).then(res => {
const { data: subscriptions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>;
res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

res?.response will still crash on undefined – the lint rule was right

const { data, total_count } = res?.response … will throw a TypeError when res is undefined because destructuring happens after the optional-chaining. Silencing no-unsafe-optional-chaining hides a real runtime risk.

-return await BaseResource._fetch({ ... }).then(res => {
-  const { data: subscriptions, total_count } =
-    res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>;
+return await BaseResource._fetch({ ... }).then(res => {
+  if (!res || !res.response) {
+    return { total_count: 0, data: [] };
+  }
+  const { data: subscriptions, total_count } =
+    res.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>;

Either assert _fetch always resolves to a response object or guard as above, then remove the lint-disable.

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts around lines
51 to 54, the destructuring of res?.response can cause a TypeError if res is
undefined because optional chaining does not prevent destructuring on undefined.
To fix this, add a guard to ensure res and res.response are defined before
destructuring, or assert that _fetch always returns a valid response object.
Remove the lint-disable comment after applying the fix.

Comment on lines +101 to 103
// oxlint-disable-next-line no-unsafe-optional-chaining
const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Repeated silencing of no-unsafe-optional-chaining hides potential crashes

Every paginated fetch follows the same pattern:

const { data, total_count } = res?.response as ClerkPaginatedResponse<...>;

If res is undefined, destructuring still executes and crashes.
Instead of sprinkling // oxlint-disable, refactor once:

function safePaginated<R, T>(res: R | undefined): ClerkPaginatedResponse<T> {
  if (!res || !(res as any).response) {
    return { total_count: 0, data: [] };
  }
  return (res as any).response as ClerkPaginatedResponse<T>;
}

Then:

const { data, total_count } = safePaginated<unknown, RoleJSON>(res);

This removes all suppressions and centralises the guard.

Also applies to: 124-126, 153-156, 175-176, 198-199, 247-249

🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/Organization.ts around lines 101 to 103,
the code unsafely destructures res?.response which can cause crashes if res is
undefined, and disables the linter repeatedly. To fix this, create a utility
function safePaginated that checks if res and res.response exist, returning a
default empty paginated response if not, otherwise returning res.response cast
properly. Replace all unsafe destructuring instances with calls to safePaginated
to centralize the guard and remove all no-unsafe-optional-chaining suppressions.
Apply this refactor also to lines 124-126, 153-156, 175-176, 198-199, and
247-249.

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: 8

🔭 Outside diff range comments (1)
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (1)

51-59: 🛠️ Refactor suggestion

Rule-suppression hides a potential runtime crash

res?.response as unknown as ClerkPaginatedResponse<…> suppresses the linter, but if BaseResource._fetch ever resolves to undefined (non-200, network failure, etc.) the subsequent destructuring will throw at runtime.

Consider defensive handling instead of disabling the lint rule:

-    }).then(res => {
-      const { data: subscriptions, total_count } =
-        res?.response as unknown as ClerkPaginatedResponse<CommerceSubscriptionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+    }).then(res => {
+      if (!res?.response) {
+        return { total_count: 0, data: [] };
+      }
+      const { data: subscriptions, total_count } =
+        res.response as ClerkPaginatedResponse<CommerceSubscriptionJSON>;

Same pattern repeats for getStatements and getPaymentAttempts.
Replacing double as unknown as with a properly typed _fetch<T>() overload would eliminate the need for rule suppression altogether.

Also applies to: 69-77, 88-92

♻️ Duplicate comments (12)
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1)

48-50: Same unsafe pattern – please add a guard instead of disabling the rule

The code is vulnerable to the same destructuring-from-undefined issue described in OrganizationMembership.ts. Apply a similar check to avoid a possible runtime crash.

-    const { data: paymentSources, total_count } =
-      res?.response as unknown as ClerkPaginatedResponse<CommercePaymentSourceJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+    if (!res?.response) {
+      throw new Error('Empty response while fetching payment sources');
+    }
+    const { data: paymentSources, total_count } =
+      res.response as ClerkPaginatedResponse<CommercePaymentSourceJSON>;
packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (1)

32-34: Guard against empty response instead of suppressing lint

Replicate the defensive check here; otherwise destructuring will explode if response is absent.

-      const { data: invites, total_count } =
-        res?.response as unknown as ClerkPaginatedResponse<UserOrganizationInvitationJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+      if (!res?.response) {
+        throw new Error('Empty response while retrieving organization invitations');
+      }
+      const { data: invites, total_count } =
+        res.response as ClerkPaginatedResponse<UserOrganizationInvitationJSON>;
packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (1)

34-36: Repeat of unsafe optional-chaining pattern

Same fix as previous comments – prefer explicit guard.

-      const { data: suggestions, total_count } =
-        res?.response as unknown as ClerkPaginatedResponse<OrganizationSuggestionJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+      if (!res?.response) {
+        throw new Error('Empty response while retrieving organization suggestions');
+      }
+      const { data: suggestions, total_count } =
+        res.response as ClerkPaginatedResponse<OrganizationSuggestionJSON>;
packages/clerk-js/src/core/resources/Organization.ts (5)

124-126: Same unsafe-destructuring issue as above – apply the guard pattern here as well.


153-155: Same unsafe-destructuring issue – needs guard.


175-176: Same unsafe-destructuring issue – needs guard.


198-199: Same unsafe-destructuring issue – needs guard.


247-248: Same unsafe-destructuring issue – needs guard.

packages/react/package.json (1)

73-73: New OXLint script added Matches the pattern established in other packages.

packages/dev-cli/package.json (1)

23-23: New OXLint script added Matches the pattern established in other packages.

packages/expo-passkeys/package.json (1)

29-29: New OXLint script added Matches the pattern established in other packages.

packages/nuxt/package.json (1)

64-64: New OXLint script added Matches the pattern established in other packages.

🧹 Nitpick comments (12)
packages/clerk-js/headless/index.js (1)

1-1: Verify OXlint directive validity.
The comment uses oxlint-disable-next-line; confirm that OXLint recognizes this syntax and that ESLint still enforces or ignores it as intended. If needed, mirror it with an eslint-disable-next-line for consistent suppression across both linters.

packages/clerk-js/no-rhc/index.js (1)

1-1: Ensure consistent linter disable directives.
This file uses oxlint-disable-next-line to silence the TS import rule. Confirm OXLint support and consider adding a matching eslint-disable-next-line to maintain parallel behavior during the transition.

packages/backend/src/runtime/node/crypto.js (1)

1-1: Align disable directives for both linters.
Here you’ve used eslint-disable-next-line but not oxlint-disable-next-line. To ensure OXLint also skips this rule, add the corresponding OXlint directive or confirm your configuration maps ESLint disables automatically.

packages/clerk-js/svgTransform.js (1)

2-2: Standardize linter suppression comments.
You’ve added // oxlint-disable-line @typescript-eslint/no-require-imports alongside the existing ESLint suppression. Verify that both linters honor these, and consider documenting the pattern in CONTRIBUTING or your lint config to keep it uniform across packages.

packages/clerk-js/src/utils/url.ts (1)

245-252: Duplicate null-byte check & regex may be simplified

/\0/ is already covered by the broader /[\x00-\x1F]/ control-character pattern below, so the extra entry (and the oxlint disable) is redundant. Removing it keeps the list compact and avoids maintaining two suppressions.

🧰 Tools
🪛 Biome (1.9.4)

[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)


[error] 251-251: Unexpected control character in a regular expression.

Control characters are unusual and potentially incorrect inputs, so they are disallowed.

(lint/suspicious/noControlCharactersInRegex)

packages/localizations/package.json (1)

104-106: Verify script naming consistency across packages

Most packages now expose both lint and lint:oxlint.
lint:attw sits between them here, while in several sibling packages it appears after lint:oxlint.
Consistent ordering eases grep-ability and automated script harvesting; consider aligning the three scripts’ order across all package.jsons.

turbo.json (1)

105-124: Potential double hashing & execution of the same glob set

The newly-added lint task repeats almost the exact inputs list already present in lint:oxlint, yet its only job is to depend on lint:oxlint.
Turborepo will hash both tasks separately, doing the same glob walk twice.

Options:

  1. Remove the inputs array from lint (rely on the dependency’s cache), or
  2. Delete lint entirely and call turbo run lint:oxlint in CI.

This avoids redundant hashing and shaves a few hundred ms from every run.

packages/astro/src/react/controlComponents.tsx (1)

88-109: Minor naming: unauthorized / authorized

Variables are now unauthorized and authorized but authorized is never used besides an immediate return.
An inlined children/fallback would remove two indirections and save a reallocation each render.
Low-impact, but worth tidying.

.oxlintrc.json (4)

7-11: Consider explicit environments for Node and Browser

Current env settings (builtin, es2021, commonjs) may not cover certain globals (e.g., window, process). It may be safer to add "node": true and/or "browser": true depending on where files run.


12-40: Simplify and dedupe ignorePatterns

There are overlapping patterns (e.g., both .turbo and **/.turbo/*) and very specific ignores that could be consolidated. Consider grouping related paths or using globs more sparingly to improve maintainability.


41-240: Leverage an extends preset instead of inlining all rules

Listing every rule explicitly makes the config hard to maintain. If OXLint provides a recommended preset, you could extends it and only override your project’s exceptions.


314-381: Refactor large integration-test override

This massive block of globals and rule tweaks could be extracted into a separate config (e.g., oxlint.integration.json) to keep the main file focused. It would also make onboarding and future updates easier.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b23d4ae and dd2716a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (41)
  • .oxlintrc.json (1 hunks)
  • package.json (2 hunks)
  • packages/agent-toolkit/package.json (1 hunks)
  • packages/astro/package.json (1 hunks)
  • packages/astro/src/astro-components/control/ProtectCSR.astro (1 hunks)
  • packages/astro/src/react/controlComponents.tsx (4 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/runtime/node/crypto.js (1 hunks)
  • packages/chrome-extension/package.json (1 hunks)
  • packages/clerk-js/headless/index.js (1 hunks)
  • packages/clerk-js/no-rhc/index.js (1 hunks)
  • packages/clerk-js/package.json (1 hunks)
  • packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (3 hunks)
  • packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (1 hunks)
  • packages/clerk-js/src/core/resources/Organization.ts (6 hunks)
  • packages/clerk-js/src/core/resources/OrganizationMembership.ts (1 hunks)
  • packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (1 hunks)
  • packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (1 hunks)
  • packages/clerk-js/src/utils/url.ts (2 hunks)
  • packages/clerk-js/svgTransform.js (1 hunks)
  • packages/dev-cli/package.json (1 hunks)
  • packages/elements/package.json (1 hunks)
  • packages/expo-passkeys/package.json (1 hunks)
  • packages/expo/package.json (1 hunks)
  • packages/express/package.json (1 hunks)
  • packages/fastify/package.json (1 hunks)
  • packages/localizations/package.json (1 hunks)
  • packages/nextjs/package.json (1 hunks)
  • packages/nuxt/package.json (1 hunks)
  • packages/react-router/package.json (1 hunks)
  • packages/react/package.json (1 hunks)
  • packages/remix/package.json (1 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/scripts/postinstall.mjs (1 hunks)
  • packages/tanstack-react-start/package.json (1 hunks)
  • packages/testing/package.json (1 hunks)
  • packages/themes/package.json (1 hunks)
  • packages/types/package.json (1 hunks)
  • packages/upgrade/package.json (1 hunks)
  • packages/vue/package.json (1 hunks)
  • turbo.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • UserOrganizationInvitationJSON (483-493)
packages/clerk-js/src/core/resources/OrganizationMembership.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationMembershipJSON (387-398)
packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • CommercePaymentSourceJSON (636-646)
packages/clerk-js/src/core/resources/OrganizationSuggestion.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (1)
  • OrganizationSuggestionJSON (464-471)
packages/clerk-js/src/core/resources/Organization.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (4)
  • OrganizationMembershipRequestJSON (473-481)
  • OrganizationMembershipJSON (387-398)
  • OrganizationInvitationJSON (400-411)
  • CommerceSubscriptionJSON (684-698)
packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts (2)
packages/types/src/pagination.ts (1)
  • ClerkPaginatedResponse (21-30)
packages/types/src/json.ts (2)
  • CommerceSubscriptionJSON (684-698)
  • CommerceStatementJSON (655-662)
⏰ Context from checks skipped due to timeout of 90000ms (20)
  • GitHub Check: Integration Tests (nextjs, chrome, 15)
  • GitHub Check: Integration Tests (nextjs, chrome, 14)
  • GitHub Check: Integration Tests (nextjs, chrome, 13)
  • GitHub Check: Integration Tests (react-router, chrome)
  • GitHub Check: Integration Tests (vue, chrome)
  • GitHub Check: Integration Tests (astro, chrome)
  • GitHub Check: Integration Tests (sessions, chrome)
  • GitHub Check: Integration Tests (tanstack-react-start, chrome)
  • GitHub Check: Integration Tests (nuxt, chrome)
  • GitHub Check: Integration Tests (billing, chrome)
  • GitHub Check: Integration Tests (tanstack-react-router, chrome)
  • GitHub Check: Integration Tests (expo-web, chrome)
  • GitHub Check: Integration Tests (ap-flows, chrome)
  • GitHub Check: Integration Tests (elements, chrome)
  • GitHub Check: Integration Tests (localhost, chrome)
  • GitHub Check: Integration Tests (quickstart, chrome)
  • GitHub Check: Integration Tests (express, chrome)
  • GitHub Check: Integration Tests (generic, chrome)
  • GitHub Check: Static analysis
  • GitHub Check: Unit Tests (22, **)
🔇 Additional comments (24)
packages/shared/scripts/postinstall.mjs (1)

52-52:

✅ Verification successful

Confirm Node version compatibility with parameter-less catch.
Using catch {} without an error binding requires Node >= 14.6.0. Verify your minimum supported Node version in the engines field.


🏁 Script executed:

#!/bin/bash
# Check the Node engine requirement in package.json
jq -r '.engines.node // "not specified"' package.json

Length of output: 65


No action needed: parameter-less catch is supported by Node ≥18.17.0
Your package.json already specifies
• engines.node: ">=18.17.0"
and Node 14.6.0+ added support for catch {} syntax, so this usage is safe.

package.json (1)

25-26: Lock oxlint to an explicitly tested version

Introducing oxlint is great 🎉. However, depending on ^1.0.0 means that any future 1.x release (1.1, 1.2, …) will be installed automatically and may introduce new rules or breaking changes that could suddenly fail CI.

-    "oxlint": "^1.0.0",
+    "oxlint": "1.0.0",

Pinning to the exact version keeps the toolchain deterministic; bump intentionally once the new version has been vetted.

Also applies to: 124-125

packages/shared/package.json (1)

137-138: Script addition looks good

"lint:oxlint": "oxlint --quiet src" mirrors the existing ESLint script and scopes linting to the package’s source – sensible default.

packages/nextjs/package.json (1)

69-70: Next.js package OXLint integration – OK

Consistent with other packages; no further comments.

packages/remix/package.json (1)

72-72: Add lint:oxlint script
Introduces OXLint alongside ESLint for faster linting of the src directory, matching the repo convention.

packages/elements/package.json (1)

68-68: Add lint:oxlint script
Aligns with other packages by enabling OXLint on src in quiet mode for consistent linting.

packages/backend/package.json (1)

98-98: Add lint:oxlint script
Enables quiet OXLint runs for backend sources, in line with the monorepo’s updated lint pipeline.

packages/types/package.json (1)

39-39: Add lint:oxlint script
Introduces OXLint for faster static checks in the types package, consistent with other workspace packages.

packages/themes/package.json (1)

38-39: Add lint:oxlint script and update comma
The comma after lint:attw is correctly added to maintain JSON validity, and lint:oxlint is introduced for standard OXLint usage.

packages/tanstack-react-start/package.json (1)

64-64: Add OXLint lint script
The new lint:oxlint script follows the established pattern and integrates Oxlint into this package’s workflow.

packages/react-router/package.json (1)

77-77: Add OXLint lint script
The lint:oxlint entry is correctly positioned after lint:attw and before lint:publint, matching other packages.

packages/clerk-js/package.json (1)

49-49: Add OXLint lint script
This update aligns the Clerk JS package with the new Oxlint setup across the monorepo.

packages/agent-toolkit/package.json (1)

44-44: Add OXLint lint script
The new script integrates Oxlint into the agent-toolkit package, consistent with the other packages.

packages/astro/package.json (1)

85-85: Add OXLint lint script
Including env.d.ts in the Oxlint invocation mirrors the existing ESLint configuration—good catch.

packages/chrome-extension/package.json (1)

43-43:

✅ Verification successful

New OXLint script added The lint:oxlint command is correctly integrated alongside ESLint. Ensure that oxlint is declared in the root devDependencies and properly hoisted into this workspace.

Run:


🏁 Script executed:

#!/bin/bash
# Verify that oxlint is declared in the root package.json
grep -R '"oxlint"' -n package.json

Length of output: 99


Approve: OXLint script and dependency are correctly configured

  • Verified that the root package.json declares "oxlint": "^1.0.0" in devDependencies (line 124), ensuring it’s hoisted into this workspace.

No further action required.

packages/expo/package.json (1)

75-75: Introduce lint:oxlint script
The new lint:oxlint script aligns with the monorepo’s linting workflow. Ensure that oxlint is added as a devDependency at the repository root and that a .oxlintrc.json config exists to standardize rules.

packages/vue/package.json (1)

53-53: Add lint:oxlint script
Consistently adds OXLint for the Vue package’s src directory.

packages/fastify/package.json (1)

60-60: Integrate OXLint script
Adds lint:oxlint to run OXLint on src in the Fastify package.

packages/express/package.json (1)

62-62: Add OXLint to Express package
The lint:oxlint script is correctly added to lint the src directory quietly.

packages/upgrade/package.json (1)

23-23: Introduce lint:oxlint script
Adds OXLint linting support for the upgrade package’s source files.

packages/astro/src/react/controlComponents.tsx (1)

62-70: Unnecessary fragment removal is fine — but mind whitespace

Removing the fragment means literal whitespace/newlines around {children} become text nodes.
React usually collapses them, yet in tight layout components this can matter.
Double-check visual diffs for any spacing regressions.

.oxlintrc.json (3)

4-6: Verify disabling of the correctness category

You’ve globally turned off the entire correctness category, which may silence critical rule violations. Ensure this was intentional and that you’re still catching all needed error-prone patterns.


199-218: Verify the no-restricted-imports pattern hack

The entry using "group": ["!@clerk/shared/*"] is a non-standard workaround. Please confirm that OXLint’s import plugin supports negated patterns in this shape and that it behaves as expected.


278-283: Clarify the ES version override for TypeScript files

You’ve set es2018 specifically for all TS/CTS/TSX files even though the global env is es2021. This downgrade may disable syntax/features you intend to lint. Ensure this is by design.

Comment on lines 42 to 44
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>; // oxlint-disable-line no-unsafe-optional-chaining

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential runtime crash – destructuring from undefined is still possible

Disabling the lint rule masks the underlying danger: if _fetch ever resolves to undefined (or to an object without response), res?.response is undefined and destructuring will throw at runtime.
Prefer an explicit guard or non-null assertion rather than silencing the warning.

-      const { data: suggestions, total_count } =
-        res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>; // oxlint-disable-line no-unsafe-optional-chaining
+      if (!res?.response) {
+        throw new Error('Empty response while retrieving organization memberships');
+      }
+      const { data: suggestions, total_count } =
+        res.response as ClerkPaginatedResponse<OrganizationMembershipJSON>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>; // oxlint-disable-line no-unsafe-optional-chaining
if (!res?.response) {
throw new Error('Empty response while retrieving organization memberships');
}
const { data: suggestions, total_count } =
res.response as ClerkPaginatedResponse<OrganizationMembershipJSON>;
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/OrganizationMembership.ts around lines
42 to 44, the destructuring of `res?.response` can cause a runtime crash if
`res` or `res.response` is undefined. To fix this, add an explicit check to
ensure `res` and `res.response` are defined before destructuring, or use a
non-null assertion if you are certain the value is never null. Remove the lint
disable comment and handle the potential undefined case safely to prevent
runtime errors.

Comment on lines +101 to 103
// oxlint-disable-next-line no-unsafe-optional-chaining
const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not paper over no-unsafe-optional-chaining; harden the fetch logic

If res or res.response is missing, the destructuring will crash despite the cast.
Add a guard (or handle the error) instead of disabling the lint rule.

-      // oxlint-disable-next-line no-unsafe-optional-chaining
-      const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;
+      if (!res?.response) {
+        throw new Error('Empty response while retrieving roles');
+      }
+      const { data: roles, total_count } = res.response as ClerkPaginatedResponse<RoleJSON>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// oxlint-disable-next-line no-unsafe-optional-chaining
const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse<RoleJSON>;
if (!res?.response) {
throw new Error('Empty response while retrieving roles');
}
const { data: roles, total_count } = res.response as ClerkPaginatedResponse<RoleJSON>;
🤖 Prompt for AI Agents
In packages/clerk-js/src/core/resources/Organization.ts around lines 101 to 103,
the code disables the no-unsafe-optional-chaining lint rule and destructures
res?.response without checking if res or res.response exists, which can cause a
runtime crash. Fix this by adding a guard to verify that res and res.response
are defined before destructuring. If either is missing, handle the error or
return early to avoid unsafe access instead of casting and disabling the lint
rule.

Comment on lines +263 to +266
// Check for null bytes in pathname
if (url.pathname.includes('\0')) {
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Encoded %00 slips through the new null-byte guard

url.pathname.includes('\0') only matches the literal null character, but URL.pathname keeps percent-encodings (%00). An attacker could therefore bypass this check with /foo%00bar.

-  if (url.pathname.includes('\0')) {
+  const decodedPath = decodeURIComponent(url.pathname);
+  if (decodedPath.includes('\0')) {
     return true;
   }

Optionally, drop the dedicated check and rely on /[\x00-\x1F]/ after decoding to catch all control characters in one place.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Check for null bytes in pathname
if (url.pathname.includes('\0')) {
return true;
}
// Check for null bytes in pathname
const decodedPath = decodeURIComponent(url.pathname);
if (decodedPath.includes('\0')) {
return true;
}
🤖 Prompt for AI Agents
In packages/clerk-js/src/utils/url.ts around lines 263 to 266, the current check
for null bytes using url.pathname.includes('\0') misses encoded null bytes like
%00 because URL.pathname retains percent-encodings. To fix this, decode the
pathname before checking and replace the dedicated null byte check with a single
regex that detects all control characters (e.g., /[\x00-\x1F]/) on the decoded
pathname to catch both literal and encoded control characters.

Comment on lines 72 to 74
"lint": "eslint src",
"lint:oxlint": "oxlint --quiet src"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add oxlint to devDependencies for local script execution

"lint:oxlint": "oxlint --quiet src" assumes oxlint is available either globally or at the repo root.
Adding the binary to this package’s devDependencies (or using the workspace-root script via pnpm exec) avoids “command not found” issues when the package is worked on in isolation.

"devDependencies": {
+  "oxlint": "^1.0.0",
   "@playwright/test": "^1.44.0",
   "cypress": "^13.9.0"
},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"lint": "eslint src",
"lint:oxlint": "oxlint --quiet src"
},
"devDependencies": {
"oxlint": "^1.0.0",
"@playwright/test": "^1.44.0",
"cypress": "^13.9.0"
},
🤖 Prompt for AI Agents
In packages/testing/package.json around lines 72 to 74, the "lint:oxlint" script
uses the "oxlint" command without ensuring it is installed locally, which can
cause "command not found" errors when working in isolation. Add "oxlint" to the
devDependencies of this package to guarantee the binary is available locally, or
alternatively modify the script to run "pnpm exec oxlint --quiet src" to use the
workspace-root version safely.

Comment on lines +47 to 54
// oxlint-disable-next-line no-unused-expressions
isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden');
}

if (this.fallbackSlot) {
// oxlint-disable-next-line no-unused-expressions
isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', '');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace ternary side-effects with explicit if to drop the disable comment

Disabling no-unused-expressions hides a genuine readability smell.
Using an explicit if keeps the intent clear and lets the code pass both ESLint and Oxlint without suppression.

-// oxlint-disable-next-line no-unused-expressions
-isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden');
+if (isUnauthorized) {
+  this.defaultSlot.setAttribute('hidden', '');
+} else {
+  this.defaultSlot.removeAttribute('hidden');
+}
...
-// oxlint-disable-next-line no-unused-expressions
-isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', '');
+if (isUnauthorized) {
+  this.fallbackSlot.removeAttribute('hidden');
+} else {
+  this.fallbackSlot.setAttribute('hidden', '');
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// oxlint-disable-next-line no-unused-expressions
isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden');
}
if (this.fallbackSlot) {
// oxlint-disable-next-line no-unused-expressions
isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', '');
}
if (this.defaultSlot) {
if (isUnauthorized) {
this.defaultSlot.setAttribute('hidden', '');
} else {
this.defaultSlot.removeAttribute('hidden');
}
}
if (this.fallbackSlot) {
if (isUnauthorized) {
this.fallbackSlot.removeAttribute('hidden');
} else {
this.fallbackSlot.setAttribute('hidden', '');
}
}
🤖 Prompt for AI Agents
In packages/astro/src/astro-components/control/ProtectCSR.astro around lines 47
to 54, replace the ternary expressions used solely for side effects with
explicit if-else statements. This means using clear if conditions to call
setAttribute or removeAttribute instead of the current ternary operators, which
improves readability and removes the need for disabling the
no-unused-expressions lint rule.

Comment on lines +52 to 60
export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactNode => {
const isLoaded = useSafeIsLoaded();

if (!isLoaded) {
return null;
}

return <>{children}</>;
return children;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Return type should be React.ReactElement | null, not React.ReactNode

A React component must return a React element (or null).
Allowing any ReactNode widens the type and enables returning primitives (string, number) accidentally, which React will render but breaks wrapper utilities (cloneElement, isValidElement, etc.).

-export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactNode => {
+export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactElement | null => {

Apply the same change to ClerkLoading and Protect.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactNode => {
const isLoaded = useSafeIsLoaded();
if (!isLoaded) {
return null;
}
return <>{children}</>;
return children;
};
export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactElement | null => {
const isLoaded = useSafeIsLoaded();
if (!isLoaded) {
return null;
}
return children;
};
🤖 Prompt for AI Agents
In packages/astro/src/react/controlComponents.tsx around lines 52 to 60, change
the return type of the ClerkLoaded component from React.ReactNode to
React.ReactElement | null to ensure it only returns a valid React element or
null. Also, apply this same return type change to the ClerkLoading and Protect
components to prevent returning primitives and maintain compatibility with React
utilities like cloneElement and isValidElement.

@@ -137,7 +142,7 @@
({ clerk, ...handleRedirectCallbackParams }: WithClerkProp<HandleOAuthCallbackParams>) => {
React.useEffect(() => {
void clerk?.handleRedirectCallback(handleRedirectCallbackParams);
}, []);
}, []); // eslint-disable-line react-hooks/exhaustive-deps
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid blanket disable of react-hooks/exhaustive-deps

Instead of disabling the rule, list the actual stable deps (clerk, those in handleRedirectCallbackParams).
If they’re intentionally omitted, add a brief comment why re-invocation is undesired; this helps future maintainers.

-}, []); // eslint-disable-line react-hooks/exhaustive-deps
+// `clerk` is stable (ClerkProvider guarantees identity) and callback params are
+// static at mount, so we run once intentionally.
+}, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
}, []); // eslint-disable-line react-hooks/exhaustive-deps
// `clerk` is stable (ClerkProvider guarantees identity) and callback params are
// static at mount, so we run once intentionally.
}, []);
🤖 Prompt for AI Agents
In packages/astro/src/react/controlComponents.tsx at line 145, avoid disabling
the react-hooks/exhaustive-deps rule with a blanket comment. Instead, explicitly
list all stable dependencies such as `clerk` and any variables used inside
`handleRedirectCallbackParams` in the dependency array. If some dependencies are
intentionally omitted to prevent unwanted re-invocation, add a clear comment
explaining this decision for future maintainers.

@@ -0,0 +1,431 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript", "import", "jsx-a11y", "react", "unicorn"],
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Critical: Missing react-hooks plugin

You’ve enabled react-hooks/rules-of-hooks and react-hooks/exhaustive-deps without declaring the react-hooks plugin. Those rules won’t be applied unless you add "react-hooks" to your plugins list.

🤖 Prompt for AI Agents
In .oxlintrc.json at line 3, the "react-hooks" plugin is missing from the
plugins array, which prevents the react-hooks rules from being applied. Add
"react-hooks" to the plugins list alongside the existing plugins to enable those
rules properly.

@@ -40,7 +40,7 @@ export class OrganizationMembership extends BaseResource implements Organization
}).then(res => {
// TODO: Fix typing
const { data: suggestions, total_count } =
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>;
res?.response as unknown as ClerkPaginatedResponse<OrganizationMembershipJSON>; // oxlint-disable-line no-unsafe-optional-chaining
Copy link
Member

Choose a reason for hiding this comment

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

should we maybe make this rule a warning (perhaps specifically for clerk-js) instead of silencing it?

Copy link
Member Author

Choose a reason for hiding this comment

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

@dstaley The reason I took this approach is because our warnings have been piling up. Setting this rule to warn in general would, IMHO, likely have a greater chance of this error being introduced in future code vs outright failing.

@@ -102,6 +102,27 @@
"cache": false
},
"lint": {
"dependsOn": ["lint:oxlint"],
Copy link
Member

Choose a reason for hiding this comment

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

the approach we took for vitest in clerk-js was to update the lint task to run both jest and vitest. not saying we should do it that way here, just offering it in the event that sounds better than creating a new turbo task

Copy link
Member Author

Choose a reason for hiding this comment

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

I kinda like that we can cache these individually and, I feel, that it enforces a generic interface (turbo) with which we run commands.

Copy link
Member

@dstaley dstaley left a comment

Choose a reason for hiding this comment

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

you love to see it 🎉

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